From 8592fa2cc95344b8ee2fe4f5211d4c08ff967a0d Mon Sep 17 00:00:00 2001 From: Don Allingham Date: Tue, 30 Mar 2004 04:50:24 +0000 Subject: [PATCH] * various: Add undo functionality svn: r3065 --- ChangeLog | 3 + src/AddMedia.py | 4 +- src/AddSpouse.py | 13 +- src/ChooseParents.py | 46 +++- src/DbPrompter.py | 17 +- src/EditPerson.py | 23 +- src/EditPlace.py | 28 +- src/EditSource.py | 38 ++- src/EventEdit.py | 4 +- src/FamilyView.py | 135 +++++---- src/GrampsCfg.py | 4 +- src/GrampsParser.py | 1 - src/ImageSelect.py | 30 +- src/Marriage.py | 4 +- src/MediaView.py | 32 ++- src/MergeData.py | 3 +- src/PeopleModel.py | 5 +- src/PeopleStore.py | 325 ---------------------- src/PeopleView.py | 15 +- src/PlaceView.py | 90 +++--- src/RelLib.py | 643 ++++++++++++++++++++++++++++++------------- src/SelectChild.py | 10 +- src/SourceView.py | 35 +-- src/gramps.glade | 44 +-- src/gramps_main.py | 111 ++++---- 25 files changed, 854 insertions(+), 809 deletions(-) delete mode 100644 src/PeopleStore.py diff --git a/ChangeLog b/ChangeLog index 11f60aed2..975b72df2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,6 @@ +2004-03-29 Don Allingham + * various: Add undo functionality + 2004-03-27 Alex Roitman * src/plugins/rel_it.py: Convert to class. diff --git a/src/AddMedia.py b/src/AddMedia.py index 4543ee019..a06f41378 100644 --- a/src/AddMedia.py +++ b/src/AddMedia.py @@ -129,7 +129,9 @@ class AddMediaObject: if self.update: self.update() self.object = mobj - self.db.commit_media_object(mobj) + trans = self.db.start_transaction() + self.db.commit_media_object(mobj,trans) + self.db.add_transaction(trans) def on_name_changed(self,obj): """ diff --git a/src/AddSpouse.py b/src/AddSpouse.py index dde37b454..d4b30b2af 100644 --- a/src/AddSpouse.py +++ b/src/AddSpouse.py @@ -217,7 +217,6 @@ class AddSpouse: self.db.add_person(person) else: self.db.add_person_no_map(person,person.get_id()) - self.db.build_person_display(person.get_id()) self.addperson(person) self.update_data(person.get_id()) #self.slist.center_selected() @@ -241,12 +240,14 @@ class AddSpouse: Utils.destroy_passed_object(obj) return + trans = self.db.start_transaction() + if not self.active_family: self.active_family = self.db.new_family() self.person.add_family_id(self.active_family.get_id()) - self.db.commit_person(self.person) + self.db.commit_person(self.person,trans) spouse.add_family_id(self.active_family.get_id()) - self.db.commit_person(spouse) + self.db.commit_person(spouse,trans) if self.person.get_gender() == RelLib.Person.male: self.active_family.set_mother_id(spouse.get_id()) @@ -255,8 +256,10 @@ class AddSpouse: self.active_family.set_father_id(spouse.get_id()) self.active_family.set_mother_id(self.person.get_id()) - self.active_family.set_relationship(const.save_frel(unicode(self.relation_type.get_text()))) - self.db.commit_family(self.active_family) + rtype = const.save_frel(unicode(self.relation_type.get_text())) + self.active_family.set_relationship(rtype) + self.db.commit_family(self.active_family,trans) + self.db.add_transaction(trans) Utils.destroy_passed_object(obj) self.update(self.active_family) diff --git a/src/ChooseParents.py b/src/ChooseParents.py index c9ec1de0d..50ffac0eb 100644 --- a/src/ChooseParents.py +++ b/src/ChooseParents.py @@ -293,7 +293,8 @@ class ChooseParents: def redrawf(self): """Redraws the potential father list""" - self.father_model = gtk.TreeModelSort(PeopleModel.PeopleModel(self.db, self.father_filter)) + self.father_nsort = PeopleModel.PeopleModel(self.db, self.father_filter) + self.father_model = gtk.TreeModelSort(self.father_nsort) self.father_list.set_model(self.father_model) if self.type == "Partners": self.flabel.set_label("%s" % _("Par_ent")) @@ -302,7 +303,8 @@ class ChooseParents: def redrawm(self): """Redraws the potential mother list""" - self.mother_model = gtk.TreeModelSort(PeopleModel.PeopleModel(self.db, self.mother_filter)) + self.mother_nsort = PeopleModel.PeopleModel(self.db, self.mother_filter) + self.mother_model = gtk.TreeModelSort(self.mother_nsort) self.mother_list.set_model(self.mother_model) if self.type == "Partners": self.mlabel.set_label("%s" % _("Pa_rent")) @@ -351,16 +353,18 @@ class ChooseParents: family.set_mother_id(mother_id) family.add_child_id(self.person.get_id()) + trans = self.db.start_transaction() if father_id: father = self.db.find_person_from_id(father_id) father.add_family_id(family.get_id()) - self.db.commit_person(father) + self.db.commit_person(father,trans) if mother_id: mother = self.db.find_person_from_id(mother_id) mother.add_family_id(family.get_id()) - self.db.commit_person(mother) + self.db.commit_person(mother,trans) - self.db.commit_family(family) + self.db.commit_family(family,trans) + self.db.add_transaction(trans) return family def mother_list_select_row(self,obj): @@ -414,8 +418,13 @@ class ChooseParents: if len(family_id_list) >= 1: family = self.db.find_family_from_id(family_id_list[0]) mother_id = family.get_mother_id() - self.mother_selection.select(mother_id) - #self.mother_model.center_selected() + mother = self.db.find_person_from_id(mother_id) + sname = mother.get_primary_name().get_surname() + tpath = self.mother_nsort.on_get_path(sname) + self.mother_list.expand_row(tpath,0) + path = self.mother_nsort.on_get_path(mother_id) + self.mother_selection.select_path(path) + self.mother_list.scroll_to_cell(path,None,1,0.5,0) def mother_list_select_row(self,obj): """Called when a row is selected in the father list. Sets the @@ -432,9 +441,14 @@ class ChooseParents: family_id_list = self.mother.get_family_id_list() if len(family_id_list) >= 1: family = self.db.find_family_from_id(family_id_list[0]) - father_id = family.get_father_id() - self.father_selection.select(father_id) - #self.father_model.center_selected() + father_id = family.get_mother_id() + father = self.db.find_person_from_id(father_id) + sname = father.get_primary_name().get_surname() + tpath = self.father_nsort.on_get_path(sname) + self.father_list.expand_row(tpath,0) + path = self.father_nsort.on_get_path(father_id) + self.father_selection.select_path(path) + self.father_list.scroll_to_cell(path,None,1,0.5,0) def save_parents_clicked(self,obj): """ @@ -491,7 +505,6 @@ class ChooseParents: id = self.db.add_person(person) else: self.db.add_person_no_map(person,id) - self.db.build_person_display(id) self.type = const.save_frel(unicode(self.prel.get_text())) dinfo = self.db.get_person_display(id) @@ -538,12 +551,15 @@ class ChooseParents: break else: self.person.add_parent_family_id(family.get_id(),mother_rel,father_rel) - self.db.commit_person(self.person) - self.db.commit_family(family) + + trans = self.db.start_transaction() + self.db.commit_person(self.person,trans) + self.db.commit_family(family,trans) if self.father: - self.db.commit_person(self.father) + self.db.commit_person(self.father,trans) if self.mother: - self.db.commit_person(self.mother) + self.db.commit_person(self.mother,trans) + self.db.add_transaction(trans) class ModifyParents: def __init__(self,db,person,family_id,family_update,full_update,parent_window=None): diff --git a/src/DbPrompter.py b/src/DbPrompter.py index d0b898884..4f9c0856f 100644 --- a/src/DbPrompter.py +++ b/src/DbPrompter.py @@ -92,7 +92,8 @@ class DbPrompter: "on_ok_button1_clicked": self.save_ok_button_clicked, "destroy_passed_object": self.cancel_button_clicked, }) - wFs.get_widget('fileselection').set_title('%s - GRAMPS' % _('Create database')) + filesel = wFs.get_widget('fileselection') + filesel.set_title('%s - GRAMPS' % _('Create database')) def save_ok_button_clicked(self,obj): filename = obj.get_filename().encode('iso8859-1') @@ -101,6 +102,18 @@ class DbPrompter: self.db.read_file(filename) def open_activate(self): + + wFs = gtk.glade.XML (const.gladeFile, "fileselection","gramps") + wFs.signal_autoconnect({ + "on_ok_button1_clicked": self.ok_button_clicked, + "destroy_passed_object": self.cancel_button_clicked, + }) + self.filesel = wFs.get_widget('fileselection') + self.filesel.set_title('%s - GRAMPS' % _('Open database')) + if GrampsCfg.lastfile: + self.filesel.set_filename(GrampsCfg.lastfile) + return + wFs = gtk.glade.XML(const.revisionFile, "dbopen","gramps") wFs.signal_autoconnect({ "on_ok_button1_clicked": self.ok_button_clicked, @@ -130,7 +143,7 @@ class DbPrompter: self.show() def ok_button_clicked(self,obj): - filename = self.dbname.get_full_path(0) + filename = self.filesel.get_filename() if not filename: return diff --git a/src/EditPerson.py b/src/EditPerson.py index 3785bdf68..0a4fdc6fd 100644 --- a/src/EditPerson.py +++ b/src/EditPerson.py @@ -1409,6 +1409,9 @@ class EditPerson: self.person.set_death_id(self.death.get_id()) def on_apply_person_clicked(self,obj): + + trans = self.db.start_transaction() + surname = unicode(self.surname_field.get_text()) suffix = unicode(self.suffix.get_text()) prefix = unicode(self.prefix.get_text()) @@ -1424,7 +1427,7 @@ class EditPerson: self.birth.set_place_id(self.get_place(self.bplace,1)) if idval != self.person.get_id(): - m = self.db.get_person_id_map() + m = self.db.get_person_keys() if not m.has_key(idval): if m.has_key(self.person.get_id()): del m[self.person.get_id()] @@ -1476,20 +1479,20 @@ class EditPerson: self.pdmap[p[0]] = key if self.orig_birth == None: - self.db.add_event(self.birth) + self.db.add_event(self.birth,trans) self.person.set_birth_id(self.birth.get_id()) elif not self.orig_birth.are_equal(self.birth): - self.db.commit_event(self.birth) + self.db.commit_event(self.birth,trans) # Update each of the families child lists to reflect any # change in ordering due to the new birth date family = self.person.get_main_parents_family_id() if (family): - f = self.db.find_family_no_map(family) + f = self.db.find_family_no_map(family,trans) new_order = self.reorder_child_list(self.person,f.get_child_id_list()) f.set_child_id_list(new_order) for (family, rel1, rel2) in self.person.get_parent_family_id_list(): - f = self.db.find_family_no_map(family) + f = self.db.find_family_no_map(family,trans) new_order = self.reorder_child_list(self.person,f.get_child_id_list()) f.set_child_id_list(new_order) @@ -1497,10 +1500,10 @@ class EditPerson: self.death.set_place_id(self.get_place(self.dplace,1)) if self.orig_death == None: - self.db.add_event(self.death) + self.db.add_event(self.death,trans) self.person.set_death_id(self.death.get_id()) elif not self.orig_death.are_equal(self.death): - self.db.commit_event(self.death) + self.db.commit_event(self.death,trans) male = self.is_male.get_active() female = self.is_female.get_active() @@ -1580,10 +1583,10 @@ class EditPerson: self.update_lists() if self.callback: change = (self.orig_surname != surname) or (self.orig_id != idval) - self.callback(self,change) - - self.db.commit_person(self.person) + self.callback(self,trans) + self.db.commit_person(self.person, trans) + self.db.add_transaction(trans) self.close(1) def get_place(self,field,makenew=0): diff --git a/src/EditPlace.py b/src/EditPlace.py index e14c467bb..a210106eb 100644 --- a/src/EditPlace.py +++ b/src/EditPlace.py @@ -369,7 +369,10 @@ class EditPlace: self.gallery_ok = 1 self.update_lists() - self.db.commit_place(self.place) + trans = self.db.start_transaction() + self.db.commit_place(self.place,trans) + self.db.add_transaction(trans) + if self.callback: self.callback(self.place) @@ -553,16 +556,25 @@ class DeletePlaceQuery: self.update = update def query_response(self): - self.db.remove_place(self.place.get_id()) + trans = self.db.start_transaction() + + self.db.remove_place(self.place.get_id(),trans) for key in self.db.get_person_keys(): p = self.db.get_person(key) - for event in [p.get_birth(), p.get_death()] + p.get_event_list(): - if event.get_place_id() == self.place: - event.set_place_id(None) - for f in self.db.get_family_id_map().values(): - for event in f.get_event_list(): - if event.get_place_id() == self.place: + for event_id in [p.get_birth_id(), p.get_death_id()] + p.get_event_list(): + event = self.db.find_event_from_id(event_id) + if event and event.get_place_id() == self.place.get_id(): event.set_place_id(None) + self.db.commit_event(event,trans) + for fid in self.db.get_family_keys(): + f = self.db.find_family_from_id(fid) + for event_id in f.get_event_list(): + event = self.db.find_event_from_id(event_id) + if event and event.get_place_id() == self.place.get_id(): + event.set_place_id(None) + self.db.commit_event(event,trans) + + self.db.add_transaction(trans) self.update(None) diff --git a/src/EditSource.py b/src/EditSource.py index 9951ce934..21e12f2f3 100644 --- a/src/EditSource.py +++ b/src/EditSource.py @@ -326,7 +326,10 @@ class EditSource: self.gallery_ok = 1 - self.db.commit_source(self.source) + trans = self.db.start_transaction() + self.db.commit_source(self.source,trans) + self.db.add_transaction(trans) + if self.callback: self.callback(self.source) self.close(obj) @@ -362,42 +365,53 @@ class DelSrcQuery: m = 1 if m: object.set_source_reference_list(l) + return m def query_response(self): - self.db.remove_source_id(self.source.get_id()) - + trans = self.db.start_transaction() + for key in self.db.get_person_keys(): + commit = 0 p = self.db.get_person(key) for v_id in p.get_event_list() + [p.get_birth_id(), p.get_death_id()]: v = self.db.find_event_from_id(v_id) if v: - self.delete_source(v) + commit += self.delete_source(v) for v in p.get_attribute_list(): - self.delete_source(v) + commit += self.delete_source(v) for v in p.get_alternate_names() + [p.get_primary_name()]: - self.delete_source(v) + commit += self.delete_source(v) for v in p.get_address_list(): - self.delete_source(v) + commit += self.delete_source(v) + if commit > 0: + self.db.commit_person(p,trans) for p_id in self.db.get_family_keys(): + commit = 0 p = self.db.find_family_from_id(p_id) for v_id in p.get_event_list(): v = self.db.find_event_from_id(v_id) if v: - self.delete_source(v) + commit += self.delete_source(v) for v in p.get_attribute_list(): - self.delete_source(v) + commit += self.delete_source(v) + if commit > 0: + self.db.commit_family(p,trans) for p_id in self.db.get_object_keys(): p = self.db.find_object_from_id(p_id) - self.delete_source(p) + if self.delete_source(p): + self.db.commit_media_object(p,trans) for key in self.db.get_place_id_keys(): p = self.db.find_place_from_id(key) - self.delete_source(self.db.find_place_from_id(key)) + if self.delete_source(self.db.find_place_from_id(key)): + self.db.commit_place(p,trans) - self.update(0) + self.db.remove_source_id(self.source.get_id(),trans) + self.db.add_transaction(trans) + self.update() diff --git a/src/EventEdit.py b/src/EventEdit.py index 6a1d8b83c..1691ae61d 100644 --- a/src/EventEdit.py +++ b/src/EventEdit.py @@ -356,7 +356,9 @@ class EventEditor: if self.event.get_privacy() != priv: self.event.set_privacy(priv) self.parent.lists_changed = 1 - self.db.commit_event(self.event) + trans = self.db.start_transaction() + self.db.commit_event(self.event,trans) + self.db.add_transaction(trans) def on_switch_page(self,obj,a,page): buf = self.note_field.get_buffer() diff --git a/src/FamilyView.py b/src/FamilyView.py index 438ce017f..d560b2a93 100644 --- a/src/FamilyView.py +++ b/src/FamilyView.py @@ -87,16 +87,26 @@ class FamilyView: self.sp_par_arrow = "Down" self.child_arrow = "Up" if not already_init: - self.top.get_widget('add_parents2').connect('clicked',self.add_parents_clicked) - self.top.get_widget('del_parents2').connect('clicked',self.del_parents_clicked) - self.top.get_widget('add_spparents2').connect('clicked',self.add_sp_parents) - self.top.get_widget('del_spparents2').connect('clicked',self.del_sp_parents) - self.top.get_widget('fam_back2').connect('clicked',self.child_back) - self.top.get_widget('del_child_btn2').connect('clicked',self.remove_child_clicked) - self.top.get_widget('add_child_btn2').connect('clicked',self.add_child_clicked) - self.top.get_widget('select_child2').connect('clicked',self.select_child_clicked) - self.top.get_widget('ap_parents_btn2').connect('clicked',self.ap_parents_clicked) - self.top.get_widget('sp_parents_btn2').connect('clicked',self.sp_parents_clicked) + self.top.get_widget('add_parents2').connect('clicked', + self.add_parents_clicked) + self.top.get_widget('del_parents2').connect('clicked', + self.del_parents_clicked) + self.top.get_widget('add_spparents2').connect('clicked', + self.add_sp_parents) + self.top.get_widget('del_spparents2').connect('clicked', + self.del_sp_parents) + self.top.get_widget('fam_back2').connect('clicked', + self.child_back) + self.top.get_widget('del_child_btn2').connect('clicked', + self.remove_child_clicked) + self.top.get_widget('add_child_btn2').connect('clicked', + self.add_child_clicked) + self.top.get_widget('select_child2').connect('clicked', + self.select_child_clicked) + self.top.get_widget('ap_parents_btn2').connect('clicked', + self.ap_parents_clicked) + self.top.get_widget('sp_parents_btn2').connect('clicked', + self.sp_parents_clicked) self.parent.views.get_nth_page(2).show_all() if self.parent.views.get_current_page() == 1: self.parent.views.set_current_page(2) @@ -117,16 +127,26 @@ class FamilyView: self.sp_par_arrow = "Right" self.child_arrow = "Left" if not already_init: - self.top.get_widget('add_parents').connect('clicked',self.add_parents_clicked) - self.top.get_widget('del_parents').connect('clicked',self.del_parents_clicked) - self.top.get_widget('add_spparents').connect('clicked',self.add_sp_parents) - self.top.get_widget('del_spparents').connect('clicked',self.del_sp_parents) - self.top.get_widget('fam_back').connect('clicked',self.child_back) - self.top.get_widget('del_child_btn').connect('clicked',self.remove_child_clicked) - self.top.get_widget('add_child_btn').connect('clicked',self.add_child_clicked) - self.top.get_widget('select_child').connect('clicked',self.select_child_clicked) - self.top.get_widget('ap_parents_btn').connect('clicked',self.ap_parents_clicked) - self.top.get_widget('sp_parents_btn').connect('clicked',self.sp_parents_clicked) + self.top.get_widget('add_parents').connect('clicked', + self.add_parents_clicked) + self.top.get_widget('del_parents').connect('clicked', + self.del_parents_clicked) + self.top.get_widget('add_spparents').connect('clicked', + self.add_sp_parents) + self.top.get_widget('del_spparents').connect('clicked', + self.del_sp_parents) + self.top.get_widget('fam_back').connect('clicked', + self.child_back) + self.top.get_widget('del_child_btn').connect('clicked', + self.remove_child_clicked) + self.top.get_widget('add_child_btn').connect('clicked', + self.add_child_clicked) + self.top.get_widget('select_child').connect('clicked', + self.select_child_clicked) + self.top.get_widget('ap_parents_btn').connect('clicked', + self.ap_parents_clicked) + self.top.get_widget('sp_parents_btn').connect('clicked', + self.sp_parents_clicked) self.parent.views.get_nth_page(1).show_all() if self.parent.views.get_current_page() == 2: self.parent.views.set_current_page(1) @@ -234,7 +254,7 @@ class FamilyView: and event.state == gtk.gdk.CONTROL_MASK: self.spouse_swap(obj) elif event.keyval == gtk.gdk.keyval_from_name("Delete") and not event.state: - self.remove_spouse(obj) + self.remove_spouse(obj,trans) elif event.keyval == gtk.gdk.keyval_from_name("Insert") and not event.state: self.select_spouse(obj) elif event.keyval == gtk.gdk.keyval_from_name("Insert") \ @@ -530,7 +550,9 @@ class FamilyView: def set_preferred_spouse(self,obj): if self.selected_spouse: self.person.set_preferred_family_id(self.family) - self.parent.db.commit_person(self.person) + trans = self.parent.db.start_transaction() + self.parent.db.commit_person(self.person,trans) + self.parent.db.add_transaction(trans) self.load_family() def edit_spouse_callback(self,obj): @@ -597,28 +619,30 @@ class FamilyView: def spouse_after_edit(self,epo): ap = self.parent.active_person if epo: - self.parent.db.build_person_display(epo.person.get_id(),epo.original_id) - self.parent.db.commit_person(epo.person) + trans = self.parent.db.start_transaction() + self.parent.db.commit_person(epo.person,trans) + self.parent.db.add_transaction(trans) self.parent.people_view.remove_from_person_list(epo.person,epo.original_id) self.parent.people_view.redisplay_person_list(epo.person) self.parent.active_person = ap self.load_family(self.family) - def new_spouse_after_edit(self,epo,change): + def new_spouse_after_edit(self,epo,trans): if epo.person.get_id() == "": - self.parent.db.add_person(epo.person) + self.parent.db.add_person(epo.person,trans) else: - self.parent.db.add_person_no_map(epo.person,epo.person.get_id()) + self.parent.db.add_person_no_map(epo.person,epo.person.get_id(),trans) + + self.family = self.parent.db.new_family(trans) self.parent.people_view.add_to_person_list(epo.person,0) - self.family = self.parent.db.new_family() self.person.add_family_id(self.family.get_id()) epo.person.add_family_id(self.family.get_id()) - self.parent.db.commit_person(epo.person) - self.parent.db.commit_person(self.person) + self.parent.db.commit_person(epo.person,trans) + self.parent.db.commit_person(self.person,trans) if self.person.get_gender() == RelLib.Person.male: self.family.set_mother_id(epo.person.get_id()) @@ -627,7 +651,7 @@ class FamilyView: self.family.set_father_id(epo.person.get_id()) self.family.set_mother_id(self.person.get_id()) - self.parent.db.commit_family(self.family) + self.parent.db.commit_family(self.family,trans) self.load_family(self.family) Marriage.Marriage(self.parent,self.family,self.parent.db, @@ -671,14 +695,13 @@ class FamilyView: self.parent.update_person_list(person) self.load_family(self.family) - def new_child_after_edit(self,epo): + def new_child_after_edit(self,epo,trans): if epo.person.get_id() == "": - self.parent.db.add_person(epo.person) + self.parent.db.add_person(epo.person,trans) else: - self.parent.db.add_person_no_map(epo.person,epo.person.get_id()) + self.parent.db.add_person_no_map(epo.person,epo.person.get_id(),trans) - self.parent.db.build_person_display(epo.person.get_id()) self.parent.people_view.add_to_person_list(epo.person,0) if not self.family: @@ -691,8 +714,8 @@ class FamilyView: self.family.add_child_id(epo.person.get_id()) epo.person.add_parent_family_id(self.family.get_id(),"Birth","Birth") - self.parent.db.commit_person(epo.person) - self.parent.db.commit_family(self.family) + self.parent.db.commit_person(epo.person,trans) + self.parent.db.commit_family(self.family,trans) self.display_marriage(self.family) def select_child_clicked(self,obj): @@ -716,6 +739,8 @@ class FamilyView: id = self.child_model.get_value(iter,2) child = self.parent.db.get_person(id) + trans = self.parent.db.start_transaction() + self.family.remove_child_id(child.get_id()) child.remove_parent_family_id(self.family.get_id()) @@ -725,8 +750,10 @@ class FamilyView: elif self.family.get_mother_id() == None: self.delete_family_from(self.family.get_father_id()) - self.parent.db.commit_person(child) - self.parent.db.commit_family(self.family) + self.parent.db.commit_person(child,trans) + self.parent.db.commit_family(self.family,trans) + self.parent.db.add_transaction(trans) + self.load_family() def remove_spouse(self,obj): @@ -752,16 +779,18 @@ class FamilyView: else: self.family.set_mother_id(None) + trans = self.parent.db.start_transaction() + if self.selected_spouse: - self.selected_spouse.remove_family_id(self.family.get_id()) - self.parent.db.commit_person(self.selected_spouse) + self.selected_spouse.remove_family_id(self.family.get_id(),trans) + self.parent.db.commit_person(self.selected_spouse,trans) - self.parent.db.commit_family(self.family) + self.parent.db.commit_family(self.family,trans) if len(self.family.get_child_id_list()) == 0: - self.person.remove_family_id(self.family.get_id()) - self.parent.db.commit_person(self.person) - self.parent.db.delete_family(self.family.get_id()) + self.person.remove_family_id(self.family.get_id(),trans) + self.parent.db.commit_person(self.person,trans) + self.parent.db.delete_family(self.family.get_id(),trans) if len(self.person.get_family_id_list()) > 0: family_id = self.person.get_family_id_list()[0] self.load_family(self.parent.db.find_family_from_id(family_id)) @@ -769,6 +798,7 @@ class FamilyView: self.load_family(self.family) else: self.load_family(self.family) + self.parent.db.add_transaction(trans) if len(self.person.get_family_id_list()) <= 1: self.spouse_selection.set_mode(gtk.SELECTION_NONE) @@ -806,7 +836,9 @@ class FamilyView: person = self.parent.db.find_person_from_id(person_id) self.parent.change_active_person(person) - self.parent.db.commit_family(family) + trans = self.parent.db.start_transaction() + self.parent.db.commit_family(family,trans) + self.parent.db.add_transaction(trans) self.load_family(family) def clear(self): @@ -938,13 +970,15 @@ class FamilyView: return _("%s: unknown") % (l) def delete_family_from(self,person): - person.remove_family_id(self.family.get_id()) - self.parent.db.delete_family(self.family.get_id()) + trans = self.parent.db.start_transaction() + person.remove_family_id(self.family.get_id(),trans) + self.parent.db.delete_family(self.family.get_id(),trans) flist = self.person.get_family_id_list() if len(flist) > 0: self.family = flist[0] else: self.family = None + self.parent.db.add_transaction(trans) def display_marriage(self,family): self.child_model.clear() @@ -1228,7 +1262,10 @@ class FamilyView: fam = person.get_parent_family_id_list()[row[0]] person.remove_parent_family_id(fam[0]) - self.parent.db.commit_person(person) + trans = self.parent.db.start_transaction() + self.parent.db.commit_person(person,trans) + self.parent.db.add_transaction(trans) + self.load_family() def drag_data_received(self,widget,context,x,y,sel_data,info,time): diff --git a/src/GrampsCfg.py b/src/GrampsCfg.py index c4d522296..ac95c512b 100644 --- a/src/GrampsCfg.py +++ b/src/GrampsCfg.py @@ -235,7 +235,7 @@ def loadConfig(call): global familyview _callback = call - lastfile = get_string("/apps/gramps/last-file") + lastfile = get_string("/apps/gramps/recent-file") uselds = get_bool("/apps/gramps/use-lds") ac = get_bool("/apps/gramps/disable-auto-complete",0) mediaref = get_bool("/apps/gramps/make-reference",1) @@ -372,7 +372,7 @@ def sync(): # #------------------------------------------------------------------------- def save_last_file(file): - set_string("/apps/gramps/last-file",file) + set_string("/apps/gramps/recent-file",file) sync() #------------------------------------------------------------------------- diff --git a/src/GrampsParser.py b/src/GrampsParser.py index 587f4ad4f..1ee0da73b 100644 --- a/src/GrampsParser.py +++ b/src/GrampsParser.py @@ -705,7 +705,6 @@ class GrampsParser: self.family = None def stop_person(self,tag): - self.db.build_person_display(self.person.get_id()) self.db.commit_person(self.person) self.person = None diff --git a/src/ImageSelect.py b/src/ImageSelect.py index 3cc9d2790..0130aa5d5 100644 --- a/src/ImageSelect.py +++ b/src/ImageSelect.py @@ -525,7 +525,7 @@ class Gallery(ImageSelect): if GrampsCfg.globalprop: GlobalMediaProperties(self.db,photo,None) else: - if self.db.get_object_map().has_key(data.data): + if self.db.has_object_id(data.data): icon_index = self.get_index(w,x,y) index = 0 for p in self.dataobj.get_media_list(): @@ -822,7 +822,10 @@ class LocalMediaProperties: if self.lists_changed: self.photo.set_attribute_list(self.alist) self.parent.lists_changed = 1 - self.db.commit_media_object(self.object) + + trans = self.db.start_transaction() + self.db.commit_media_object(self.object,trans) + self.db.add_transaction(trans) def on_help_clicked(self, obj): """Display the relevant portion of GRAMPS manual""" @@ -1061,7 +1064,9 @@ class GlobalMediaProperties: self.object.set_attribute_list(self.alist) if self.update != None: self.update() - self.db.commit_media_object(self.object) + trans = self.db.start_transaction() + self.db.commit_media_object(self.object,trans) + self.db.add_transaction(trans) def on_help_clicked(self, obj): """Display the relevant portion of GRAMPS manual""" @@ -1115,8 +1120,8 @@ class DeleteMediaQuery: self.update = update def query_response(self): - del self.db.get_object_map()[self.media.get_id()] - + trans = self.db.start_transaction() + for key in self.db.get_person_keys(): p = self.db.get_person(key) nl = [] @@ -1128,8 +1133,10 @@ class DeleteMediaQuery: change = 1 if change: p.set_media_list(nl) + self.db.commit_person(p,trans) - for p in self.db.get_family_id_map().values(): + for fid in self.db.get_family_keys(): + p = self.db.find_family_from_id(fid) nl = [] change = 0 for photo in p.get_media_list(): @@ -1139,9 +1146,10 @@ class DeleteMediaQuery: change = 1 if change: p.set_media_list(nl) + self.db.commit_family(p,trans) for key in self.db.get_source_keys(): - p = self.db.get_source(key) + sid = self.db.find_source_from_id(key,trans) nl = [] change = 0 for photo in p.get_media_list(): @@ -1151,9 +1159,10 @@ class DeleteMediaQuery: change = 1 if change: p.set_media_list(nl) + self.db.commit_source(p,trans) for key in self.db.get_place_id_keys(): - p = self.db.get_place_id(key) + p = self.db.find_place_from_id(key) nl = [] change = 0 for photo in p.get_media_list(): @@ -1163,6 +1172,9 @@ class DeleteMediaQuery: change = 1 if change: p.set_media_list(nl) + self.db.commit_place(p,trans) + self.db.remove_object(self.media.get_id(),trans) + self.db.add_transaction(trans) if self.update: - self.update(0) + self.update() diff --git a/src/Marriage.py b/src/Marriage.py index f0344e9d3..29aecb142 100644 --- a/src/Marriage.py +++ b/src/Marriage.py @@ -635,7 +635,9 @@ class Marriage: self.update_lists() self.update_fv(self.family) - self.db.commit_family(self.family) + trans = self.db.start_transaction() + self.db.commit_family(self.family,trans) + self.db.add_transaction(trans) self.close(1) diff --git a/src/MediaView.py b/src/MediaView.py index 86eff00a2..636b3c1d1 100644 --- a/src/MediaView.py +++ b/src/MediaView.py @@ -150,14 +150,6 @@ class MediaView: self.build_columns() self.build_tree() - def goto(self,id): - self.selection.unselect_all() - iter = self.id2col[id] - self.selection.select_iter(iter) - itpath = self.model.get_path (iter) - col = self.list.get_column (0) - self.list.scroll_to_cell (itpath, col, gtk.TRUE, 0.5, 0) - def build_tree(self): self.list.set_model(None) self.model = gtk.TreeModelSort(DisplayModels.MediaModel(self.parent.db)) @@ -295,7 +287,7 @@ class MediaView: id = store.get_value(iter,1) mobj = self.db.find_object_from_id(id) if self.is_object_used(mobj): - ans = ImageSelect.DeleteMediaQuery(mobj,self.db,self.update) + ans = ImageSelect.DeleteMediaQuery(mobj,self.db,self.build_tree) QuestionDialog(_('Delete Media Object?'), _('This media object is currently being used. ' 'If you delete this object, it will be removed ' @@ -304,8 +296,10 @@ class MediaView: _('_Delete Media Object'), ans.query_response) else: - self.db.remove_object(mobj.get_id()) - self.update(0) + trans = self.db.start_transaction() + self.db.remove_object(mobj.get_id(),trans) + self.db.add_transaction(trans) + self.build_tree() def is_object_used(self,mobj): for family_id in self.db.get_family_keys(): @@ -366,7 +360,8 @@ class MediaView: photo.set_thumbnail(RelImage.build_thumbnail(name)) description = os.path.basename(name) photo.set_description(description) - self.db.add_object(photo) + trans = self.db.start_transaction() + self.db.add_object(photo,trans) self.load_media() if GrampsCfg.mediaref == 0: name = RelImage.import_media_object(name, @@ -375,7 +370,10 @@ class MediaView: if name: photo.set_path(name) photo.setLocal(1) - self.db.commit_media_object(photo) + + self.db.commit_media_object(photo,trans) + self.db.add_transaction(trans) + if GrampsCfg.globalprop: ImageSelect.GlobalMediaProperties(self.db,photo,self.load_media) elif protocol != "": @@ -394,7 +392,8 @@ class MediaView: photo.set_description(d) photo.setLocal(1) photo.set_path(tfile) - self.db.add_object(photo) + trans = self.db.start_transaction() + self.db.add_object(photo,trans) oref = RelLib.MediaRef() oref.set_reference(photo) try: @@ -407,7 +406,10 @@ class MediaView: except: photo.set_path(tfile) return - self.db.commit_media_object(photo) + + self.db.commit_media_object(photo,trans) + self.db.add_transaction(trans) + if GrampsCfg.globalprop: ImageSelect.GlobalMediaProperties(self.db,photo,None) diff --git a/src/MergeData.py b/src/MergeData.py index 978b8bcfa..46dc50e90 100644 --- a/src/MergeData.py +++ b/src/MergeData.py @@ -307,7 +307,7 @@ class MergePeople: event = self.p2.get_death() event.set_name("Alternate Death") self.p1.add_event(event) - + if self.glade.get_widget("bfather2").get_active(): orig_family = self.p1.get_main_parents_family_id() if orig_family: @@ -347,7 +347,6 @@ class MergePeople: try: self.db.remove_person_id(self.p2.get_id()) self.db.personMap[self.p1.get_id()] = self.p1 - self.db.build_person_display(self.p1.get_id(),old_id) except: print "%s is not in the person map!" % (GrampsCfg.nameof(self.p2)) self.update(self.p1,self.p2,old_id) diff --git a/src/PeopleModel.py b/src/PeopleModel.py index 639d613ff..07a52c733 100644 --- a/src/PeopleModel.py +++ b/src/PeopleModel.py @@ -62,7 +62,7 @@ class PeopleModel(gtk.GenericTreeModel): if not self.db.is_open(): return - + for person_id in self.db.get_person_keys(): person = self.db.find_person_from_id(person_id) @@ -141,7 +141,8 @@ class PeopleModel(gtk.GenericTreeModel): else: return u'' else: - return self.fmap[col](self.db.person_map[str(iter)]) + val = self.fmap[col](self.db.person_map[str(iter)]) + return val def on_iter_next(self, node): '''returns the next node at this level of the tree''' diff --git a/src/PeopleStore.py b/src/PeopleStore.py deleted file mode 100644 index ee46e1bd6..000000000 --- a/src/PeopleStore.py +++ /dev/null @@ -1,325 +0,0 @@ -# -# Gramps - a GTK+/GNOME based genealogy program -# -# Copyright (C) 2000 Donald N. Allingham -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# - -#------------------------------------------------------------------------- -# -# GNOME -# -#------------------------------------------------------------------------- -from gobject import TYPE_STRING, TYPE_INT -import gtk -import pango - -#------------------------------------------------------------------------- -# -# internationalization -# -#------------------------------------------------------------------------- -from gettext import gettext as _ - -#------------------------------------------------------------------------- -# -# constants -# -#------------------------------------------------------------------------- -_BCOL = 8 -_IDCOL = 1 - -_TOP_FONT=pango.WEIGHT_ULTRABOLD -_TEXT_FONT=pango.WEIGHT_NORMAL - -#------------------------------------------------------------------------- -# -# PeopleStore -# -#------------------------------------------------------------------------- -class PeopleStore: - def __init__(self,tree,parent,select_func=None,event_func=None, - mode=gtk.SELECTION_SINGLE): - - self.titles = [ - (_('Name'),5,250), (_('ID'),1,50),(_('Gender'),2,70), - (_('Birth date'),6,150),(_('Death date'),7,150) - ] - - ncols = len(self.titles) + 3 - self.tree = tree - self.parent = parent - self.tree.connect('row-expanded',self.on_row_expanded) - self.mylist = [TYPE_STRING]*ncols + [TYPE_INT] - - self.tree.set_rules_hint(gtk.TRUE) - self.model = None - self.tree_roots = {} - self.tree_open = {} - self.tree_list = {} - self.selection = None - self.mode = mode - self.new_model() - self.count = 0 - self.cid = None - self.cids = [] - - cnum = 0 - for name in self.titles: - renderer = gtk.CellRendererText() - renderer.set_fixed_height_from_font(1) - if name[0] != '': - column = gtk.TreeViewColumn(name[0],renderer,text=cnum) - column.set_min_width(name[2]) - column.set_resizable(gtk.TRUE) - column.set_clickable(gtk.TRUE) - column.set_sort_column_id(name[1]) - - cnum += 1 - self.cids.append(name[1]) - self.tree.append_column(column) - - self.connect_model() - - if select_func: - self.selection.connect('changed',select_func) - if event_func: - self.double_click = event_func - self.tree.connect('row_activated', self.row_activated) - - def row_activated (self, treeview, path, column): - self.double_click (treeview) - - def enable_sort(self): - if self.cids[0] != -1: - self.model.set_sort_column_id(self.cids[0],gtk.SORT_ASCENDING) - - def unselect(self): - self.selection.unselect_all() - - def set_reorderable(self,order): - self.tree.set_reorderable(order) - - def new_model(self): - if self.model: - self.cid = self.model.get_sort_column_id() - del self.model - del self.selection - self.count = 0 - - self.model = gtk.TreeStore(*self.mylist) - self.selection = self.tree.get_selection() - self.selection.set_mode(self.mode) - self.sel_iter = None - - def connect_model(self): - self.tree.set_model(self.model) - if self.sel_iter: - self.selection.select_iter(self.sel_iter) - if self.cid: - self.model.set_sort_column_id(self.cid[0],self.cid[1]) - self.sort() - - def sort(self): - val = self.model.get_sort_column_id() - col = val[0] - if col < 0: - return - if col > 0: - self.model.set_sort_column_id(col,val[1]) - else: - self.model.set_sort_column_id(self.cids[0],val[1]) - self.model.sort_column_changed() - - def get_selected(self): - return self.selection.get_selected() - - def get_row_at(self,x,y): - path = self.tree.get_path_at_pos(x,y) - if path == None: - return self.count -1 - else: - return path[0][0]-1 - - def get_selected_row(self): - store, iter = self.selection.get_selected() - if iter: - rows = store.get_path(iter) - return rows[0] - else: - return -1 - - def get_selected_objects(self): - if self.count == 0: - return [] - elif self.mode == gtk.SELECTION_SINGLE: - store,iter = self.selection.get_selected() - if iter: - return [self.model.get_value(iter,_IDCOL)] - else: - return [] - else: - mlist = [] - self.selection.selected_foreach(self.blist,mlist) - return mlist - - def get_icon(self): - if self.mode == gtk.SELECTION_SINGLE: - store,iter = self.selection.get_selected() - path = self.model.get_path(iter) - else: - mlist = [] - self.selection.selected_foreach(self.blist,mlist) - path = self.model.get_path(mlist[0]) - return self.tree.create_row_drag_icon(path) - - def blist(self,store,path,iter,id_list): - id_list.append(self.model.get_value(iter,_IDCOL)) - - def clear(self): - self.count = 0 - self.tree_roots = {} - self.tree_open = {} - self.model.clear() - - def remove(self,iter): - try: - iter_parent = self.model.iter_parent (iter) - self.model.remove(iter) - if iter_parent and not self.model.iter_has_child (iter_parent): - name = unicode(self.model.get_value(iter_parent,0)) - self.model.remove (iter_parent) - if self.tree_roots.has_key(name): - del self.tree_roots[name] - if self.tree_open.has_key(name): - del self.tree_open[name] - if self.tree_list.has_key(name): - del self.tree_list[name] - self.count = self.count - 1 - except: - pass - - def get_row(self,iter): - row = self.model.get_path(iter) - return row[0] - - def select_row(self,row): - self.selection.select_path((row)) - - def select_iter(self,iter): - self.selection.select_iter(iter) - - def get_object(self,iter): - return self.model.get_value(iter,_IDCOL) - - def insert(self,position,data,info=None,select=0): - self.count = self.count + 1 - iter = self.model.insert(position) - col = 0 - for object in data: - self.model.set_value(iter,col,object) - col = col + 1 - self.model.set_value(iter,_IDCOL,info) - self.model.set_value(iter,_BCOL,_TOP_FONT) - if select: - self.selection.select_iter(iter) - return iter - - def get_data(self,iter,cols): - return [ self.model.get_value(iter,c) for c in cols ] - - def on_row_expanded(self, view, iter, path): - name = self.model.get_value(iter,0) - self.fill_row(name,iter) - - def expand_row(self,name,iter=None): - path = self.model.get_path(self.tree_roots[name]) - self.parent.parent.status_text(_('Updating display...')) - self.tree.expand_row(path,1) - self.parent.parent.modify_statusbar() - - def fill_row(self,name,iter=None): - name = unicode(name) - - if not iter: - iter = self.tree_roots[name] - child = self.model.iter_children(iter) - - if self.model.get_value(child,0) is None: - self.model.remove(child) - for d in self.tree_list[name]: - new_iter = self.model.append(iter) - self.model.set(new_iter,0,d[0],1,d[1],2,d[2],3,d[3],4,d[4], - 5,d[5],6,d[6],7,d[7]) - self.parent.id2col[d[1]] = (self,new_iter) - self.expand_row (name, iter) - - def add(self,data,select=0): - self.count = self.count + 1 - - name = data[-1] - if self.tree_roots.has_key(name): - top = self.tree_roots[name] - else: - top = self.model.append(None) - self.model.append(top) - self.tree_open[name] = 0 - self.tree_list[name] = [] - self.model.set_value(top,0,name) - self.model.set_value(top,5,name.upper()) - self.model.set_value(top,_BCOL,_TOP_FONT) - self.tree_roots[name] = top - - if self.tree_open[name] or select: - iter = self.model.append(top) - col = 0 - for object in data[:-1]: - self.model.set_value(iter,col,object) - col = col + 1 - self.model.set_value(iter,_BCOL,_TEXT_FONT) - if select: - self.sel_iter = iter - self.selection.select_iter(self.sel_iter) - return iter - else: - self.tree_list[name].append(data) - return None - - def set(self,iter,data,select=0): - col = 0 - for object in data: - self.model.set_value(iter,col,object) - col = col + 1 - self.model.set_value(iter,_BCOL,_TEXT_FONT) - if select: - self.sel_iter = iter - return iter - - def add_and_select(self,data): - self.count = self.count + 1 - iter = self.model.append() - col = 0 - for object in data: - self.model.set_value(iter,col,object) - col = col + 1 - self.model.set_value(iter,_BCOL,_TEXT_FONT) - self.selection.select_iter(iter) - - def center_selected(self): - model,iter = self.selection.get_selected() - if iter: - path = model.get_path(iter) - self.tree.scroll_to_cell(path,None,gtk.TRUE,0.5,0.5) diff --git a/src/PeopleView.py b/src/PeopleView.py index f2a01bb27..10e8cc3e8 100644 --- a/src/PeopleView.py +++ b/src/PeopleView.py @@ -151,11 +151,7 @@ class PeopleView: 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""" - if old_id == None or person.get_id() == old_id: - path = self.person_model.on_get_path(person.get_id()) - self.person_model.row_deleted(path) - else: - self.person_model.rebuild_data() + self.build_tree() def remove_from_history(self,person,old_id=None): """Removes a person from the history list""" @@ -187,8 +183,8 @@ class PeopleView: self.apply_filter(self.person_tree) self.goto_active_person() - def add_to_person_list(self,person,change): - self.rebuild_data() + def add_to_person_list(self,person,change=0): + self.build_tree() def goto_active_person(self,first=0): if not self.parent.active_person: @@ -253,4 +249,7 @@ class PeopleView: menu.popup(None,None,None,event.button,event.time) def redisplay_person_list(self,person): - self.person_model.rebuild_data() + self.person_model = PeopleModel.PeopleModel(self.parent.db) + self.sort_model = gtk.TreeModelSort(self.person_model) + self.person_tree.set_model(self.sort_model) + diff --git a/src/PlaceView.py b/src/PlaceView.py index 1fed562aa..f452ff5d1 100644 --- a/src/PlaceView.py +++ b/src/PlaceView.py @@ -68,21 +68,18 @@ class PlaceView: def __init__(self,parent,db,glade,update): self.parent = parent - self.db = db self.glade = glade + self.db = db self.list = glade.get_widget("place_list") - self.update = update + self.list.connect('button-press-event',self.button_press) + self.list.connect('key-press-event',self.key_press) + self.selection = self.list.get_selection() + self.selection.set_mode(gtk.SELECTION_MULTIPLE) self.renderer = gtk.CellRendererText() - self.active = None - self.model = gtk.TreeModelSort(DisplayModels.PlaceModel(self.db)) self.list.set_model(self.model) - self.selection = self.list.get_selection() - self.selection.set_mode(gtk.SELECTION_MULTIPLE) - self.list.connect('button-press-event',self.button_press) - self.list.connect('key-press-event',self.key_press) self.topWindow = self.glade.get_widget("gramps") self.columns = [] @@ -127,35 +124,6 @@ class PlaceView: self.list.set_model(self.model) self.selection = self.list.get_selection() - def load_places(self,id=None): - """Rebuilds the entire place view. This can be very time consuming - on large databases, and should only be called when absolutely - necessary""" - pass - #self.build_tree() - - def goto(self,id): - self.selection.unselect_all() - iter = self.id2col[id] - self.selection.select_iter(iter) - itpath = self.model.get_path (iter) - col = self.list.get_column (0) - self.list.scroll_to_cell (itpath, col, gtk.TRUE, 0.5, 0) - - def merge(self): - mlist = [] - self.selection.selected_foreach(self.blist,mlist) - - if len(mlist) != 2: - msg = _("Cannot merge places.") - msg2 = _("Exactly two places must be selected to perform a merge. " - "A second place can be selected by holding down the " - "control key while clicking on the desired place.") - ErrorDialog(msg,msg2) - else: - import MergeData - MergeData.MergePlaces(self.db,mlist[0],mlist[1],self.load_places) - def button_press(self,obj,event): if event.type == gtk.gdk._2BUTTON_PRESS and event.button == 1: mlist = [] @@ -201,26 +169,25 @@ class PlaceView: menu.append(item) menu.popup(None,None,None,event.button,event.time) - def new_place_after_edit(self,place): - self.db.add_place(place) - self.update(0) - - def update_display(self,place): - if place: - self.db.build_place_display(place.get_id()) - self.update(0) - def on_add_place_clicked(self,obj): EditPlace.EditPlace(self.parent,RelLib.Place(),self.new_place_after_edit) + def new_place_after_edit(self,place): + self.db.add_place(place) + + def update_display(self,place): + self.build_tree() + def on_delete_clicked(self,obj): mlist = [] self.selection.selected_foreach(self.blist,mlist) - + + trans = self.db.start_transaction() + for place in mlist: used = 0 for key in self.db.get_person_keys(): - p = self.db.get_person(key) + p = self.db.find_person_from_id(key) event_list = [] for e in [p.get_birth_id(),p.get_death_id()] + p.get_event_list(): event = self.db.find_event_from_id(e) @@ -233,7 +200,8 @@ class PlaceView: if p.get_lds_sealing(): event_list.append(p.get_lds_sealing()) for event in event_list: - if event.get_place_id() == place: + if event.get_place_id() == place.get_id(): + print event.get_id() used = 1 for fid in self.db.get_family_keys(): @@ -246,7 +214,8 @@ class PlaceView: if f.get_lds_sealing(): event_list.append(f.get_lds_sealing()) for event in event_list: - if event.get_place_id() == place: + if event.get_place_id() == place.get_id(): + print event.get_id() used = 1 if used == 1: @@ -259,8 +228,10 @@ class PlaceView: _('_Delete Place'), ans.query_response) else: - self.db.remove_place(place.get_id()) - self.update(0) + trans = self.db.start_transaction() + self.db.remove_place(place.get_id(),trans) + self.db.add_transaction(trans) + self.build_tree() def on_edit_clicked(self,obj): """Display the selected places in the EditPlace display""" @@ -273,3 +244,18 @@ class PlaceView: def blist(self,store,path,iter,list): id = self.db.get_place_id(store.get_value(iter,1)) list.append(id) + + def merge(self): + mlist = [] + self.selection.selected_foreach(self.blist,mlist) + + if len(mlist) != 2: + msg = _("Cannot merge places.") + msg2 = _("Exactly two places must be selected to perform a merge. " + "A second place can be selected by holding down the " + "control key while clicking on the desired place.") + ErrorDialog(msg,msg2) + else: + import MergeData + MergeData.MergePlaces(self.db,mlist[0],mlist[1],self.build_tree) + diff --git a/src/RelLib.py b/src/RelLib.py index dd061d713..7b102a73c 100644 --- a/src/RelLib.py +++ b/src/RelLib.py @@ -57,6 +57,13 @@ CONF_NORMAL = 2 CONF_LOW = 1 CONF_VERY_LOW = 0 +PERSON_KEY = 0 +FAMILY_KEY = 1 +SOURCE_KEY = 2 +EVENT_KEY = 3 +MEDIA_KEY = 4 +PLACE_KEY = 5 + #------------------------------------------------------------------------- # # ID regular expression @@ -65,6 +72,11 @@ CONF_VERY_LOW = 0 _id_reg = compile("%\d+d") +#------------------------------------------------------------------------- +# +# SourceNote +# +#------------------------------------------------------------------------- class SourceNote: """Base class for storing source references and notes""" @@ -84,9 +96,9 @@ class SourceNote: else: self.note = None - def add_source_reference(self,id) : + def add_source_reference(self,gid) : """Set the source reference""" - self.source_list.append(id) + self.source_list.append(gid) def get_source_references(self) : """Return the source reference""" @@ -133,6 +145,11 @@ class SourceNote: """Creates a unique instance of the current note""" self.note = Note(self.note.get()) +#------------------------------------------------------------------------- +# +# LdsOrd +# +#------------------------------------------------------------------------- class LdsOrd(SourceNote): """LDS Ordinance support""" def __init__(self,source=None): @@ -160,7 +177,6 @@ class LdsOrd(SourceNote): def set_place_id(self,place): """sets the Place instance of the Event""" - assert(type(place) == types.StringType or type(place) == types.UnicodeType) self.place = place def get_place_id(self): @@ -247,6 +263,11 @@ class LdsOrd(SourceNote): index = index + 1 return 1 +#------------------------------------------------------------------------- +# +# DataObj +# +#------------------------------------------------------------------------- class DataObj(SourceNote): """Base class for data elements, providing source, note, and privacy data""" @@ -267,6 +288,11 @@ class DataObj(SourceNote): """Returns the privacy level of the data""" return self.private +#------------------------------------------------------------------------- +# +# Place +# +#------------------------------------------------------------------------- class Place(SourceNote): """Contains information related to a place, including multiple address information (since place names can change with time), longitude, latitude, @@ -323,9 +349,9 @@ class Place(SourceNote): """Add a URL to the URL list""" self.urls.append(url) - def set_id(self,id): + def set_id(self,gid): """Sets the gramps ID for the place object""" - self.id = id + self.id = gid def get_id(self): """Returns the gramps ID for the place object""" @@ -407,6 +433,11 @@ class Place(SourceNote): else: return [self.title,self.id,'','','','','',self.title.upper(), '','','','',''] +#------------------------------------------------------------------------- +# +# Researcher +# +#------------------------------------------------------------------------- class Researcher: """Contains the information about the owner of the database""" @@ -472,6 +503,11 @@ class Researcher: if email: self.email = email.strip() +#------------------------------------------------------------------------- +# +# Location +# +#------------------------------------------------------------------------- class Location: """Provides information about a place, including city, county, state, and country. Multiple Location objects can represent the same place, @@ -584,6 +620,11 @@ class Note: """return the note's format""" return self.format +#------------------------------------------------------------------------- +# +# MediaObject +# +#------------------------------------------------------------------------- class MediaObject(SourceNote): """Containter for information about an image file, including location, description and privacy""" @@ -621,9 +662,9 @@ class MediaObject(SourceNote): (self.id, junk, self.path, self.mime, self.desc, self.attrlist, self.source_list, self.note) = data - def set_id(self,id): + def set_id(self,gid): """Sets the gramps ID for the place object""" - self.id = id + self.id = gid def get_id(self): """Returns the gramps ID for the place object""" @@ -664,7 +705,11 @@ class MediaObject(SourceNote): def set_attribute_list(self,list): self.attrlist = list - +#------------------------------------------------------------------------- +# +# MediaRef +# +#------------------------------------------------------------------------- class MediaRef: """Object reference class""" def __init__(self,source=None): @@ -745,6 +790,11 @@ class MediaRef: """sets the property list associated with the image""" self.attrlist = list +#------------------------------------------------------------------------- +# +# Attribute +# +#------------------------------------------------------------------------- class Attribute(DataObj): """Provides a simple key/value pair for describing properties. Used by the Person and Family objects to store descriptive information.""" @@ -776,7 +826,11 @@ class Attribute(DataObj): """returns the value of the Attribute instance""" return self.value - +#------------------------------------------------------------------------- +# +# Address +# +#------------------------------------------------------------------------- class Address(DataObj): """Provides address information for a person""" @@ -873,6 +927,11 @@ class Address(DataObj): """returns the postal code of the Address""" return self.postal +#------------------------------------------------------------------------- +# +# Name +# +#------------------------------------------------------------------------- class Name(DataObj): """Provides name information about a person. A person may have more that one name throughout his or her life.""" @@ -1047,6 +1106,11 @@ class Name(DataObj): index = index + 1 return 1 +#------------------------------------------------------------------------- +# +# Url +# +#------------------------------------------------------------------------- class Url: """Contains information related to internet Uniform Resource Locators, allowing gramps to store information about internet resources""" @@ -1096,7 +1160,11 @@ class Url: return 0 return 1 - +#------------------------------------------------------------------------- +# +# Person +# +#------------------------------------------------------------------------- class Person(SourceNote): """Represents an individual person in the gramps database""" @@ -1104,10 +1172,10 @@ class Person(SourceNote): male = 1 female = 0 - def __init__(self,id=""): + def __init__(self,gid=""): """creates a new Person instance""" SourceNote.__init__(self) - self.id = id + self.id = gid self.primary_name = Name() self.event_list = [] self.family_list = [] @@ -1226,9 +1294,9 @@ class Person(SourceNote): """adds a URL instance to the list""" self.urls.append(url) - def set_id(self,id): + def set_id(self,gid): """sets the gramps ID for the Person""" - self.id = str(id) + self.id = str(gid) def get_id(self): """returns the gramps ID for the Person""" @@ -1321,8 +1389,7 @@ class Person(SourceNote): """adds the specified Family instance to the list of families/marriages/partnerships in which the person is a parent or spouse""" - assert(type(family_id) == types.StringType or type(family_id) == types.UnicodeType) - + self.family_list.append(family_id) def set_preferred_family_id(self,family): @@ -1338,7 +1405,7 @@ class Person(SourceNote): def clear_family_id_list(self) : self.family_list = [] - def remove_family_id(self,family): + def remove_family_id(self,family,trans=None): """removes the specified Family instance from the list of marriages/partnerships""" assert(type(family) == types.StringType or type(family) == types.UnicodeType) @@ -1589,6 +1656,11 @@ class Person(SourceNote): return 1 +#------------------------------------------------------------------------- +# +# Event +# +#------------------------------------------------------------------------- class Event(DataObj): """Event record, recording the event type, description, place, and date of a particular event""" @@ -1652,9 +1724,9 @@ class Event(DataObj): self.place, self.cause, self.private, self.source_list, self.note, self.witness) = data - def set_id(self,id): + def set_id(self,gid): """Sets the gramps ID for the place object""" - self.id = id + self.id = gid def get_id(self): """Returns the gramps ID for the place object""" @@ -1739,7 +1811,6 @@ class Event(DataObj): def set_place_id(self,place): """sets the Place instance of the Event""" - assert(type(place) == types.StringType or type(place) == types.UnicodeType) self.place = place def get_place_id(self): @@ -1797,6 +1868,11 @@ class Event(DataObj): """sets the Date object associated with the Event""" self.date = date +#------------------------------------------------------------------------- +# +# Witness +# +#------------------------------------------------------------------------- class Witness: def __init__(self,type=Event.NAME,val="",comment=""): self.set_type(type) @@ -1821,6 +1897,11 @@ class Witness: def get_comment(self): return self.comment +#------------------------------------------------------------------------- +# +# Family +# +#------------------------------------------------------------------------- class Family(SourceNote): """Represents a family unit in the gramps database""" @@ -1884,9 +1965,9 @@ class Family(SourceNote): """sets the attribute list to the specified list""" self.attribute_list = list - def set_id(self,id) : + def set_id(self,gid) : """sets the gramps ID for the Family""" - self.id = str(id) + self.id = str(gid) def get_id(self) : """returns the gramps ID for the Family""" @@ -2006,6 +2087,11 @@ class Family(SourceNote): return 1 return None +#------------------------------------------------------------------------- +# +# Source +# +#------------------------------------------------------------------------- class Source: """A record of a source of information""" @@ -2207,6 +2293,11 @@ class SourceRef: """Creates a unique instance of the current note""" self.comments = Note(self.comments.get()) +#------------------------------------------------------------------------- +# +# GenderStats +# +#------------------------------------------------------------------------- class GenderStats: def __init__ (self): self.stats = {} @@ -2280,6 +2371,11 @@ except ImportError: # try python2.2 def find_surname(key,data): return str(data[2].get_surname()) +#------------------------------------------------------------------------- +# +# GrampsDB +# +#------------------------------------------------------------------------- class GrampsDB: """GRAMPS database object. This object is a base class for other objects.""" @@ -2421,34 +2517,48 @@ class GrampsDB: data[5], GrampsCfg.display_surname(data[2])] - def commit_person(self,person): - assert(person.get_id()) - self.person_map.put(str(person.get_id()),person.serialize()) - - def commit_media_object(self,object): + def commit_person(self,person,transaction=None): + gid = str(person.get_id()) + if transaction != None: + old_data = self.person_map.get(gid) + transaction.add(PERSON_KEY,gid,old_data) + self.person_map.put(gid,person.serialize()) + + def commit_media_object(self,object,transaction=None): + gid = str(object.get_id()) + if transaction != None: + old_data = self.media_map.get(gid) + transaction.add(MEDIA_KEY,gid,old_data) self.media_map.put(str(object.get_id()),object.serialize()) - def commit_source(self,source): + def commit_source(self,source,transaction=None): + gid = str(source.get_id()) + if transaction != None: + old_data = self.source_map.get(gid) + transaction.add(SOURCE_KEY,gid,old_data) self.source_map.put(str(source.get_id()),source.serialize()) - def commit_place(self,place): + def commit_place(self,place,transaction=None): + gid = str(place.get_id()) + if transaction != None: + old_data = self.place_map.get(gid) + transaction.add(PLACE_KEY,gid,old_data) self.place_map.put(str(place.get_id()),place.serialize()) - def commit_event(self,event): + def commit_event(self,event,transaction=None): + gid = str(event.get_id()) + if transaction != None: + old_data = self.event_map.get(gid) + transaction.add(EVENT_KEY,gid,old_data) self.event_map.put(str(event.get_id()),event.serialize()) - def commit_family(self,family): + def commit_family(self,family,transaction=None): + gid = str(family.get_id()) + if transaction != None: + old_data = self.family_map.get(gid) + transaction.add(FAMILY_KEY,gid,old_data) self.family_map.put(str(family.get_id()),family.serialize()) - def build_person_display(self,nkey,okey=None): - pass - - def rebuild_person_table(self): - pass - - def build_place_display(self,nkey,okey=None): - pass - def set_iprefix(self,val): if val: if _id_reg.search(val): @@ -2506,6 +2616,7 @@ class GrampsDB: def new(self): """initializes the GrampsDB to empty values""" + self.translist = [] self.smap_index = 0 self.emap_index = 0 self.pmap_index = 0 @@ -2520,16 +2631,60 @@ class GrampsDB: self.genderStats = GenderStats () def start_transaction(self): - pass + return Transaction() - def end_transaction(self): - pass + def add_transaction(self,transaction): + print "---- Add" + transaction.display() + self.translist.append(transaction) - def abort_transaction(self): - pass + def undo(self): + if len(self.translist) == 0: + return + transaction = self.translist.pop() + print "---- undo" + transaction.display() + + subitems = transaction.get_data() + subitems.reverse() + for (key, gid, data) in subitems: + if key == PERSON_KEY: + if data == None: + print "removing PERSON",gid + del self.person_map[gid] + else: + print "altering PERSON",gid + self.person_map.put(gid,data) + elif key == FAMILY_KEY: + if data == None: + print "removing FAMILY",gid + del self.family_map[gid] + else: + print "altering FAMILY",gid + self.family_map.put(gid,data) + elif key == SOURCE_KEY: + if data == None: + del self.source_map[gid] + else: + self.source_map.put(gid,data) + elif key == EVENT_KEY: + if data == None: + print "removing EVENT",gid + del self.event_map[gid] + else: + print "altering EVENT",gid + self.event_map.put(gid,data) + elif key == PLACE_KEY: + if data == None: + del self.place_map[gid] + else: + self.place_map.put(gid,data) + elif key == MEDIA_KEY: + if data == None: + del self.media_map[gid] + else: + self.media_map.put(gid,data) - #EARNEY, may eventually be able to use secondary indexes for this - #that way we will not have to track these with code. def get_surnames(self): names = self.surnames.keys() a = {} @@ -2569,25 +2724,25 @@ class GrampsDB: # if person: # self.default.set_ancestor(1) - def set_default_person_id(self,id): + def set_default_person_id(self,gid): """sets the default Person to the passed instance""" - assert(type(id) == types.StringType or type(id) == types.UnicodeType) - self.metadata['default'] = id + assert(type(gid) == types.StringType or type(gid) == types.UnicodeType) + self.metadata['default'] = gid def get_default_person(self): """returns the default Person of the database""" if self.metadata and self.metadata.has_key('default'): person = Person() - id = self.metadata['default'] - data = self.person_map.get(str(id)) + gid = self.metadata['default'] + data = self.person_map.get(str(gid)) person.unserialize(data) return person return None - def get_person(self,id): + def get_person(self,gid): """returns a Person from a GRAMPS's ID""" p = Person() - data = self.person_map.get(str(id)) + data = self.person_map.get(str(gid)) p.unserialize(data) return p @@ -2599,9 +2754,9 @@ class GrampsDB: """sets the map of gramps's IDs to Place instances""" self.place_map = map - def get_family_id(self,id): + def get_family_id(self,gid): """returns a map of gramps's IDs to Family instances""" - return self.family_map.get(str(id)) + return self.family_map.get(str(gid)) def get_save_path(self): """returns the save path of the file, or "" if one does not exist""" @@ -2662,58 +2817,83 @@ class GrampsDB: # map[family.get_relationship()] = 1 return map.keys() - def remove_person_id(self,id): -# self.genderStats.uncount_person (self.person_map[id]) - self.person_map.delete(str(id)) + def remove_person_id(self,gid,transaction=None): +# self.genderStats.uncount_person (self.person_map[gid]) + if transaction != None: + old_data = self.person_map.get(str(gid)) + transaction.add(PERSON_KEY,gid,old_data) + self.person_map.delete(str(gid)) - def remove_source_id(self,id): - self.source_map.delete(str(id)) + def remove_source_id(self,gid,transaction=None): + if transaction != None: + old_data = self.source_map.get(str(gid)) + transaction.add(SOURCE_KEY,gid,old_data) + self.source_map.delete(str(gid)) - def remove_event_id(self,id): - self.event_map.delete(str(id)) + def remove_event_id(self,gid,transaction=None): + if transaction != None: + old_data = self.event_map.get(str(gid)) + transaction.add(EVENT_KEY,gid,old_data) + self.event_map.delete(str(gid)) - def add_person_as(self,person): - assert(person.get_id()) + def add_person_as(self,person,trans=None): + if trans != None: + trans.add(PERSON_KEY, person.get_id(),None) self.person_map.put(str(person.get_id()),person.serialize()) # self.genderStats.count_person (person, self) return person.get_id() - def add_person(self,person): + def add_person(self,person,trans=None): """adds a Person to the database, assigning a gramps' ID""" index = self.iprefix % self.pmap_index while self.person_map.get(str(index)): self.pmap_index = self.pmap_index + 1 index = self.iprefix % self.pmap_index person.set_id(index) - assert(person.get_id()) + if trans != None: + trans.add(PERSON_KEY, person.get_id(),None) self.person_map.put(str(index),person.serialize()) self.pmap_index = self.pmap_index + 1 self.genderStats.count_person (person, self) return index - def find_person(self,idVal,map): - """finds a Person in the database using the idVal and map + def find_person(self,gid,map,trans=None): + """finds a Person in the database using the gid and map variables to translate between the external ID and gramps' internal ID. If no such Person exists, a new Person instance is created. - idVal - external ID number + gid - external ID number map - map build by findPerson of external to gramp's IDs""" - idVal = str(idVal) + gid = str(gid) person = Person() - if map.has_key(idVal): - person.unserialize(self.person_map.get(str(map[idVal]))) + if map.has_key(gid): + person.unserialize(self.person_map.get(str(map[gid]))) else: person = Person() - map[idVal] = self.add_person(person) + map[gid] = self.add_person(person,trans) self.genderStats.count_person (person, self) return person def has_person_id(self,val): #what does this function do? return self.person_map.get(str(val)) #EARNEY - def find_person_from_id(self,val): + + def try_to_find_person_from_id(self,val,trans=None): + """finds a Person in the database from the passed gramps' ID. + If no such Person exists, a new Person is added to the database.""" + + person = Person() + data = self.person_map.get(str(val)) + + if data: + person.unserialize(data) + return person + else: + return None + + def find_person_from_id(self,val,trans=None): """finds a Person in the database from the passed gramps' ID. If no such Person exists, a new Person is added to the database.""" @@ -2724,21 +2904,24 @@ class GrampsDB: person.unserialize(data) else: person.set_id(val) - assert(person.get_id()) + if trans != None: + trans.add(PERSON_KEY, val, None) self.person_map.put(str(val), person.serialize()) self.pmap_index = self.pmap_index+1 # self.genderStats.count_person (person, self) return person - def add_person_no_map(self,person,id): + def add_person_no_map(self,person,gid,trans=None): """adds a Person to the database if the gramps' ID is known""" - id = str(id) - person.set_id(id) - self.person_map.set(str(id),person.serialize()) + gid = str(gid) + person.set_id(gid) + if trans != None: + trans.add(PERSON_KEY, gid, None) + self.person_map.set(str(gid),person.serialize()) self.pmap_index = self.pmap_index+1 # self.genderStats.count_person (person, self) - return id + return gid def add_source(self,source): """adds a Source instance to the database, assigning it a gramps' @@ -2749,11 +2932,13 @@ class GrampsDB: self.smap_index = self.smap_index + 1 index = self.sprefix % self.smap_index source.set_id(index) + if trans != None: + trans.add(SOURCE_KEY,index,None) self.source_map.put(str(index),source.serialize()) self.smap_index = self.smap_index + 1 return index - def add_event(self,event): + def add_event(self,event,trans=None): """adds a Event instance to the database, assigning it a gramps' ID number""" index = self.eprefix % self.emap_index @@ -2761,62 +2946,67 @@ class GrampsDB: self.emap_index += 1 index = self.eprefix % self.emap_index event.set_id(index) + if trans != None: + trans.add(EVENT_KEY,index,None) self.event_map.put(str(index),event.serialize()) self.emap_index += 1 return index - def add_source_no_map(self,source,index): + def add_source_no_map(self,source,index,trans=None): """adds a Source to the database if the gramps' ID is known""" source.set_id(index) + if trans != None: + trans.add(SOURCE_KEY,index,None) self.source_map.put(str(index),source.serialize()) self.smap_index = self.smap_index + 1 return index - def add_event_no_map(self,event,index): + def add_event_no_map(self,event,index,trans=None): """adds a Source to the database if the gramps' ID is known""" return event.set_id(index) + if trans != None: + trans.add(EVENT_KEY,index,None) self.event_map.put(str(index),event.serialize()) self.emap_index += 1 return index - def find_source(self,idVal,map): - """finds a Source in the database using the idVal and map + def find_source(self,gid,map,trans=None): + """finds a Source in the database using the gid and map variables to translate between the external ID and gramps' internal ID. If no such Source exists, a new Source instance is created. - idVal - external ID number + gid - external ID number map - map build by find_source of external to gramp's IDs""" - if map.has_key(idVal): - data = self.source_map.get(str(map[idVal])) + if map.has_key(gid): + data = self.source_map.get(str(map[gid])) source = Source() source.unserialize(data) else: source = Source() - map[idVal] = self.add_source(source) + map[gid] = self.add_source(source,trans) return source - def find_event(self,idVal,map): - """finds a Event in the database using the idVal and map + def find_event(self,gid,map,trans=None): + """finds a Event in the database using the gid and map variables to translate between the external ID and gramps' internal ID. If no such Event exists, a new Event instance is created. - idVal - external ID number + gid - external ID number map - map build by find_source of external to gramp's IDs""" event = Event() - if map.has_key(idVal): - pass -# data = self.event_map.get(str(map[idVal])) -# event.serialize(data) + if map.has_key(gid): + data = self.event_map.get(str(map[gid])) + event.serialize(data) else: - map[idVal] = self.add_event(event) + map[gid] = self.add_event(event,trans) return event - def find_source_from_id(self,val): + def find_source_from_id(self,val,trans): """finds a Source in the database from the passed gramps' ID. If no such Source exists, a new Source is added to the database.""" @@ -2824,7 +3014,7 @@ class GrampsDB: if self.source_map.get(str(val)): source.unserialize(self.source_map.get(str(val))) else: - self.add_source_no_map(source,val) + self.add_source_no_map(source,val,trans) return source def find_event_from_id(self,val): @@ -2838,7 +3028,7 @@ class GrampsDB: else: return None - def add_object(self,object): + def add_object(self,object,trans=None): """adds an Object instance to the database, assigning it a gramps' ID number""" @@ -2847,74 +3037,84 @@ class GrampsDB: self.omap_index = self.omap_index + 1 index = self.oprefix % self.omap_index object.set_id(index) + if trans != None: + trans.add(MEDIA_KEY,index,None) self.media_map.put(str(index),object.serialize()) self.omap_index = self.omap_index + 1 self.added_files.append(object) return index - def get_object(self,id): - return self.media_map[str(id)] + def get_object(self,gid): + return self.media_map[str(gid)] - def find_object(self,idVal,map): - """finds an Object in the database using the idVal and map + def find_object(self,gid,map,trans=None): + """finds an Object in the database using the gid and map variables to translate between the external ID and gramps' internal ID. If no such Object exists, a new Object instance is created. - idVal - external ID number + gid - external ID number map - map build by find_object of external to gramp's IDs""" - idVal = str(idVal) + gid = str(gid) object = MediaObject() - if map.has_key(idVal): - object.unserialize(self.media_map.get(str(map[idVal]))) + if map.has_key(gid): + object.unserialize(self.media_map.get(str(map[gid]))) else: - map[idVal] = self.add_object(object) + map[gid] = self.add_object(object,trans) return object - def find_object_no_conflicts(self,idVal,map): - """finds an Object in the database using the idVal and map + def find_object_no_conflicts(self,gid,map,trans=None): + """finds an Object in the database using the gid and map variables to translate between the external ID and gramps' internal ID. If no such Object exists, a new Object instance is created. - idVal - external ID number + gid - external ID number map - map build by find_object of external to gramp's IDs""" - idVal = str(idVal) + gid = str(gid) object = MediaObject() - if map.has_key(idVal): - object.unserialize(self.media_map.get(str(map[idVal]))) + if map.has_key(gid): + object.unserialize(self.media_map.get(str(map[gid]))) else: - if self.media_map.get(str(idVal)): - map[idVal] = self.add_object(object) + if self.media_map.get(str(gid)): + map[gid] = self.add_object(object,trans) else: - map[idVal] = self.add_object_no_map(object,idVal) + map[gid] = self.add_object_no_map(object,gid,trans) return object - def add_object_no_map(self,object,index): + def add_object_no_map(self,object,index,trans=None): """adds an Object to the database if the gramps' ID is known""" index = str(index) object.set_id(index) + if trans != None: + trans.add(MEDIA_KEY,index,None) self.media_map.put(str(index),object.serialize()) self.omap_index = self.omap_index + 1 self.added_files.append(object) return index - def find_object_from_id(self,idVal): + def find_object_from_id(self,gid,trans=None): """finds an Object in the database from the passed gramps' ID. If no such Source exists, a new Source is added to the database.""" object = MediaObject() - if self.media_map.get(str(idVal)): - object.unserialize(self.media_map.get(str(idVal))) + if self.media_map.get(str(gid)): + object.unserialize(self.media_map.get(str(gid))) else: - self.add_object_no_map(object,idVal) + self.add_object_no_map(object,gid,trans) return object - def add_place(self,place): + def has_object_id(self,gid): + """finds an Object in the database from the passed gramps' ID. + If no such Source exists, a new Source is added to the database.""" + + return self.media_map.get(str(gid)) != None + + def add_place(self,place,trans=None): """adds a Place instance to the database, assigning it a gramps' ID number""" @@ -2923,61 +3123,75 @@ class GrampsDB: self.lmap_index = self.lmap_index + 1 index = self.pprefix % self.lmap_index place.set_id(index) + if trans != None: + trans.add(PLACE_KEY,index,None) self.place_map.put(str(index),place.serialize()) self.lmap_index = self.lmap_index + 1 return index - def remove_object(self,id): - self.media_map.delete(str(id)) + def remove_object(self,gid,transaction=None): + if transaction != None: + old_data = self.media_map.get(str(gid)) + transaction.add(MEDIA_KEY,gid,old_data) + self.media_map.delete(str(gid)) - def remove_place(self,id): - self.place_map.delete(str(id)) + def remove_place(self,gid,transaction=None): + if transaction != None: + old_data = self.place_map.get(str(gid)) + transaction.add(PLACE_KEY,gid,old_data) + self.place_map.delete(str(gid)) - def add_place_as(self,place): + def add_place_as(self,place,trans=None): + if trans != None: + trans.add(PLACE_KEY,index,None) self.place_map.put(str(place.get_id()),place.serialize()) return place.get_id() - def find_place_no_conflicts(self,idVal,map): - """finds a Place in the database using the idVal and map + def find_place_no_conflicts(self,gid,map,trans=None): + """finds a Place in the database using the gid and map variables to translate between the external ID and gramps' internal ID. If no such Place exists, a new Place instance is created. - idVal - external ID number + gid - external ID number map - map build by findPlace of external to gramp's IDs""" - if map.has_key(str(idVal)): + if map.has_key(str(gid)): place = Place() - data = self.place_map[str(map[idVal])] + data = self.place_map[str(map[gid])] place.unserialize(data) else: place = Place() - if self.place_map.has_key(str(idVal)): - map[idVal] = self.add_place(place) + if self.place_map.has_key(str(gid)): + map[gid] = self.add_place(place,trans) else: - place.set_id(str(idVal)) - map[str(idVal)] = self.add_place_as(place) - self.place_map.put(str(idVal),place.serialize()) + place.set_id(str(gid)) + map[str(gid)] = self.add_place_as(place,trans) + self.place_map.put(str(gid),place.serialize()) return place - def add_place_no_map(self,place,index): + def add_place_no_map(self,place,index,trans=None): """adds a Place to the database if the gramps' ID is known""" index = str(index) place.set_id(index) + if trans != None: + trans.add(PLACE_KEY,index,None) self.place_map.put(str(index), place.serialize()) self.lmap_index = self.lmap_index + 1 return index - def find_place_from_id(self,id): + def find_place_from_id(self,gid,trans=None): """finds a Place in the database from the passed gramps' ID. If no such Place exists, a new Place is added to the database.""" - data = self.place_map.get(str(id)) + data = self.place_map.get(str(gid)) place = Place() if not data: - place.id = id - self.place_map.put(str(id),place.serialize()) + place.id = gid + if trans != None: + trans.add(PLACE_KEY,gid,None) + self.place_map.put(str(gid),place.serialize()) self.lmap_index = self.lmap_index + 1 else: place.unserialize(data) @@ -3073,8 +3287,9 @@ class GrampsDB: def build_source_display(self,nkey,okey=None): pass - def new_family(self): + def new_family(self,trans=None): """adds a Family to the database, assigning a gramps' ID""" + index = self.fprefix % self.fmap_index while self.family_map.get(str(index)): self.fmap_index = self.fmap_index + 1 @@ -3082,39 +3297,43 @@ class GrampsDB: self.fmap_index = self.fmap_index + 1 family = Family() family.set_id(index) + if trans != None: + trans.add(FAMILY_KEY, index, None) self.family_map.put(str(index),family.serialize()) return family - def new_family_no_map(self,id): + def new_family_no_map(self,gid,trans=None): """finds a Family in the database from the passed gramps' ID. If no such Family exists, a new Family is added to the database.""" family = Family() - id = str(id) - family.set_id(id) - self.family_map.put(str(id),family.serialize()) + gid = str(gid) + family.set_id(gid) + if trans != None: + trans.add(FAMILY_KEY, index, None) + self.family_map.put(str(gid),family.serialize()) self.fmap_index = self.fmap_index + 1 return family - def find_family_with_map(self,idVal,map): - """finds a Family in the database using the idVal and map + def find_family_with_map(self,gid,map,trans=None): + """finds a Family in the database using the gid and map variables to translate between the external ID and gramps' internal ID. If no such Family exists, a new Family instance is created. - idVal - external ID number + gid - external ID number map - map build by find_family_with_map of external to gramp's IDs""" - if map.has_key(idVal): + if map.has_key(gid): family = Family() - data = self.family_map.get(str(map[idVal])) + data = self.family_map.get(str(map[gid])) family.unserialize(data) else: family = self.new_family() - map[idVal] = family.get_id() + map[gid] = family.get_id() return family - def find_family_no_map(self,val): + def find_family_no_map(self,val,trans=None): """finds a Family in the database from the passed gramps' ID. If no such Family exists, a new Family is added to the database.""" @@ -3124,6 +3343,8 @@ class GrampsDB: family.unserialize(data) else: family.id = val + if trans: + trans.add(FAMILY_KEY,val,None) self.family_map.put(str(val),family.serialize()) self.fmap_index = self.fmap_index + 1 return family @@ -3139,68 +3360,71 @@ class GrampsDB: else: return None - def delete_family(self,family_id): + def delete_family(self,family_id,trans=None): """deletes the Family instance from the database""" if self.family_map.get(str(family_id)): + if trans != None: + old_data = self.family_map.get(str(family_id)) + trans.add(FAMILY_KEY,family_id,old_data) self.family_map.delete(str(family_id)) - def find_person_no_conflicts(self,idVal,map): - """finds a Person in the database using the idVal and map + def find_person_no_conflicts(self,gid,map,trans=None): + """finds a Person in the database using the gid and map variables to translate between the external ID and gramps' internal ID. If no such Person exists, a new Person instance is created. - idVal - external ID number + gid - external ID number map - map build by findPerson of external to gramp's IDs""" person = Person() - if map.has_key(idVal): - person.unserialize(self.person_map.get(str(map[idVal]))) + if map.has_key(gid): + person.unserialize(self.person_map.get(str(map[gid]))) else: - if self.person_map.get(str(idVal)): - map[idVal] = self.add_person(person) + if self.person_map.get(str(gid)): + map[gid] = self.add_person(person,trans) else: - person.set_id(idVal) - map[idVal] = self.add_person_as(person) + person.set_id(gid) + map[gid] = self.add_person_as(person,trans) return person - def find_family_no_conflicts(self,idVal,map): - """finds a Family in the database using the idVal and map + def find_family_no_conflicts(self,gid,map,trans=None): + """finds a Family in the database using the gid and map variables to translate between the external ID and gramps' internal ID. If no such Family exists, a new Family instance is created. - idVal - external ID number + gid - external ID number map - map build by findFamily of external to gramp's IDs""" - if map.has_key(str(idVal)): + if map.has_key(str(gid)): family = Family() - family.unserialize(self.family_map.get(str(map[str(idVal)]))) + family.unserialize(self.family_map.get(str(map[str(gid)]))) else: - if self.family_map.has_key(str(idVal)): - family = self.new_family() + if self.family_map.has_key(str(gid)): + family = self.new_family(trans) else: - family = self.new_family_no_map(str(idVal)) - map[idVal] = family.get_id() + family = self.new_family_no_map(str(gid),trans) + map[gid] = family.get_id() return family - def find_source_no_conflicts(self,idVal,map): - """finds a Source in the database using the idVal and map + def find_source_no_conflicts(self,gid,map,trans=None): + """finds a Source in the database using the gid and map variables to translate between the external ID and gramps' internal ID. If no such Source exists, a new Source instance is created. - idVal - external ID number + gid - external ID number map - map build by findSource of external to gramp's IDs""" source = Source() - if map.has_key(idVal): - source.unserialize(self.source_map.get(str(map[idVal]))) + if map.has_key(gid): + source.unserialize(self.source_map.get(str(map[gid]))) else: - if self.source_map.get(str(idVal)): - map[idVal] = self.add_source(source) + if self.source_map.get(str(gid)): + map[gid] = self.add_source(source,trans) else: - map[idVal] = self.add_source(source) + map[gid] = self.add_source(source,trans) return source def set_column_order(self,list): @@ -3257,4 +3481,55 @@ class GrampsDB: return cols + default[len(cols):] else: return cols +#------------------------------------------------------------------------- +# +# Transaction +# +#------------------------------------------------------------------------- +class Transaction: + def __init__(self): + self.data = [] + + def add(self, type, gid, data): + self.data.append((type, gid, data)) + + def get_data(self): + return self.data + + def __len__(self): + return len(self.data) + + def display(self): + print self + for (key,gid,val) in self.data: + if key == PERSON_KEY: + if val: + print "PERSON %s change" % gid + else: + print "PERSON %s remove" % gid + elif key == FAMILY_KEY: + if val: + print "FAMILY %s change" % gid + else: + print "FAMILY %s remove" % gid + elif key == EVENT_KEY: + if val: + print "EVENT %s change" % gid + else: + print "EVENT %s remove" % gid + elif key == SOURCE_KEY: + if val: + print "SOURCE %s change" % gid + else: + print "SOURCE %s remove" % gid + elif key == MEDIA_KEY: + if val: + print "MEDIA %s change" % gid + else: + print "MEDIA %s remove" % gid + elif key == PLACE_KEY: + if val: + print "PLACE %s change" % gid + else: + print "PLACE %s remove" % gid diff --git a/src/SelectChild.py b/src/SelectChild.py index f44513927..b5eca42a2 100644 --- a/src/SelectChild.py +++ b/src/SelectChild.py @@ -300,7 +300,10 @@ class SelectChild: select_child.add_parent_family_id(self.family.get_id(),mrel,frel) - self.db.commit_person(select_child) + trans = self.db.start_transaction() + self.db.commit_person(select_child,trans) + self.db.add_transaction(trans) + self.redraw(self.family) self.close(obj) @@ -430,6 +433,9 @@ class EditRel: frel = "Unknown" self.child.change_parent_family_id(self.family.get_id(),mrel,frel) - self.db.commit_person(self.child) + trans = self.start_transaction() + self.db.commit_person(self.child,trans) + self.db.add_transaction(trans) + self.update() self.top.destroy() diff --git a/src/SourceView.py b/src/SourceView.py index 80f591fbc..65c538e99 100644 --- a/src/SourceView.py +++ b/src/SourceView.py @@ -68,8 +68,8 @@ class SourceView: self.db = db self.update = update self.list = glade.get_widget("source_list") + self.list.connect('button-press-event',self.button_press) self.selection = self.list.get_selection() - colno = 0 self.renderer = gtk.CellRendererText() @@ -80,12 +80,6 @@ class SourceView: self.columns = [] self.build_columns() - def load_sources(self,id=None): - pass - - def on_click(self,column): - self.click_col = column - def build_columns(self): for column in self.columns: self.list.remove_column(column) @@ -112,25 +106,18 @@ class SourceView: self.list.append_column(column) index += 1 + def on_click(self,column): + self.click_col = column + def change_db(self,db): self.build_columns() self.build_tree() - def goto(self,id): - iter = self.map[id] - self.list.get_selection().select_iter(iter) - itpath = self.model.get_path (iter) - col = self.list.get_column (0) - self.list.scroll_to_cell (itpath, col, gtk.TRUE, 0.5, 0) - def build_tree(self): self.list.set_model(None) self.model = gtk.TreeModelSort(DisplayModels.SourceModel(self.parent.db)) - self.list.set_model(self.model) - self.selection = self.list.get_selection() - self.list.connect('button-press-event',self.button_press) def button_press(self,obj,event): if event.type == gtk.gdk._2BUTTON_PRESS and event.button == 1: @@ -182,7 +169,6 @@ class SourceView: self.topWindow,self.new_after_edit) def on_delete_clicked(self,obj): - store,iter = self.selection.get_selected() if not iter: return @@ -191,7 +177,7 @@ class SourceView: source = self.db.get_source(id) if self.is_used(source): - ans = EditSource.DelSrcQuery(source,self.db,self.update) + ans = EditSource.DelSrcQuery(source,self.db,self.build_tree) QuestionDialog(_('Delete %s?') % source.get_title(), _('This source is currently being used. Deleting it ' @@ -200,8 +186,10 @@ class SourceView: _('_Delete Source'), ans.query_response,self.topWindow) else: - self.db.remove_source_id(source.get_id()) - self.update(0) + trans = self.db.start_transaction() + self.db.remove_source_id(source.get_id(),trans) + self.db.add_transaction(trans) + self.build_tree() def is_used(self,source): for key in self.db.get_place_id_keys(): @@ -258,8 +246,7 @@ class SourceView: def new_after_edit(self,source): self.db.add_source(source) - self.update(0) + self.build_tree() def update_display(self,place): - self.db.build_source_display(place.get_id()) - self.update(0) + self.build_tree() diff --git a/src/gramps.glade b/src/gramps.glade index b0a4e2539..cb33868ab 100644 --- a/src/gramps.glade +++ b/src/gramps.glade @@ -51,7 +51,7 @@ - + True gtk-new 1 @@ -73,7 +73,7 @@ - + True gtk-open 1 @@ -107,7 +107,7 @@ True - + True gtk-convert 1 @@ -135,7 +135,7 @@ - + True gtk-quit 1 @@ -171,7 +171,7 @@ - + True gtk-add 1 @@ -194,7 +194,7 @@ - + True gtk-remove 1 @@ -207,6 +207,14 @@ + + + True + GNOMEUIINFO_MENU_UNDO_ITEM + + + + True @@ -232,7 +240,7 @@ - + True gtk-find 1 @@ -254,7 +262,7 @@ - + True gtk-convert 1 @@ -281,7 +289,7 @@ - + True gtk-preferences 1 @@ -302,7 +310,7 @@ - + True gtk-properties 1 @@ -323,7 +331,7 @@ - + True gtk-home 1 @@ -409,7 +417,7 @@ - + True gtk-index 1 @@ -431,7 +439,7 @@ - + True gnome-stock-book-open 1 @@ -504,7 +512,7 @@ - + True gtk-help 1 @@ -525,7 +533,7 @@ - + True gnome-stock-book-open 1 @@ -552,7 +560,7 @@ - + True gtk-jump-to 1 @@ -573,7 +581,7 @@ - + True gnome-stock-mail 1 @@ -627,7 +635,7 @@ - + True gnome-stock-about 1 diff --git a/src/gramps_main.py b/src/gramps_main.py index f91ce52e2..8654c1d8f 100755 --- a/src/gramps_main.py +++ b/src/gramps_main.py @@ -148,7 +148,6 @@ class Gramps: self.db.set_researcher(GrampsCfg.get_researcher()) def pref_callback(self,val): - self.db.rebuild_person_table() self.modify_statusbar() self.family_view.init_interface() self.update_display(1) @@ -259,6 +258,7 @@ class Gramps: self.child_windows = {} self.gtop.signal_autoconnect({ + "on_undo_activate" : self.undo, "on_column_order_activate": self.column_order, "on_back_clicked" : self.back_clicked, "on_back_pressed" : self.back_pressed, @@ -346,6 +346,16 @@ class Gramps: self.topWindow.show() self.enable_toolbar(self.use_toolbar) + def undo(self,*args): + self.db.undo() + p = self.db.try_to_find_person_from_id(self.active_person.get_id()) + self.change_active_person(p) + self.place_view.change_db(self.db) + self.people_view.change_db(self.db) + self.source_view.change_db(self.db) + self.media_view.change_db(self.db) + self.family_view.load_family() + def set_column_order(self,list): self.db.set_column_order(list) self.people_view.build_columns() @@ -894,8 +904,6 @@ class Gramps: self.family_view.clear() self.family_view.load_family() self.pedigree_view.clear() - self.source_view.load_sources() - self.place_view.load_places() self.media_view.load_media() def tool_callback(self,val): @@ -931,17 +939,12 @@ class Gramps: self.family_view.load_family() elif page == PEDIGREE_VIEW: self.pedigree_view.load_canvas(self.active_person) - elif page == SOURCE_VIEW: - self.source_view.load_sources() elif page == PLACE_VIEW: if len(self.db.get_place_id_keys()) > 2000: self.status_text(_('Updating display - this may take a few seconds...')) else: self.status_text(_('Updating display...')) - self.place_view.load_places() self.modify_statusbar() - else: - self.media_view.load_media() def on_tools_clicked(self,obj): if self.active_person: @@ -953,23 +956,13 @@ class Gramps: Plugins.ReportPlugins(self,self.db,self.active_person) def on_ok_button1_clicked(self,obj): - - dbname = obj.get_data("dbname") - getoldrev = obj.get_data("getoldrev") - filename = dbname.get_full_path(0) - + filename = self.filesel.get_filename() if filename == "" or filename == None: return filename = os.path.normpath(os.path.abspath(filename)) - + self.filesel.destroy() self.clear_database() - - if getoldrev.get_active(): - vc = VersionControl.RcsVersionControl(filename) - VersionControl.RevisionSelect(self.db,filename,vc, - self.load_revision) - else: - self.auto_save_load(filename) + self.auto_save_load(filename) def on_help_dbopen_clicked(self,obj): """Display the relevant portion of GRAMPS manual""" @@ -1053,7 +1046,10 @@ class Gramps: if o.get_reference_id() == ObjectId: nl.remove(o) p.set_media_list(nl) - self.db.remove_object(ObjectId) + + trans = self.db.start_transaction() + self.db.remove_object(ObjectId) + self.db.add_transaction(trans) def leave_clicked(): # File is lost => do nothing, leave as is @@ -1210,6 +1206,8 @@ class Gramps: def delete_person_response(self): + trans = self.db.start_transaction() + if self.db.get_default_person() == self.active_person: self.db.set_default_person(None) @@ -1222,7 +1220,8 @@ class Gramps: for child_id in family.get_child_id_list(): child = self.db.find_person_from_id(child_id) child.remove_parent_family_id(family.get_id()) - self.db.delete_family(family.get_id()) + self.db.commit_person(child,trans) + self.db.delete_family(family.get_id(),trans) else: family.set_father_id(None) else: @@ -1230,23 +1229,27 @@ class Gramps: for child_id in family.get_child_id_list(): child = self.db.find_person_from_id(child_id) child.remove_parent_family_id(family) - self.db.delete_family(family) + self.db.commit_person(child,trans) + self.db.delete_family(family,trans) else: family.set_mother_id(None) - + self.db.commit_family(family,trans) + for (family_id,mrel,frel) in self.active_person.get_parent_family_id_list(): if family_id: family = self.db.find_family_from_id(family_id) family.remove_child_id(self.active_person.get_id()) - + self.db.commit_family(family,trans) + self.people_view.remove_from_history(self.active_person) - self.db.remove_person_id(self.active_person.get_id()) + self.db.remove_person_id(self.active_person.get_id(),trans) self.people_view.remove_from_person_list(self.active_person) if self.hindex >= 0: self.active_person = self.db.get_person(self.history[self.hindex]) else: self.change_active_person(None) + self.db.add_transaction(trans) self.redraw_histmenu() def merge_update(self,p1,p2,old_id): @@ -1261,15 +1264,16 @@ class Gramps: def goto_active_person(self,first=0): self.people_view.goto_active_person(first) - def change_active_person(self,person): + def change_active_person(self,person,force=0): + self.active_person = person if person == None: self.set_buttons(0) self.active_person = None self.modify_statusbar() elif self.active_person == None or \ person.get_id() != self.active_person.get_id(): - self.active_person = person self.modify_statusbar() + self.set_buttons(1) if person: if self.hindex+1 < len(self.history): self.history = self.history[0:self.hindex+1] @@ -1292,6 +1296,7 @@ class Gramps: else: self.backbtn.set_sensitive(0) self.back.set_sensitive(0) + else: self.set_buttons(1) def modify_statusbar(self): @@ -1327,31 +1332,19 @@ class Gramps: DisplayTrace.DisplayTrace() return "" + def fs_close_window(self,obj): + self.filesel.destroy() + def on_open_activate(self,obj): - wFs = gtk.glade.XML(const.revisionFile, "dbopen","gramps") - - self.dbopen_fs = wFs.get_widget("dbopen") - - Utils.set_titles(self.dbopen_fs, wFs.get_widget('title'), - _('Open a database')) - - dbname = wFs.get_widget("dbname") - getoldrev = wFs.get_widget("getoldrev") - self.dbopen_fs.set_data("dbname",dbname) - dbname.set_default_path(GrampsCfg.db_dir) - dbname.set_filename(GrampsCfg.db_dir) - dbname.gtk_entry().set_position(len(GrampsCfg.db_dir)) - - self.dbopen_fs.set_data("getoldrev",getoldrev) - getoldrev.set_sensitive(GrampsCfg.usevc) - self.dbopen_fs.set_transient_for(self.topWindow) - self.dbopen_fs.show() - self.dbopen_button = self.dbopen_fs.run() - if self.dbopen_button == gtk.RESPONSE_OK: - self.on_ok_button1_clicked(self.dbopen_fs) - elif self.dbopen_button == gtk.RESPONSE_HELP: - self.on_help_dbopen_clicked(obj) - self.dbopen_fs.destroy() + + top = gtk.glade.XML (const.gladeFile, "fileselection","gramps") + top.signal_autoconnect({ + "on_ok_button1_clicked": self.on_ok_button1_clicked, + "destroy_passed_object": self.fs_close_window, + }) + self.filesel = top.get_widget('fileselection') + if GrampsCfg.lastfile: + self.filesel.set_filename(GrampsCfg.lastfile) def on_revert_activate(self,obj): pass @@ -1429,15 +1422,12 @@ class Gramps: elif page == SOURCE_VIEW: self.enable_buttons(1) self.merge_button.set_sensitive(0) - self.source_view.load_sources() elif page == PLACE_VIEW: self.enable_buttons(1) - self.place_view.load_places() self.merge_button.set_sensitive(1) elif page == MEDIA_VIEW: self.enable_buttons(1) self.merge_button.set_sensitive(0) - self.media_view.load_media() def on_apply_filter_clicked(self,obj): self.people_view.apply_filter_clicked() @@ -1455,15 +1445,14 @@ class Gramps: filter.hide() filter.set_sensitive(qual) - def new_after_edit(self,epo): + def new_after_edit(self,epo,trans): if epo: if epo.person.get_id() == "": - self.db.add_person(epo.person) + self.db.add_person(epo.person,trans) else: - self.db.add_person_no_map(epo.person,epo.person.get_id()) - self.db.build_person_display(epo.person.get_id()) + self.db.add_person_no_map(epo.person,epo.person.get_id(),trans) self.change_active_person(epo.person) - self.people_view.redisplay_person_list(epo.person) + self.people_view.add_to_person_list(epo.person) if self.views.get_current_page() in [FAMILY_VIEW1,FAMILY_VIEW2]: self.family_view.load_family()