From 82bfe43483ea65b184a24330d62956c124253fd4 Mon Sep 17 00:00:00 2001 From: Tim G L Lyons Date: Sun, 23 Sep 2012 22:28:34 +0000 Subject: [PATCH] 0006061: GEDCOM import: link from FAM to child but missing link from child to FAM causes inconsistent displays. Fixed in GEDCOM import, importxml and Check and repair. (Also minor fixes for improved diagnostics when importxml just completely fails and for exportxml illegal characters in mime_type). svn: r20438 --- src/plugins/export/ExportXml.py | 3 +- src/plugins/import/ImportXml.py | 79 +++++++++++++++++++++++++++++++++ src/plugins/lib/libgedcom.py | 22 +++++++++ src/plugins/tool/Check.py | 7 ++- 4 files changed, 106 insertions(+), 5 deletions(-) diff --git a/src/plugins/export/ExportXml.py b/src/plugins/export/ExportXml.py index 9c120b18c..99af90837 100644 --- a/src/plugins/export/ExportXml.py +++ b/src/plugins/export/ExportXml.py @@ -1208,7 +1208,8 @@ class GrampsXmlWriter(UpdateCallback): # from Windows to Linux of gpkg's path to images does not work. path = path.replace('\\','/') self.g.write('%s\n' - % (" "*(index+1), self.fix(path), mime_type, desc_text)) + % (" "*(index+1), self.fix(path), self.fix(mime_type), + desc_text)) self.write_attribute_list(obj.get_attribute_list()) self.write_note_list(obj.get_note_list(), index+1) dval = obj.get_date_object() diff --git a/src/plugins/import/ImportXml.py b/src/plugins/import/ImportXml.py index d34da3bec..8270e0119 100644 --- a/src/plugins/import/ImportXml.py +++ b/src/plugins/import/ImportXml.py @@ -137,6 +137,7 @@ def importData(database, filename, callback=None): return except ExpatError, msg: ErrorDialog(_("Error reading %s") % filename, + str(msg) + "\n" + _("The file is probably either corrupt or not a " "valid Gramps database.")) return @@ -220,6 +221,7 @@ class ImportInfo(object): self.data_mergecandidate = [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}] self.data_newobject = [0] * 10 self.data_unknownobject = [0] * 10 + self.data_families = '' self.expl_note = '' self.data_relpath = False @@ -237,6 +239,11 @@ class ImportInfo(object): self.data_unknownobject[self.key2data[key]] += 1 elif category == 'relative-path': self.data_relpath = True + elif category == 'unlinked-family': + # This is a bit ugly because it isn't using key in the same way as + # the rest of the categories, but it is only the calling routine + # that really knows what the error message should be. + self.data_families += key + "\n" def _extract_mergeinfo(self, key, obj, sec_obj): """ @@ -325,6 +332,11 @@ class ImportInfo(object): datakey = self.key2data[key] for handle in self.data_mergecandidate[datakey].keys(): txt += self.data_mergecandidate[datakey][handle] + + if self.data_families: + txt += "\n\n" + txt += self.data_families + return txt class LineParser(object): @@ -903,6 +915,7 @@ class GrampsParser(UpdateCallback): ) % self.mediapath ) self.fix_not_instantiated() + self.fix_families() for key in self.func_map.keys(): del self.func_map[key] del self.func_map @@ -2962,6 +2975,72 @@ class GrampsParser(UpdateCallback): key = CLASS_TO_KEY_MAP[obj.__class__.__name__] self.info.add('unknown-object', key, obj) + def fix_families(self): + # Fix any imported families where there is a link from the family to an + # individual, but no corresponding link from the individual to the + # family. + for orig_handle in self.import_handles.keys(): + for target in self.import_handles[orig_handle].keys(): + if target == 'family': + family_handle = self.import_handles[orig_handle][target][HANDLE] + family = self.db.get_family_from_handle(family_handle) + father_handle = family.get_father_handle() + mother_handle = family.get_mother_handle() + + if father_handle: + father = self.db.get_person_from_handle(father_handle) + if father and \ + family_handle not in father.get_family_handle_list(): + father.add_family_handle(family_handle) + self.db.commit_person(father, self.trans) + txt = _("Error: family '%(family)s'" + " father '%(father)s'" + " does not refer" + " back to the family." + " Reference added." % + {'family' : family.gramps_id, + 'father' : father.gramps_id}) + self.info.add('unlinked-family', txt, None) + LOG.warn(txt) + + if mother_handle: + mother = self.db.get_person_from_handle(mother_handle) + if mother and \ + family_handle not in mother.get_family_handle_list(): + mother.add_family_handle(family_handle) + self.db.commit_person(mother, self.trans) + txt = _("Error: family '%(family)s'" + " mother '%(mother)s'" + " does not refer" + " back to the family." + " Reference added." % + {'family' : family.gramps_id, + 'mother' : mother.gramps_id}) + self.info.add('unlinked-family', txt, None) + LOG.warn(txt) + + for child_ref in family.get_child_ref_list(): + child_handle = child_ref.ref + child = self.db.get_person_from_handle(child_handle) + if child: + if family_handle not in \ + child.get_parent_family_handle_list(): + # The referenced child has no reference to the + # family. There was a link from the FAM record + # to the child, but no FAMC link from the child + # to the FAM. + child.add_parent_family_handle(family_handle) + self.db.commit_person(child, self.trans) + txt = _("Error: family '%(family)s'" + " child '%(child)s'" + " does not " + "refer back to the family. " + "Reference added." % + {'family' : family.gramps_id, + 'child' : child.gramps_id}) + self.info.add('unlinked-family', txt, None) + LOG.warn(txt) + def append_value(orig, val): if orig: return "%s, %s" % (orig, val) diff --git a/src/plugins/lib/libgedcom.py b/src/plugins/lib/libgedcom.py index 121217866..85fde65a3 100644 --- a/src/plugins/lib/libgedcom.py +++ b/src/plugins/lib/libgedcom.py @@ -3028,6 +3028,28 @@ class GedcomParser(UpdateCallback): 'orig_mother' : __input_pid(mother.gramps_id)}) + for child_ref in family.get_child_ref_list(): + child_handle = child_ref.ref + child = self.dbase.get_person_from_handle(child_handle) + if child: + if family_handle not in \ + child.get_parent_family_handle_list(): + # The referenced child has no reference to the family. + # There was a link from the FAM record to the child, but + # no FAMC link from the child to the FAM. + child.add_parent_family_handle(family_handle) + self.dbase.commit_person(child, self.trans) + self.__add_msg("Error: family '%(family)s' (input as" + " @%(orig_family)s@) child '%(child)s'" + " (input as '%(orig_child)s') does not " + "refer back to the family. " + "Reference added." % + {'family' : family.gramps_id, + 'orig_family' : input_id, + 'child' : child.gramps_id, + 'orig_child' : + __input_pid(child.gramps_id)}) + if self.missing_references: self.dbase.commit_note(self.explanation, self.trans, time.time()) txt = _("\nThe imported file was not self-contained.\n" diff --git a/src/plugins/tool/Check.py b/src/plugins/tool/Check.py index 8fb0a0dd9..1b2df4ca1 100644 --- a/src/plugins/tool/Check.py +++ b/src/plugins/tool/Check.py @@ -481,12 +481,11 @@ class CheckIntegrity(object): # is "Broken8" logging.warning(" FAIL: family '%(fam_gid)s' " "child '%(child_gid)s' has no reference" - " to the family" % + " to the family. Reference added" % {'fam_gid' : family.gramps_id, 'child_gid' : child.gramps_id}) - family.remove_child_ref(child_ref) - self.db.commit_family(family, self.trans) - self.broken_links.append((child_handle, family_handle)) + child.add_parent_family_handle(family_handle) + self.db.commit_person(child, self.trans) else: # The person referenced by the child handle # does not exist in the database