def create_tag(self, tag_name, tag_color): """ Create a tag if it doesn't already exist. """ tag = self.db.get_tag_from_name(tag_name) if tag is None: tag = Tag() tag.set_name(tag_name) if tag_color is not None: tag.set_color(tag_color) tag.set_priority(self.db.get_number_of_tags()) tag_handle = self.db.add_tag(tag, self.trans) else: tag_handle = tag.get_handle() return tag_handle
def on_ok_clicked(self, obj): clean = self.clear_button.get_active() copy = self.copy_button.get_active() tag = self.tag_button.get_active() if not (copy or clean or tag): return self.db.disable_signals() if tag: tag_name = _('Legacy place') # start the db transaction with DbTxn("Tag for place titles", self.db) as self.tag_trans: mark = self.db.get_tag_from_name(tag_name) if not mark: # create the tag if it doesn't already exist mark = Tag() mark.set_name(tag_name) mark.set_priority(self.db.get_number_of_tags()) tag_handle = self.db.add_tag(mark, self.tag_trans) else: tag_handle = mark.get_handle() with DbTxn(_("Modify Place titles"), self.db, batch=True) as trans: for row in self.model: if row[1] == True: place = self.db.get_place_from_handle(row[0]) if copy: self.create_note(place, row[2], trans) if clean: place.set_title("") if tag: place.add_tag(tag_handle) self.db.commit_place(place, trans) self.db.enable_signals() self.db.request_rebuild() self.close()
def applyTagClicked(self, button) : progress = None rows = self.treeSelection.count_selected_rows() tag_name = str(self.tagcombo.get_active_text()) # start the db transaction with DbTxn("Tag not related", self.db) as transaction: tag = self.db.get_tag_from_name(tag_name) if not tag: # create the tag if it doesn't already exist tag = Tag() tag.set_name(tag_name) tag.set_priority(self.db.get_number_of_tags()) tag_handle = self.db.add_tag(tag, transaction) else: tag_handle = tag.get_handle() # if more than 1 person is selected, use a progress indicator if rows > 1: progress = ProgressMeter(self.title,_('Starting'), parent=self.window) progress.set_pass( # translators: leave all/any {...} untranslated #TRANS: no singular form needed, as rows is always > 1 ngettext("Setting tag for {number_of} person", "Setting tag for {number_of} people", rows).format(number_of=rows), rows) # iterate through all of the selected rows (model, paths) = self.treeSelection.get_selected_rows() for path in paths: if progress: progress.step() # for the current row, get the GID and the person from the database iter = self.model.get_iter(path) personGid = self.model.get_value(iter, 1) person = self.db.get_person_from_gramps_id(personGid) # add the tag to the person person.add_tag(tag_handle) # save this change self.db.commit_person(person, transaction) # refresh the tags column self.treeView.set_model(None) for path in paths: iter = self.model.get_iter(path) personGid = self.model.get_value(iter, 1) person = self.db.get_person_from_gramps_id(personGid) self.model.set_value(iter, 3, self.get_tag_list(person)) self.treeView.set_model(self.model) self.treeView.expand_all() if progress: progress.close()
class CSVParser: """Class to read data in CSV format from a file object.""" def __init__(self, dbase, user, default_tag_format=None): self.db = dbase self.user = user self.trans = None self.lineno = 0 self.index = 0 self.fam_count = 0 self.indi_count = 0 self.place_count = 0 self.pref = {} # person ref, internal to this sheet self.fref = {} # family ref, internal to this sheet self.placeref = {} self.place_types = {} # Build reverse dictionary, name to type number for items in PlaceType().get_map().items(): # (0, 'Custom') self.place_types[items[1]] = items[0] self.place_types[items[1].lower()] = items[0] if _(items[1]) != items[1]: self.place_types[_(items[1])] = items[0] # Add custom types: for custom_type in self.db.get_place_types(): self.place_types[custom_type] = 0 self.place_types[custom_type.lower()] = 0 column2label = { "surname": ("Lastname", "Surname", _("Surname"), "lastname", "last_name", "surname", _("surname")), "firstname": ("Firstname", "Given name", _("Given name"), "Given", _("Given"), "firstname", "first_name", "given_name", "given name", _("given name"), "given", _("given")), "callname": ("Callname", "Call name", _("Call name"), "Call", _("Call"), "callname", "call_name", "call name", "call", _("call")), "title": ("Title", _("Person or Place|Title"), "title", _("Person or Place|title")), "prefix": ("Prefix", _("Prefix"), "prefix", _("prefix")), "suffix": ("Suffix", _("Suffix"), "suffix", _("suffix")), "gender": ("Gender", _("Gender"), "gender", _("gender")), "source": ("Source", _("Source"), "source", _("source")), "note": ("Note", _("Note"), "note", _("note")), "birthplace": ("Birthplace", "Birth place", _("Birth place"), "birthplace", "birth_place", "birth place", _("birth place")), "birthplace_id": ("Birthplaceid", "Birth place id", _("Birth place id"), "birthplaceid", "birth_place_id", "birth place id", _("birth place id"), "birthplace_id"), "birthdate": ("Birthdate", "Birth date", _("Birth date"), "birthdate", "birth_date", "birth date", _("birth date")), "birthsource": ("Birthsource", "Birth source", _("Birth source"), "birthsource", "birth_source", "birth source", _("birth source")), "baptismplace": ("Baptismplace", "Baptism place", _("Baptism place"), "baptismplace", "baptism place", _("baptism place")), "baptismplace_id": ("Baptismplaceid", "Baptism place id", _("Baptism place id"), "baptismplaceid", "baptism place id", _("baptism place id"), "baptism_place_id", "baptismplace_id"), "baptismdate": ("Baptismdate", "Baptism date", _("Baptism date"), "baptismdate", "baptism date", _("baptism date")), "baptismsource": ("Baptismsource", "Baptism source", _("Baptism source"), "baptismsource", "baptism source", _("baptism source")), "burialplace": ("Burialplace", "Burial place", _("Burial place"), "burialplace", "burial place", _("burial place")), "burialplace_id": ("Burialplaceid", "Burial place id", _("Burial place id"), "burialplaceid", "burial place id", _("burial place id"), "burial_place_id", "burialplace_id"), "burialdate": ("Burialdate", "Burial date", _("Burial date"), "burialdate", "burial date", _("burial date")), "burialsource": ("Burialsource", "Burial source", _("Burial source"), "burialsource", "burial source", _("burial source")), "deathplace": ("Deathplace", "Death place", _("Death place"), "deathplace", "death_place", "death place", _("death place")), "deathplace_id": ("Deathplaceid", "Death place id", _("Death place id"), "deathplaceid", "death_place_id", "death place id", _("death place id"), "death_place_id", "deathplace_id"), "deathdate": ("Deathdate", "Death date", _("Death date"), "deathdate", "death_date", "death date", _("death date")), "deathsource": ("Deathsource", "Death source", _("Death source"), "deathsource", "death_source", "death source", _("death source")), "deathcause": ("Deathcause", "Death cause", _("Death cause"), "deathcause", "death_cause", "death cause", _("death cause")), "grampsid": ("Grampsid", "ID", "Gramps id", _("Gramps ID"), "grampsid", "id", "gramps_id", "gramps id", _("Gramps id")), "person": ("Person", _("Person"), "person", _("person")), # ---------------------------------- "child": ("Child", _("Child"), "child", _("child")), "family": ("Family", _("Family"), "family", _("family")), # ---------------------------------- "wife": ("Mother", _("Mother"), "Wife", _("Wife"), "Parent2", _("Parent2"), "mother", _("mother"), "wife", _("wife"), "parent2", _("parent2")), "husband": ("Father", _("Father"), "Husband", _("Husband"), "Parent1", _("Parent1"), "father", _("father"), "husband", _("husband"), "parent1", _("parent1")), "marriage": ("Marriage", _("Marriage"), "marriage", _("marriage")), "date": ("Date", _("Date"), "date", _("date")), "place": ("Place", _("Place"), "place", _("place")), "place_id": ("Placeid", "place id", "Place id", "place_id", "placeid"), "name": ("Name", _("Name"), "name", _("name")), "type": ("Type", _("Type"), "type", _("type")), "latitude": ("Latitude", _("latitude"), "latitude", _("latitude")), "longitude": ("Longitude", _("Longitude"), "longitude", _("longitude")), "code": ("Code", _("Code"), "code", _("code")), "enclosed_by": ("Enclosed by", _("Enclosed by"), "enclosed by", _("enclosed by"), "enclosed_by", _("enclosed_by"), "Enclosed_by", _("Enclosed_by"), "enclosedby") } lab2col_dict = [] for key in list(column2label.keys()): for val in column2label[key]: lab2col_dict.append((val, key)) self.label2column = dict(lab2col_dict) if default_tag_format: name = time.strftime(default_tag_format) tag = self.db.get_tag_from_name(name) if tag: self.default_tag = tag else: self.default_tag = Tag() self.default_tag.set_name(name) else: self.default_tag = None def cleanup_column_name(self, column): """Handle column aliases for CSV spreadsheet import and SQL.""" return self.label2column.get(column, column) def read_csv(self, filehandle): "Read the data from the file and return it as a list." try: data = [[r.strip() for r in row] for row in csv.reader(filehandle)] except csv.Error as err: self.user.notify_error(_('format error: line %(line)d: %(zero)s') % { 'line' : reader.line_num, 'zero' : err } ) return None return data def lookup(self, type_, id_): """ Return the object of type type_ with id id_ from db or previously stored value. """ if id_ is None: return None if type_ == "family": if id_.startswith("[") and id_.endswith("]"): id_ = self.db.fid2user_format(id_[1:-1]) db_lookup = self.db.get_family_from_gramps_id(id_) if db_lookup is None: return self.lookup(type_, id_) else: return db_lookup elif id_.lower() in self.fref: return self.fref[id_.lower()] else: return None elif type_ == "person": if id_.startswith("[") and id_.endswith("]"): id_ = self.db.id2user_format(id_[1:-1]) db_lookup = self.db.get_person_from_gramps_id(id_) if db_lookup is None: return self.lookup(type_, id_) else: return db_lookup elif id_.lower() in self.pref: return self.pref[id_.lower()] else: return None elif type_ == "place": if id_.startswith("[") and id_.endswith("]"): id_ = self.db.id2user_format(id_[1:-1]) db_lookup = self.db.get_place_from_gramps_id(id_) if db_lookup is None: return self.lookup(type_, id_) else: return db_lookup elif id_.lower() in self.placeref: return self.placeref[id_.lower()] else: return None else: LOG.warn("invalid lookup type in CSV import: '%s'" % type_) return None def storeup(self, type_, id_, object_): "Store object object_ of type type_ in a dictionary under key id_." if id_.startswith("[") and id_.endswith("]"): id_ = id_[1:-1] #return # do not store gramps people; go look them up if type_ == "person": id_ = self.db.id2user_format(id_) self.pref[id_.lower()] = object_ elif type_ == "family": id_ = self.db.fid2user_format(id_) self.fref[id_.lower()] = object_ elif type_ == "place": id_ = self.db.pid2user_format(id_) self.placeref[id_.lower()] = object_ else: LOG.warn("invalid storeup type in CSV import: '%s'" % type_) def parse(self, filehandle): """ Prepare the database and parse the input file. :param filehandle: open file handle positioned at start of the file """ progress_title = _('CSV Import') with self.user.progress(progress_title, _('Reading data...'), 1) as step: data = self.read_csv(filehandle) with self.user.progress(progress_title, _('Importing data...'), len(data)) as step: tym = time.time() self.db.disable_signals() with DbTxn(_("CSV import"), self.db, batch=True) as self.trans: if self.default_tag and self.default_tag.handle is None: self.db.add_tag(self.default_tag, self.trans) self._parse_csv_data(data, step) self.db.enable_signals() self.db.request_rebuild() tym = time.time() - tym # translators: leave all/any {...} untranslated msg = ngettext('Import Complete: {number_of} second', 'Import Complete: {number_of} seconds', tym ).format(number_of=tym) LOG.debug(msg) LOG.debug("New Families: %d" % self.fam_count) LOG.debug("New Individuals: %d" % self.indi_count) def _parse_csv_data(self, data, step): """Parse each line of the input data and act accordingly.""" self.lineno = 0 self.index = 0 self.fam_count = 0 self.indi_count = 0 self.place_count = 0 self.pref = {} # person ref, internal to this sheet self.fref = {} # family ref, internal to this sheet self.placeref = {} header = None line_number = 0 for row in data: step() line_number += 1 if "".join(row) == "": # no blanks are allowed inside a table header = None # clear headers, ready for next "table" continue ###################################### if header is None: header = [self.cleanup_column_name(r) for r in row] col = {} count = 0 for key in header: col[key] = count count += 1 continue # four different kinds of data: person, family, and marriage if (("marriage" in header) or ("husband" in header) or ("wife" in header)): self._parse_marriage(line_number, row, col) elif "family" in header: self._parse_family(line_number, row, col) elif "surname" in header: self._parse_person(line_number, row, col) elif "place" in header: self._parse_place(line_number, row, col) else: LOG.warn("ignoring line %d" % line_number) return None def _parse_marriage(self, line_number, row, col): "Parse the content of a Marriage,Husband,Wife line." marriage_ref = rd(line_number, row, col, "marriage") husband = rd(line_number, row, col, "husband") wife = rd(line_number, row, col, "wife") marriagedate = rd(line_number, row, col, "date") marriageplace = rd(line_number, row, col, "place") marriageplace_id = rd(line_number, row, col, "place_id") marriagesource = rd(line_number, row, col, "source") note = rd(line_number, row, col, "note") wife = self.lookup("person", wife) husband = self.lookup("person", husband) if husband is None and wife is None: # might have children, so go ahead and add LOG.warn("no parents on line %d; adding family anyway" % line_number) family = self.get_or_create_family(marriage_ref, husband, wife) # adjust gender, if not already provided if husband: # this is just a guess, if unknown if husband.get_gender() == Person.UNKNOWN: husband.set_gender(Person.MALE) self.db.commit_person(husband, self.trans) if wife: # this is just a guess, if unknown if wife.get_gender() == Person.UNKNOWN: wife.set_gender(Person.FEMALE) self.db.commit_person(wife, self.trans) if marriage_ref: self.storeup("family", marriage_ref.lower(), family) if marriagesource: # add, if new new, marriagesource = self.get_or_create_source(marriagesource) if marriageplace and marriageplace_id: raise Error("Error in marriage: can't have a place and place_id") if marriageplace: # add, if new new, marriageplace = self.get_or_create_place(marriageplace) elif marriageplace_id: # better exist already, locally or in database: marriageplace = self.lookup("place", marriageplace_id) if marriagedate: marriagedate = _dp.parse(marriagedate) if marriagedate or marriageplace or marriagesource or note: # add, if new; replace, if different new, marriage = self.get_or_create_event(family, EventType.MARRIAGE, marriagedate, marriageplace, marriagesource) if new: mar_ref = EventRef() mar_ref.set_reference_handle(marriage.get_handle()) family.add_event_ref(mar_ref) self.db.commit_family(family, self.trans) # only add note to event: # append notes, if previous notes if note: previous_notes_list = marriage.get_note_list() updated_note = False for note_handle in previous_notes_list: previous_note = self.db.get_note_from_handle( note_handle) if previous_note.type == NoteType.EVENT: previous_text = previous_note.get() if note not in previous_text: note = previous_text + "\n" + note previous_note.set(note) self.db.commit_note(previous_note, self.trans) updated_note = True break if not updated_note: # add new note here new_note = Note() new_note.handle = create_id() new_note.type.set(NoteType.EVENT) new_note.set(note) if self.default_tag: new_note.add_tag(self.default_tag.handle) self.db.add_note(new_note, self.trans) marriage.add_note(new_note.handle) self.db.commit_event(marriage, self.trans) def _parse_family(self, line_number, row, col): "Parse the content of a family line" family_ref = rd(line_number, row, col, "family") if family_ref is None: LOG.warn("no family reference found for family on line %d" % line_number) return # required child = rd(line_number, row, col, "child") source = rd(line_number, row, col, "source") note = rd(line_number, row, col, "note") gender = rd(line_number, row, col, "gender") child = self.lookup("person", child) family = self.lookup("family", family_ref) if family is None: LOG.warn("no matching family reference found for family " "on line %d" % line_number) return if child is None: LOG.warn("no matching child reference found for family " "on line %d" % line_number) return # is this child already in this family? If so, don't add LOG.debug("children: %s", [ref.ref for ref in family.get_child_ref_list()]) LOG.debug("looking for: %s", child.get_handle()) if child.get_handle() not in [ref.ref for ref in family.get_child_ref_list()]: # add child to family LOG.debug(" adding child [%s] to family [%s]", child.get_gramps_id(), family.get_gramps_id()) childref = ChildRef() childref.set_reference_handle(child.get_handle()) family.add_child_ref( childref) self.db.commit_family(family, self.trans) child.add_parent_family_handle(family.get_handle()) if gender: # replace gender = gender.lower() if gender == gender_map[Person.MALE].lower(): gender = Person.MALE elif gender == gender_map[Person.FEMALE].lower(): gender = Person.FEMALE else: gender = Person.UNKNOWN child.set_gender(gender) if source: # add, if new dummy_new, source = self.get_or_create_source(source) self.find_and_set_citation(child, source) # put note on child if note: # append notes, if previous notes previous_notes_list = child.get_note_list() updated_note = False for note_handle in previous_notes_list: previous_note = self.db.get_note_from_handle(note_handle) if previous_note.type == NoteType.PERSON: previous_text = previous_note.get() if note not in previous_text: note = previous_text + "\n" + note previous_note.set(note) self.db.commit_note(previous_note, self.trans) updated_note = True break if not updated_note: # add new note here new_note = Note() new_note.handle = create_id() new_note.type.set(NoteType.PERSON) new_note.set(note) if self.default_tag: new_note.add_tag(self.default_tag.handle) self.db.add_note(new_note, self.trans) child.add_note(new_note.handle) self.db.commit_person(child, self.trans) def _parse_person(self, line_number, row, col): "Parse the content of a Person line." surname = rd(line_number, row, col, "surname") firstname = rd(line_number, row, col, "firstname", "") callname = rd(line_number, row, col, "callname") title = rd(line_number, row, col, "title") prefix = rd(line_number, row, col, "prefix") suffix = rd(line_number, row, col, "suffix") gender = rd(line_number, row, col, "gender") source = rd(line_number, row, col, "source") note = rd(line_number, row, col, "note") birthplace = rd(line_number, row, col, "birthplace") birthplace_id = rd(line_number, row, col, "birthplace_id") birthdate = rd(line_number, row, col, "birthdate") birthsource = rd(line_number, row, col, "birthsource") baptismplace = rd(line_number, row, col, "baptismplace") baptismplace_id = rd(line_number, row, col, "baptismplace_id") baptismdate = rd(line_number, row, col, "baptismdate") baptismsource = rd(line_number, row, col, "baptismsource") burialplace = rd(line_number, row, col, "burialplace") burialplace_id = rd(line_number, row, col, "burialplace_id") burialdate = rd(line_number, row, col, "burialdate") burialsource = rd(line_number, row, col, "burialsource") deathplace = rd(line_number, row, col, "deathplace") deathplace_id = rd(line_number, row, col, "deathplace_id") deathdate = rd(line_number, row, col, "deathdate") deathsource = rd(line_number, row, col, "deathsource") deathcause = rd(line_number, row, col, "deathcause") grampsid = rd(line_number, row, col, "grampsid") person_ref = rd(line_number, row, col, "person") ######################################################### # if this person already exists, don't create them person = self.lookup("person", person_ref) if person is None: if surname is None: LOG.warn("empty surname for new person on line %d" % line_number) surname = "" # new person person = self.create_person() name = Name() name.set_type(NameType(NameType.BIRTH)) name.set_first_name(firstname) surname_obj = Surname() surname_obj.set_surname(surname) name.add_surname(surname_obj) person.set_primary_name(name) else: name = person.get_primary_name() ######################################################### if person_ref is not None: self.storeup("person", person_ref, person) # replace if surname is not None: name.get_primary_surname().set_surname(surname) if firstname is not None: name.set_first_name(firstname) if callname is not None: name.set_call_name(callname) if title is not None: name.set_title(title) if prefix is not None: name.get_primary_surname().set_prefix(prefix) name.group_as = '' # HELP? what should I do here? if suffix is not None: name.set_suffix(suffix) if note is not None: # append notes, if previous notes previous_notes_list = person.get_note_list() updated_note = False for note_handle in previous_notes_list: previous_note = self.db.get_note_from_handle(note_handle) if previous_note.type == NoteType.PERSON: previous_text = previous_note.get() if note not in previous_text: note = previous_text + "\n" + note previous_note.set(note) self.db.commit_note(previous_note, self.trans) updated_note = True break if not updated_note: # add new note here new_note = Note() new_note.handle = create_id() new_note.type.set(NoteType.PERSON) new_note.set(note) if self.default_tag: new_note.add_tag(self.default_tag.handle) self.db.add_note(new_note, self.trans) person.add_note(new_note.handle) if grampsid is not None: person.gramps_id = grampsid elif person_ref is not None: if person_ref.startswith("[") and person_ref.endswith("]"): person.gramps_id = self.db.id2user_format(person_ref[1:-1]) if (person.get_gender() == Person.UNKNOWN and gender is not None): gender = gender.lower() if gender == gender_map[Person.MALE].lower(): gender = Person.MALE elif gender == gender_map[Person.FEMALE].lower(): gender = Person.FEMALE else: gender = Person.UNKNOWN person.set_gender(gender) ######################################################### # add if new, replace if different # Birth: if birthdate is not None: birthdate = _dp.parse(birthdate) if birthplace and birthplace_id: raise Error("Error in person: can't have a birthplace and birthplace_id") if birthplace is not None: new, birthplace = self.get_or_create_place(birthplace) elif birthplace_id: # better exist already, locally or in database: birthplace = self.lookup("place", birthplace_id) if birthsource is not None: new, birthsource = self.get_or_create_source(birthsource) if birthdate or birthplace or birthsource: new, birth = self.get_or_create_event(person, EventType.BIRTH, birthdate, birthplace, birthsource) birth_ref = person.get_birth_ref() if birth_ref is None: # new birth_ref = EventRef() birth_ref.set_reference_handle( birth.get_handle()) person.set_birth_ref( birth_ref) # Baptism: if baptismdate is not None: baptismdate = _dp.parse(baptismdate) if baptismplace and baptismplace_id: raise Error("Error in person: can't have a baptismplace and baptismplace_id") if baptismplace is not None: new, baptismplace = self.get_or_create_place(baptismplace) elif baptismplace_id: # better exist already, locally or in database: baptismplace = self.lookup("place", baptismplace_id) if baptismsource is not None: new, baptismsource = self.get_or_create_source(baptismsource) if baptismdate or baptismplace or baptismsource: new, baptism = self.get_or_create_event(person, EventType.BAPTISM, baptismdate, baptismplace, baptismsource) baptism_ref = get_primary_event_ref_from_type(self.db, person, "Baptism") if baptism_ref is None: # new baptism_ref = EventRef() baptism_ref.set_reference_handle( baptism.get_handle()) person.add_event_ref( baptism_ref) # Death: if deathdate is not None: deathdate = _dp.parse(deathdate) if deathplace and deathplace_id: raise Error("Error in person: can't have a deathplace and deathplace_id") if deathplace is not None: new, deathplace = self.get_or_create_place(deathplace) elif deathplace_id: # better exist already, locally or in database: deathplace = self.lookup("place", deathplace_id) if deathsource is not None: new, deathsource = self.get_or_create_source(deathsource) if deathdate or deathplace or deathsource or deathcause: new, death = self.get_or_create_event(person, EventType.DEATH, deathdate, deathplace, deathsource) if deathcause: death.set_description(deathcause) self.db.commit_event(death, self.trans) death_ref = person.get_death_ref() if death_ref is None: # new death_ref = EventRef() death_ref.set_reference_handle(death.get_handle()) person.set_death_ref(death_ref) # Burial: if burialdate is not None: burialdate = _dp.parse(burialdate) if burialplace and burialplace_id: raise Error("Error in person: can't have a burialplace and burialplace_id") if burialplace is not None: new, burialplace = self.get_or_create_place(burialplace) elif burialplace_id: # better exist already, locally or in database: burialplace = self.lookup("place", burialplace_id) if burialsource is not None: new, burialsource = self.get_or_create_source(burialsource) if burialdate or burialplace or burialsource: new, burial = self.get_or_create_event(person, EventType.BURIAL, burialdate, burialplace, burialsource) burial_ref = get_primary_event_ref_from_type(self.db, person, "Burial") if burial_ref is None: # new burial_ref = EventRef() burial_ref.set_reference_handle( burial.get_handle()) person.add_event_ref( burial_ref) if source: # add, if new new, source = self.get_or_create_source(source) self.find_and_set_citation(person, source) self.db.commit_person(person, self.trans) def _parse_place(self, line_number, row, col): "Parse the content of a Place line." place_id = rd(line_number, row, col, "place") place_title = rd(line_number, row, col, "title") place_name = rd(line_number, row, col, "name") place_type_str = rd(line_number, row, col, "type") place_latitude = rd(line_number, row, col, "latitude") place_longitude = rd(line_number, row, col, "longitude") place_code = rd(line_number, row, col, "code") place_enclosed_by_id = rd(line_number, row, col, "enclosed_by") place_date = rd(line_number, row, col, "date") ######################################################### # if this place already exists, don't create it place = self.lookup("place", place_id) if place is None: # new place place = self.create_place() self.storeup("place", place_id.lower(), place) if place_title is not None: place.title = place_title if place_name is not None: place.name = PlaceName(value=place_name) if place_type_str is not None: place.place_type = self.get_place_type(place_type_str) if place_latitude is not None: place.lat = place_latitude if place_longitude is not None: place.long = place_longitude if place_code is not None: place.code = place_code if place_enclosed_by_id is not None: place_enclosed_by = self.lookup("place", place_enclosed_by_id) if place_enclosed_by is None: raise Exception("cannot enclose %s in %s as it doesn't exist" % (place.gramps_id, place_enclosed_by_id)) if not place_enclosed_by.handle in place.placeref_list: placeref = PlaceRef() placeref.ref = place_enclosed_by.handle if place_date: placeref.date = _dp.parse(place_date) place.placeref_list.append(placeref) ######################################################### self.db.commit_place(place, self.trans) def get_place_type(self, place_type_str): if place_type_str in self.place_types: return PlaceType((self.place_types[place_type_str], place_type_str)) else: # New custom type: return PlaceType((0, place_type_str)) def get_or_create_family(self, family_ref, husband, wife): "Return the family object for the give family ID." # if a gramps_id and exists: LOG.debug("get_or_create_family") if family_ref.startswith("[") and family_ref.endswith("]"): id_ = self.db.fid2user_format(family_ref[1:-1]) family = self.db.get_family_from_gramps_id(id_) if family: # don't delete, only add fam_husband_handle = family.get_father_handle() fam_wife_handle = family.get_mother_handle() if husband: if husband.get_handle() != fam_husband_handle: # this husband is not the same old one! Add him! family.set_father_handle(husband.get_handle()) if wife: if wife.get_handle() != fam_wife_handle: # this wife is not the same old one! Add her! family.set_mother_handle(wife.get_handle()) LOG.debug(" returning existing family") return family # if not, create one: family = Family() # was marked with a gramps_id, but didn't exist, so we'll use it: if family_ref.startswith("[") and family_ref.endswith("]"): id_ = self.db.fid2user_format(family_ref[1:-1]) family.set_gramps_id(id_) # add it: family.set_handle(create_id()) if self.default_tag: family.add_tag(self.default_tag.handle) if husband: family.set_father_handle(husband.get_handle()) husband.add_family_handle(family.get_handle()) if wife: family.set_mother_handle(wife.get_handle()) wife.add_family_handle(family.get_handle()) if husband and wife: family.set_relationship(FamilyRelType.MARRIED) self.db.add_family(family, self.trans) if husband: self.db.commit_person(husband, self.trans) if wife: self.db.commit_person(wife, self.trans) self.fam_count += 1 return family def get_or_create_event(self, object_, type_, date=None, place=None, source=None): """ Add or find a type event on object """ # first, see if it exists LOG.debug("get_or_create_event") ref_list = object_.get_event_ref_list() LOG.debug("refs: %s", ref_list) # look for a match, and possible correction for ref in ref_list: event = self.db.get_event_from_handle(ref.ref) LOG.debug(" compare event type %s == %s", int(event.get_type()), type_) if int(event.get_type()) == type_: # Match! Let's update if date: event.set_date_object(date) if place: event.set_place_handle(place.get_handle()) if source: self.find_and_set_citation(event, source) self.db.commit_event(event, self.trans) LOG.debug(" returning existing event") return (0, event) # else create it: LOG.debug(" creating event") event = Event() if type_: event.set_type(EventType(type_)) if date: event.set_date_object(date) if place: event.set_place_handle(place.get_handle()) if source: self.find_and_set_citation(event, source) self.db.add_event(event, self.trans) return (1, event) def create_person(self): """ Used to create a new person we know doesn't exist """ person = Person() if self.default_tag: person.add_tag(self.default_tag.handle) self.db.add_person(person, self.trans) self.indi_count += 1 return person def create_place(self): """ Used to create a new person we know doesn't exist """ place = Place() if self.default_tag: place.add_tag(self.default_tag.handle) self.db.add_place(place, self.trans) self.place_count += 1 return place def get_or_create_place(self, place_name): "Return the requested place object tuple-packed with a new indicator." LOG.debug("get_or_create_place: looking for: %s", place_name) for place_handle in self.db.iter_place_handles(): place = self.db.get_place_from_handle(place_handle) place_title = place_displayer.display(self.db, place) if place_title == place_name: return (0, place) place = Place() place.set_title(place_name) place.name = PlaceName(value=place_name) self.db.add_place(place, self.trans) return (1, place) def get_or_create_source(self, source_text): "Return the requested source object tuple-packed with a new indicator." source_list = self.db.get_source_handles(sort_handles=False) LOG.debug("get_or_create_source: list: %s", source_list) LOG.debug("get_or_create_source: looking for: %s", source_text) for source_handle in source_list: source = self.db.get_source_from_handle(source_handle) if source.get_title() == source_text: LOG.debug(" returning existing source") return (0, source) LOG.debug(" creating source") source = Source() source.set_title(source_text) self.db.add_source(source, self.trans) return (1, source) def find_and_set_citation(self, obj, source): # look for the source in the existing citations for the object LOG.debug("find_and_set_citation: looking for source: %s", source.get_gramps_id()) for citation_handle in obj.get_citation_list(): citation = self.db.get_citation_from_handle(citation_handle) LOG.debug("find_and_set_citation: existing citation: %s", citation.get_gramps_id()) poss_source = self.db.get_source_from_handle( citation.get_reference_handle()) LOG.debug(" compare source %s == %s", source.get_gramps_id(), poss_source.get_gramps_id()) if poss_source.get_handle() == source.get_handle(): # The source is already cited LOG.debug(" source already cited") return # we couldn't find an appropriate citation, so we have to create one. citation = Citation() LOG.debug(" creating citation") citation.set_reference_handle(source.get_handle()) self.db.add_citation(citation, self.trans) LOG.debug(" created citation, citation %s %s" % (citation, citation.get_gramps_id())) obj.add_citation(citation.get_handle())
def applyTagClicked(self, button) : progress = None rows = self.treeSelection.count_selected_rows() tag_name = str(self.tagcombo.get_active_text()) # start the db transaction with DbTxn("Tag not related", self.db) as transaction: tag = self.db.get_tag_from_name(tag_name) if not tag: # create the tag if it doesn't already exist tag = Tag() tag.set_name(tag_name) tag.set_priority(self.db.get_number_of_tags()) tag_handle = self.db.add_tag(tag, transaction) else: tag_handle = tag.get_handle() # if more than 1 person is selected, use a progress indicator if rows > 1: progress = ProgressMeter(self.title, _('Starting'), parent=self.window) progress.set_pass( # translators: leave all/any {...} untranslated #TRANS: no singular form needed, as rows is always > 1 ngettext("Setting tag for {number_of} person", "Setting tag for {number_of} people", rows).format(number_of=rows), rows) # iterate through all of the selected rows (model, paths) = self.treeSelection.get_selected_rows() for path in paths: if progress: progress.step() # for the current row, get the GID and the person from the database iter = self.model.get_iter(path) personGid = self.model.get_value(iter, 1) person = self.db.get_person_from_gramps_id(personGid) # add the tag to the person person.add_tag(tag_handle) # save this change self.db.commit_person(person, transaction) # refresh the tags column self.treeView.set_model(None) for path in paths: iter = self.model.get_iter(path) personGid = self.model.get_value(iter, 1) person = self.db.get_person_from_gramps_id(personGid) self.model.set_value(iter, 3, self.get_tag_list(person)) self.treeView.set_model(self.model) self.treeView.expand_all() if progress: progress.close()
class CSVParser(object): """Class to read data in CSV format from a file object.""" def __init__(self, dbase, user, default_tag_format=None): self.db = dbase self.user = user self.trans = None self.lineno = 0 self.index = 0 self.fam_count = 0 self.indi_count = 0 self.pref = {} # person ref, internal to this sheet self.fref = {} # family ref, internal to this sheet column2label = { "surname": ("Lastname", "Surname", _("Surname"), "lastname", "last_name", "surname", _("surname")), "firstname": ("Firstname", "Given name", _("Given name"), "Given", _("Given"), "firstname", "first_name", "given_name", "given name", _("given name"), "given", _("given")), "callname": ("Callname", "Call name", _("Call name"), "Call", _("Call"), "callname", "call_name", "call name", "call", _("call")), "title": ("Title", _("Person|Title"), "title", _("Person|title")), "prefix": ("Prefix", _("Prefix"), "prefix", _("prefix")), "suffix": ("Suffix", _("Suffix"), "suffix", _("suffix")), "gender": ("Gender", _("Gender"), "gender", _("gender")), "source": ("Source", _("Source"), "source", _("source")), "note": ("Note", _("Note"), "note", _("note")), "birthplace": ("Birthplace", "Birth place", _("Birth place"), "birthplace", "birth_place", "birth place", _("birth place")), "birthdate": ("Birthdate", "Birth date", _("Birth date"), "birthdate", "birth_date", "birth date", _("birth date")), "birthsource": ("Birthsource", "Birth source", _("Birth source"), "birthsource", "birth_source", "birth source", _("birth source")), "baptismplace": ("Baptismplace", "Baptism place", _("Baptism place"), "baptismplace", "baptism place", _("baptism place")), "baptismdate": ("Baptismdate", "Baptism date", _("Baptism date"), "baptismdate", "baptism date", _("baptism date")), "baptismsource": ("Baptismsource", "Baptism source", _("Baptism source"), "baptismsource", "baptism source", _("baptism source")), "burialplace": ("Burialplace", "Burial place", _("Burial place"), "burialplace", "burial place", _("burial place")), "burialdate": ("Burialdate", "Burial date", _("Burial date"), "burialdate", "burial date", _("burial date")), "burialsource": ("Burialsource", "Burial source", _("Burial source"), "burialsource", "burial source", _("burial source")), "deathplace": ("Deathplace", "Death place", _("Death place"), "deathplace", "death_place", "death place", _("death place")), "deathdate": ("Deathdate", "Death date", _("Death date"), "deathdate", "death_date", "death date", _("death date")), "deathsource": ("Deathsource", "Death source", _("Death source"), "deathsource", "death_source", "death source", _("death source")), "deathcause": ("Deathcause", "Death cause", _("Death cause"), "deathcause", "death_cause", "death cause", _("death cause")), "grampsid": ("Grampsid", "ID", "Gramps id", _("Gramps ID"), "grampsid", "id", "gramps_id", "gramps id", _("Gramps id")), "person": ("Person", _("Person"), "person", _("person")), # ---------------------------------- "child": ("Child", _("Child"), "child", _("child")), "family": ("Family", _("Family"), "family", _("family")), # ---------------------------------- "wife": ("Mother", _("Mother"), "Wife", _("Wife"), "Parent2", _("Parent2"), "mother", _("mother"), "wife", _("wife"), "parent2", _("parent2")), "husband": ("Father", _("Father"), "Husband", _("Husband"), "Parent1", _("Parent1"), "father", _("father"), "husband", _("husband"), "parent1", _("parent1")), "marriage": ("Marriage", _("Marriage"), "marriage", _("marriage")), "date": ("Date", _("Date"), "date", _("date")), "place": ("Place", _("Place"), "place", _("place")), } lab2col_dict = [] for key in list(column2label.keys()): for val in column2label[key]: lab2col_dict.append((val, key)) self.label2column = dict(lab2col_dict) if default_tag_format: name = time.strftime(default_tag_format) tag = self.db.get_tag_from_name(name) if tag: self.default_tag = tag else: self.default_tag = Tag() self.default_tag.set_name(name) else: self.default_tag = None def cleanup_column_name(self, column): """Handle column aliases for CSV spreadsheet import and SQL.""" return self.label2column.get(column, column) def read_csv(self, filehandle): "Read the data from the file and return it as a list." reader = UnicodeReader(filehandle) try: data = [[r.strip() for r in row] for row in reader] except csv.Error as err: self.user.notify_error(_('format error: line %(line)d: %(zero)s') % { 'line' : reader.reader.line_num, 'zero' : err } ) return None return data def lookup(self, type_, id_): """ Return the object of type type_ with id id_ from db or previously stored value. """ if id_ is None: return None if type_ == "family": if id_.startswith("[") and id_.endswith("]"): id_ = self.db.fid2user_format(id_[1:-1]) db_lookup = self.db.get_family_from_gramps_id(id_) if db_lookup is None: return self.lookup(type_, id_) else: return db_lookup elif id_.lower() in self.fref: return self.fref[id_.lower()] else: return None elif type_ == "person": if id_.startswith("[") and id_.endswith("]"): id_ = self.db.id2user_format(id_[1:-1]) db_lookup = self.db.get_person_from_gramps_id(id_) if db_lookup is None: return self.lookup(type_, id_) else: return db_lookup elif id_.lower() in self.pref: return self.pref[id_.lower()] else: return None else: LOG.warn("invalid lookup type in CSV import: '%s'" % type_) return None def storeup(self, type_, id_, object_): "Store object object_ of type type_ in a dictionary under key id_." if id_.startswith("[") and id_.endswith("]"): id_ = id_[1:-1] #return # do not store gramps people; go look them up if type_ == "person": id_ = self.db.id2user_format(id_) self.pref[id_.lower()] = object_ elif type_ == "family": id_ = self.db.fid2user_format(id_) self.fref[id_.lower()] = object_ else: LOG.warn("invalid storeup type in CSV import: '%s'" % type_) def parse(self, filehandle): """ Prepare the database and parse the input file. :param filehandle: open file handle positioned at start of the file """ progress_title = _('CSV Import') with self.user.progress(progress_title, _('Reading data...'), 1) as step: data = self.read_csv(filehandle) with self.user.progress(progress_title, _('Importing data...'), len(data)) as step: tym = time.time() self.db.disable_signals() with DbTxn(_("CSV import"), self.db, batch=True) as self.trans: if self.default_tag and self.default_tag.handle is None: self.db.add_tag(self.default_tag, self.trans) self._parse_csv_data(data, step) self.db.enable_signals() self.db.request_rebuild() tym = time.time() - tym # translators: leave all/any {...} untranslated msg = ngettext('Import Complete: {number_of} second', 'Import Complete: {number_of} seconds', tym ).format(number_of=tym) LOG.debug(msg) LOG.debug("New Families: %d" % self.fam_count) LOG.debug("New Individuals: %d" % self.indi_count) def _parse_csv_data(self, data, step): """Parse each line of the input data and act accordingly.""" self.lineno = 0 self.index = 0 self.fam_count = 0 self.indi_count = 0 self.pref = {} # person ref, internal to this sheet self.fref = {} # family ref, internal to this sheet header = None line_number = 0 for row in data: step() line_number += 1 if "".join(row) == "": # no blanks are allowed inside a table header = None # clear headers, ready for next "table" continue ###################################### if header is None: header = [self.cleanup_column_name(r) for r in row] col = {} count = 0 for key in header: col[key] = count count += 1 continue # three different kinds of data: person, family, and marriage if (("marriage" in header) or ("husband" in header) or ("wife" in header)): self._parse_marriage(line_number, row, col) elif "family" in header: self._parse_family(line_number, row, col) elif "surname" in header: self._parse_person(line_number, row, col) else: LOG.warn("ignoring line %d" % line_number) return None def _parse_marriage(self, line_number, row, col): "Parse the content of a Marriage,Husband,Wife line." marriage_ref = rd(line_number, row, col, "marriage") husband = rd(line_number, row, col, "husband") wife = rd(line_number, row, col, "wife") marriagedate = rd(line_number, row, col, "date") marriageplace = rd(line_number, row, col, "place") marriagesource = rd(line_number, row, col, "source") note = rd(line_number, row, col, "note") wife = self.lookup("person", wife) husband = self.lookup("person", husband) if husband is None and wife is None: # might have children, so go ahead and add LOG.warn("no parents on line %d; adding family anyway" % line_number) family = self.get_or_create_family(marriage_ref, husband, wife) # adjust gender, if not already provided if husband: # this is just a guess, if unknown if husband.get_gender() == Person.UNKNOWN: husband.set_gender(Person.MALE) self.db.commit_person(husband, self.trans) if wife: # this is just a guess, if unknown if wife.get_gender() == Person.UNKNOWN: wife.set_gender(Person.FEMALE) self.db.commit_person(wife, self.trans) if marriage_ref: self.storeup("family", marriage_ref.lower(), family) if marriagesource: # add, if new new, marriagesource = self.get_or_create_source(marriagesource) if marriageplace: # add, if new new, marriageplace = self.get_or_create_place(marriageplace) if marriagedate: marriagedate = _dp.parse(marriagedate) if marriagedate or marriageplace or marriagesource or note: # add, if new; replace, if different new, marriage = self.get_or_create_event(family, EventType.MARRIAGE, marriagedate, marriageplace, marriagesource) if new: mar_ref = EventRef() mar_ref.set_reference_handle(marriage.get_handle()) family.add_event_ref(mar_ref) self.db.commit_family(family, self.trans) # only add note to event: # append notes, if previous notes if note: previous_notes_list = marriage.get_note_list() updated_note = False for note_handle in previous_notes_list: previous_note = self.db.get_note_from_handle( note_handle) if previous_note.type == NoteType.EVENT: previous_text = previous_note.get() if note not in previous_text: note = previous_text + "\n" + note previous_note.set(note) self.db.commit_note(previous_note, self.trans) updated_note = True break if not updated_note: # add new note here new_note = Note() new_note.handle = create_id() new_note.type.set(NoteType.EVENT) new_note.set(note) if self.default_tag: new_note.add_tag(self.default_tag.handle) self.db.add_note(new_note, self.trans) marriage.add_note(new_note.handle) self.db.commit_event(marriage, self.trans) def _parse_family(self, line_number, row, col): "Parse the content of a family line" family_ref = rd(line_number, row, col, "family") if family_ref is None: LOG.warn("no family reference found for family on line %d" % line_number) return # required child = rd(line_number, row, col, "child") source = rd(line_number, row, col, "source") note = rd(line_number, row, col, "note") gender = rd(line_number, row, col, "gender") child = self.lookup("person", child) family = self.lookup("family", family_ref) if family is None: LOG.warn("no matching family reference found for family " "on line %d" % line_number) return if child is None: LOG.warn("no matching child reference found for family " "on line %d" % line_number) return # is this child already in this family? If so, don't add LOG.debug("children: %s", [ref.ref for ref in family.get_child_ref_list()]) LOG.debug("looking for: %s", child.get_handle()) if child.get_handle() not in [ref.ref for ref in family.get_child_ref_list()]: # add child to family LOG.debug(" adding child [%s] to family [%s]", child.get_gramps_id(), family.get_gramps_id()) childref = ChildRef() childref.set_reference_handle(child.get_handle()) family.add_child_ref( childref) self.db.commit_family(family, self.trans) child.add_parent_family_handle(family.get_handle()) if gender: # replace gender = gender.lower() if gender == gender_map[Person.MALE].lower(): gender = Person.MALE elif gender == gender_map[Person.FEMALE].lower(): gender = Person.FEMALE else: gender = Person.UNKNOWN child.set_gender(gender) if source: # add, if new dummy_new, source = self.get_or_create_source(source) self.find_and_set_citation(child, source) # put note on child if note: # append notes, if previous notes previous_notes_list = child.get_note_list() updated_note = False for note_handle in previous_notes_list: previous_note = self.db.get_note_from_handle(note_handle) if previous_note.type == NoteType.PERSON: previous_text = previous_note.get() if note not in previous_text: note = previous_text + "\n" + note previous_note.set(note) self.db.commit_note(previous_note, self.trans) updated_note = True break if not updated_note: # add new note here new_note = Note() new_note.handle = create_id() new_note.type.set(NoteType.PERSON) new_note.set(note) if self.default_tag: new_note.add_tag(self.default_tag.handle) self.db.add_note(new_note, self.trans) child.add_note(new_note.handle) self.db.commit_person(child, self.trans) def _parse_person(self, line_number, row, col): "Parse the content of a Person line." surname = rd(line_number, row, col, "surname") firstname = rd(line_number, row, col, "firstname", "") callname = rd(line_number, row, col, "callname") title = rd(line_number, row, col, "title") prefix = rd(line_number, row, col, "prefix") suffix = rd(line_number, row, col, "suffix") gender = rd(line_number, row, col, "gender") source = rd(line_number, row, col, "source") note = rd(line_number, row, col, "note") birthplace = rd(line_number, row, col, "birthplace") birthdate = rd(line_number, row, col, "birthdate") birthsource = rd(line_number, row, col, "birthsource") baptismplace = rd(line_number, row, col, "baptismplace") baptismdate = rd(line_number, row, col, "baptismdate") baptismsource = rd(line_number, row, col, "baptismsource") burialplace = rd(line_number, row, col, "burialplace") burialdate = rd(line_number, row, col, "burialdate") burialsource = rd(line_number, row, col, "burialsource") deathplace = rd(line_number, row, col, "deathplace") deathdate = rd(line_number, row, col, "deathdate") deathsource = rd(line_number, row, col, "deathsource") deathcause = rd(line_number, row, col, "deathcause") grampsid = rd(line_number, row, col, "grampsid") person_ref = rd(line_number, row, col, "person") ######################################################### # if this person already exists, don't create them person = self.lookup("person", person_ref) if person is None: if surname is None: LOG.warn("empty surname for new person on line %d" % line_number) surname = "" # new person person = self.create_person() name = Name() name.set_type(NameType(NameType.BIRTH)) name.set_first_name(firstname) surname_obj = Surname() surname_obj.set_surname(surname) name.add_surname(surname_obj) person.set_primary_name(name) else: name = person.get_primary_name() ######################################################### if person_ref is not None: self.storeup("person", person_ref, person) # replace if surname is not None: name.get_primary_surname().set_surname(surname) if firstname is not None: name.set_first_name(firstname) if callname is not None: name.set_call_name(callname) if title is not None: name.set_title(title) if prefix is not None: name.get_primary_surname().set_prefix(prefix) name.group_as = '' # HELP? what should I do here? if suffix is not None: name.set_suffix(suffix) if note is not None: # append notes, if previous notes previous_notes_list = person.get_note_list() updated_note = False for note_handle in previous_notes_list: previous_note = self.db.get_note_from_handle(note_handle) if previous_note.type == NoteType.PERSON: previous_text = previous_note.get() if note not in previous_text: note = previous_text + "\n" + note previous_note.set(note) self.db.commit_note(previous_note, self.trans) updated_note = True break if not updated_note: # add new note here new_note = Note() new_note.handle = create_id() new_note.type.set(NoteType.PERSON) new_note.set(note) if self.default_tag: new_note.add_tag(self.default_tag.handle) self.db.add_note(new_note, self.trans) person.add_note(new_note.handle) if grampsid is not None: person.gramps_id = grampsid elif person_ref is not None: if person_ref.startswith("[") and person_ref.endswith("]"): person.gramps_id = self.db.id2user_format(person_ref[1:-1]) if (person.get_gender() == Person.UNKNOWN and gender is not None): gender = gender.lower() if gender == gender_map[Person.MALE].lower(): gender = Person.MALE elif gender == gender_map[Person.FEMALE].lower(): gender = Person.FEMALE else: gender = Person.UNKNOWN person.set_gender(gender) ######################################################### # add if new, replace if different # Birth: if birthdate is not None: birthdate = _dp.parse(birthdate) if birthplace is not None: new, birthplace = self.get_or_create_place(birthplace) if birthsource is not None: new, birthsource = self.get_or_create_source(birthsource) if birthdate or birthplace or birthsource: new, birth = self.get_or_create_event(person, EventType.BIRTH, birthdate, birthplace, birthsource) birth_ref = person.get_birth_ref() if birth_ref is None: # new birth_ref = EventRef() birth_ref.set_reference_handle( birth.get_handle()) person.set_birth_ref( birth_ref) # Baptism: if baptismdate is not None: baptismdate = _dp.parse(baptismdate) if baptismplace is not None: new, baptismplace = self.get_or_create_place(baptismplace) if baptismsource is not None: new, baptismsource = self.get_or_create_source(baptismsource) if baptismdate or baptismplace or baptismsource: new, baptism = self.get_or_create_event(person, EventType.BAPTISM, baptismdate, baptismplace, baptismsource) baptism_ref = get_primary_event_ref_from_type(self.db, person, "Baptism") if baptism_ref is None: # new baptism_ref = EventRef() baptism_ref.set_reference_handle( baptism.get_handle()) person.add_event_ref( baptism_ref) # Death: if deathdate is not None: deathdate = _dp.parse(deathdate) if deathplace is not None: new, deathplace = self.get_or_create_place(deathplace) if deathsource is not None: new, deathsource = self.get_or_create_source(deathsource) if deathdate or deathplace or deathsource or deathcause: new, death = self.get_or_create_event(person, EventType.DEATH, deathdate, deathplace, deathsource) if deathcause: death.set_description(deathcause) self.db.commit_event(death, self.trans) death_ref = person.get_death_ref() if death_ref is None: # new death_ref = EventRef() death_ref.set_reference_handle(death.get_handle()) person.set_death_ref(death_ref) # Burial: if burialdate is not None: burialdate = _dp.parse(burialdate) if burialplace is not None: new, burialplace = self.get_or_create_place(burialplace) if burialsource is not None: new, burialsource = self.get_or_create_source(burialsource) if burialdate or burialplace or burialsource: new, burial = self.get_or_create_event(person, EventType.BURIAL, burialdate, burialplace, burialsource) burial_ref = get_primary_event_ref_from_type(self.db, person, "Burial") if burial_ref is None: # new burial_ref = EventRef() burial_ref.set_reference_handle( burial.get_handle()) person.add_event_ref( burial_ref) if source: # add, if new new, source = self.get_or_create_source(source) self.find_and_set_citation(person, source) self.db.commit_person(person, self.trans) def get_or_create_family(self, family_ref, husband, wife): "Return the family object for the give family ID." # if a gramps_id and exists: LOG.debug("get_or_create_family") if family_ref.startswith("[") and family_ref.endswith("]"): id_ = self.db.fid2user_format(family_ref[1:-1]) family = self.db.get_family_from_gramps_id(id_) if family: # don't delete, only add fam_husband_handle = family.get_father_handle() fam_wife_handle = family.get_mother_handle() if husband: if husband.get_handle() != fam_husband_handle: # this husband is not the same old one! Add him! family.set_father_handle(husband.get_handle()) if wife: if wife.get_handle() != fam_wife_handle: # this wife is not the same old one! Add her! family.set_mother_handle(wife.get_handle()) LOG.debug(" returning existing family") return family # if not, create one: family = Family() # was marked with a gramps_id, but didn't exist, so we'll use it: if family_ref.startswith("[") and family_ref.endswith("]"): id_ = self.db.fid2user_format(family_ref[1:-1]) family.set_gramps_id(id_) # add it: family.set_handle(create_id()) if self.default_tag: family.add_tag(self.default_tag.handle) if husband: family.set_father_handle(husband.get_handle()) husband.add_family_handle(family.get_handle()) if wife: family.set_mother_handle(wife.get_handle()) wife.add_family_handle(family.get_handle()) if husband and wife: family.set_relationship(FamilyRelType.MARRIED) self.db.add_family(family, self.trans) if husband: self.db.commit_person(husband, self.trans) if wife: self.db.commit_person(wife, self.trans) self.fam_count += 1 return family def get_or_create_event(self, object_, type_, date=None, place=None, source=None): """ Add or find a type event on object """ # first, see if it exists LOG.debug("get_or_create_event") ref_list = object_.get_event_ref_list() LOG.debug("refs: %s", ref_list) # look for a match, and possible correction for ref in ref_list: event = self.db.get_event_from_handle(ref.ref) LOG.debug(" compare event type %s == %s", int(event.get_type()), type_) if int(event.get_type()) == type_: # Match! Let's update if date: event.set_date_object(date) if place: event.set_place_handle(place.get_handle()) if source: self.find_and_set_citation(event, source) self.db.commit_event(event, self.trans) LOG.debug(" returning existing event") return (0, event) # else create it: LOG.debug(" creating event") event = Event() if type_: event.set_type(EventType(type_)) if date: event.set_date_object(date) if place: event.set_place_handle(place.get_handle()) if source: self.find_and_set_citation(event, source) self.db.add_event(event, self.trans) return (1, event) def create_person(self): """ Used to create a new person we know doesn't exist """ person = Person() if self.default_tag: person.add_tag(self.default_tag.handle) self.db.add_person(person, self.trans) self.indi_count += 1 return person def get_or_create_place(self, place_name): "Return the requested place object tuple-packed with a new indicator." LOG.debug("get_or_create_place: looking for: %s", place_name) for place_handle in self.db.iter_place_handles(): place = self.db.get_place_from_handle(place_handle) place_title = place_displayer.display(self.db, place) if place_title == place_name: return (0, place) place = Place() place.set_title(place_name) self.db.add_place(place, self.trans) return (1, place) def get_or_create_source(self, source_text): "Return the requested source object tuple-packed with a new indicator." source_list = self.db.get_source_handles(sort_handles=False) LOG.debug("get_or_create_source: list: %s", source_list) LOG.debug("get_or_create_source: looking for: %s", source_text) for source_handle in source_list: source = self.db.get_source_from_handle(source_handle) if source.get_title() == source_text: LOG.debug(" returning existing source") return (0, source) LOG.debug(" creating source") source = Source() source.set_title(source_text) self.db.add_source(source, self.trans) return (1, source) def find_and_set_citation(self, obj, source): # look for the source in the existing citations for the object LOG.debug("find_and_set_citation: looking for source: %s", source.get_gramps_id()) for citation_handle in obj.get_citation_list(): citation = self.db.get_citation_from_handle(citation_handle) LOG.debug("find_and_set_citation: existing citation: %s", citation.get_gramps_id()) poss_source = self.db.get_source_from_handle( citation.get_reference_handle()) LOG.debug(" compare source %s == %s", source.get_gramps_id(), poss_source.get_gramps_id()) if poss_source.get_handle() == source.get_handle(): # The source is already cited LOG.debug(" source already cited") return # we couldn't find an appropriate citation, so we have to create one. citation = Citation() LOG.debug(" creating citation") citation.set_reference_handle(source.get_handle()) self.db.add_citation(citation, self.trans) LOG.debug(" created citation, citation %s %s" % (citation, citation.get_gramps_id())) obj.add_citation(citation.get_handle())