* src/PeopleModel.py: New GenericTreeView based model

* src/RelLib.py: metadata/people model support
* src/gramps_main.py: PeopleModel support
* src/PeopleView.py: PeopleModel support


svn: r2978
This commit is contained in:
Don Allingham 2004-03-07 21:50:41 +00:00
parent 0b235a68f3
commit 151c988230
5 changed files with 293 additions and 307 deletions

182
src/PeopleModel.py Normal file
View File

@ -0,0 +1,182 @@
import gobject
import gtk
import gtk.glade
import gnome
import gnome.ui
from RelLib import *
def unique(mylist):
a = {}
for val in mylist:
a[val] = 1
return a.keys()
def callback(foo):
pass
class JunkIter(gtk.TreeIter):
def __init__(self):
pass
class PeopleModel(gtk.GenericTreeModel):
def __init__(self,db):
gtk.GenericTreeModel.__init__(self)
self.db = db
self.rebuild_data()
self.connect('row-inserted',self.on_row_inserted)
self.connect('row-deleted',self.on_row_deleted)
def rebuild_data(self):
self.top_iter2path = {}
self.top_path2iter = {}
self.iter2path = {}
self.path2iter = {}
self.sname_sub = {}
if not self.db.is_open():
return
val = 0
name_list = self.db.get_surnames()
for name in name_list:
self.top_iter2path[unicode(name)] = (val,)
self.top_path2iter[val] = unicode(name)
val += 1
for person_id in self.db.get_person_keys():
person = self.db.find_person_from_id(person_id)
surname = unicode(person.get_primary_name().get_surname())
if self.sname_sub.has_key(surname):
val = len(self.sname_sub[surname])
self.sname_sub[surname].append(person_id)
else:
self.sname_sub[surname] = [person_id]
val = 0
tpl = (surname,val)
self.iter2path[person_id] = tpl
self.path2iter[tpl] = person_id
def on_row_inserted(self,obj,path,iter):
self.rebuild_data()
def on_row_deleted(self,obj,path):
self.rebuild_data()
def find_path(self,iter):
if self.top_iter2path.has_key(iter):
return self.top_iter2path[iter]
else:
path = self.iter2path.get(iter)
if path:
return (self.top_iter2path[path[0]][0],path[1]);
else:
return None
def on_get_flags(self):
'''returns the GtkTreeModelFlags for this particular type of model'''
return 0
def on_get_n_columns(self):
return 5
def on_get_path(self, node):
'''returns the tree path (a tuple of indices at the various
levels) for a particular node.'''
if self.top_iter2path.has_key(node):
return self.top_iter2path[node]
else:
(surname,index) = self.iter2path[node]
return (self.top_iter2path[surname][0],index)
def on_get_column_type(self,index):
return gobject.TYPE_STRING
def on_get_iter(self, path):
try:
if len(path)==1:
return self.top_path2iter[path[0]]
else:
surname = self.top_path2iter[path[0]]
return self.path2iter[(surname,path[1])]
except:
return None
def on_get_value(self,iter,col):
if self.top_iter2path.has_key(iter):
if col == 0:
return iter
else:
return ''
else:
data = self.db.person_map[str(iter)]
if col==0:
return str(data[2].get_name())
elif col == 1:
return str(data[0])
elif col == 2:
if data[1]:
return "male"
else:
return "female"
elif col == 3:
if data[5]:
return self.db.find_event_from_id(data[5]).get_date()
else:
return u""
elif col == 4:
if data[6]:
return self.db.find_event_from_id(data[6]).get_date()
else:
return u""
def on_iter_next(self, node):
'''returns the next node at this level of the tree'''
if self.top_iter2path.has_key(node):
path = self.top_iter2path[node]
return self.top_path2iter.get(path[0]+1)
else:
(surname,val) = self.iter2path[node]
return self.path2iter.get((surname,val+1))
def on_iter_children(self,node):
if node == None:
return self.top_path2iter[0]
if self.top_iter2path.has_key(node):
return self.path2iter.get((node,0))
return None
def on_iter_has_child(self, node):
'''returns true if this node has children'''
if node == None:
return 1
if self.top_iter2path.has_key(node):
return 1
return 0
def on_iter_n_children(self,node):
if node == NONE:
return len(self.sname_sub)
if self.iter2path.has_key(node):
return len(self.sname_sub[node])
return 0
def on_iter_nth_child(self,node,n):
path = self.top_iter2path.get(node)
if path:
return self.path2iter.get((node,n))
else:
return None
def on_iter_parent(self, node):
'''returns the parent of this node'''
path = self.iter2path[node]
if path:
return path[0]
return None

