From d6c5b2746ff6fb521d338cdd606cb470b30a2795 Mon Sep 17 00:00:00 2001 From: Don Allingham Date: Sun, 7 Mar 2004 21:50:41 +0000 Subject: [PATCH] * 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 --- gramps2/src/PeopleModel.py | 182 ++++++++++++++++++++++ gramps2/src/PeopleView.py | 309 +++++++++---------------------------- gramps2/src/RelLib.py | 30 +++- gramps2/src/gramps.glade | 57 ++----- gramps2/src/gramps_main.py | 22 +-- 5 files changed, 293 insertions(+), 307 deletions(-) create mode 100644 gramps2/src/PeopleModel.py diff --git a/gramps2/src/PeopleModel.py b/gramps2/src/PeopleModel.py new file mode 100644 index 000000000..4f3016e54 --- /dev/null +++ b/gramps2/src/PeopleModel.py @@ -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 diff --git a/gramps2/src/PeopleView.py b/gramps2/src/PeopleView.py index 3742962d0..784d2a8f2 100644 --- a/gramps2/src/PeopleView.py +++ b/gramps2/src/PeopleView.py @@ -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() diff --git a/gramps2/src/RelLib.py b/gramps2/src/RelLib.py index f060a4323..10258c1ac 100644 --- a/gramps2/src/RelLib.py +++ b/gramps2/src/RelLib.py @@ -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) diff --git a/gramps2/src/gramps.glade b/gramps2/src/gramps.glade index bbfa4104c..fb3567db7 100644 --- a/gramps2/src/gramps.glade +++ b/gramps2/src/gramps.glade @@ -1345,60 +1345,23 @@ - - 3 + True True - True - False - GTK_POS_BOTTOM - False - False - + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT - + True True - GTK_POLICY_AUTOMATIC - GTK_POLICY_AUTOMATIC - GTK_SHADOW_NONE - GTK_CORNER_TOP_LEFT - - - - True - True - True - True - False - True - - + True + False + False + True - - False - True - - - - - - True - Other - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - - - tab - diff --git a/gramps2/src/gramps_main.py b/gramps2/src/gramps_main.py index 987f74028..ea886d140 100755 --- a/gramps2/src/gramps_main.py +++ b/gramps2/src/gramps_main.py @@ -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)