From e3d70bb4a20698c78d5b384e9f172524f36a08c0 Mon Sep 17 00:00:00 2001 From: Richard Taylor Date: Thu, 22 Dec 2005 12:02:06 +0000 Subject: [PATCH] * src/EditPlace.py: changed display_references to use find_backlink_handles * src/EditRepository.py: modified to use find_backlink_handles and fixed subtle bug * src/RelLib/_Source.py: added reporef_list to referent object lists so that backref are put in reference_map * test/GrampsDb/GrampsDbBase_Test.py: added unittest for source/reference backlinks * test/GrampsDb/GrampsDbTestBase.py: added unittest for source/reference backlinks svn: r5616 --- gramps2/ChangeLog | 8 ++ gramps2/src/EditPlace.py | 105 ++++++++++++++++++++- gramps2/src/EditRepository.py | 14 +-- gramps2/src/RelLib/_Source.py | 2 +- gramps2/test/GrampsDb/GrampsDbBase_Test.py | 11 +++ gramps2/test/GrampsDb/GrampsDbTestBase.py | 17 +++- 6 files changed, 148 insertions(+), 9 deletions(-) diff --git a/gramps2/ChangeLog b/gramps2/ChangeLog index 0febb3f7e..bfdc2fa96 100644 --- a/gramps2/ChangeLog +++ b/gramps2/ChangeLog @@ -1,3 +1,11 @@ +2005-12-22 Richard Taylor + * src/EditPlace.py: changed display_references to use find_backlink_handles + * src/EditRepository.py: modified to use find_backlink_handles and fixed subtle bug + * src/RelLib/_Source.py: added reporef_list to referent object lists so that backref + are put in reference_map + * test/GrampsDb/GrampsDbBase_Test.py: added unittest for source/reference backlinks + * test/GrampsDb/GrampsDbTestBase.py: added unittest for source/reference backlinks + 2005-12-21 Don Allingham * src/DisplayState.py: remove print statements * src/ViewManger.py: Fix const.app_* diff --git a/gramps2/src/EditPlace.py b/gramps2/src/EditPlace.py index ccfc0c56f..0c557084c 100644 --- a/gramps2/src/EditPlace.py +++ b/gramps2/src/EditPlace.py @@ -28,6 +28,9 @@ import cPickle as pickle import gc from gettext import gettext as _ +import sys + +log = sys.stderr.write #------------------------------------------------------------------------- # @@ -75,6 +78,7 @@ class EditPlace(DisplayState.ManagedWindow): self.db = dbstate.db self.path = dbstate.db.get_save_path() self.not_loaded = True + self.model = None # becomes the model for back references. self.lists_changed = 0 if place: self.srcreflist = place.get_source_references() @@ -165,8 +169,9 @@ class EditPlace(DisplayState.ManagedWindow): self.country.set_text(mloc.get_country()) self.longitude.set_text(place.get_longitude()) self.latitude.set_text(place.get_latitude()) - self.plist = self.top_window.get_widget("plist") + self.plist = self.top_window.get_widget("refinfo") self.slist = self.top_window.get_widget("slist") + self.sources_label = self.top_window.get_widget("sourcesPlaceEdit") self.names_label = self.top_window.get_widget("namesPlaceEdit") self.notes_label = self.top_window.get_widget("notesPlaceEdit") @@ -524,6 +529,104 @@ class EditPlace(DisplayState.ManagedWindow): self,", ", event, None, 0, None, None, self.db.readonly) def display_references(self): + + + if not self.model: + self.any_refs = False + place_handle = self.place.get_handle() + + titles = [(_('Type'),0,150),(_('Name'),1,150), + (_('ID'),2,75),(_('Event Name'),3,150)] + + self.model = ListModel.ListModel(self.plist, + titles, + event_func=self.button_press) + self.backlink_generator = self.db.find_backlink_handles(place_handle) + + + while True: # The loop is broken when the backlink_generator finishes + + try: + reference = self.backlink_generator.next() + except StopIteration: + # Last reference reached. + break + + cls_name,handle = reference + + if cls_name == 'Person': + person = self.db.get_person_from_handle(handle) + for event_handle in [person.get_birth_handle(), + person.get_death_handle()] \ + + person.get_event_list(): + event = self.db.get_event_from_handle(event_handle) + if event and event.get_place_handle() == place_handle: + pname = self.name_display(person) + gramps_id = person.get_gramps_id() + ename = event.get_name() + self.model.add( + [_("Personal Event"),pname,gramps_id,ename], + (0,event_handle)) + self.any_refs = True + + elif cls_name == 'Family': + family = self.db.get_family_from_handle(handle) + for event_handle in family.get_event_list(): + event = self.db.get_event_from_handle(event_handle) + if event and event.get_place_handle() == place_handle: + father = family.get_father_handle() + mother = family.get_mother_handle() + if father and mother: + fname = _("%(father)s and %(mother)s") % { + "father" : self.name_display( + self.db.get_person_from_handle(father)), + "mother" : self.name_display( + self.db.get_person_from_handle(mother)) + } + elif father: + fname = self.name_display( + self.db.get_person_from_handle(father)) + else: + fname = self.name_display( + self.db.get_person_from_handle(mother)) + + gramps_id = family.get_gramps_id() + ename = event.get_name() + self.model.add( + [_("Family Event"),fname,gramps_id,ename], + (1,event_handle)) + self.any_refs = True + + elif cls_name == 'Event': + event = self.db.get_event_from_handle(handle) + ev_type = event.get_type()[1] + description = event.get_description() + gramps_id = event.get_gramps_id() + self.model.add([_("Event"),str(ev_type),gramps_id,description],(2,handle)) + + else: + # If we get here it means there is a new Primary object type + # that has been added to the database or that Place has started + # to be referenced by a different primary object. Print a warning + # to remind us that this code need updating. + log("WARNING: Unhandled Primary object type returned from " + "find_backlink_handles(): %s \n" % str(cls_name)) + + if gtk.events_pending(): + return True + + if self.any_refs: + Utils.bold_label(self.refs_label,self.top) + else: + Utils.unbold_label(self.refs_label,self.top) + + self.ref_not_loaded = 0 + self.backlink_generator = None + + return False + + + place_handle = self.place.get_handle() # Initialize things if we're entering this functioin # for the first time diff --git a/gramps2/src/EditRepository.py b/gramps2/src/EditRepository.py index 1a5b4520c..d57b8a27d 100644 --- a/gramps2/src/EditRepository.py +++ b/gramps2/src/EditRepository.py @@ -76,10 +76,10 @@ class ReposSrcListModel(gtk.ListStore): # Get the list of sources that reference this repository repos_handle = self._repos.get_handle() - source_list = [ src_handle for src_handle \ - in self._db.get_source_handles() \ - if self._db.get_source_from_handle(src_handle).has_repo_reference(repos_handle)] + # find_backlink_handles returns a list of (class_name,handle) tuples + # so src[1] is just the handle of the source. + source_list = [ src[1] for src in self._db.find_backlink_handles(repos_handle,['Source']) ] # Add each (source,repos_ref) to list. It is possible for # a source to reference to same repository more than once. @@ -116,7 +116,7 @@ class ReposSrcListModel(gtk.ListStore): found = False for val in range(0,len(self)): iter = self.get_iter(val) - if source.get_handle() == self.get_value(iter,0).get_handle and \ + if source.get_handle() == self.get_value(iter,0).get_handle() and \ repos_ref == self.get_value(iter,1): self.row_changed(self.get_path(iter),iter) found = True @@ -558,6 +558,7 @@ class EditRepository: # These are the ones that are in the list model but not in the # original sources list. items_added = self.repos_source_model.get_added_items() + for item in items_added: item[1].set_reference_handle(handle) @@ -580,10 +581,11 @@ class EditRepository: stripped_list = [ repos_ref for repos_ref \ in original_list \ if repos_ref.get_reference_handle() != self.repository.get_handle() ] + # Now add back in those to be added and updated new_list = stripped_list + \ - [ item[1] for item in items_added ] + \ - [ item[1] for item in items_updated ] + [ item[1] for item in items_added if item[0] == source_hdl ] + \ + [ item[1] for item in items_updated if item[0] == source_hdl ] # Set the new list on the source diff --git a/gramps2/src/RelLib/_Source.py b/gramps2/src/RelLib/_Source.py index fd325c837..c817dbaae 100644 --- a/gramps2/src/RelLib/_Source.py +++ b/gramps2/src/RelLib/_Source.py @@ -112,7 +112,7 @@ class Source(PrimaryObject,MediaBase,NoteBase): @return: Returns the list of objects refereincing primary objects. @rtype: list """ - return self.media_list + return self.media_list + self.reporef_list def has_source_reference(self,src_handle) : """ diff --git a/gramps2/test/GrampsDb/GrampsDbBase_Test.py b/gramps2/test/GrampsDb/GrampsDbBase_Test.py index 636d33504..919633b1b 100644 --- a/gramps2/test/GrampsDb/GrampsDbBase_Test.py +++ b/gramps2/test/GrampsDb/GrampsDbBase_Test.py @@ -89,6 +89,17 @@ class ReferenceMapTest (GrampsDbBaseTest): assert len(references) == 1 assert references[0] == (RelLib.Person.__name__,person.get_handle()) + def test_backlink_for_repository(self): + """check that the source / repos backlink lookup works.""" + + repos = self._add_repository() + source = self._add_source(repos=repos) + + references = [ ref for ref in self._db.find_backlink_handles(repos.get_handle()) ] + + assert len(references) == 1 + assert references[0] == (RelLib.Source.__name__,source.get_handle()) + def test_class_limited_lookup(self): """check that class limited lookups work.""" diff --git a/gramps2/test/GrampsDb/GrampsDbTestBase.py b/gramps2/test/GrampsDb/GrampsDbTestBase.py index aec3f16fa..869921706 100644 --- a/gramps2/test/GrampsDb/GrampsDbTestBase.py +++ b/gramps2/test/GrampsDb/GrampsDbTestBase.py @@ -79,17 +79,32 @@ class GrampsDbBaseTest(unittest.TestCase): return - def _add_source(self): + def _add_source(self,repos=None): # Add a Source tran = self._db.transaction_begin() source = RelLib.Source() + if repos != None: + repo_ref = RelLib.RepoRef() + repo_ref.set_reference_handle(repos.get_handle()) + source.add_repo_reference(repo_ref) self._db.add_source(source,tran) self._db.commit_source(source,tran) self._db.transaction_commit(tran, "Add Source") return source + def _add_repository(self): + # Add a Repository + + tran = self._db.transaction_begin() + repos = RelLib.Repository() + self._db.add_repository(repos,tran) + self._db.commit_repository(repos,tran) + self._db.transaction_commit(tran, "Add Repository") + + return repos + def _add_object_with_source(self,sources,object_class,add_method,commit_method):