View File

@ -45,7 +45,7 @@ _sel_mode = gtk.SELECTION_MULTIPLE
# gtk
#
#-------------------------------------------------------------------------
import PeopleStore
import PeopleModel
import Filter
#-------------------------------------------------------------------------
@ -59,94 +59,83 @@ class PeopleView:
self.parent = parent
self.DataFilter = Filter.Filter("")
self.ptabs = self.parent.gtop.get_widget("ptabs")
self.pl_other = self.parent.gtop.get_widget("pl_other")
self.ptabs.set_show_tabs(0)
self.pl_page = [
PeopleStore.PeopleStore(self.pl_other, self, self.row_changed,
self.alpha_event, _sel_mode),
]
self.person_tree = self.pl_page[0]
self.person_list = self.pl_page[0].tree
self.person_model = self.pl_page[0].model
self.person_list.connect('button-press-event',self.on_plist_button_press)
self.pscroll = self.parent.gtop.get_widget("pscroll")
self.person_tree = self.parent.gtop.get_widget("person_tree")
self.person_tree.set_rules_hint(gtk.TRUE)
self.default_list = self.pl_page[-1]
renderer = gtk.CellRendererText()
column_n = gtk.TreeViewColumn(_('Name'), renderer,text=0)
column_n.set_resizable(gtk.TRUE)
column_n.set_clickable(gtk.TRUE)
column_n.set_min_width(225)
self.person_tree.append_column(column_n)
self.alpha_page = {}
self.model2page = {}
self.model_used = {}
self.tab_list = []
self.clearing_tabs = 0
column_i = gtk.TreeViewColumn(_('ID'), renderer,text=1)
column_i.set_resizable(gtk.TRUE)
column_i.set_clickable(gtk.TRUE)
column_i.set_min_width(75)
self.person_tree.append_column(column_i)
column_g = gtk.TreeViewColumn(_('Gender'), renderer,text=2)
column_g.set_resizable(gtk.TRUE)
column_g.set_clickable(gtk.TRUE)
column_g.set_min_width(75)
self.person_tree.append_column(column_g)
column_b = gtk.TreeViewColumn(_('Birth Date'), renderer,text=3)
column_b.set_resizable(gtk.TRUE)
column_b.set_clickable(gtk.TRUE)
column_b.set_min_width(150)
self.person_tree.append_column(column_b)
column_d = gtk.TreeViewColumn(_('Death Date'), renderer,text=4)
column_d.set_resizable(gtk.TRUE)
column_d.set_clickable(gtk.TRUE)
column_d.set_min_width(150)
self.person_tree.append_column(column_d)
self.build_tree()
def build_tree(self):
self.person_tree.set_model(None)
self.person_model = PeopleModel.PeopleModel(self.parent.db)
self.person_tree.set_model(self.person_model)
self.person_selection = self.person_tree.get_selection()
self.person_selection.connect('changed',self.row_changed)
self.person_tree.connect('row_activated', self.alpha_event)
self.person_tree.connect('button-press-event',self.on_plist_button_press)
def blist(self,store,path,iter,id_list):
id_list.append(self.person_model.get_value(iter,1))
def get_selected_objects(self):
mlist = []
self.person_selection.selected_foreach(self.blist,mlist)
return mlist
def row_changed(self,obj):
"""Called with a row is changed. Check the selected objects from the person_tree
to get the IDs of the selected objects. Set the active person to the first person
in the list. If no one is selected, set the active person to None"""
selected_id_list = self.person_tree.get_selected_objects()
selected_id_list = self.get_selected_objects()
if selected_id_list and selected_id_list[0]:
try:
self.parent.change_active_person(self.parent.db.get_person(selected_id_list[0]))
person = self.parent.db.get_person(selected_id_list[0])
self.parent.change_active_person(person)
except:
self.parent.change_active_person(None)
self.person_tree.unselect()
def change_alpha_page(self,obj,junk,page):
"""Change the page. Be careful not to take action while the pages
are begin removed. If clearing_tabs is set, then we don't do anything"""
if self.clearing_tabs:
return
self.person_tree = self.pl_page[page]
self.person_list = self.pl_page[page].tree
self.person_model = self.pl_page[page].model
if not self.model_used.has_key(self.person_tree) or self.model_used[self.person_tree] == 0:
self.model_used[self.person_tree] = 1
self.apply_filter(self.person_tree)
self.person_list.connect('button-press-event',self.on_plist_button_press)
def clear_person_tabs(self):
self.clearing_tabs = 1
self.ptabs.hide()
for i in range(0,len(self.tab_list)):
self.ptabs.remove_page(0)
self.ptabs.set_show_tabs(0)
self.ptabs.show()
self.clearing_tabs = 0
self.default_list.clear()
for page in self.pl_page[0:-1]:
del page
self.pl_page = [
self.default_list
]
self.person_tree = self.pl_page[-1]
self.person_list = self.pl_page[-1].tree
self.person_model = self.pl_page[-1].model
self.id2col = {}
self.tab_list = []
self.alpha_page = {}
self.model2page = {self.default_list : 0}
self.model_used = {}
def change_db(self,db):
self.id2col = {}
self.build_tree()
def clear(self):
for model in self.pl_page:
model.clear()
pass
def remove_from_person_list(self,person,old_id=None):
"""Remove the selected person from the list. A person object is expected,
not an ID"""
person_id = person.get_id()
if old_id:
del_id = old_id
@ -235,168 +224,24 @@ class PeopleView:
def goto_active_person(self,first=0):
if not self.parent.active_person:
if first:
page = 0
else:
page = self.ptabs.get_current_page()
self.person_tree = self.pl_page[page]
self.person_list = self.pl_page[page].tree
self.person_model = self.pl_page[page].model
self.ptabs.set_current_page(page)
return
id = self.parent.active_person.get_id()
val = self.parent.db.get_person_display(id)
if self.id2col.has_key(id):
(model,iter) = self.id2col[id]
else:
pg = val[5]
if pg and pg != '@':
pg = pg[0]
else:
pg = ''
if not self.alpha_page.has_key(pg):
self.create_new_panel(pg)
model = self.alpha_page[pg]
iter = None
p = self.parent.active_person
id = p.get_id()
path = self.person_model.find_path(id)
top_path = self.person_model.find_path(p.get_primary_name().get_surname())
self.person_tree.expand_row(top_path,1)
self.person_selection.select_path(path)
self.person_tree.scroll_to_cell(path,None,1,0.5,0)
self.ptabs.set_current_page(self.model2page[model])
# itpath = model.model.get_path(iter)
# col = model.tree.get_column(0)
if not self.model_used.has_key(model) or self.model_used[model] == 0 or not iter:
self.model_used[model] = 1
self.apply_filter(model)
try:
(model,iter) = self.id2col[id]
except KeyError:
return
if not iter:
self.parent.status_text(_('Updating display...'))
model.fill_row(val[-1])
(m,iter) = self.id2col[id]
self.parent.modify_statusbar()
try:
model.selection.unselect_all()
model.selection.select_iter(iter)
except:
print iter
itpath = model.model.get_path(iter)
col = model.tree.get_column(0)
model.tree.scroll_to_cell(itpath,col,1,0.5,0)
def alpha_event(self,obj):
def alpha_event(self,obj,a,b):
self.parent.load_person(self.parent.active_person)
def apply_filter(self,current_model=None):
self.parent.status_text(_('Updating display...'))
datacomp = self.DataFilter.compare
if current_model == None:
self.id2col = {}
for key in self.parent.db.sort_person_keys():
person = self.parent.db.get_person(key)
val = self.parent.db.get_person_display(key)
pg = val[5]
if pg and pg != '@':
pg = pg[0]
else:
pg = ''
if datacomp(person):
if self.id2col.has_key(key):
continue
if pg and pg != '@':
if not self.alpha_page.has_key(pg):
self.create_new_panel(pg)
model = self.alpha_page[pg]
else:
model = self.default_list
if current_model == model:
if val[3]:
bdate_obj = self.parent.db.find_event_from_id(val[3])
if bdate_obj:
bdate = bdate_obj.get_date()
else:
bdate = ""
else:
bdate = ""
if val[4]:
ddate_obj = self.parent.db.find_event_from_id(val[4])
if ddate_obj:
ddate = ddate_obj.get_date()
else:
ddate = ""
else:
ddate = ""
iter = model.add([val[0],val[1],val[2],bdate,ddate,val[5],
val[6],val[7],val[8]])
self.id2col[key] = (model,iter)
else:
if self.id2col.has_key(key):
(model,iter) = self.id2col[key]
if iter:
model.remove(iter)
del self.id2col[key]
for i in self.pl_page:
i.sort()
self.parent.modify_statusbar()
def create_new_panel(self,pg):
display = gtk.ScrolledWindow()
display.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC)
tree = gtk.TreeView()
tree.show()
display.add(tree)
display.show()
model = PeopleStore.PeopleStore(tree, self, self.row_changed,
self.alpha_event,_sel_mode)
self.alpha_page[pg] = model
for index in range(0,len(self.tab_list)):
try:
if pg < self.tab_list[index]:
self.ptabs.insert_page(display,gtk.Label(pg),index)
self.ptabs.set_show_tabs(1)
self.tab_list.insert(index,pg)
self.pl_page.insert(index,model)
break
except:
print index
else:
#added by EARNEY on 5/5/2003
#modified the block below because sometimes certain
#letters under people panel
#will not load properly after a quick add
#(ie, adding a parent under the family panel)
index=len(self.tab_list)
self.ptabs.insert_page(display,gtk.Label(pg),index)
self.ptabs.set_show_tabs(1)
self.tab_list.insert(index,pg)
self.pl_page.insert(index,model)
#instead of the following..
#self.ptabs.insert_page(display,gtk.Label(pg),len(self.tab_list))
#self.ptabs.set_show_tabs(1)
#self.tab_list.append(pg)
#self.pl_page = self.pl_page[0:-1] + [model,self.default_list]
for index in range(0,len(self.tab_list)):
model = self.alpha_page[self.tab_list[index]]
self.model2page[model] = index
self.model_used[model] = 0
self.model2page[self.default_list] = len(self.tab_list)
self.model_used[self.default_list] = 0
def on_plist_button_press(self,obj,event):
if event.type == gtk.gdk.BUTTON_PRESS and event.button == 3:
@ -443,21 +288,7 @@ class PeopleView:
menu.popup(None,None,None,event.button,event.time)
def redisplay_person_list(self,person):
self.add_to_person_list(person,1)
self.person_model.rebuild_data()
def update_person_list(self,person,old_id):
key = person.get_id()
if old_id != key:
(model,iter) = self.id2col[old_id]
del self.id2col[old_id]
self.id2col[key] = (model,iter)
else:
(model,iter) = self.id2col[key]
val = self.parent.db.get_person_display(person.get_id())
pg = unicode(val[5])[0]
if self.DataFilter.compare(person):
col = 0
for object in val[:-1]:
model.model.set_value(iter,col,object)
col = col + 1
self.person_model.rebuild_data()

