From 142c6c69cfa7e45b82c097fd47a30a3b5dbb66b2 Mon Sep 17 00:00:00 2001 From: Tim G L Lyons Date: Thu, 2 Feb 2012 23:02:18 +0000 Subject: [PATCH] Added a report for GEDCOM import showing lines that were not imported, and build notes containing the unimported data. The notes are attached, where possible, to appropriate objects. This resolves the following two issues: 0001371: source record ignores useful DATA block 0001571: Option on import to preserve Non-standard data from GEDCOM files (currently discarded without notice) svn: r18815 --- src/plugins/lib/libgedcom.py | 343 ++++++++++++++++++++++------------- 1 file changed, 215 insertions(+), 128 deletions(-) diff --git a/src/plugins/lib/libgedcom.py b/src/plugins/lib/libgedcom.py index 1b3a819d0..c79e692a6 100644 --- a/src/plugins/lib/libgedcom.py +++ b/src/plugins/lib/libgedcom.py @@ -121,7 +121,7 @@ import LdsUtils import Utils from DateHandler._DateParser import DateParser from gen.db.dbconst import EVENT_KEY -from QuestionDialog import WarningDialog +from QuestionDialog import WarningDialog, InfoDialog #------------------------------------------------------------------------- # @@ -1499,6 +1499,7 @@ class CurrentState(object): self.event = event self.event_ref = event_ref self.source_ref = None + self.msg = "" def __getattr__(self, name): """ @@ -1716,6 +1717,8 @@ class GedcomParser(UpdateCallback): self.set_total(stage_one.get_line_count()) self.repo2id = {} self.trans = None + self.errors = [] + self.number_of_errors = 0 self.maxpeople = stage_one.get_person_count() self.dbase = dbase self.emapper = IdFinder(dbase.get_gramps_ids(EVENT_KEY), @@ -2446,6 +2449,12 @@ class GedcomParser(UpdateCallback): self.dbase.enable_signals() self.dbase.request_rebuild() + if self.number_of_errors == 0: + message = _("GEDCOM import report: No errors detected") + else: + message = _("GEDCOM import report: %s errors detected") % \ + self.number_of_errors + InfoDialog(message, "".join(self.errors), monospaced=True) def __find_person_handle(self, gramps_id): """ @@ -2684,14 +2693,19 @@ class GedcomParser(UpdateCallback): # EOF ? if not self.groups: self.backoff = False - self.__warn(self.__TRUNC_MSG) + # We will add the truncation warning message to the error + # messages report, even though it probably won't be reported + # because the exception below gets raised before the report is + # produced. We do this in case __add_msg is changed in the + # future to do something else + self.__add_msg(self.__TRUNC_MSG) self.groups = None raise Errors.GedcomError(self.__TRUNC_MSG) self.backoff = False return self.groups - def __not_recognized(self, line, level): + def __not_recognized(self, line, level, state): """ Prints a message when an undefined token is found. All subordinate items to the current item are ignored. @@ -2699,16 +2713,35 @@ class GedcomParser(UpdateCallback): @param level: Current level in the file @type level: int """ - msg = _("Line %d was not understood, so it was ignored.") % line.line - self.__warn(msg) - self.__skip_subordinate_levels(level) + self.__add_msg(_("Line ignored as not understood"), line, state) + self.__skip_subordinate_levels(level, state) - def __warn(self, msg): - """ - Displays a msg using the logging facilities. - """ - LOG.warning(msg) - self.error_count += 1 + def __add_msg(self, problem, line=None, state=None): + if problem != "": + self.number_of_errors += 1 + if line: + problem = problem.ljust(33)[0:32] + message = "%s Line %5d: %s %s %s\n" % (problem, line.line, + line.level, + line.token_text, + line.data) + else: + message = problem + "\n" + if state: + state.msg += message + self.errors.append(message) + + def __check_msgs(self, record_name, state, object, trans): + if state.msg == "": + return + message = "Records not inported into " + record_name + ":\n\n" + \ + state.msg + new_note = gen.lib.Note(message) + new_note.set_handle(Utils.create_id()) + self.dbase.add_note(new_note, self.trans) + # If possible, attach the note to the relevant object + if object: + object.add_note(new_note.get_handle()) def _backup(self): """ @@ -2724,7 +2757,9 @@ class GedcomParser(UpdateCallback): try: line = self.__get_next_line() if line and line.token != TOKEN_TRLR: - self.__not_recognized(line, 0) + state = CurrentState() + self.__not_recognized(line, 0, state) + self.__check_msgs("TRLR (trailer)", state, None, self.trans) except TypeError: return @@ -2746,6 +2781,7 @@ class GedcomParser(UpdateCallback): state.res = researcher state.level = 1 self.__parse_level(state, self.subm_parse_tbl, self.__undefined) + self.__check_msgs("SUBM (submitter)", state, None, self.trans) self.dbase.set_researcher(state.res) def __parse_record(self): @@ -2778,7 +2814,9 @@ class GedcomParser(UpdateCallback): self._backup() break if line.token == TOKEN_UNKNOWN: - self.__skip_subordinate_levels(1) + state = CurrentState() + self.__skip_subordinate_levels(1, state) + self.__check_msgs("Top Level", state, None, self.trans) elif key in ("FAM", "FAMILY"): self.__parse_fam(line) elif key in ("INDI", "INDIVIDUAL"): @@ -2790,9 +2828,13 @@ class GedcomParser(UpdateCallback): elif key in ("SUBM", "SUBMITTER"): self.__parse_submitter(line) elif key in ("SUBN"): - self.__skip_subordinate_levels(1) + state = CurrentState() + self.__skip_subordinate_levels(1, state) + self.__check_msgs("Top Level", state, None, self.trans) elif line.token in (TOKEN_SUBM, TOKEN_SUBN, TOKEN_IGNORE): - self.__skip_subordinate_levels(1) + state = CurrentState() + self.__skip_subordinate_levels(1, state) + self.__check_msgs("Top Level", state, None, self.trans) elif key in ("SOUR", "SOURCE"): self.__parse_source(line.token_text, 1) elif (line.data.startswith("SOUR ") or @@ -2811,8 +2853,8 @@ class GedcomParser(UpdateCallback): line.data = None self.__parse_inline_note(line, 1) else: - self.__not_recognized(line, 1) - + self.__not_recognized(line, 1, state) + def __parse_level(self, state, __map, default): """ Loop trough the current GEDCOM level, calling the appropriate @@ -2838,7 +2880,7 @@ class GedcomParser(UpdateCallback): @param state: The current state @type state: CurrentState """ - self.__not_recognized(line, state.level+1) + self.__not_recognized(line, state.level+1, state) #---------------------------------------------------------------------- # @@ -2889,6 +2931,8 @@ class GedcomParser(UpdateCallback): # Add the default reference if no source has found self.__add_default_source(person) + self.__check_msgs("INDI (individual) Gramps ID %s" % + person.get_gramps_id(), state, person, self.trans) # commit the person to the database self.dbase.commit_person(person, self.trans, state.person.change) @@ -2899,7 +2943,7 @@ class GedcomParser(UpdateCallback): @param state: The current state @type state: CurrentState """ - citation_handle = self.handle_source(line, state.level) + citation_handle = self.handle_source(line, state.level, state) state.person.add_citation(citation_handle) def __person_attr(self, line, state): @@ -2913,7 +2957,7 @@ class GedcomParser(UpdateCallback): attr.set_type((gen.lib.AttributeType.CUSTOM, line.token_text)) attr.set_value(line.data) state.person.add_attribute(attr) - self.__skip_subordinate_levels(state.level+1) + self.__skip_subordinate_levels(state.level+1, state) def __person_event(self, line, state): """ @@ -2944,7 +2988,7 @@ class GedcomParser(UpdateCallback): @param state: The current state @type state: CurrentState """ - self.__skip_subordinate_levels(2) + self.__skip_subordinate_levels(2, state) def __person_chan(self, line, state): """ @@ -2953,7 +2997,7 @@ class GedcomParser(UpdateCallback): @param state: The current state @type state: CurrentState """ - self.__parse_change(line, state.person, state.level+1) + self.__parse_change(line, state.person, state.level+1, state) def __person_resn(self, line, state): """ @@ -2992,6 +3036,7 @@ class GedcomParser(UpdateCallback): sub_state.level = 2 self.__parse_level(sub_state, self.name_parse_tbl, self.__undefined) + state.msg += sub_state.msg def __person_object(self, line, state): """ @@ -3020,7 +3065,7 @@ class GedcomParser(UpdateCallback): ref.set_reference_handle(handle) state.person.add_media_reference(ref) else: - (form, filename, title, note) = self.__obje(state.level+1) + (form, filename, title, note) = self.__obje(state.level+1, state) self.build_media_object(state.person, form, filename, title, note) def __person_name(self, line, state): @@ -3074,6 +3119,7 @@ class GedcomParser(UpdateCallback): sub_state.level = state.level+1 self.__parse_level(sub_state, self.name_parse_tbl, self.__undefined) + state.msg += sub_state.msg def __person_sex(self, line, state): """ @@ -3129,6 +3175,7 @@ class GedcomParser(UpdateCallback): sub_state.event_ref = event_ref self.__parse_level(sub_state, self.event_parse_tbl, self.__undefined) + state.msg += sub_state.msg self.dbase.commit_event(event, self.trans) event_ref.ref = event.handle @@ -3225,7 +3272,7 @@ class GedcomParser(UpdateCallback): @param state: The current state @type state: CurrentState """ - self.__parse_note(line, state.person, 1) + self.__parse_note(line, state.person, 1, state) def __person_rnote(self, line, state): """ @@ -3236,7 +3283,7 @@ class GedcomParser(UpdateCallback): @param state: The current state @type state: CurrentState """ - self.__parse_note(line, state.person, 1) + self.__parse_note(line, state.person, 1, state) def __person_addr(self, line, state): """ @@ -3263,6 +3310,7 @@ class GedcomParser(UpdateCallback): sub_state.addr.set_street(line.data) state.person.add_address(sub_state.addr) self.__parse_level(sub_state, self.parse_addr_tbl, self.__ignore) + state.msg += sub_state.msg def __person_phon(self, line, state): """ @@ -3277,7 +3325,7 @@ class GedcomParser(UpdateCallback): addr.set_street("Unknown") addr.set_phone(line.data) state.person.add_address(addr) - self.__skip_subordinate_levels(state.level+1) + self.__skip_subordinate_levels(state.level+1, state) def __person_email(self, line, state): """ @@ -3329,6 +3377,7 @@ class GedcomParser(UpdateCallback): sub_state.event_ref = event_ref self.__parse_level(sub_state, self.event_parse_tbl, self.__undefined) + state.msg += sub_state.msg self.dbase.add_event(event, self.trans) event_ref.ref = event.handle @@ -3363,7 +3412,7 @@ class GedcomParser(UpdateCallback): @param state: The current state @type state: CurrentState """ - self.__parse_note(line, state.name, state.level+1) + self.__parse_note(line, state.name, state.level+1, state) def __name_alia(self, line, state): """ @@ -3385,7 +3434,7 @@ class GedcomParser(UpdateCallback): @type state: CurrentState """ state.name.set_title(line.data.strip()) - self.__skip_subordinate_levels(state.level+1) + self.__skip_subordinate_levels(state.level+1, state) def __name_givn(self, line, state): """ @@ -3395,7 +3444,7 @@ class GedcomParser(UpdateCallback): @type state: CurrentState """ state.name.set_first_name(line.data.strip()) - self.__skip_subordinate_levels(state.level+1) + self.__skip_subordinate_levels(state.level+1, state) def __name_spfx(self, line, state): """ @@ -3411,7 +3460,7 @@ class GedcomParser(UpdateCallback): surn.set_prefix(line.data.strip()) surn.set_primary() state.name.set_surname_list([surn]) - self.__skip_subordinate_levels(state.level+1) + self.__skip_subordinate_levels(state.level+1, state) def __name_surn(self, line, state): """ @@ -3427,7 +3476,7 @@ class GedcomParser(UpdateCallback): surn.set_surname(line.data.strip()) surn.set_primary() state.name.set_surname_list([surn]) - self.__skip_subordinate_levels(state.level+1) + self.__skip_subordinate_levels(state.level+1, state) def __name_marnm(self, line, state): """ @@ -3464,7 +3513,7 @@ class GedcomParser(UpdateCallback): else: #previously set suffix different, to not loose information, append state.name.set_suffix(state.name.get_suffix() + ' ' + line.data) - self.__skip_subordinate_levels(state.level+1) + self.__skip_subordinate_levels(state.level+1, state) def __name_nick(self, line, state): """ @@ -3474,7 +3523,7 @@ class GedcomParser(UpdateCallback): @type state: CurrentState """ state.name.set_nick_name(line.data.strip()) - self.__skip_subordinate_levels(state.level+1) + self.__skip_subordinate_levels(state.level+1, state) def __name_aka(self, line, state): """ @@ -3506,7 +3555,7 @@ class GedcomParser(UpdateCallback): @param state: The current state @type state: CurrentState """ - citation_handle = self.handle_source(line, state.level) + citation_handle = self.handle_source(line, state.level, state) state.name.add_citation(citation_handle) def __ignore(self, line, state): @@ -3518,7 +3567,8 @@ class GedcomParser(UpdateCallback): @param state: The current state @type state: CurrentState """ - self.__skip_subordinate_levels(state.level+1) + self.__add_msg(_("Tag recognised but not supported"), line, state) + self.__skip_subordinate_levels(state.level+1, state) def __person_std_attr(self, line, state): """ @@ -3536,6 +3586,7 @@ class GedcomParser(UpdateCallback): state.person.add_attribute(sub_state.attr) self.__parse_level(sub_state, self.person_attr_parse_tbl, self.__ignore) + state.msg += sub_state.msg def __person_fact(self, line, state): """ @@ -3554,6 +3605,7 @@ class GedcomParser(UpdateCallback): state.person.add_attribute(sub_state.attr) self.__parse_level(sub_state, self.person_fact_parse_tbl, self.__ignore) + state.msg += sub_state.msg def __person_fact_type(self, line, state): state.attr.set_type(line.data) @@ -3621,6 +3673,7 @@ class GedcomParser(UpdateCallback): state.person.lds_ord_list.append(sub_state.lds_ord) self.__parse_level(sub_state, self.lds_parse_tbl, self.__ignore) + state.msg += sub_state.msg if sub_state.place: sub_state.place_fields.load_place(sub_state.place, @@ -3700,7 +3753,7 @@ class GedcomParser(UpdateCallback): @param state: The current state @type state: CurrentState """ - citation_handle = self.handle_source(line, state.level) + citation_handle = self.handle_source(line, state.level, state) state.lds_ord.add_citation(citation_handle) def __lds_note(self, line, state): @@ -3712,7 +3765,7 @@ class GedcomParser(UpdateCallback): @param state: The current state @type state: CurrentState """ - self.__parse_note(line, state.lds_ord, state.level+1) + self.__parse_note(line, state.lds_ord, state.level+1, state) def __lds_stat(self, line, state): """ @@ -3751,6 +3804,7 @@ class GedcomParser(UpdateCallback): handle = self.__find_family_handle(gid) self.__parse_level(sub_state, self.famc_parse_tbl, self.__undefined) + state.msg += sub_state.msg # if the handle is not already in the person's parent family list, we # need to add it to thie list. @@ -3808,7 +3862,7 @@ class GedcomParser(UpdateCallback): @param state: The current state @type state: CurrentState """ - self.__parse_note(line, state.person, state.level+1) + self.__parse_note(line, state.person, state.level+1, state) def __person_famc_primary(self, line, state): """ @@ -3833,7 +3887,7 @@ class GedcomParser(UpdateCallback): @param state: The current state @type state: CurrentState """ - citation_handle = self.handle_source(line, state.level) + citation_handle = self.handle_source(line, state.level, state) state.person.add_citation(citation_handle) def __person_fams(self, line, state): @@ -3855,6 +3909,7 @@ class GedcomParser(UpdateCallback): sub_state = CurrentState(level=state.level+1) sub_state.obj = state.person self.__parse_level(sub_state, self.opt_note_tbl, self.__ignore) + state.msg += sub_state.msg def __person_asso(self, line, state): """ @@ -3894,6 +3949,7 @@ class GedcomParser(UpdateCallback): sub_state.ignore = False self.__parse_level(sub_state, self.asso_parse_tbl, self.__ignore) + state.msg += sub_state.msg if not sub_state.ignore: state.person.add_person_ref(sub_state.ref) @@ -3917,7 +3973,7 @@ class GedcomParser(UpdateCallback): @param state: The current state @type state: CurrentState """ - state.ref.add_citation(self.handle_source(line, state.level)) + state.ref.add_citation(self.handle_source(line, state.level, state)) def __person_asso_note(self, line, state): """ @@ -3928,7 +3984,7 @@ class GedcomParser(UpdateCallback): @param state: The current state @type state: CurrentState """ - self.__parse_note(line, state.ref, state.level) + self.__parse_note(line, state.ref, state.level, state) #------------------------------------------------------------------- # @@ -3987,6 +4043,8 @@ class GedcomParser(UpdateCallback): # add default reference if no reference exists self.__add_default_source(family) + self.__check_msgs("FAM (family) Gramps ID %s" % family.get_gramps_id(), + state, family, self.trans) # commit family to database self.dbase.commit_family(family, self.trans, family.change) @@ -4043,6 +4101,7 @@ class GedcomParser(UpdateCallback): sub_state.event_ref = event_ref self.__parse_level(sub_state, self.event_parse_tbl, self.__undefined) + state.msg += sub_state.msg if event.type == gen.lib.EventType.MARRIAGE: descr = event.get_description() @@ -4085,6 +4144,7 @@ class GedcomParser(UpdateCallback): sub_state.event_ref = event_ref self.__parse_level(sub_state, self.event_parse_tbl, self.__undefined) + state.msg += sub_state.msg self.dbase.commit_event(event, self.trans) event_ref.ref = event.handle @@ -4108,6 +4168,7 @@ class GedcomParser(UpdateCallback): sub_state.frel = None self.__parse_level(sub_state, self.family_rel_tbl, self.__ignore) + state.msg += sub_state.msg child = self.__find_or_create_person(self.pid_map[line.data]) @@ -4166,6 +4227,7 @@ class GedcomParser(UpdateCallback): state.family.lds_ord_list.append(sub_state.lds_ord) self.__parse_level(sub_state, self.lds_parse_tbl, self.__ignore) + state.msg += sub_state.msg if sub_state.place: sub_state.place_fields.load_place(sub_state.place, @@ -4192,7 +4254,7 @@ class GedcomParser(UpdateCallback): @param state: The current state @type state: CurrentState """ - citation_handle = self.handle_source(line, state.level) + citation_handle = self.handle_source(line, state.level, state) state.family.add_citation(citation_handle) def __family_object(self, line, state): @@ -4205,9 +4267,9 @@ class GedcomParser(UpdateCallback): @type state: CurrentState """ if line.data and line.data[0] == '@': - self.__not_recognized(line, state.level) + self.__not_recognized(line, state.level, state) else: - (form, filename, title, note) = self.__obje(state.level + 1) + (form, filename, title, note) = self.__obje(state.level + 1, state) self.build_media_object(state.family, form, filename, title, note) def __family_comm(self, line, state): @@ -4219,7 +4281,7 @@ class GedcomParser(UpdateCallback): """ note = line.data state.family.add_note(note) - self.__skip_subordinate_levels(state.level+1) + self.__skip_subordinate_levels(state.level+1, state) def __family_note(self, line, state): """ @@ -4230,7 +4292,7 @@ class GedcomParser(UpdateCallback): @param state: The current state @type state: CurrentState """ - self.__parse_note(line, state.family, state.level) + self.__parse_note(line, state.family, state.level, state) def __family_chan(self, line, state): """ @@ -4241,7 +4303,7 @@ class GedcomParser(UpdateCallback): @param state: The current state @type state: CurrentState """ - self.__parse_change(line, state.family, state.level+1) + self.__parse_change(line, state.family, state.level+1, state) def __family_addr(self, line, state): """ @@ -4275,7 +4337,7 @@ class GedcomParser(UpdateCallback): attr.set_value(line.data) state.family.add_attribute(attr) - def __obje(self, level): + def __obje(self, level, state): """ n OBJE {1:1} +1 FORM {1:1} @@ -4296,6 +4358,7 @@ class GedcomParser(UpdateCallback): sub_state.level = level self.__parse_level(sub_state, self.object_parse_tbl, self.__ignore) + state.msg += sub_state.msg return (sub_state.form, sub_state.filename, sub_state.title, sub_state.note) @@ -4403,9 +4466,9 @@ class GedcomParser(UpdateCallback): @type state: CurrentState """ if line.data and line.data[0] == '@': - self.__not_recognized(line, state.level) + self.__not_recognized(line, state.level, state) else: - (form, filename, title, note) = self.__obje(state.level + 1) + (form, filename, title, note) = self.__obje(state.level + 1, state) self.build_media_object(state.event, form, filename, title, note) def __event_type(self, line, state): @@ -4479,6 +4542,7 @@ class GedcomParser(UpdateCallback): self.__parse_level(sub_state, self.event_place_map, self.__undefined) + state.msg += sub_state.msg sub_state.pf.load_place(place, place.get_title()) self.dbase.commit_place(place, self.trans) @@ -4490,7 +4554,7 @@ class GedcomParser(UpdateCallback): @param state: The current state @type state: CurrentState """ - self.__parse_note(line, state.place, state.level+1) + self.__parse_note(line, state.place, state.level+1, state) def __event_place_form(self, line, state): """ @@ -4509,9 +4573,9 @@ class GedcomParser(UpdateCallback): @type state: CurrentState """ if line.data and line.data[0] == '@': - self.__not_recognized(line, state.level) + self.__not_recognized(line, state.level, state) else: - (form, filename, title, note) = self.__obje(state.level) + (form, filename, title, note) = self.__obje(state.level, state) self.build_media_object(state.place, form, filename, title, note) def __event_place_sour(self, line, state): @@ -4521,7 +4585,7 @@ class GedcomParser(UpdateCallback): @param state: The current state @type state: CurrentState """ - state.place.add_citation(self.handle_source(line, state.level)) + state.place.add_citation(self.handle_source(line, state.level, state)) def __place_map(self, line, state): """ @@ -4539,6 +4603,7 @@ class GedcomParser(UpdateCallback): sub_state.level = state.level + 1 sub_state.place = state.place self.__parse_level(sub_state, self.place_map_tbl, self.__undefined) + state.msg += sub_state.msg state.place = sub_state.place def __place_lati(self, line, state): @@ -4573,6 +4638,7 @@ class GedcomParser(UpdateCallback): sub_state.event = state.event self.__parse_level(sub_state, self.parse_loc_tbl, self.__undefined) + state.msg += sub_state.msg location = sub_state.location note_list = sub_state.note @@ -4622,7 +4688,7 @@ class GedcomParser(UpdateCallback): @param state: The current state @type state: CurrentState """ - self.__parse_note(line, state.event, state.level+1) + self.__parse_note(line, state.event, state.level+1, state) def __event_inline_note(self, line, state): """ @@ -4637,15 +4703,13 @@ class GedcomParser(UpdateCallback): if not line.data: # empty: discard, with warning and skip subs # Note: level+2 - msg = _("Line %d: empty event note was ignored.") % ( - line.line) - self.__warn(msg) - self.__skip_subordinate_levels(state.level+2) + self.__add_msg(_("Empty event note ignored"), line, state) + self.__skip_subordinate_levels(state.level+2, state) else: new_note = gen.lib.Note(line.data) new_note.set_handle(Utils.create_id()) self.dbase.add_note(new_note, self.trans) - self.__skip_subordinate_levels(state.level+2) + self.__skip_subordinate_levels(state.level+2, state) state.event.add_note(new_note.get_handle()) def __event_source(self, line, state): @@ -4655,7 +4719,7 @@ class GedcomParser(UpdateCallback): @param state: The current state @type state: CurrentState """ - state.event.add_citation(self.handle_source(line, state.level)) + state.event.add_citation(self.handle_source(line, state.level, state)) def __event_cause(self, line, state): """ @@ -4675,6 +4739,7 @@ class GedcomParser(UpdateCallback): sub_state.attr = attr self.__parse_level(sub_state, self.event_cause_tbl, self.__undefined) + state.msg += sub_state.msg def __event_cause_source(self, line, state): """ @@ -4683,7 +4748,7 @@ class GedcomParser(UpdateCallback): @param state: The current state @type state: CurrentState """ - state.attr.add_citation(self.handle_source(line, state.level)) + state.attr.add_citation(self.handle_source(line, state.level, state)) def __event_age(self, line, state): """ @@ -4819,6 +4884,7 @@ class GedcomParser(UpdateCallback): self.__parse_level(sub_state, self.parse_person_adopt, self.__undefined) + state.msg += sub_state.msg if (int(sub_state.mrel) == gen.lib.ChildRefType.BIRTH and int(sub_state.frel) == gen.lib.ChildRefType.BIRTH): @@ -4973,7 +5039,7 @@ class GedcomParser(UpdateCallback): @param state: The current state @type state: CurrentState """ - state.addr.add_citation(self.handle_source(line, state.level)) + state.addr.add_citation(self.handle_source(line, state.level, state)) def __address_note(self, line, state): """ @@ -4984,7 +5050,7 @@ class GedcomParser(UpdateCallback): @param state: The current state @type state: CurrentState """ - self.__parse_note(line, state.addr, state.level+1) + self.__parse_note(line, state.addr, state.level+1, state) def __citation_page(self, line, state): """ @@ -5021,6 +5087,7 @@ class GedcomParser(UpdateCallback): sub_state.citation = state.citation self.__parse_level(sub_state, self.citation_data_tbl, self.__undefined) + state.msg += sub_state.msg def __citation_data_date(self, line, state): state.citation.set_date_object(line.data) @@ -5046,7 +5113,7 @@ class GedcomParser(UpdateCallback): state.citation.add_note(note.get_handle()) def __citation_data_note(self, line, state): - self.__parse_note(line, state.citation, state.level) + self.__parse_note(line, state.citation, state.level, state) def __citation_obje(self, line, state): """ @@ -5058,9 +5125,9 @@ class GedcomParser(UpdateCallback): @type state: CurrentState """ if line.data and line.data[0] == '@': - self.__not_recognized(line, state.level) + self.__not_recognized(line, state.level, state) else: - (form, filename, title, note) = self.__obje(state.level) + (form, filename, title, note) = self.__obje(state.level, state) self.build_media_object(state.citation, form, filename, title, note) def __citation_refn(self, line, state): @@ -5072,7 +5139,7 @@ class GedcomParser(UpdateCallback): @param state: The current state @type state: CurrentState """ - self.__skip_subordinate_levels(state.level+1) + self.__skip_subordinate_levels(state.level+1, state) def __citation_even(self, line, state): """ @@ -5088,6 +5155,7 @@ class GedcomParser(UpdateCallback): sub_state.citation = state.citation self.__parse_level(sub_state, self.citation_even_tbl, self.__undefined) + state.msg += sub_state.msg def __citation_even_role(self, line, state): """ @@ -5129,7 +5197,7 @@ class GedcomParser(UpdateCallback): @param state: The current state @type state: CurrentState """ - self.__parse_note(line, state.citation, state.level+1) + self.__parse_note(line, state.citation, state.level+1, state) #---------------------------------------------------------------------- # @@ -5167,6 +5235,9 @@ class GedcomParser(UpdateCallback): state.level = level self.__parse_level(state, self.source_func, self.__undefined) + self.__check_msgs("SOUR (source) Gramps ID %s" % + state.source.get_gramps_id(), + state, state.source, self.trans) self.dbase.commit_source(state.source, self.trans, state.source.change) def __source_attr(self, line, state): @@ -5186,9 +5257,9 @@ class GedcomParser(UpdateCallback): @type state: CurrentState """ if line.data and line.data[0] == '@': - self.__not_recognized(line, state.level) + self.__not_recognized(line, state.level, state) else: - (form, filename, title, note) = self.__obje(state.level+1) + (form, filename, title, note) = self.__obje(state.level+1, state) self.build_media_object(state.source, form, filename, title, note) def __source_chan(self, line, state): @@ -5198,7 +5269,7 @@ class GedcomParser(UpdateCallback): @param state: The current state @type state: CurrentState """ - self.__parse_change(line, state.source, state.level+1) + self.__parse_change(line, state.source, state.level+1, state) def __source_undef(self, line, state): """ @@ -5207,7 +5278,7 @@ class GedcomParser(UpdateCallback): @param state: The current state @type state: CurrentState """ - self.__not_recognized(line, state.level+1) + self.__not_recognized(line, state.level+1, state) def __source_repo(self, line, state): """ @@ -5233,6 +5304,7 @@ class GedcomParser(UpdateCallback): sub_state.level = state.level + 1 self.__parse_level(sub_state, self.repo_ref_tbl, self.__undefined) + state.msg += sub_state.msg state.source.add_repo_reference(repo_ref) @@ -5244,7 +5316,7 @@ class GedcomParser(UpdateCallback): @type state: CurrentState """ state.repo_ref.set_call_number(line.data) - #self.__skip_subordinate_levels(state.level+1) + #self.__skip_subordinate_levels(state.level+1, state) def __repo_ref_medi(self, line, state): name = line.data @@ -5259,7 +5331,7 @@ class GedcomParser(UpdateCallback): @param state: The current state @type state: CurrentState """ - self.__parse_note(line, state.repo_ref, state.level+1) + self.__parse_note(line, state.repo_ref, state.level+1, state) def __repo_chan(self, line, state): """ @@ -5268,7 +5340,7 @@ class GedcomParser(UpdateCallback): @param state: The current state @type state: CurrentState """ - self.__parse_change(line, state.repo, state.level+1) + self.__parse_change(line, state.repo, state.level+1, state) def __source_abbr(self, line, state): """ @@ -5298,7 +5370,7 @@ class GedcomParser(UpdateCallback): @param state: The current state @type state: CurrentState """ - self.__parse_note(line, state.source, state.level+1) + self.__parse_note(line, state.source, state.level+1, state) def __source_auth(self, line, state): """ @@ -5317,7 +5389,7 @@ class GedcomParser(UpdateCallback): @type state: CurrentState """ state.source.set_publication_info(line.data) - self.__skip_subordinate_levels(state.level+1) + self.__skip_subordinate_levels(state.level+1, state) def __source_title(self, line, state): """ @@ -5370,6 +5442,8 @@ class GedcomParser(UpdateCallback): # Add the default reference if no source has found self.__add_default_source(media) + self.__check_msgs("OBJE (multi-media object) Gramps ID %s" % + media.get_gramps_id(), state, media, self.trans) # commit the person to the database self.dbase.commit_media_object(media, self.trans, media.change) @@ -5382,7 +5456,7 @@ class GedcomParser(UpdateCallback): """ # TODO: FIX THIS!!! state.media_form = line.data.strip() - self.__skip_subordinate_levels(state.level+1) + self.__skip_subordinate_levels(state.level+1, state) def __obje_file(self, line, state): """ @@ -5394,7 +5468,8 @@ class GedcomParser(UpdateCallback): (file_ok, filename) = self.__find_file(line.data, self.dir_path) if state.media != "URL": if not file_ok: - self.__warn(_("Could not import %s") % filename[0]) + self.__add_msg(_("Could not import %s") % filename[0], line, + state) path = filename[0].replace('\\', os.path.sep) state.media.set_path(path) state.media.set_mime_type(gen.mime.get_type(path)) @@ -5417,7 +5492,7 @@ class GedcomParser(UpdateCallback): @param state: The current state @type state: CurrentState """ - self.__parse_note(line, state.media, state.level+1) + self.__parse_note(line, state.media, state.level+1, state) def __obje_blob(self, line, state): """ @@ -5426,7 +5501,7 @@ class GedcomParser(UpdateCallback): @param state: The current state @type state: CurrentState """ - self.__skip_subordinate_levels(state.level+1) + self.__skip_subordinate_levels(state.level+1, state) def __obje_refn(self, line, state): """ @@ -5435,7 +5510,7 @@ class GedcomParser(UpdateCallback): @param state: The current state @type state: CurrentState """ - self.__skip_subordinate_levels(state.level+1) + self.__skip_subordinate_levels(state.level+1, state) def __obje_type(self, line, state): """ @@ -5444,7 +5519,7 @@ class GedcomParser(UpdateCallback): @param state: The current state @type state: CurrentState """ - self.__skip_subordinate_levels(state.level+1) + self.__skip_subordinate_levels(state.level+1, state) def __obje_rin(self, line, state): """ @@ -5453,7 +5528,7 @@ class GedcomParser(UpdateCallback): @param state: The current state @type state: CurrentState """ - self.__skip_subordinate_levels(state.level+1) + self.__skip_subordinate_levels(state.level+1, state) def __obje_chan(self, line, state): """ @@ -5462,7 +5537,7 @@ class GedcomParser(UpdateCallback): @param state: The current state @type state: CurrentState """ - self.__parse_change(line, state.media, state.level+1) + self.__parse_change(line, state.media, state.level+1, state) def __person_attr_type(self, line, state): """ @@ -5489,7 +5564,7 @@ class GedcomParser(UpdateCallback): @param state: The current state @type state: CurrentState """ - state.attr.add_citation(self.handle_source(line, state.level)) + state.attr.add_citation(self.handle_source(line, state.level, state)) def __person_attr_place(self, line, state): """ @@ -5501,7 +5576,7 @@ class GedcomParser(UpdateCallback): val = line.data if state.attr.get_value() == "": state.attr.set_value(val) - self.__skip_subordinate_levels(state.level) + self.__skip_subordinate_levels(state.level, state) def __person_attr_note(self, line, state): """ @@ -5510,7 +5585,7 @@ class GedcomParser(UpdateCallback): @param state: The current state @type state: CurrentState """ - self.__parse_note(line, state.attr, state.level+1) + self.__parse_note(line, state.attr, state.level+1, state) #---------------------------------------------------------------------- # @@ -5535,6 +5610,8 @@ class GedcomParser(UpdateCallback): state.level = 1 self.__parse_level(state, self.repo_parse_tbl, self.__ignore) + self.__check_msgs("REPO (repository) Gramps ID %s" % + repo.get_gramps_id(), state, repo, self.trans) self.dbase.commit_repository(repo, self.trans, repo.change) def __repo_name(self, line, state): @@ -5553,7 +5630,7 @@ class GedcomParser(UpdateCallback): @param state: The current state @type state: CurrentState """ - self.__parse_note(line, state.repo, state.level+1) + self.__parse_note(line, state.repo, state.level+1, state) def __repo_addr(self, line, state): """ @@ -5580,6 +5657,7 @@ class GedcomParser(UpdateCallback): sub_state.addr = addr self.__parse_level(sub_state, self.parse_addr_tbl, self.__ignore) + state.msg += sub_state.msg text = addr.get_street() if not (addr.get_city() or addr.get_state() or @@ -5749,9 +5827,9 @@ class GedcomParser(UpdateCallback): if not state.location: state.location = gen.lib.Location() if state.event: - self.__parse_note(line, state.event, state.level+1) + self.__parse_note(line, state.event, state.level+1, state) else: - self.__not_recognized(line, state.level) + self.__not_recognized(line, state.level, state) def __optional_note(self, line, state): """ @@ -5760,7 +5838,7 @@ class GedcomParser(UpdateCallback): @param state: The current state @type state: CurrentState """ - self.__parse_note(line, state.obj, state.level) + self.__parse_note(line, state.obj, state.level, state) #---------------------------------------------------------------------- # @@ -5806,6 +5884,7 @@ class GedcomParser(UpdateCallback): """ state = CurrentState(level=1) self.__parse_level(state, self.header_sour, self.__undefined) + self.__check_msgs("SOUR (header level source)", state, None, self.trans) def __header_sour(self, line, state): """ @@ -5860,6 +5939,7 @@ class GedcomParser(UpdateCallback): """ sub_state = CurrentState(level=state.level+1) self.__parse_level(sub_state, self.header_subm, self.__ignore) + state.msg += sub_state.msg def __header_dest(self, line, state): """ @@ -5872,13 +5952,13 @@ class GedcomParser(UpdateCallback): self.gedsource = self.gedmap.get_from_source_tag(line.data) if state.genby.upper() == "LEGACY": - fname = os.path.basename(self.filename) - WarningDialog( - _("Import of GEDCOM file %s with DEST=%s, " - "could cause errors in the resulting database!") - % (fname, state.genby), - _("Look for nameless events.") - ) + fname = os.path.basename(self.filename) + WarningDialog( + _("Import of GEDCOM file %s with DEST=%s, " + "could cause errors in the resulting database!") + % (fname, state.genby), + _("Look for nameless events.") + ) def __header_plac(self, line, state): """ @@ -5889,6 +5969,7 @@ class GedcomParser(UpdateCallback): """ sub_state = CurrentState(level=state.level+1) self.__parse_level(sub_state, self.place_form, self.__undefined) + state.msg += sub_state.msg def __place_form(self, line, state): """ @@ -5917,7 +5998,7 @@ class GedcomParser(UpdateCallback): @type state: CurrentState """ if self.use_def_src: - self.__parse_note(line, self.def_src, 2) + self.__parse_note(line, self.def_src, 2, state) def __header_subm_name(self, line, state): """ @@ -5929,21 +6010,20 @@ class GedcomParser(UpdateCallback): if self.use_def_src: self.def_src.set_author(line.data) - def __parse_note(self, line, obj, level): + def __parse_note(self, line, obj, level, state): if line.token == TOKEN_RNOTE: # reference to a named note defined elsewhere gid = line.data.strip() obj.add_note(self.__find_note_handle(self.nid_map[gid])) else: if not line.data: - msg = _("Line %d: empty note was ignored.") % line.line - self.__warn(msg) - self.__skip_subordinate_levels(level+1) + self.__add_msg(_("Empty note ignored"), line, state) + self.__skip_subordinate_levels(level+1, state) else: new_note = gen.lib.Note(line.data) new_note.set_handle(Utils.create_id()) self.dbase.add_note(new_note, self.trans) - self.__skip_subordinate_levels(level+1) + self.__skip_subordinate_levels(level+1, state) obj.add_note(new_note.get_handle()) #---------------------------------------------------------------------- @@ -5964,28 +6044,31 @@ class GedcomParser(UpdateCallback): +1 RIN {0:1} +1 <> {0:1} """ + state = CurrentState() gid = self.nid_map[line.token_text] handle = self.nid2id.get(gid) if not line.data and handle is None: - msg = _("Line %d: empty note was ignored.") % line.line - self.__warn(msg) - self.__skip_subordinate_levels(level) + self.__add_msg(_("Empty note ignored"), line, state) + self.__skip_subordinate_levels(level, state) else: new_note = gen.lib.Note(line.data) new_note.set_handle(handle) new_note.set_gramps_id(gid) self.dbase.add_note(new_note, self.trans) self.nid2id[new_note.gramps_id] = new_note.handle - self.__skip_subordinate_levels(level) + self.__skip_subordinate_levels(level, state) + self.__check_msgs("NOTE Gramps ID %s" % new_note.get_gramps_id(), + state, None, self.trans) - def __parse_source_reference(self, citation, level, handle): + def __parse_source_reference(self, citation, level, handle, state): """ Read the data associated with a SOUR reference. """ - state = CurrentState(level=level+1) - state.citation = citation - state.handle = handle - self.__parse_level(state, self.citation_parse_tbl, self.__ignore) + sub_state = CurrentState(level=level+1) + sub_state.citation = citation + sub_state.handle = handle + self.__parse_level(sub_state, self.citation_parse_tbl, self.__ignore) + state.msg += sub_state.msg def __parse_header_head(self): """ @@ -5995,7 +6078,7 @@ class GedcomParser(UpdateCallback): if line.token != TOKEN_HEAD: raise Errors.GedcomError("%s is not a GEDCOM file" % self.filename) - def __skip_subordinate_levels(self, level): + def __skip_subordinate_levels(self, level, state): """ Skip add lines of the specified level or lower. """ @@ -6003,14 +6086,15 @@ class GedcomParser(UpdateCallback): while True: line = self.__get_next_line() if self.__level_is_finished(line, level): - if skips and self.want_parse_warnings: - msg = _("skipped %(skip)d subordinate(s) at line %(line)d") % { - 'skip' : skips, 'line' : line.line - skips } - self.__warn(msg) + if skips: + # This improves formatting when there are long sequences of + # skipped lines + self.__add_msg("", None, None) return + self.__add_msg(_("Skipped subordinate line"), line, state) skips += 1 - def handle_source(self, line, level): + def handle_source(self, line, level, state): """ Handle the specified source, building a source reference to the object. @@ -6026,12 +6110,12 @@ class GedcomParser(UpdateCallback): else: src = self.__find_or_create_source(self.sid_map[line.data]) self.dbase.commit_source(src, self.trans) - self.__parse_source_reference(citation, level, src.handle) + self.__parse_source_reference(citation, level, src.handle, state) citation.set_reference_handle(src.handle) self.dbase.add_citation(citation, self.trans) return citation.handle - def __parse_change(self, line, obj, level): + def __parse_change(self, line, obj, level, state): """ CHANGE_DATE:= @@ -6061,9 +6145,9 @@ class GedcomParser(UpdateCallback): #Lexer converted already to Date object dobj = line.data elif line.token == TOKEN_NOTE: - self.__skip_subordinate_levels(level+1) + self.__skip_subordinate_levels(level+1, state) else: - self.__not_recognized(line, level+1) + self.__not_recognized(line, level+1, state) # Attempt to convert the values to a valid change time if dobj: @@ -6096,7 +6180,7 @@ class GedcomParser(UpdateCallback): else: (valid, path) = self.__find_file(filename, self.dir_path) if not valid: - self.__warn(_("Could not import %s") % filename) + self.__add_msg(_("Could not import %s") % filename) path = filename.replace('\\', os.path.sep) photo_handle = self.media_map.get(path) if photo_handle is None: @@ -6147,6 +6231,7 @@ class GedcomParser(UpdateCallback): sub_state.person = state.person self.__parse_level(sub_state, event_map, self.__undefined) + state.msg += sub_state.msg self.dbase.commit_event(event, self.trans) event_ref.set_reference_handle(event.handle) @@ -6170,6 +6255,7 @@ class GedcomParser(UpdateCallback): sub_state.event_ref = event_ref self.__parse_level(sub_state, event_map, self.__undefined) + state.msg += sub_state.msg self.dbase.commit_event(event, self.trans) event_ref.set_reference_handle(event.handle) @@ -6193,7 +6279,7 @@ class GedcomParser(UpdateCallback): ## Okay we have no clue which temple this is. ## We should tell the user and store it anyway. - self.__warn("Invalid temple code '%s'" % (line.data, )) + self.__add_msg(_("Invalid temple code"), line, None) return line.data def __add_default_source(self, obj): @@ -6227,6 +6313,7 @@ class GedcomParser(UpdateCallback): sub_state.location.set_street(line.data) self.__parse_level(sub_state, self.parse_loc_tbl, self.__undefined) + state.msg += sub_state.msg location = sub_state.location state.res.set_address(location.get_street())