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:
Benny Malengier 2012-07-10 03:32:08 +00:00
parent 0b8d0a1a95
commit 9da71185a6
9 changed files with 215 additions and 116 deletions

View File

@ -58,7 +58,7 @@ from gen.lib import (MediaObject, Person, Family, Source, Citation, Event,
NameOriginType)
from gen.db.dbconst import *
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.utils.id import create_id
from gen.errors import DbError
@ -826,10 +826,10 @@ class DbBsddbRead(DbReadBase, Callback):
Return type is a unicode object
"""
if isinstance(surname, unicode):
ssurname = conv_unicode_tosrtkey(surname)
return unicode(self.name_group.get(ssurname, ssurname), 'utf-8')
ssurname = surname.encode('utf-8')
return conv_dbstr_to_unicode(self.name_group.get(ssurname, ssurname))
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):
"""
@ -844,7 +844,7 @@ class DbBsddbRead(DbReadBase, Callback):
# The use of has_key seems allright because there is no write lock
# on the name_group table when this is called.
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:
return self.name_group.has_key(name)

View File

@ -62,8 +62,7 @@ from gen.db import (DbBsddbRead, DbWriteBase, BSDDBTxn,
find_surname_name, DbUndoBSDDB as DbUndo)
from gen.db.dbconst import *
from gen.utils.callback import Callback
from gen.utils.cast import (conv_unicode_tosrtkey_ongtk, conv_dbstr_to_unicode,
conv_unicode_tosrtkey)
from gen.utils.cast import (conv_unicode_tosrtkey_ongtk, conv_dbstr_to_unicode)
from gen.updatecallback import UpdateCallback
from gen.errors import DbError
from gen.constfunc import win
@ -1416,7 +1415,7 @@ class DbBsddb(DbBsddbRead, DbWriteBase, UpdateCallback):
if not self.readonly:
# Start transaction
with BSDDBTxn(self.env, self.name_group) as txn:
sname = conv_unicode_tosrtkey(name)
sname = name.encode('utf-8')
data = txn.get(sname)
if data is not None:
txn.delete(sname)

View File

@ -107,9 +107,9 @@ class Name(SecondaryObject, PrivacyBase, SurnameBase, CitationBase, NoteBase,
self.group_as = ""
self.sort_as = self.DEF
self.display_as = self.DEF
self.call = u''
self.nick = u''
self.famnick = u''
self.call = ""
self.nick = ""
self.famnick = ""
def serialize(self):
"""
@ -130,9 +130,9 @@ class Name(SecondaryObject, PrivacyBase, SurnameBase, CitationBase, NoteBase,
"""
Indicate if the name is empty.
"""
namefieldsempty = (self.first_name == u"" and
self.suffix == u"" and self.title == u"" and self.nick ==u""
and self.famnick == u"")
namefieldsempty = (self.first_name == "" and
self.suffix == "" and self.title == "" and self.nick == ""
and self.famnick == "")
surnamefieldsempty = not (False in
[surn.is_empty() for surn in self.surname_list])
return namefieldsempty and surnamefieldsempty

View File

@ -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(
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')
def cast_to_bool(val):

View File

@ -378,8 +378,9 @@ class ListView(NavigationView):
if self.type_list() == LISTFLAT:
# Flat
iter = self.model.nodemap.new_iter(handle)
try:
path = self.model.on_get_path(handle)
path = self.model.do_get_path(iter)
except:
path = None
else:
@ -387,15 +388,17 @@ class ListView(NavigationView):
path = None
node = self.model.get_node(handle)
if node:
parent_node = self.model.on_iter_parent(node)
if parent_node:
parent_path = self.model.on_get_path(parent_node)
iter = self.model.get_iter(node)
has_parent, parent_iter = self.model.do_iter_parent(iter)
if has_parent:
parent_path = self.model.do_get_path(parent_iter)
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(
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)
path = self.model.on_get_path(node)
path = self.model.do_get_path(iter)
if path is not None:
self.selection.unselect_all()
@ -535,11 +538,14 @@ class ListView(NavigationView):
if not prompt:
self.uistate.set_busy_cursor(0)
def blist(self, store, path, node, sel_list):
if store.get_flags() & Gtk.TreeModelFlags.LIST_ONLY:
handle = store.get_value(node, self.handle_col)
def blist(self, store, path, iter, sel_list):
'''GtkTreeSelectionForeachFunc
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:
handle = store.get_handle(store.on_get_iter(path))
handle = store.get_handle(store.get_node_from_iter(iter))
if handle is not None:
sel_list.append(handle)
@ -756,7 +762,8 @@ class ListView(NavigationView):
store, paths = self.selection.get_selected_rows()
if paths:
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:
return self.expand_collapse_tree_branch()
else:
@ -832,7 +839,8 @@ class ListView(NavigationView):
store, paths = self.selection.get_selected_rows()
if paths:
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:
return self.expand_collapse_tree_branch()
else:
@ -840,7 +848,8 @@ class ListView(NavigationView):
store, paths = self.selection.get_selected_rows()
if paths:
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:
return self.expand_collapse_tree()
else:
@ -857,7 +866,8 @@ class ListView(NavigationView):
store, paths = self.selection.get_selected_rows()
if paths:
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:
return False
if self.list.row_expanded(firstsel):
@ -875,7 +885,8 @@ class ListView(NavigationView):
store, paths = self.selection.get_selected_rows()
if paths:
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:
return False
if self.list.row_expanded(firstsel):
@ -996,7 +1007,7 @@ class ListView(NavigationView):
ofile.end_row()
else:
# 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)
ofile.end_page()
@ -1006,18 +1017,20 @@ class ListView(NavigationView):
if node is None:
return
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):
ofile.start_row()
padded_level = new_level + [''] * (depth - len(new_level))
map(ofile.write_cell, padded_level)
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()
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)
node = self.model.on_iter_next(node)
has_next = self.model.do_iter_next(node)
if not has_next:
node = None
####################################################################
# Template functions

View File

@ -151,15 +151,14 @@ class FlatNodeMap(object):
Reverse sets up how the path is determined from the index. If True the
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
a subset of all possible data.
Set iter=None, it will be set internally
:type index2hndllist: a list of (sortkey, handle) tuples
: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.
: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
same list, so only one is kept in memory.
:type identical: bool
@ -446,7 +445,10 @@ class FlatBaseModel(GObject.Object, Gtk.TreeModel):
#inheriting classes must set self.map to obtain the data
self.prev_handle = None
self.prev_data = None
#GTK3 We leak ref, yes??
#self.set_property("leak_references", False)
self.db = db
#normally sort on first column, so scol=0
if sort_map:
@ -752,7 +754,7 @@ class FlatBaseModel(GObject.Object, Gtk.TreeModel):
data = self.map(str(handle))
if data is None:
#object is no longer present
return u''
return ''
self.prev_data = data
self.prev_handle = handle
val = self.fmap[col](self.prev_data)
@ -784,13 +786,14 @@ class FlatBaseModel(GObject.Object, Gtk.TreeModel):
else:
return False
def do_iter_children(self, iter):
def do_iter_children(self, iterparent):
"""
Return the first child of the node
See Gtk.TreeModel
"""
#print 'do_iter_children'
print 'ERROR: iter children, should not be called in flat base!!'
raise NotImplementedError
if handle is None and len(self.node_map):
return self.node_map.get_first_handle()
return None

View File

@ -90,7 +90,7 @@ class PeopleBaseModel(object):
"""
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
COLUMN_INT_ID = 10 # dynamic calculation of column indices
@ -191,7 +191,11 @@ class PeopleBaseModel(object):
return len(self.fmap)+1
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):
handle = data[0]
@ -199,6 +203,9 @@ class PeopleBaseModel(object):
name = self.lru_name[handle]
else:
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:
self.lru_name[handle] = name
return name
@ -214,7 +221,7 @@ class PeopleBaseModel(object):
return value
def _get_spouse_data(self, data):
spouses_names = u""
spouses_names = ""
for family_handle in data[COLUMN_FAMILY]:
family = self.db.get_family_from_handle(family_handle)
for spouse_id in [family.get_father_handle(),
@ -231,7 +238,7 @@ class PeopleBaseModel(object):
def column_id(self, data):
return data[COLUMN_ID]
def sort_change(self,data):
return "%012x" % data[COLUMN_CHANGE]
@ -274,7 +281,7 @@ class PeopleBaseModel(object):
else:
return retval
except:
return u''
return ''
for event_ref in data[COLUMN_EVENT]:
er = EventRef()
@ -288,13 +295,13 @@ class PeopleBaseModel(object):
if sort_mode:
retval = "%09d" % event.get_date_object().get_sort_value()
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):
return invalid_date_format % retval
else:
return retval
return u""
return ""
def column_death_day(self, data):
handle = data[0]
@ -329,7 +336,7 @@ class PeopleBaseModel(object):
else:
return retval
except:
return u''
return ''
for event_ref in data[COLUMN_EVENT]:
er = EventRef()
@ -350,7 +357,7 @@ class PeopleBaseModel(object):
return invalid_date_format % retval
else:
return retval
return u""
return ""
def column_birth_place(self, data):
index = data[COLUMN_BIRTH]
@ -368,7 +375,7 @@ class PeopleBaseModel(object):
if place_title:
return cgi.escape(place_title)
except:
return u''
return ''
for event_ref in data[COLUMN_EVENT]:
er = EventRef()
@ -385,7 +392,7 @@ class PeopleBaseModel(object):
if place_title:
return "<i>%s</i>" % cgi.escape(place_title)
return u""
return ""
def column_death_place(self, data):
index = data[COLUMN_DEATH]
@ -403,7 +410,7 @@ class PeopleBaseModel(object):
if place_title:
return cgi.escape(place_title)
except:
return u''
return ''
for event_ref in data[COLUMN_EVENT]:
er = EventRef()
@ -420,10 +427,10 @@ class PeopleBaseModel(object):
place_title = place.get_title()
if place_title != "":
return "<i>" + cgi.escape(place_title) + "</i>"
return u""
return ""
def column_tooltip(self, data):
return u'Person tooltip'
return 'Person tooltip'
def column_int_id(self, data):
return data[0]
@ -528,6 +535,8 @@ class PersonTreeModel(PeopleBaseModel, TreeBaseModel):
name_data = data[COLUMN_NAME]
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)
#if group_name not in self.group_list:

View File

@ -4,7 +4,7 @@
# Copyright (C) 2000-2007 Donald N. Allingham
# Copyright (C) 2009 Gary Burton
# Copyright (C) 2009-2011 Nick Hall
# Copyright (C) 2009 Benny Malengier
# Copyright (C) 2009-2012 Benny Malengier
# Copyright (C) 2011 Tim G L lyons
#
# 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
#
#-------------------------------------------------------------------------
from __future__ import with_statement
from __future__ import with_statement, print_function
import time
import locale
from gen.ggettext import gettext as _
@ -55,7 +55,7 @@ from gi.repository import Gtk
# 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
from lru import LRU
from bisect import bisect_right
@ -87,10 +87,17 @@ class Node(object):
'prev', 'next', 'children')#, '__weakref__')
def __init__(self, ref, parent, sortkey, handle, secondary):
self.name = 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:
self.name = ''
self.sortkey = None
self.ref = ref
self.handle = handle
@ -284,10 +291,15 @@ class TreeBaseModel(GObject.Object, Gtk.TreeModel):
nrgroups = 1,
group_can_have_handle = False,
has_secondary=False):
#TODO GTK3, first get flatbasemodel working !
raise NotImplementedError
cput = time.clock()
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
self.prev_handle = None
self.prev_data = None
@ -306,7 +318,9 @@ class TreeBaseModel(GObject.Object, Gtk.TreeModel):
self.nodemap = NodeMap()
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
if sort_map:
#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
if self.nodemap:
self.nodemap.destroy()
self.nodemap = None
self.rebuild_data = None
self._build_data = None
@ -422,10 +437,9 @@ class TreeBaseModel(GObject.Object, Gtk.TreeModel):
"""
Clear the data map.
"""
#invalidate the iters within gtk
self.invalidate_iters()
self.tree.clear()
self.handle2node.clear()
self.stamp += 1
self.nodemap.clear()
#start with creating the new iters
topnode = Node(None, None, None, None, False)
@ -450,7 +464,7 @@ class TreeBaseModel(GObject.Object, Gtk.TreeModel):
if search[1]:
# we have search[1] = (index, text_unicode, inversion)
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]:
self.search = ExactSearchFilter(func, text, inv)
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.
#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):
"""
Get the gramps handle for a node. Return None if the node does
not correspond to a gramps object.
"""
return node.handle
def get_node(self, 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))
# 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
See Gtk.GenericTreeModel
See Gtk.TreeModel
"""
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:
return object
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 = id(nodeid)
nodeid = long(iter.user_data)
node = self.nodemap.node(nodeid)
if node.handle is None:
# Header rows dont get the foreground color set
if col == self.color_column():
return None
return "#000000000000"
# Return the node name for the first column
if col == 0:
return self.column_header(node)
else:
#no value to show in other header column
return ''
else:
# return values for 'data' row, calling a function
# 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):
"""
Returns the contents of a given column of a gramps object
@ -864,29 +910,38 @@ class TreeBaseModel(GObject.Object, Gtk.TreeModel):
try:
if not secondary:
return (self.fmap[col](data))
return self.fmap[col](data)
else:
return (self.fmap2[col](data))
return self.fmap2[col](data)
except:
return None
return ''
def on_get_iter(self, path):
def do_get_iter(self, path):
"""
Returns a node from a given path.
"""
if not self.tree or not self.tree[None].children:
return None
return False, Gtk.TreeIter()
node = self.tree[None]
pathlist = list(path)
pathlist = path.get_indices()
for index in pathlist:
_index = (-index - 1) if self.__reverse else index
node = self.nodemap.node(node.children[_index][1])
return node
def on_get_path(self, node):
return True, self.get_iter(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.
"""
node = self.get_node_from_iter(iter)
pathlist = []
while node.parent is not None:
parent = self.nodemap.node(node.parent)
@ -901,62 +956,79 @@ class TreeBaseModel(GObject.Object, Gtk.TreeModel):
if pathlist is not None:
pathlist.reverse()
return tuple(pathlist)
return Gtk.TreePath(tuple(pathlist))
else:
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.
"""
node = self.get_node_from_iter(iter)
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.
"""
if node is None:
node = self.tree[None]
if node.children:
return self.nodemap.node(
node.children[-1 if self.__reverse else 0][1])
if iterparent is None:
nodeid = id(self.tree[None])
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.
"""
if node is None:
node = self.tree[None]
node = self.get_node_from_iter(iter)
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.
"""
if node is None:
if iter is None:
node = self.tree[None]
else:
node = self.get_node_from_iter(iter)
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.
"""
if node is None:
if iterparent is None:
node = self.tree[None]
else:
node = self.get_node_from_iter(iterparent)
if node.children:
if len(node.children) > 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:
return None
return False, None
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.
"""
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

View File

@ -53,7 +53,7 @@ from gen.ggettext import gettext as _
#-------------------------------------------------------------------------
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):
BasePersonView.__init__(self, pdata, dbstate, uistate,