View File

@ -2281,6 +2281,7 @@ class GrampsDB:
self.pprefix = "P%04d"
self.fprefix = "F%04d"
self.eprefix = "E%04d"
self.open = 0
self.new()
self.added_files = []
self.genderStats = GenderStats ()
@ -2309,6 +2310,7 @@ class GrampsDB:
self.source_map = dbshelve.open(name, dbname="sources",dbenv=self.env)
self.media_map = dbshelve.open(name, dbname="media", dbenv=self.env)
self.event_map = dbshelve.open(name, dbname="events", dbenv=self.env)
self.metadata = dbshelve.open(name, dbname="meta", dbenv=self.env)
self.surnames = db.DB(self.env)
self.surnames.set_flags(db.DB_DUP)
@ -2323,9 +2325,23 @@ class GrampsDB:
self.source_map.close()
self.media_map.close()
self.event_map.close()
self.metadata.close()
self.surnames.close()
self.env.close()
self.person_map = None
self.family_map = None
self.place_map = None
self.source_map = None
self.media_map = None
self.event_map = None
self.surnames = None
self.env = None
self.metadata = None
def is_open(self):
return self.person_map != None
def get_added_media_objects(self):
return self.added_files
@ -2535,18 +2551,19 @@ class GrampsDB:
"""sets the default Person to the passed instance"""
# if (self.default):
# self.default.set_ancestor(0)
self.default = str(person)
self.metadata['default'] = str(person.get_id())
# if person:
# self.default.set_ancestor(1)
def get_default_person(self):
"""returns the default Person of the database"""
if self.default == None:
if self.metadata.has_key('default'):
person = Person()
data = self.person_map.get(self.metadata['default'])
person.unserialize(data)
return person
else:
return None
person = Person()
data = self.person_map.get(self.default)
person.unserialize(data)
return person
def get_person(self,id):
"""returns a Person from a GRAMPS's ID"""
@ -2689,7 +2706,6 @@ class GrampsDB:
else:
person.set_id(val)
assert(person.get_id())
assert(person.get_id()[0] == 'I')
self.person_map.put(str(val), person.serialize())
self.pmap_index = self.pmap_index+1
# self.genderStats.count_person (person, self)

