diff --git a/ChangeLog b/ChangeLog index 51fa96237..64586688d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,26 @@ +2007-12-14 Benny Malengier + * src/Editors/_EditEvent.py: first attribute tab THEN backref + * src/DisplayTabs/_BackRefList.py: whitespace change + * src/gen/lib/repo.py: correct error with source backref too + * src/gen/lib/personref.py: + * src/gen/lib/mediaref.py: + * src/gen/lib/childref.py: + * src/gen/lib/place.py: + * src/gen/lib/address.py: + * src/gen/lib/src.py: + * src/gen/lib/person.py: + * src/gen/lib/mediaobj.py: + * src/gen/lib/eventref.py: + * src/gen/lib/name.py: + * src/gen/lib/family.py: + * src/gen/lib/event.py: + * src/gen/lib/ldsord.py: + Add get_note_child_list method to allow recursive deletion of notes in + child objects + * src/gen/lib/notebase.py: add remove_note that recursively searches + in the child secondary objects + * src/plugins/Check.py: fix broken note links, fix broken repo-source link + 2007-12-14 Jerome Rapinat * src/plugins/holidays.xml: update french holidays. diff --git a/src/DisplayTabs/_BackRefList.py b/src/DisplayTabs/_BackRefList.py index a9f6e4522..cc68d3020 100644 --- a/src/DisplayTabs/_BackRefList.py +++ b/src/DisplayTabs/_BackRefList.py @@ -54,8 +54,8 @@ class BackRefList(EmbeddedList): _column_names = [ (_('Type'), 0, 100), - (_('ID'), 1, 75), - (_('Name'), 2, 250), + (_('ID'), 1, 75), + (_('Name'), 2, 250), ] def __init__(self, dbstate, uistate, track, obj, refmodel, callback=None): diff --git a/src/Editors/_EditEvent.py b/src/Editors/_EditEvent.py index c25a53339..6fff0df6d 100644 --- a/src/Editors/_EditEvent.py +++ b/src/Editors/_EditEvent.py @@ -174,20 +174,16 @@ class EditEvent(EditPrimary): GalleryTab(self.dbstate, self.uistate, self.track, self.obj.get_media_list())) + self.attr_ref_list = self._add_tab( + notebook, + AttrEmbedList(self.dbstate, self.uistate, self.track, + self.obj.get_attribute_list())) + self.backref_tab = self._add_tab( notebook, EventBackRefList(self.dbstate, self.uistate, self.track, self.dbstate.db.find_backlink_handles(self.obj.handle))) - try: - self.attr_ref_list = self._add_tab( - notebook, - AttrEmbedList(self.dbstate, self.uistate, self.track, - self.obj.get_attribute_list())) - except AttributeError: - print "Attribute list not available yet" - - self._setup_notebook_tabs( notebook) notebook.show_all() diff --git a/src/gen/lib/address.py b/src/gen/lib/address.py index b5fc4fcae..ddb1759d3 100644 --- a/src/gen/lib/address.py +++ b/src/gen/lib/address.py @@ -97,6 +97,15 @@ class Address(SecondaryObject, PrivacyBase, SourceBase, NoteBase, DateBase, """ return self.source_list + def get_note_child_list(self): + """ + Returns the list of child secondary objects that may refer notes. + + @return: Returns the list of child secondary child objects that may refer notes. + @rtype: list + """ + return self.source_list + def get_handle_referents(self): """ Returns the list of child objects which may, directly or through diff --git a/src/gen/lib/childref.py b/src/gen/lib/childref.py index 336eb5e7d..6220dbb3c 100644 --- a/src/gen/lib/childref.py +++ b/src/gen/lib/childref.py @@ -110,6 +110,15 @@ class ChildRef(SecondaryObject, PrivacyBase, SourceBase, NoteBase, RefBase): """ return self.source_list + def get_note_child_list(self): + """ + Returns the list of child secondary objects that may refer notes. + + @return: Returns the list of child secondary child objects that may refer notes. + @rtype: list + """ + return self.source_list + def get_referenced_handles(self): """ Returns the list of (classname,handle) tuples for all directly diff --git a/src/gen/lib/event.py b/src/gen/lib/event.py index aab15d33c..c43c306dd 100644 --- a/src/gen/lib/event.py +++ b/src/gen/lib/event.py @@ -199,6 +199,15 @@ class Event(SourceBase, NoteBase, MediaBase, AttributeBase, """ return self.media_list + self.attribute_list + def get_note_child_list(self): + """ + Returns the list of child secondary objects that may refer notes. + + @return: Returns the list of child secondary child objects that may refer notes. + @rtype: list + """ + return self.media_list + self.attribute_list + self.source_list + def get_referenced_handles(self): """ Returns the list of (classname,handle) tuples for all directly diff --git a/src/gen/lib/eventref.py b/src/gen/lib/eventref.py index 667c4dc82..beae8a7a0 100644 --- a/src/gen/lib/eventref.py +++ b/src/gen/lib/eventref.py @@ -118,6 +118,15 @@ class EventRef(SecondaryObject, PrivacyBase, NoteBase, AttributeBase, RefBase): """ return self.attribute_list[:] + def get_note_child_list(self): + """ + Returns the list of child secondary objects that may refer notes. + + @return: Returns the list of child secondary child objects that may refer notes. + @rtype: list + """ + return self.attribute_list[:] + def get_referenced_handles(self): """ Returns the list of (classname,handle) tuples for all directly diff --git a/src/gen/lib/family.py b/src/gen/lib/family.py index 8913dec61..e51444fad 100644 --- a/src/gen/lib/family.py +++ b/src/gen/lib/family.py @@ -259,6 +259,17 @@ class Family(SourceBase, NoteBase, MediaBase, AttributeBase, LdsOrdBase, self.lds_ord_list + self.child_ref_list return check_list + def get_note_child_list(self): + """ + Returns the list of child secondary objects that may refer notes. + + @return: Returns the list of child secondary child objects that may refer notes. + @rtype: list + """ + check_list = self.media_list + self.attribute_list + \ + self.lds_ord_list + self.child_ref_list + self.source_list + return check_list + def get_referenced_handles(self): """ Returns the list of (classname,handle) tuples for all directly diff --git a/src/gen/lib/ldsord.py b/src/gen/lib/ldsord.py index 14a26adf1..69215fecf 100644 --- a/src/gen/lib/ldsord.py +++ b/src/gen/lib/ldsord.py @@ -171,6 +171,15 @@ class LdsOrd(SecondaryObject, SourceBase, NoteBase, """ return self.source_list + def get_note_child_list(self): + """ + Returns the list of child secondary objects that may refer notes. + + @return: Returns the list of child secondary child objects that may refer notes. + @rtype: list + """ + return self.source_list + def get_referenced_handles(self): """ Returns the list of (classname,handle) tuples for all directly diff --git a/src/gen/lib/mediaobj.py b/src/gen/lib/mediaobj.py index 8368d6a71..500b37ea2 100644 --- a/src/gen/lib/mediaobj.py +++ b/src/gen/lib/mediaobj.py @@ -154,6 +154,15 @@ class MediaObject(SourceBase, NoteBase, DateBase, AttributeBase, """ return self.attribute_list + def get_note_child_list(self): + """ + Returns the list of child secondary objects that may refer notes. + + @return: Returns the list of child secondary child objects that may refer notes. + @rtype: list + """ + return self.attribute_list + self.source_list + def get_referenced_handles(self): """ Returns the list of (classname,handle) tuples for all directly diff --git a/src/gen/lib/mediaref.py b/src/gen/lib/mediaref.py index af9ea7a82..be475192c 100644 --- a/src/gen/lib/mediaref.py +++ b/src/gen/lib/mediaref.py @@ -99,6 +99,15 @@ class MediaRef(SecondaryObject, PrivacyBase, SourceBase, NoteBase, RefBase, """ return self.attribute_list + def get_note_child_list(self): + """ + Returns the list of child secondary objects that may refer notes. + + @return: Returns the list of child secondary child objects that may refer notes. + @rtype: list + """ + return self.attribute_list + self.source_list + def get_referenced_handles(self): """ Returns the list of (classname,handle) tuples for all directly diff --git a/src/gen/lib/name.py b/src/gen/lib/name.py index 229c01e64..3b38fc9f3 100644 --- a/src/gen/lib/name.py +++ b/src/gen/lib/name.py @@ -151,6 +151,15 @@ class Name(SecondaryObject, PrivacyBase, SourceBase, NoteBase, DateBase): """ return self.source_list + def get_note_child_list(self): + """ + Returns the list of child secondary objects that may refer notes. + + @return: Returns the list of child secondary child objects that may refer notes. + @rtype: list + """ + return self.source_list + def get_handle_referents(self): """ Returns the list of child objects which may, directly or through diff --git a/src/gen/lib/notebase.py b/src/gen/lib/notebase.py index 0ae733e18..bd7640bfc 100644 --- a/src/gen/lib/notebase.py +++ b/src/gen/lib/notebase.py @@ -82,19 +82,28 @@ class NoteBase: def remove_note(self,handle): """ - Removes the specified handle from the list of note handles. + Removes the specified handle from the list of note handles, and all + and all secondary child objects. @param handle: L{Note} handle to remove from the list of notes @type handle: str - - @return: True if handle was removed, False if it was not in the list - @rtype: bool """ if handle in self.note_list: self.note_list.remove(handle) - return True - else: - return False + + for item in self.get_note_child_list(): + item.remove_note(handle) + + def get_note_child_list(self): + """ + Returns the list of child secondary objects that may refer notes. + All methods which inherit from NoteBase and have other child objects + with notes, should return here a list of child objects which are NoteBase + + @return: Returns the list of child secondary child objects that may refer notes. + @rtype: list + """ + return [] def get_note_list(self): """ diff --git a/src/gen/lib/person.py b/src/gen/lib/person.py index fe3b9e6b5..c088f7317 100644 --- a/src/gen/lib/person.py +++ b/src/gen/lib/person.py @@ -330,6 +330,18 @@ class Person(SourceBase, NoteBase, AttributeBase, MediaBase, self.attribute_list + self.lds_ord_list + \ self.person_ref_list + def get_note_child_list(self): + """ + Returns the list of child secondary objects that may refer notes. + + @return: Returns the list of child secondary child objects that may refer notes. + @rtype: list + """ + return [self.primary_name] + self.media_list + \ + self.alternate_names + self.address_list + \ + self.attribute_list + self.lds_ord_list + \ + self.person_ref_list + self.source_list + def get_referenced_handles(self): """ Returns the list of (classname, handle) tuples for all directly diff --git a/src/gen/lib/personref.py b/src/gen/lib/personref.py index e7c3a2984..a837814ca 100644 --- a/src/gen/lib/personref.py +++ b/src/gen/lib/personref.py @@ -100,6 +100,15 @@ class PersonRef(SecondaryObject, PrivacyBase, SourceBase, NoteBase, RefBase): """ return self.source_list + def get_note_child_list(self): + """ + Returns the list of child secondary objects that may refer notes. + + @return: Returns the list of child secondary child objects that may refer notes. + @rtype: list + """ + return self.source_list + def get_referenced_handles(self): """ Returns the list of (classname,handle) tuples for all directly diff --git a/src/gen/lib/place.py b/src/gen/lib/place.py index a71bdadc7..b6c16780d 100644 --- a/src/gen/lib/place.py +++ b/src/gen/lib/place.py @@ -167,6 +167,15 @@ class Place(SourceBase, NoteBase, MediaBase, UrlBase, PrimaryObject): """ return self.media_list + def get_note_child_list(self): + """ + Returns the list of child secondary objects that may refer notes. + + @return: Returns the list of child secondary child objects that may refer notes. + @rtype: list + """ + return self.media_list + self.source_list + def get_handle_referents(self): """ Returns the list of child objects which may, directly or through diff --git a/src/gen/lib/repo.py b/src/gen/lib/repo.py index 7764d0191..7cb9eb72c 100644 --- a/src/gen/lib/repo.py +++ b/src/gen/lib/repo.py @@ -102,6 +102,34 @@ class Repository(NoteBase, AddressBase, UrlBase, PrimaryObject): """ return self.address_list + self.urls + def get_sourcref_child_list(self): + """ + Returns the list of child secondary objects that may refer sources. + + @return: Returns the list of child secondary child objects that may refer sources. + @rtype: list + """ + return self.address_list + + def get_note_child_list(self): + """ + Returns the list of child secondary objects that may refer notes. + + @return: Returns the list of child secondary child objects that may refer notes. + @rtype: list + """ + return self.address_list + + def get_handle_referents(self): + """ + Returns the list of child objects which may, directly or through + their children, reference primary objects. + + @return: Returns the list of objects refereincing primary objects. + @rtype: list + """ + return self.address_list + def get_referenced_handles(self): """ Returns the list of (classname,handle) tuples for all directly @@ -112,6 +140,46 @@ class Repository(NoteBase, AddressBase, UrlBase, PrimaryObject): """ return self.get_referenced_note_handles() + def has_source_reference(self, src_handle) : + """ + Returns True if any of the child objects has reference + to this source handle. + + @param src_handle: The source handle to be checked. + @type src_handle: str + @return: Returns whether any of it's child objects has reference to this source handle. + @rtype: bool + """ + for item in self.get_sourcref_child_list(): + if item.has_source_reference(src_handle): + return True + + return False + + def remove_source_references(self, src_handle_list): + """ + Removes references to all source handles in the list + in all child objects. + + @param src_handle_list: The list of source handles to be removed. + @type src_handle_list: list + """ + for item in self.get_sourcref_child_list(): + item.remove_source_references(src_handle_list) + + def replace_source_references(self, old_handle, new_handle): + """ + Replaces references to source handles in the list + in this object and all child objects. + + @param old_handle: The source handle to be replaced. + @type old_handle: str + @param new_handle: The source handle to replace the old one with. + @type new_handle: str + """ + for item in self.get_sourcref_child_list(): + item.replace_source_references(old_handle, new_handle) + def set_type(self, the_type): """ @param the_type: descriptive type of the Repository diff --git a/src/gen/lib/src.py b/src/gen/lib/src.py index 1c15c6ca7..4470aaeea 100644 --- a/src/gen/lib/src.py +++ b/src/gen/lib/src.py @@ -165,6 +165,15 @@ class Source(MediaBase, NoteBase, PrimaryObject): """ return self.media_list + def get_note_child_list(self): + """ + Returns the list of child secondary objects that may refer notes. + + @return: Returns the list of child secondary child objects that may refer notes. + @rtype: list + """ + return self.media_list + self.reporef_list + def get_handle_referents(self): """ Returns the list of child objects which may, directly or through diff --git a/src/plugins/Check.py b/src/plugins/Check.py index 5225a5658..dc43ce30c 100644 --- a/src/plugins/Check.py +++ b/src/plugins/Check.py @@ -78,12 +78,14 @@ def low_level(db): The name indicates the problematic table (empty if status is True). """ - for the_map in [('Person',db.person_map), - ('Family',db.family_map), - ('Event',db.event_map), - ('Place',db.place_map), - ('Source',db.source_map), - ('Media',db.media_map)]: + for the_map in [('Person', db.person_map), + ('Family', db.family_map), + ('Event', db.event_map), + ('Place', db.place_map), + ('Source', db.source_map), + ('Media', db.media_map), + ('Repository', db.repository_map), + ('Note', db.note_map)]: print "Low-level repair: table: %s" % the_map[0] if _table_low_level(db,the_map[1]): @@ -107,8 +109,8 @@ def _table_low_level(db,table): print " No dupes found for this table" return True - import GrampsBSDDB - table_cursor = GrampsBSDDB.GrampsBSDDBDupCursor(table) + import gen.db + table_cursor = gen.db.GrampsDBDirDupCursor(table) for handle in dup_handles: print " Duplicates found for handle: %s" % handle try: @@ -156,8 +158,8 @@ class Check(Tool.BatchTool): # The low-level repair is bypassing the transaction mechanism. # As such, we run it before starting the transaction. - # We only do this for the BSDDB backend. - if self.db.__class__.__name__ == 'GrampsBSDDB': + # We only do this for the dbdir backend. + if self.db.__class__.__name__ == 'GrampsDBDir': low_level(self.db) trans = self.db.transaction_begin("",batch=True) @@ -188,6 +190,7 @@ class Check(Tool.BatchTool): checker.check_source_references() checker.check_media_references() checker.check_repo_references() + checker.check_note_references() self.db.transaction_commit(trans, _("Check Integrity")) self.db.enable_signals() self.db.request_rebuild() @@ -222,6 +225,7 @@ class CheckIntegrity: self.invalid_source_references = [] self.invalid_repo_references = [] self.invalid_media_references = [] + self.invalid_note_references = [] self.removed_name_format = [] self.empty_objects = {'persons' : [], 'families': [], @@ -900,7 +904,8 @@ class CheckIntegrity: total = self.db.get_number_of_people() + self.db.get_number_of_families() + \ self.db.get_number_of_events() + self.db.get_number_of_places() + \ self.db.get_number_of_media_objects() + \ - self.db.get_number_of_sources() + self.db.get_number_of_sources() + \ + self.db.get_number_of_repositories() self.progress.set_pass(_('Looking for source reference problems'), total) @@ -952,7 +957,23 @@ class CheckIntegrity: new_bad_handles = [handle for handle in bad_handles if handle not in self.invalid_source_references] self.invalid_source_references += new_bad_handles - + + for handle in self.db.repository_map.keys(): + self.progress.step() + info = self.db.repository_map[handle] + repo = gen.lib.Repository() + repo.unserialize(info) + handle_list = repo.get_referenced_handles_recursively() + bad_handles = [ item[1] for item in handle_list + if item[0] == 'Source' and + item[1] not in known_handles ] + if bad_handles: + repo.remove_source_references(bad_handles) + self.db.commit_repository(repo,self.trans) + new_bad_handles = [handle for handle in bad_handles if handle + not in self.invalid_source_references] + self.invalid_source_references += new_bad_handles + #I think this for loop is useless! sources in sources map exist... for handle in known_handles: self.progress.step() @@ -1092,6 +1113,137 @@ class CheckIntegrity: not in self.invalid_media_references] self.invalid_media_references += new_bad_handles + def check_note_references(self): + known_handles = self.db.get_note_handles() + + total = self.db.get_number_of_people() + self.db.get_number_of_families() + \ + self.db.get_number_of_events() + self.db.get_number_of_places() + \ + self.db.get_number_of_media_objects() + \ + self.db.get_number_of_sources() + \ + self.db.get_number_of_repositories() + + self.progress.set_pass(_('Looking for note reference problems'), + total) + + for handle in self.db.person_map.keys(): + self.progress.step() + info = self.db.person_map[handle] + person = gen.lib.Person() + person.unserialize(info) + handle_list = person.get_referenced_handles_recursively() + bad_handles = [ item[1] for item in handle_list + if item[0] == 'Note' and + item[1] not in known_handles ] + for bad_handle in bad_handles: + person.remove_note(bad_handle) + if bad_handles: + self.db.commit_person(person,self.trans) + new_bad_handles = [handle for handle in bad_handles if handle + not in self.invalid_note_references] + self.invalid_note_references += new_bad_handles + + for handle in self.db.family_map.keys(): + self.progress.step() + info = self.db.family_map[handle] + family = gen.lib.Family() + family.unserialize(info) + handle_list = family.get_referenced_handles_recursively() + bad_handles = [ item[1] for item in handle_list + if item[0] == 'Note' and + item[1] not in known_handles ] + for bad_handle in bad_handles: + family.remove_note(bad_handle) + if bad_handles: + self.db.commit_family(family,self.trans) + new_bad_handles = [handle for handle in bad_handles if handle + not in self.invalid_note_references] + self.invalid_note_references += new_bad_handles + + for handle in self.db.place_map.keys(): + self.progress.step() + info = self.db.place_map[handle] + place = gen.lib.Place() + place.unserialize(info) + handle_list = place.get_referenced_handles_recursively() + bad_handles = [ item[1] for item in handle_list + if item[0] == 'Note' and + item[1] not in known_handles ] + for bad_handle in bad_handles: + place.remove_note(bad_handle) + if bad_handles: + self.db.commit_place(place,self.trans) + new_bad_handles = [handle for handle in bad_handles if handle + not in self.invalid_note_references] + self.invalid_note_references += new_bad_handles + + for handle in self.db.source_map.keys(): + self.progress.step() + info = self.db.source_map[handle] + source = gen.lib.Source() + source.unserialize(info) + handle_list = source.get_referenced_handles_recursively() + bad_handles = [ item[1] for item in handle_list + if item[0] == 'Note' and + item[1] not in known_handles ] + for bad_handle in bad_handles: + source.remove_note(bad_handle) + if bad_handles: + self.db.commit_source(source,self.trans) + new_bad_handles = [handle for handle in bad_handles if handle + not in self.invalid_note_references] + self.invalid_note_references += new_bad_handles + + for handle in self.db.media_map.keys(): + self.progress.step() + info = self.db.media_map[handle] + obj = gen.lib.MediaObject() + obj.unserialize(info) + handle_list = obj.get_referenced_handles_recursively() + bad_handles = [ item[1] for item in handle_list + if item[0] == 'Note' and + item[1] not in known_handles ] + for bad_handle in bad_handles: + obj.remove_note(bad_handle) + if bad_handles: + self.db.commit_object(obj,self.trans) + new_bad_handles = [handle for handle in bad_handles if handle + not in self.invalid_note_references] + self.invalid_note_references += new_bad_handles + + for handle in self.db.event_map.keys(): + self.progress.step() + info = self.db.event_map[handle] + event = gen.lib.Event() + event.unserialize(info) + handle_list = event.get_referenced_handles_recursively() + bad_handles = [ item[1] for item in handle_list + if item[0] == 'Note' and + item[1] not in known_handles ] + for bad_handle in bad_handles: + event.remove_note(bad_handle) + if bad_handles: + self.db.commit_event(event,self.trans) + new_bad_handles = [handle for handle in bad_handles if handle + not in self.invalid_note_references] + self.invalid_note_references += new_bad_handles + + for handle in self.db.repository_map.keys(): + self.progress.step() + info = self.db.repository_map[handle] + repo = gen.lib.Repository() + repo.unserialize(info) + handle_list = repo.get_referenced_handles_recursively() + bad_handles = [ item[1] for item in handle_list + if item[0] == 'Note' and + item[1] not in known_handles ] + for bad_handle in bad_handles: + repo.remove_note(bad_handle) + if bad_handles: + self.db.commit_repository(repo,self.trans) + new_bad_handles = [handle for handle in bad_handles if handle + not in self.invalid_note_references] + self.invalid_note_references += new_bad_handles + def build_report(self,cl=0): self.progress.close() bad_photos = len(self.bad_photo) @@ -1112,6 +1264,7 @@ class CheckIntegrity: source_references = len(self.invalid_source_references) repo_references = len(self.invalid_repo_references) media_references = len(self.invalid_media_references) + note_references = len(self.invalid_note_references) name_format = len(self.removed_name_format) empty_objs = ( len(self.empty_objects['persons']) + len(self.empty_objects['families']) @@ -1126,7 +1279,7 @@ class CheckIntegrity: errors = (photos + efam + blink + plink + slink + rel + event_invalid + person + person_references + place_references + source_references - + repo_references + media_references + + repo_references + media_references + note_references + name_format + empty_objs ) @@ -1268,6 +1421,12 @@ class CheckIntegrity: self.text.write(_("%d media objects were referenced, " "but not found\n") % media_references) + if note_references == 1: + self.text.write(_("1 note object was referenced but not found\n")) + elif note_references > 1: + self.text.write(_("%d note objects were referenced, " + "but not found\n") % note_references) + if name_format == 1: self.text.write(_("1 invalid name format reference was removed\n")) elif name_format > 1: