Working person treeview, insert/add/delete still todo
read/write db, make sure unicode or utf8, nothing else! svn: r19966
This commit is contained in:
parent
0b8d0a1a95
commit
9da71185a6
@ -58,7 +58,7 @@ from gen.lib import (MediaObject, Person, Family, Source, Citation, Event,
|
|||||||
NameOriginType)
|
NameOriginType)
|
||||||
from gen.db.dbconst import *
|
from gen.db.dbconst import *
|
||||||
from gen.utils.callback import Callback
|
from gen.utils.callback import Callback
|
||||||
from gen.utils.cast import conv_dbstr_to_unicode, conv_unicode_tosrtkey
|
from gen.utils.cast import conv_dbstr_to_unicode
|
||||||
from gen.db import (BsddbBaseCursor, DbReadBase)
|
from gen.db import (BsddbBaseCursor, DbReadBase)
|
||||||
from gen.utils.id import create_id
|
from gen.utils.id import create_id
|
||||||
from gen.errors import DbError
|
from gen.errors import DbError
|
||||||
@ -826,10 +826,10 @@ class DbBsddbRead(DbReadBase, Callback):
|
|||||||
Return type is a unicode object
|
Return type is a unicode object
|
||||||
"""
|
"""
|
||||||
if isinstance(surname, unicode):
|
if isinstance(surname, unicode):
|
||||||
ssurname = conv_unicode_tosrtkey(surname)
|
ssurname = surname.encode('utf-8')
|
||||||
return unicode(self.name_group.get(ssurname, ssurname), 'utf-8')
|
return conv_dbstr_to_unicode(self.name_group.get(ssurname, ssurname))
|
||||||
else:
|
else:
|
||||||
return unicode(self.name_group.get(surname, surname), 'utf-8')
|
return conv_dbstr_to_unicode(self.name_group.get(surname, surname))
|
||||||
|
|
||||||
def get_name_group_keys(self):
|
def get_name_group_keys(self):
|
||||||
"""
|
"""
|
||||||
@ -844,7 +844,7 @@ class DbBsddbRead(DbReadBase, Callback):
|
|||||||
# The use of has_key seems allright because there is no write lock
|
# The use of has_key seems allright because there is no write lock
|
||||||
# on the name_group table when this is called.
|
# on the name_group table when this is called.
|
||||||
if isinstance(name, unicode):
|
if isinstance(name, unicode):
|
||||||
return self.name_group.has_key(conv_unicode_tosrtkey(name))
|
return self.name_group.has_key(name.encode('utf-8'))
|
||||||
else:
|
else:
|
||||||
return self.name_group.has_key(name)
|
return self.name_group.has_key(name)
|
||||||
|
|
||||||
|
@ -62,8 +62,7 @@ from gen.db import (DbBsddbRead, DbWriteBase, BSDDBTxn,
|
|||||||
find_surname_name, DbUndoBSDDB as DbUndo)
|
find_surname_name, DbUndoBSDDB as DbUndo)
|
||||||
from gen.db.dbconst import *
|
from gen.db.dbconst import *
|
||||||
from gen.utils.callback import Callback
|
from gen.utils.callback import Callback
|
||||||
from gen.utils.cast import (conv_unicode_tosrtkey_ongtk, conv_dbstr_to_unicode,
|
from gen.utils.cast import (conv_unicode_tosrtkey_ongtk, conv_dbstr_to_unicode)
|
||||||
conv_unicode_tosrtkey)
|
|
||||||
from gen.updatecallback import UpdateCallback
|
from gen.updatecallback import UpdateCallback
|
||||||
from gen.errors import DbError
|
from gen.errors import DbError
|
||||||
from gen.constfunc import win
|
from gen.constfunc import win
|
||||||
@ -1416,7 +1415,7 @@ class DbBsddb(DbBsddbRead, DbWriteBase, UpdateCallback):
|
|||||||
if not self.readonly:
|
if not self.readonly:
|
||||||
# Start transaction
|
# Start transaction
|
||||||
with BSDDBTxn(self.env, self.name_group) as txn:
|
with BSDDBTxn(self.env, self.name_group) as txn:
|
||||||
sname = conv_unicode_tosrtkey(name)
|
sname = name.encode('utf-8')
|
||||||
data = txn.get(sname)
|
data = txn.get(sname)
|
||||||
if data is not None:
|
if data is not None:
|
||||||
txn.delete(sname)
|
txn.delete(sname)
|
||||||
|
@ -107,9 +107,9 @@ class Name(SecondaryObject, PrivacyBase, SurnameBase, CitationBase, NoteBase,
|
|||||||
self.group_as = ""
|
self.group_as = ""
|
||||||
self.sort_as = self.DEF
|
self.sort_as = self.DEF
|
||||||
self.display_as = self.DEF
|
self.display_as = self.DEF
|
||||||
self.call = u''
|
self.call = ""
|
||||||
self.nick = u''
|
self.nick = ""
|
||||||
self.famnick = u''
|
self.famnick = ""
|
||||||
|
|
||||||
def serialize(self):
|
def serialize(self):
|
||||||
"""
|
"""
|
||||||
@ -130,9 +130,9 @@ class Name(SecondaryObject, PrivacyBase, SurnameBase, CitationBase, NoteBase,
|
|||||||
"""
|
"""
|
||||||
Indicate if the name is empty.
|
Indicate if the name is empty.
|
||||||
"""
|
"""
|
||||||
namefieldsempty = (self.first_name == u"" and
|
namefieldsempty = (self.first_name == "" and
|
||||||
self.suffix == u"" and self.title == u"" and self.nick ==u""
|
self.suffix == "" and self.title == "" and self.nick == ""
|
||||||
and self.famnick == u"")
|
and self.famnick == "")
|
||||||
surnamefieldsempty = not (False in
|
surnamefieldsempty = not (False in
|
||||||
[surn.is_empty() for surn in self.surname_list])
|
[surn.is_empty() for surn in self.surname_list])
|
||||||
return namefieldsempty and surnamefieldsempty
|
return namefieldsempty and surnamefieldsempty
|
||||||
|
@ -48,6 +48,9 @@ conv_unicode_tosrtkey = lambda x: locale.strxfrm(x.encode('utf-8', 'replace'))
|
|||||||
conv_unicode_tosrtkey_ongtk = lambda x: locale.strxfrm(x.encode(
|
conv_unicode_tosrtkey_ongtk = lambda x: locale.strxfrm(x.encode(
|
||||||
codeset, 'replace'))
|
codeset, 'replace'))
|
||||||
|
|
||||||
|
conv_str_tosrtkey_ongtk = lambda x: locale.strxfrm(unicode(x,'utf-8').encode(
|
||||||
|
codeset, 'replace'))
|
||||||
|
|
||||||
conv_dbstr_to_unicode = lambda x: unicode(x, 'utf-8')
|
conv_dbstr_to_unicode = lambda x: unicode(x, 'utf-8')
|
||||||
|
|
||||||
def cast_to_bool(val):
|
def cast_to_bool(val):
|
||||||
|
@ -378,8 +378,9 @@ class ListView(NavigationView):
|
|||||||
|
|
||||||
if self.type_list() == LISTFLAT:
|
if self.type_list() == LISTFLAT:
|
||||||
# Flat
|
# Flat
|
||||||
|
iter = self.model.nodemap.new_iter(handle)
|
||||||
try:
|
try:
|
||||||
path = self.model.on_get_path(handle)
|
path = self.model.do_get_path(iter)
|
||||||
except:
|
except:
|
||||||
path = None
|
path = None
|
||||||
else:
|
else:
|
||||||
@ -387,15 +388,17 @@ class ListView(NavigationView):
|
|||||||
path = None
|
path = None
|
||||||
node = self.model.get_node(handle)
|
node = self.model.get_node(handle)
|
||||||
if node:
|
if node:
|
||||||
parent_node = self.model.on_iter_parent(node)
|
iter = self.model.get_iter(node)
|
||||||
if parent_node:
|
has_parent, parent_iter = self.model.do_iter_parent(iter)
|
||||||
parent_path = self.model.on_get_path(parent_node)
|
if has_parent:
|
||||||
|
parent_path = self.model.do_get_path(parent_iter)
|
||||||
if parent_path:
|
if parent_path:
|
||||||
for i in range(len(parent_path)):
|
parent_path_list = parent_path.get_indices()
|
||||||
|
for i in range(len(parent_path_list)):
|
||||||
expand_path = Gtk.TreePath(
|
expand_path = Gtk.TreePath(
|
||||||
tuple([x for x in parent_path[:i+1]]))
|
tuple([x for x in parent_path_list[:i+1]]))
|
||||||
self.list.expand_row(expand_path, False)
|
self.list.expand_row(expand_path, False)
|
||||||
path = self.model.on_get_path(node)
|
path = self.model.do_get_path(iter)
|
||||||
|
|
||||||
if path is not None:
|
if path is not None:
|
||||||
self.selection.unselect_all()
|
self.selection.unselect_all()
|
||||||
@ -535,11 +538,14 @@ class ListView(NavigationView):
|
|||||||
if not prompt:
|
if not prompt:
|
||||||
self.uistate.set_busy_cursor(0)
|
self.uistate.set_busy_cursor(0)
|
||||||
|
|
||||||
def blist(self, store, path, node, sel_list):
|
def blist(self, store, path, iter, sel_list):
|
||||||
if store.get_flags() & Gtk.TreeModelFlags.LIST_ONLY:
|
'''GtkTreeSelectionForeachFunc
|
||||||
handle = store.get_value(node, self.handle_col)
|
construct a list sel_list with all selected handles
|
||||||
|
'''
|
||||||
|
if store.do_get_flags() & Gtk.TreeModelFlags.LIST_ONLY:
|
||||||
|
handle = store.node_map.get_handle(path)
|
||||||
else:
|
else:
|
||||||
handle = store.get_handle(store.on_get_iter(path))
|
handle = store.get_handle(store.get_node_from_iter(iter))
|
||||||
|
|
||||||
if handle is not None:
|
if handle is not None:
|
||||||
sel_list.append(handle)
|
sel_list.append(handle)
|
||||||
@ -756,7 +762,8 @@ class ListView(NavigationView):
|
|||||||
store, paths = self.selection.get_selected_rows()
|
store, paths = self.selection.get_selected_rows()
|
||||||
if paths:
|
if paths:
|
||||||
firstsel = paths[0]
|
firstsel = paths[0]
|
||||||
firstnode = self.model.on_get_iter(firstsel)
|
firstnode = self.model.get_node_from_iter(
|
||||||
|
self.model.do_get_iter(firstsel)[1])
|
||||||
if len(paths)==1 and firstnode.handle is None:
|
if len(paths)==1 and firstnode.handle is None:
|
||||||
return self.expand_collapse_tree_branch()
|
return self.expand_collapse_tree_branch()
|
||||||
else:
|
else:
|
||||||
@ -832,7 +839,8 @@ class ListView(NavigationView):
|
|||||||
store, paths = self.selection.get_selected_rows()
|
store, paths = self.selection.get_selected_rows()
|
||||||
if paths:
|
if paths:
|
||||||
firstsel = paths[0]
|
firstsel = paths[0]
|
||||||
firstnode = self.model.on_get_iter(firstsel)
|
firstnode = self.model.get_node_from_iter(
|
||||||
|
self.model.do_get_iter(firstsel)[1])
|
||||||
if len(paths) == 1 and firstnode.handle is None:
|
if len(paths) == 1 and firstnode.handle is None:
|
||||||
return self.expand_collapse_tree_branch()
|
return self.expand_collapse_tree_branch()
|
||||||
else:
|
else:
|
||||||
@ -840,7 +848,8 @@ class ListView(NavigationView):
|
|||||||
store, paths = self.selection.get_selected_rows()
|
store, paths = self.selection.get_selected_rows()
|
||||||
if paths:
|
if paths:
|
||||||
firstsel = paths[0]
|
firstsel = paths[0]
|
||||||
firstnode = self.model.on_get_iter(firstsel)
|
firstnode = self.model.get_node_from_iter(
|
||||||
|
self.model.do_get_iter(firstsel)[1])
|
||||||
if len(paths) == 1 and firstnode.handle is None:
|
if len(paths) == 1 and firstnode.handle is None:
|
||||||
return self.expand_collapse_tree()
|
return self.expand_collapse_tree()
|
||||||
else:
|
else:
|
||||||
@ -857,7 +866,8 @@ class ListView(NavigationView):
|
|||||||
store, paths = self.selection.get_selected_rows()
|
store, paths = self.selection.get_selected_rows()
|
||||||
if paths:
|
if paths:
|
||||||
firstsel = paths[0]
|
firstsel = paths[0]
|
||||||
firstnode = self.model.on_get_iter(firstsel)
|
firstnode = self.model.get_node_from_iter(
|
||||||
|
self.model.do_get_iter(firstsel)[1])
|
||||||
if firstnode.handle:
|
if firstnode.handle:
|
||||||
return False
|
return False
|
||||||
if self.list.row_expanded(firstsel):
|
if self.list.row_expanded(firstsel):
|
||||||
@ -875,7 +885,8 @@ class ListView(NavigationView):
|
|||||||
store, paths = self.selection.get_selected_rows()
|
store, paths = self.selection.get_selected_rows()
|
||||||
if paths:
|
if paths:
|
||||||
firstsel = paths[0]
|
firstsel = paths[0]
|
||||||
firstnode = self.model.on_get_iter(firstsel)
|
firstnode = self.model.get_node_from_iter(
|
||||||
|
self.model.do_get_iter(firstsel)[1])
|
||||||
if firstnode.handle:
|
if firstnode.handle:
|
||||||
return False
|
return False
|
||||||
if self.list.row_expanded(firstsel):
|
if self.list.row_expanded(firstsel):
|
||||||
@ -996,7 +1007,7 @@ class ListView(NavigationView):
|
|||||||
ofile.end_row()
|
ofile.end_row()
|
||||||
else:
|
else:
|
||||||
# Tree model
|
# Tree model
|
||||||
node = self.model.on_get_iter((0,))
|
node = self.model.get_node_from_iter(self.model.do_get_iter((0,))[1])
|
||||||
self.write_node(node, len(levels), [], ofile, data_cols)
|
self.write_node(node, len(levels), [], ofile, data_cols)
|
||||||
|
|
||||||
ofile.end_page()
|
ofile.end_page()
|
||||||
@ -1006,18 +1017,20 @@ class ListView(NavigationView):
|
|||||||
if node is None:
|
if node is None:
|
||||||
return
|
return
|
||||||
while node is not None:
|
while node is not None:
|
||||||
new_level = level + [self.model.on_get_value(node, 0)]
|
new_level = level + [self.model.do_get_value(node, 0)]
|
||||||
if self.model.get_handle(node):
|
if self.model.get_handle(node):
|
||||||
ofile.start_row()
|
ofile.start_row()
|
||||||
padded_level = new_level + [''] * (depth - len(new_level))
|
padded_level = new_level + [''] * (depth - len(new_level))
|
||||||
map(ofile.write_cell, padded_level)
|
map(ofile.write_cell, padded_level)
|
||||||
for index in data_cols:
|
for index in data_cols:
|
||||||
ofile.write_cell(self.model.on_get_value(node, index))
|
ofile.write_cell(self.model.do_get_value(node, index))
|
||||||
ofile.end_row()
|
ofile.end_row()
|
||||||
|
|
||||||
first_child = self.model.on_iter_children(node)
|
has_child, first_child = self.model.do_iter_children(node)
|
||||||
self.write_node(first_child, depth, new_level, ofile, data_cols)
|
self.write_node(first_child, depth, new_level, ofile, data_cols)
|
||||||
node = self.model.on_iter_next(node)
|
has_next = self.model.do_iter_next(node)
|
||||||
|
if not has_next:
|
||||||
|
node = None
|
||||||
|
|
||||||
####################################################################
|
####################################################################
|
||||||
# Template functions
|
# Template functions
|
||||||
|
@ -151,15 +151,14 @@ class FlatNodeMap(object):
|
|||||||
Reverse sets up how the path is determined from the index. If True the
|
Reverse sets up how the path is determined from the index. If True the
|
||||||
first index is the last path
|
first index is the last path
|
||||||
|
|
||||||
:param index2hndllist: the ascending sorted (sortkey, handle, iter) values
|
:param index2hndllist: the ascending sorted (sortkey, handle) values
|
||||||
as they will appear in the flat treeview. This often is
|
as they will appear in the flat treeview. This often is
|
||||||
a subset of all possible data.
|
a subset of all possible data.
|
||||||
Set iter=None, it will be set internally
|
|
||||||
:type index2hndllist: a list of (sortkey, handle) tuples
|
:type index2hndllist: a list of (sortkey, handle) tuples
|
||||||
:param fullhndllist: the list of all possilbe ascending sorted
|
:param fullhndllist: the list of all possilbe ascending sorted
|
||||||
[sortkey, handle, iter] values as they will appear in the flat
|
(sortkey, handle) values as they will appear in the flat
|
||||||
treeview if all data is shown.
|
treeview if all data is shown.
|
||||||
:type fullhndllist: a list of (sortkey, handle, iter) tuples
|
:type fullhndllist: a list of (sortkey, handl) tuples
|
||||||
:param identical: identify if index2hndllist and fullhndllist are the
|
:param identical: identify if index2hndllist and fullhndllist are the
|
||||||
same list, so only one is kept in memory.
|
same list, so only one is kept in memory.
|
||||||
:type identical: bool
|
:type identical: bool
|
||||||
@ -446,7 +445,10 @@ class FlatBaseModel(GObject.Object, Gtk.TreeModel):
|
|||||||
#inheriting classes must set self.map to obtain the data
|
#inheriting classes must set self.map to obtain the data
|
||||||
self.prev_handle = None
|
self.prev_handle = None
|
||||||
self.prev_data = None
|
self.prev_data = None
|
||||||
|
|
||||||
|
#GTK3 We leak ref, yes??
|
||||||
#self.set_property("leak_references", False)
|
#self.set_property("leak_references", False)
|
||||||
|
|
||||||
self.db = db
|
self.db = db
|
||||||
#normally sort on first column, so scol=0
|
#normally sort on first column, so scol=0
|
||||||
if sort_map:
|
if sort_map:
|
||||||
@ -752,7 +754,7 @@ class FlatBaseModel(GObject.Object, Gtk.TreeModel):
|
|||||||
data = self.map(str(handle))
|
data = self.map(str(handle))
|
||||||
if data is None:
|
if data is None:
|
||||||
#object is no longer present
|
#object is no longer present
|
||||||
return u''
|
return ''
|
||||||
self.prev_data = data
|
self.prev_data = data
|
||||||
self.prev_handle = handle
|
self.prev_handle = handle
|
||||||
val = self.fmap[col](self.prev_data)
|
val = self.fmap[col](self.prev_data)
|
||||||
@ -784,13 +786,14 @@ class FlatBaseModel(GObject.Object, Gtk.TreeModel):
|
|||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def do_iter_children(self, iter):
|
def do_iter_children(self, iterparent):
|
||||||
"""
|
"""
|
||||||
Return the first child of the node
|
Return the first child of the node
|
||||||
See Gtk.TreeModel
|
See Gtk.TreeModel
|
||||||
"""
|
"""
|
||||||
#print 'do_iter_children'
|
#print 'do_iter_children'
|
||||||
print 'ERROR: iter children, should not be called in flat base!!'
|
print 'ERROR: iter children, should not be called in flat base!!'
|
||||||
|
raise NotImplementedError
|
||||||
if handle is None and len(self.node_map):
|
if handle is None and len(self.node_map):
|
||||||
return self.node_map.get_first_handle()
|
return self.node_map.get_first_handle()
|
||||||
return None
|
return None
|
||||||
|
@ -90,7 +90,7 @@ class PeopleBaseModel(object):
|
|||||||
"""
|
"""
|
||||||
Basic Model interface to handle the PersonViews
|
Basic Model interface to handle the PersonViews
|
||||||
"""
|
"""
|
||||||
_GENDER = [ _(u'female'), _(u'male'), _(u'unknown') ]
|
_GENDER = [ _('female'), _('male'), _('unknown') ]
|
||||||
|
|
||||||
# The following is accessed from the Person Selector
|
# The following is accessed from the Person Selector
|
||||||
COLUMN_INT_ID = 10 # dynamic calculation of column indices
|
COLUMN_INT_ID = 10 # dynamic calculation of column indices
|
||||||
@ -191,7 +191,11 @@ class PeopleBaseModel(object):
|
|||||||
return len(self.fmap)+1
|
return len(self.fmap)+1
|
||||||
|
|
||||||
def sort_name(self, data):
|
def sort_name(self, data):
|
||||||
return name_displayer.raw_sorted_name(data[COLUMN_NAME])
|
name = name_displayer.raw_sorted_name(data[COLUMN_NAME])
|
||||||
|
# internally we work with utf-8
|
||||||
|
if isinstance(name, unicode):
|
||||||
|
name = name.encode('utf-8')
|
||||||
|
return name
|
||||||
|
|
||||||
def column_name(self, data):
|
def column_name(self, data):
|
||||||
handle = data[0]
|
handle = data[0]
|
||||||
@ -199,6 +203,9 @@ class PeopleBaseModel(object):
|
|||||||
name = self.lru_name[handle]
|
name = self.lru_name[handle]
|
||||||
else:
|
else:
|
||||||
name = name_displayer.raw_display_name(data[COLUMN_NAME])
|
name = name_displayer.raw_display_name(data[COLUMN_NAME])
|
||||||
|
# internally we work with utf-8
|
||||||
|
if isinstance(name, unicode):
|
||||||
|
name = name.encode('utf-8')
|
||||||
if not self._in_build:
|
if not self._in_build:
|
||||||
self.lru_name[handle] = name
|
self.lru_name[handle] = name
|
||||||
return name
|
return name
|
||||||
@ -214,7 +221,7 @@ class PeopleBaseModel(object):
|
|||||||
return value
|
return value
|
||||||
|
|
||||||
def _get_spouse_data(self, data):
|
def _get_spouse_data(self, data):
|
||||||
spouses_names = u""
|
spouses_names = ""
|
||||||
for family_handle in data[COLUMN_FAMILY]:
|
for family_handle in data[COLUMN_FAMILY]:
|
||||||
family = self.db.get_family_from_handle(family_handle)
|
family = self.db.get_family_from_handle(family_handle)
|
||||||
for spouse_id in [family.get_father_handle(),
|
for spouse_id in [family.get_father_handle(),
|
||||||
@ -231,7 +238,7 @@ class PeopleBaseModel(object):
|
|||||||
|
|
||||||
def column_id(self, data):
|
def column_id(self, data):
|
||||||
return data[COLUMN_ID]
|
return data[COLUMN_ID]
|
||||||
|
|
||||||
def sort_change(self,data):
|
def sort_change(self,data):
|
||||||
return "%012x" % data[COLUMN_CHANGE]
|
return "%012x" % data[COLUMN_CHANGE]
|
||||||
|
|
||||||
@ -274,7 +281,7 @@ class PeopleBaseModel(object):
|
|||||||
else:
|
else:
|
||||||
return retval
|
return retval
|
||||||
except:
|
except:
|
||||||
return u''
|
return ''
|
||||||
|
|
||||||
for event_ref in data[COLUMN_EVENT]:
|
for event_ref in data[COLUMN_EVENT]:
|
||||||
er = EventRef()
|
er = EventRef()
|
||||||
@ -288,13 +295,13 @@ class PeopleBaseModel(object):
|
|||||||
if sort_mode:
|
if sort_mode:
|
||||||
retval = "%09d" % event.get_date_object().get_sort_value()
|
retval = "%09d" % event.get_date_object().get_sort_value()
|
||||||
else:
|
else:
|
||||||
retval = u"<i>%s</i>" % cgi.escape(date_str)
|
retval = "<i>%s</i>" % cgi.escape(date_str)
|
||||||
if not gen.datehandler.get_date_valid(event):
|
if not gen.datehandler.get_date_valid(event):
|
||||||
return invalid_date_format % retval
|
return invalid_date_format % retval
|
||||||
else:
|
else:
|
||||||
return retval
|
return retval
|
||||||
|
|
||||||
return u""
|
return ""
|
||||||
|
|
||||||
def column_death_day(self, data):
|
def column_death_day(self, data):
|
||||||
handle = data[0]
|
handle = data[0]
|
||||||
@ -329,7 +336,7 @@ class PeopleBaseModel(object):
|
|||||||
else:
|
else:
|
||||||
return retval
|
return retval
|
||||||
except:
|
except:
|
||||||
return u''
|
return ''
|
||||||
|
|
||||||
for event_ref in data[COLUMN_EVENT]:
|
for event_ref in data[COLUMN_EVENT]:
|
||||||
er = EventRef()
|
er = EventRef()
|
||||||
@ -350,7 +357,7 @@ class PeopleBaseModel(object):
|
|||||||
return invalid_date_format % retval
|
return invalid_date_format % retval
|
||||||
else:
|
else:
|
||||||
return retval
|
return retval
|
||||||
return u""
|
return ""
|
||||||
|
|
||||||
def column_birth_place(self, data):
|
def column_birth_place(self, data):
|
||||||
index = data[COLUMN_BIRTH]
|
index = data[COLUMN_BIRTH]
|
||||||
@ -368,7 +375,7 @@ class PeopleBaseModel(object):
|
|||||||
if place_title:
|
if place_title:
|
||||||
return cgi.escape(place_title)
|
return cgi.escape(place_title)
|
||||||
except:
|
except:
|
||||||
return u''
|
return ''
|
||||||
|
|
||||||
for event_ref in data[COLUMN_EVENT]:
|
for event_ref in data[COLUMN_EVENT]:
|
||||||
er = EventRef()
|
er = EventRef()
|
||||||
@ -385,7 +392,7 @@ class PeopleBaseModel(object):
|
|||||||
if place_title:
|
if place_title:
|
||||||
return "<i>%s</i>" % cgi.escape(place_title)
|
return "<i>%s</i>" % cgi.escape(place_title)
|
||||||
|
|
||||||
return u""
|
return ""
|
||||||
|
|
||||||
def column_death_place(self, data):
|
def column_death_place(self, data):
|
||||||
index = data[COLUMN_DEATH]
|
index = data[COLUMN_DEATH]
|
||||||
@ -403,7 +410,7 @@ class PeopleBaseModel(object):
|
|||||||
if place_title:
|
if place_title:
|
||||||
return cgi.escape(place_title)
|
return cgi.escape(place_title)
|
||||||
except:
|
except:
|
||||||
return u''
|
return ''
|
||||||
|
|
||||||
for event_ref in data[COLUMN_EVENT]:
|
for event_ref in data[COLUMN_EVENT]:
|
||||||
er = EventRef()
|
er = EventRef()
|
||||||
@ -420,10 +427,10 @@ class PeopleBaseModel(object):
|
|||||||
place_title = place.get_title()
|
place_title = place.get_title()
|
||||||
if place_title != "":
|
if place_title != "":
|
||||||
return "<i>" + cgi.escape(place_title) + "</i>"
|
return "<i>" + cgi.escape(place_title) + "</i>"
|
||||||
return u""
|
return ""
|
||||||
|
|
||||||
def column_tooltip(self, data):
|
def column_tooltip(self, data):
|
||||||
return u'Person tooltip'
|
return 'Person tooltip'
|
||||||
|
|
||||||
def column_int_id(self, data):
|
def column_int_id(self, data):
|
||||||
return data[0]
|
return data[0]
|
||||||
@ -528,6 +535,8 @@ class PersonTreeModel(PeopleBaseModel, TreeBaseModel):
|
|||||||
|
|
||||||
name_data = data[COLUMN_NAME]
|
name_data = data[COLUMN_NAME]
|
||||||
group_name = ngn(self.db, name_data)
|
group_name = ngn(self.db, name_data)
|
||||||
|
if isinstance(group_name, unicode):
|
||||||
|
group_name = group_name.encode('utf-8')
|
||||||
sort_key = self.sort_func(data)
|
sort_key = self.sort_func(data)
|
||||||
|
|
||||||
#if group_name not in self.group_list:
|
#if group_name not in self.group_list:
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
# Copyright (C) 2000-2007 Donald N. Allingham
|
# Copyright (C) 2000-2007 Donald N. Allingham
|
||||||
# Copyright (C) 2009 Gary Burton
|
# Copyright (C) 2009 Gary Burton
|
||||||
# Copyright (C) 2009-2011 Nick Hall
|
# Copyright (C) 2009-2011 Nick Hall
|
||||||
# Copyright (C) 2009 Benny Malengier
|
# Copyright (C) 2009-2012 Benny Malengier
|
||||||
# Copyright (C) 2011 Tim G L lyons
|
# Copyright (C) 2011 Tim G L lyons
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify
|
# This program is free software; you can redistribute it and/or modify
|
||||||
@ -34,7 +34,7 @@ This module provides the model that is used for all hierarchical treeviews.
|
|||||||
# Standard python modules
|
# Standard python modules
|
||||||
#
|
#
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
from __future__ import with_statement
|
from __future__ import with_statement, print_function
|
||||||
import time
|
import time
|
||||||
import locale
|
import locale
|
||||||
from gen.ggettext import gettext as _
|
from gen.ggettext import gettext as _
|
||||||
@ -55,7 +55,7 @@ from gi.repository import Gtk
|
|||||||
# GRAMPS modules
|
# GRAMPS modules
|
||||||
#
|
#
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
from gen.utils.cast import conv_unicode_tosrtkey_ongtk
|
from gen.utils.cast import conv_str_tosrtkey_ongtk, conv_unicode_tosrtkey_ongtk
|
||||||
import gui.widgets.progressdialog as progressdlg
|
import gui.widgets.progressdialog as progressdlg
|
||||||
from lru import LRU
|
from lru import LRU
|
||||||
from bisect import bisect_right
|
from bisect import bisect_right
|
||||||
@ -87,10 +87,17 @@ class Node(object):
|
|||||||
'prev', 'next', 'children')#, '__weakref__')
|
'prev', 'next', 'children')#, '__weakref__')
|
||||||
|
|
||||||
def __init__(self, ref, parent, sortkey, handle, secondary):
|
def __init__(self, ref, parent, sortkey, handle, secondary):
|
||||||
self.name = sortkey
|
|
||||||
if sortkey:
|
if sortkey:
|
||||||
self.sortkey = map(conv_unicode_tosrtkey_ongtk, sortkey)
|
if isinstance(sortkey, unicode):
|
||||||
|
self.name = sortkey.encode('utf-8')
|
||||||
|
#sortkey must be localized sort, so
|
||||||
|
self.sortkey = conv_unicode_tosrtkey_ongtk(sortkey)
|
||||||
|
else:
|
||||||
|
self.name = sortkey
|
||||||
|
#sortkey must be localized sort, so
|
||||||
|
self.sortkey = conv_str_tosrtkey_ongtk(sortkey)
|
||||||
else:
|
else:
|
||||||
|
self.name = ''
|
||||||
self.sortkey = None
|
self.sortkey = None
|
||||||
self.ref = ref
|
self.ref = ref
|
||||||
self.handle = handle
|
self.handle = handle
|
||||||
@ -284,10 +291,15 @@ class TreeBaseModel(GObject.Object, Gtk.TreeModel):
|
|||||||
nrgroups = 1,
|
nrgroups = 1,
|
||||||
group_can_have_handle = False,
|
group_can_have_handle = False,
|
||||||
has_secondary=False):
|
has_secondary=False):
|
||||||
#TODO GTK3, first get flatbasemodel working !
|
|
||||||
raise NotImplementedError
|
|
||||||
cput = time.clock()
|
cput = time.clock()
|
||||||
GObject.GObject.__init__(self)
|
GObject.GObject.__init__(self)
|
||||||
|
#We create a stamp to recognize invalid iterators. From the docs:
|
||||||
|
#Set the stamp to be equal to your model's stamp, to mark the
|
||||||
|
#iterator as valid. When your model's structure changes, you should
|
||||||
|
#increment your model's stamp to mark all older iterators as invalid.
|
||||||
|
#They will be recognised as invalid because they will then have an
|
||||||
|
#incorrect stamp.
|
||||||
|
self.stamp = 0
|
||||||
#two unused attributes pesent to correspond to flatbasemodel
|
#two unused attributes pesent to correspond to flatbasemodel
|
||||||
self.prev_handle = None
|
self.prev_handle = None
|
||||||
self.prev_data = None
|
self.prev_data = None
|
||||||
@ -306,7 +318,9 @@ class TreeBaseModel(GObject.Object, Gtk.TreeModel):
|
|||||||
self.nodemap = NodeMap()
|
self.nodemap = NodeMap()
|
||||||
self.handle2node = {}
|
self.handle2node = {}
|
||||||
|
|
||||||
self.set_property("leak_references", False)
|
#GTK3 We leak ref, yes??
|
||||||
|
#self.set_property("leak_references", False)
|
||||||
|
|
||||||
#normally sort on first column, so scol=0
|
#normally sort on first column, so scol=0
|
||||||
if sort_map:
|
if sort_map:
|
||||||
#sort_map is the stored order of the columns and if they are
|
#sort_map is the stored order of the columns and if they are
|
||||||
@ -349,6 +363,7 @@ class TreeBaseModel(GObject.Object, Gtk.TreeModel):
|
|||||||
self.sort_func2 = None
|
self.sort_func2 = None
|
||||||
if self.nodemap:
|
if self.nodemap:
|
||||||
self.nodemap.destroy()
|
self.nodemap.destroy()
|
||||||
|
|
||||||
self.nodemap = None
|
self.nodemap = None
|
||||||
self.rebuild_data = None
|
self.rebuild_data = None
|
||||||
self._build_data = None
|
self._build_data = None
|
||||||
@ -422,10 +437,9 @@ class TreeBaseModel(GObject.Object, Gtk.TreeModel):
|
|||||||
"""
|
"""
|
||||||
Clear the data map.
|
Clear the data map.
|
||||||
"""
|
"""
|
||||||
#invalidate the iters within gtk
|
|
||||||
self.invalidate_iters()
|
|
||||||
self.tree.clear()
|
self.tree.clear()
|
||||||
self.handle2node.clear()
|
self.handle2node.clear()
|
||||||
|
self.stamp += 1
|
||||||
self.nodemap.clear()
|
self.nodemap.clear()
|
||||||
#start with creating the new iters
|
#start with creating the new iters
|
||||||
topnode = Node(None, None, None, None, False)
|
topnode = Node(None, None, None, None, False)
|
||||||
@ -450,7 +464,7 @@ class TreeBaseModel(GObject.Object, Gtk.TreeModel):
|
|||||||
if search[1]:
|
if search[1]:
|
||||||
# we have search[1] = (index, text_unicode, inversion)
|
# we have search[1] = (index, text_unicode, inversion)
|
||||||
col, text, inv = search[1]
|
col, text, inv = search[1]
|
||||||
func = lambda x: self._get_value(x, col) or u""
|
func = lambda x: self._get_value(x, col) or ""
|
||||||
if search[2]:
|
if search[2]:
|
||||||
self.search = ExactSearchFilter(func, text, inv)
|
self.search = ExactSearchFilter(func, text, inv)
|
||||||
else:
|
else:
|
||||||
@ -783,14 +797,39 @@ class TreeBaseModel(GObject.Object, Gtk.TreeModel):
|
|||||||
|
|
||||||
# If the node hasn't moved, all we need is to call row_changed.
|
# If the node hasn't moved, all we need is to call row_changed.
|
||||||
#self.row_changed(path, node)
|
#self.row_changed(path, node)
|
||||||
|
|
||||||
|
def new_iter(self, nodeid):
|
||||||
|
"""
|
||||||
|
Return a new iter containing the nodeid in the nodemap
|
||||||
|
"""
|
||||||
|
iter = Gtk.TreeIter()
|
||||||
|
iter.stamp = self.stamp
|
||||||
|
#user data should be an object, so we store the long as str
|
||||||
|
|
||||||
|
iter.user_data = str(nodeid)
|
||||||
|
return iter
|
||||||
|
|
||||||
|
def get_iter(self, node):
|
||||||
|
"""
|
||||||
|
Return an iter from the node.
|
||||||
|
iters are always created afresh
|
||||||
|
|
||||||
|
Will raise IndexError if the maps are not filled yet, or if it is empty.
|
||||||
|
Caller should take care of this if it allows calling with invalid path
|
||||||
|
|
||||||
|
:param path: node as it appears in the treeview
|
||||||
|
:type path: Node
|
||||||
|
"""
|
||||||
|
iter = self.new_iter(id(node))
|
||||||
|
return iter
|
||||||
|
|
||||||
def get_handle(self, node):
|
def get_handle(self, node):
|
||||||
"""
|
"""
|
||||||
Get the gramps handle for a node. Return None if the node does
|
Get the gramps handle for a node. Return None if the node does
|
||||||
not correspond to a gramps object.
|
not correspond to a gramps object.
|
||||||
"""
|
"""
|
||||||
return node.handle
|
return node.handle
|
||||||
|
|
||||||
def get_node(self, handle):
|
def get_node(self, handle):
|
||||||
"""
|
"""
|
||||||
Get the node for a handle.
|
Get the node for a handle.
|
||||||
@ -804,50 +843,57 @@ class TreeBaseModel(GObject.Object, Gtk.TreeModel):
|
|||||||
"""
|
"""
|
||||||
return self.on_get_path(self.get_node(handle))
|
return self.on_get_path(self.get_node(handle))
|
||||||
|
|
||||||
# The following implement the public interface of Gtk.GenericTreeModel
|
# The following implement the public interface of Gtk.TreeModel
|
||||||
|
|
||||||
def on_get_flags(self):
|
def do_get_flags(self):
|
||||||
"""
|
"""
|
||||||
See Gtk.GenericTreeModel
|
See Gtk.TreeModel
|
||||||
"""
|
"""
|
||||||
return Gtk.TreeModelFlags.ITERS_PERSIST
|
return 0 #Gtk.TreeModelFlags.ITERS_PERSIST
|
||||||
|
|
||||||
def on_get_n_columns(self):
|
def do_get_n_columns(self):
|
||||||
"""
|
"""
|
||||||
Return the number of columns. Must be implemented in the child objects
|
Return the number of columns. Must be implemented in the child objects
|
||||||
See Gtk.GenericTreeModel
|
See Gtk.TreeModel
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def on_get_column_type(self, index):
|
def do_get_column_type(self, index):
|
||||||
"""
|
"""
|
||||||
See Gtk.GenericTreeModel
|
See Gtk.TreeModel
|
||||||
"""
|
"""
|
||||||
if index == self._tooltip_column:
|
if index == self._tooltip_column:
|
||||||
return object
|
return object
|
||||||
return str
|
return str
|
||||||
|
|
||||||
def on_get_value(self, nodeid, col):
|
def do_get_value(self, iter, col):
|
||||||
"""
|
"""
|
||||||
See Gtk.GenericTreeModel
|
See Gtk.TreeModel
|
||||||
"""
|
"""
|
||||||
#print 'get_value', nodeid, col
|
nodeid = long(iter.user_data)
|
||||||
nodeid = id(nodeid)
|
|
||||||
node = self.nodemap.node(nodeid)
|
node = self.nodemap.node(nodeid)
|
||||||
if node.handle is None:
|
if node.handle is None:
|
||||||
# Header rows dont get the foreground color set
|
# Header rows dont get the foreground color set
|
||||||
if col == self.color_column():
|
if col == self.color_column():
|
||||||
return None
|
return "#000000000000"
|
||||||
|
|
||||||
# Return the node name for the first column
|
# Return the node name for the first column
|
||||||
if col == 0:
|
if col == 0:
|
||||||
return self.column_header(node)
|
return self.column_header(node)
|
||||||
|
else:
|
||||||
|
#no value to show in other header column
|
||||||
|
return ''
|
||||||
else:
|
else:
|
||||||
# return values for 'data' row, calling a function
|
# return values for 'data' row, calling a function
|
||||||
# according to column_defs table
|
# according to column_defs table
|
||||||
return self._get_value(node.handle, col, node.secondary)
|
val = self._get_value(node.handle, col, node.secondary)
|
||||||
|
#GTK 3 should convert unicode objects automatically, but this
|
||||||
|
# gives wrong column values, so we convert
|
||||||
|
if isinstance(val, unicode):
|
||||||
|
return val.encode('utf-8')
|
||||||
|
else:
|
||||||
|
return val
|
||||||
|
|
||||||
def _get_value(self, handle, col, secondary=False):
|
def _get_value(self, handle, col, secondary=False):
|
||||||
"""
|
"""
|
||||||
Returns the contents of a given column of a gramps object
|
Returns the contents of a given column of a gramps object
|
||||||
@ -864,29 +910,38 @@ class TreeBaseModel(GObject.Object, Gtk.TreeModel):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
if not secondary:
|
if not secondary:
|
||||||
return (self.fmap[col](data))
|
return self.fmap[col](data)
|
||||||
else:
|
else:
|
||||||
return (self.fmap2[col](data))
|
return self.fmap2[col](data)
|
||||||
except:
|
except:
|
||||||
return None
|
return ''
|
||||||
|
|
||||||
def on_get_iter(self, path):
|
def do_get_iter(self, path):
|
||||||
"""
|
"""
|
||||||
Returns a node from a given path.
|
Returns a node from a given path.
|
||||||
"""
|
"""
|
||||||
if not self.tree or not self.tree[None].children:
|
if not self.tree or not self.tree[None].children:
|
||||||
return None
|
return False, Gtk.TreeIter()
|
||||||
node = self.tree[None]
|
node = self.tree[None]
|
||||||
pathlist = list(path)
|
pathlist = path.get_indices()
|
||||||
for index in pathlist:
|
for index in pathlist:
|
||||||
_index = (-index - 1) if self.__reverse else index
|
_index = (-index - 1) if self.__reverse else index
|
||||||
node = self.nodemap.node(node.children[_index][1])
|
node = self.nodemap.node(node.children[_index][1])
|
||||||
return node
|
return True, self.get_iter(node)
|
||||||
|
|
||||||
def on_get_path(self, node):
|
def get_node_from_iter(self, iter):
|
||||||
|
if iter and iter.user_data:
|
||||||
|
return self.nodemap.node(long(iter.user_data))
|
||||||
|
else:
|
||||||
|
print ('Problem', iter, iter.user_data)
|
||||||
|
raise NotImplementedError
|
||||||
|
return None
|
||||||
|
|
||||||
|
def do_get_path(self, iter):
|
||||||
"""
|
"""
|
||||||
Returns a path from a given node.
|
Returns a path from a given node.
|
||||||
"""
|
"""
|
||||||
|
node = self.get_node_from_iter(iter)
|
||||||
pathlist = []
|
pathlist = []
|
||||||
while node.parent is not None:
|
while node.parent is not None:
|
||||||
parent = self.nodemap.node(node.parent)
|
parent = self.nodemap.node(node.parent)
|
||||||
@ -901,62 +956,79 @@ class TreeBaseModel(GObject.Object, Gtk.TreeModel):
|
|||||||
|
|
||||||
if pathlist is not None:
|
if pathlist is not None:
|
||||||
pathlist.reverse()
|
pathlist.reverse()
|
||||||
return tuple(pathlist)
|
return Gtk.TreePath(tuple(pathlist))
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def on_iter_next(self, node):
|
def do_iter_next(self, iter):
|
||||||
"""
|
"""
|
||||||
|
Sets iter to the next node at this level of the tree
|
||||||
|
See Gtk.TreeModel
|
||||||
Get the next node with the same parent as the given node.
|
Get the next node with the same parent as the given node.
|
||||||
"""
|
"""
|
||||||
|
node = self.get_node_from_iter(iter)
|
||||||
val = node.prev if self.__reverse else node.next
|
val = node.prev if self.__reverse else node.next
|
||||||
return val and self.nodemap.node(val)
|
if val:
|
||||||
|
#user_data contains the nodeid
|
||||||
|
iter.user_data = str(val)
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
def on_iter_children(self, node):
|
def do_iter_children(self, iterparent):
|
||||||
"""
|
"""
|
||||||
Get the first child of the given node.
|
Get the first child of the given node.
|
||||||
"""
|
"""
|
||||||
if node is None:
|
if iterparent is None:
|
||||||
node = self.tree[None]
|
nodeid = id(self.tree[None])
|
||||||
if node.children:
|
|
||||||
return self.nodemap.node(
|
|
||||||
node.children[-1 if self.__reverse else 0][1])
|
|
||||||
else:
|
else:
|
||||||
return None
|
nodeparent = self.get_node_from_iter(iterparent)
|
||||||
|
if nodeparent.children:
|
||||||
|
nodeid = nodeparent.children[-1 if self.__reverse else 0][1]
|
||||||
|
else:
|
||||||
|
return False, None
|
||||||
|
return True, self.new_iter(nodeid)
|
||||||
|
|
||||||
def on_iter_has_child(self, node):
|
def do_iter_has_child(self, iter):
|
||||||
"""
|
"""
|
||||||
Find if the given node has any children.
|
Find if the given node has any children.
|
||||||
"""
|
"""
|
||||||
if node is None:
|
node = self.get_node_from_iter(iter)
|
||||||
node = self.tree[None]
|
|
||||||
return True if node.children else False
|
return True if node.children else False
|
||||||
|
|
||||||
def on_iter_n_children(self, node):
|
def do_iter_n_children(self, iter):
|
||||||
"""
|
"""
|
||||||
Get the number of children of the given node.
|
Get the number of children of the given node.
|
||||||
"""
|
"""
|
||||||
if node is None:
|
if iter is None:
|
||||||
node = self.tree[None]
|
node = self.tree[None]
|
||||||
|
else:
|
||||||
|
node = self.get_node_from_iter(iter)
|
||||||
return len(node.children)
|
return len(node.children)
|
||||||
|
|
||||||
def on_iter_nth_child(self, node, index):
|
def do_iter_nth_child(self, iterparent, index):
|
||||||
"""
|
"""
|
||||||
Get the nth child of the given node.
|
Get the nth child of the given node.
|
||||||
"""
|
"""
|
||||||
if node is None:
|
if iterparent is None:
|
||||||
node = self.tree[None]
|
node = self.tree[None]
|
||||||
|
else:
|
||||||
|
node = self.get_node_from_iter(iterparent)
|
||||||
if node.children:
|
if node.children:
|
||||||
if len(node.children) > index:
|
if len(node.children) > index:
|
||||||
_index = (-index - 1) if self.__reverse else index
|
_index = (-index - 1) if self.__reverse else index
|
||||||
return self.nodemap.node(node.children[_index][1])
|
return True, self.new_iter(node.children[_index][1])
|
||||||
else:
|
else:
|
||||||
return None
|
return False, None
|
||||||
else:
|
else:
|
||||||
return None
|
return False, None
|
||||||
|
|
||||||
def on_iter_parent(self, node):
|
def do_iter_parent(self, iterchild):
|
||||||
"""
|
"""
|
||||||
Get the parent of the given node.
|
Get the parent of the given node.
|
||||||
"""
|
"""
|
||||||
return node.parent and self.nodemap.node(node.parent)
|
node = self.get_node_from_iter(iterchild)
|
||||||
|
if node.parent:
|
||||||
|
return True, self.new_iter(node.parent)
|
||||||
|
else:
|
||||||
|
return False, None
|
||||||
|
@ -53,7 +53,7 @@ from gen.ggettext import gettext as _
|
|||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
class PersonTreeView(BasePersonView):
|
class PersonTreeView(BasePersonView):
|
||||||
"""
|
"""
|
||||||
A hierarchical view of the top three levels of places.
|
A hierarchical view of the people based on family name.
|
||||||
"""
|
"""
|
||||||
def __init__(self, pdata, dbstate, uistate, nav_group=0):
|
def __init__(self, pdata, dbstate, uistate, nav_group=0):
|
||||||
BasePersonView.__init__(self, pdata, dbstate, uistate,
|
BasePersonView.__init__(self, pdata, dbstate, uistate,
|
||||||
|
Loading…
Reference in New Issue
Block a user