View File

@ -1345,60 +1345,23 @@
</child>
<child>
<widget class="GtkNotebook" id="ptabs">
<property name="border_width">3</property>
<widget class="GtkScrolledWindow" id="pscroll">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="show_tabs">True</property>
<property name="show_border">False</property>
<property name="tab_pos">GTK_POS_BOTTOM</property>
<property name="scrollable">False</property>
<property name="enable_popup">False</property>
<signal name="switch_page" handler="on_alpha_switch_page" last_modification_time="Sat, 09 Nov 2002 22:11:07 GMT"/>
<property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<property name="shadow_type">GTK_SHADOW_IN</property>
<property name="window_placement">GTK_CORNER_TOP_LEFT</property>
<child>
<widget class="GtkScrolledWindow" id="scrolledwindow59">
<widget class="GtkTreeView" id="person_tree">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<property name="shadow_type">GTK_SHADOW_NONE</property>
<property name="window_placement">GTK_CORNER_TOP_LEFT</property>
<child>
<widget class="GtkTreeView" id="pl_other">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="headers_visible">True</property>
<property name="rules_hint">True</property>
<property name="reorderable">False</property>
<property name="enable_search">True</property>
</widget>
</child>
<property name="headers_visible">True</property>
<property name="rules_hint">False</property>
<property name="reorderable">False</property>
<property name="enable_search">True</property>
</widget>
<packing>
<property name="tab_expand">False</property>
<property name="tab_fill">True</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="pllabel">
<property name="visible">True</property>
<property name="label" translatable="yes">Other</property>
<property name="use_underline">False</property>
<property name="use_markup">False</property>
<property name="justify">GTK_JUSTIFY_LEFT</property>
<property name="wrap">False</property>
<property name="selectable">False</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
</widget>
<packing>
<property name="type">tab</property>
</packing>
</child>
</widget>
<packing>

View File

@ -159,7 +159,6 @@ class Gramps:
self.db.rebuild_person_table()
self.modify_statusbar()
self.family_view.init_interface()
self.people_view.clear_person_tabs()
self.update_display(1)
self.goto_active_person()
self.toolbar.set_style(GrampsCfg.toolbar)
@ -272,7 +271,6 @@ class Gramps:
"on_editbtn_clicked" : self.edit_button_clicked,
"on_addbtn_clicked" : self.add_button_clicked,
"on_removebtn_clicked" : self.remove_button_clicked,
"on_alpha_switch_page" : self.people_view.change_alpha_page,
"delete_event" : self.delete_event,
"destroy_passed_object" : Utils.destroy_passed_object,
"on_about_activate" : self.on_about_activate,
@ -425,7 +423,7 @@ class Gramps:
person = self.db.get_person(pid)
item = gtk.MenuItem("_%d. %s [%s]" %
(num,person.get_primary_name().get_name(),pid))
item.connect("activate",self.bookmark_callback,person)
item.connect("activate",self.bookmark_callback,person.get_id())
item.show()
gomenu.append(item)
num = num + 1
@ -454,7 +452,7 @@ class Gramps:
hotkey = "_%s" % chr(ord('a')+num-11)
elif num >= 21:
break
person = self.db.get_person(pid)
person = self.db.find_person_from_id(pid)
item = gtk.MenuItem("%s. %s [%s]" %
(hotkey,person.get_primary_name().get_name(),pid))
item.connect("activate",self.back_clicked,num)
@ -836,6 +834,8 @@ class Gramps:
def clear_database(self):
"""Clear out the database if permission was granted"""
return
const.personalEvents = const.init_personal_event_list()
const.personalAttributes = const.init_personal_attribute_list()
const.marriageEvents = const.init_marriage_event_list()
@ -847,8 +847,6 @@ class Gramps:
self.hindex = -1
self.redraw_histmenu()
self.people_view.clear_person_tabs()
self.relationship.set_db(self.db)
self.place_view.change_db(self.db)
@ -876,7 +874,6 @@ class Gramps:
self.import_tool_callback()
def import_tool_callback(self):
self.people_view.clear_person_tabs()
if Utils.wasHistory_broken():
self.clear_history()
Utils.clearHistory_broken()
@ -997,8 +994,6 @@ class Gramps:
def read_file(self,filename):
self.topWindow.set_resizable(gtk.FALSE)
filename = os.path.normpath(os.path.abspath(filename))
self.clear_database()
if self.load_database(filename) == 1:
if filename[-1] == '/':
filename = filename[:-1]
@ -1111,7 +1106,6 @@ class Gramps:
def save_file(self,filename,comment):
print "save",filename
path = filename
filename = os.path.normpath(os.path.abspath(filename))
self.status_text(_("Saving %s ...") % filename)
@ -1142,7 +1136,6 @@ class Gramps:
old_file = filename
filename = "%s/%s" % (filename,self.db.get_base())
print filename
try:
self.db.clear_added_media_objects()
except (OSError,IOError), msg:
@ -1603,7 +1596,8 @@ class Gramps:
self.statusbar.set_progress_percentage(1.0)
self.full_update()
self.people_view.change_db(self.db)
#self.full_update()
self.change_active_person(self.find_initial_person())
self.goto_active_person()
@ -1622,7 +1616,7 @@ class Gramps:
def load_database(self,name):
filename = name
self.clear_database()
#self.clear_database()
self.status_text(_("Loading %s...") % name)
if self.db.load(filename,self.load_progress) == 0:
@ -1683,7 +1677,7 @@ class Gramps:
self.change_active_person(person)
self.update_display(0)
except TypeError:
WarningDialog(_("Could Not Go to a Person"),
WarningDialog(_("Could not go to a Person"),
_("Either stale bookmark or broken history caused by IDs reorder."))
self.clear_history()
self.change_active_person(old_person)