def run_mother(database, document, person): """ Function writing the mother lineage quick report """ sa = SimpleAccess(database) sd = SimpleDoc(document) # display the results # feature request 2356: avoid genitive form sd.title(_("Mother lineage for %s") % sa.name(person)) sd.paragraph("") sd.paragraph( _("" "This report shows the mother lineage, also called matronymic lineage " "mtDNA lineage." " People in this lineage all share the same Mitochondrial DNA (mtDNA)." )) sd.paragraph("") stab = QuickTable(sa) stab.columns(_("Name Mother"), _("Birth"), _("Death Date"), _("Remark")) make_details(Person.FEMALE, person, sa, sd, database, stab) stab.write(sd) sd.paragraph("") if person.gender == Person.MALE: return sd.header2((_("Direct line female descendants"))) sd.paragraph("") make_details_child(Person.FEMALE, person, sa, sd, database)
def get_parents_desc(database, person): """ Return text describing person's parents """ sa = SimpleAccess(database) narrator = Narrator(database, verbose=True, use_call_name=True, use_fulldate=True) narrator.set_subject(person) family_handle = person.get_main_parents_family_handle() if family_handle: family = database.get_family_from_handle(family_handle) mother_handle = family.get_mother_handle() father_handle = family.get_father_handle() if mother_handle: mother = database.get_person_from_handle(mother_handle) mother_name = sa.name(mother) else: mother_name = "" if father_handle: father = database.get_person_from_handle(father_handle) father_name = sa.name(father) else: father_name = "" return narrator.get_child_string(father_name, mother_name)
def run_mother(database, document, person): """ Function writing the mother lineage quick report """ sa = SimpleAccess(database) sd = SimpleDoc(document) # display the results # feature request 2356: avoid genitive form sd.title(_("Mother lineage for %s") % sa.name(person)) sd.paragraph("") sd.paragraph(_("" "This report shows the mother lineage, also called matronymic lineage " "mtDNA lineage." " People in this lineage all share the same Mitochondrial DNA (mtDNA)." )) sd.paragraph("") stab = QuickTable(sa) stab.columns(_("Name Mother"), _("Birth"), _("Death Date"), _("Remark")) make_details(Person.FEMALE, person, sa, sd, database, stab) stab.write(sd) sd.paragraph("") if person.gender == Person.MALE : return sd.header2((_("Direct line female descendants"))) sd.paragraph("") make_details_child(Person.FEMALE, person, sa, sd, database)
def get_sources(database, person): """ Create list of sources for person's events """ sources = list() sa = SimpleAccess(database) events = sa.events(person) # Get family events also for family in sa.parent_in(person): for event in sa.events(family): events.append(event) for event in events: for handle in event.citation_list: citation = database.get_citation_from_handle(handle) page = citation.page source = database.get_source_from_handle(citation.source_handle) title = source.title author = source.author if author: source_desc = '* {}, {} - {}'.format(author, title, page) else: source_desc = '* {} - {}'.format(title, page) if source_desc not in sources: sources.append(source_desc) return sources
def run(database, document, person): """ Display a person's timeline. """ sa = SimpleAccess(database) sd = SimpleDoc(document) sd.title(_("Timeline for %s") % sa.name(person)) sd.paragraph("") stab = QuickTable(sa) stab.columns(_("Date"), _("Event"), _("Age"), _("Place"), _("People involved")) stab.set_link_col(4) handled = {} birth_ref = gramps.gen.lib.Person.get_birth_ref(person) birth_date = get_event_date_from_ref(database, birth_ref) event_list = [] process(database, sa, event_list, handled, person, False, person) for (event, obj, desc) in sorted(event_list, key=by_date): edate = sa.event_date_obj(event) span_str, span_int = format_date(birth_date, edate, obj == person) if desc == None: desc = event stab.row(edate, desc, span_str, sa.event_place(event), obj) stab.row_sort_val(2, span_int) today = Today() span_str, span_int = format_date(birth_date, today, False) stab.row(today, _("Today"), span_str, "", person) stab.row_sort_val(2, span_int) stab.write(sd) sd.paragraph("")
def __init__(self, database, document, person): self.database = database self.person = person self.sdb = SimpleAccess(database) self.sdoc = SimpleDoc(document) self.rel_class = get_relationship_calculator(glocale) self.msg_list = []
def run(database, document, person): """ Loops through the families that the person is a child in, and display the information about the other children. """ # setup the simple access functions sdb = SimpleAccess(database) sdoc = SimpleDoc(document) stab = QuickTable(sdb) rel_class = get_relationship_calculator(glocale) # display the title # feature request 2356: avoid genitive form sdoc.title(_("Siblings of %s") % sdb.name(person)) sdoc.paragraph("") stab.columns(_("Sibling"), _("Gender"), _("Birth Date"), _("Type")) # grab our current id (self): gid = sdb.gid(person) # loop through each family in which the person is a child document.has_data = False for family in sdb.child_in(person): # loop through each child in the family for child in sdb.children(family): # only display if this child is not the active person if sdb.gid(child) != gid: rel_str = rel_class.get_sibling_relationship_string( rel_class.get_sibling_type(database, person, child), person.get_gender(), child.get_gender()) else: rel_str = _('self') # pass row the child object to make link: stab.row(child, sdb.gender(child), sdb.birth_or_fallback(child), rel_str) document.has_data = True stab.write(sdoc)
def run(database, document, person): """ Output a text biography of active person """ sa = SimpleAccess(database) sd = SimpleDoc(document) sd.title(_("Biography for %s") % sa.name(person)) sd.paragraph('') narrator = Narrator(database, verbose=True, use_call_name=True, use_fulldate=True) narrator.set_subject(person) # Birth Details text = narrator.get_born_string() if text: sd.paragraph(text) text = narrator.get_baptised_string() if text: sd.paragraph(text) text = narrator.get_christened_string() if text: sd.paragraph(text) text = get_parents_desc(database, person) if text: sd.paragraph(text) sd.paragraph('') # Family Details for family in sa.parent_in(person): text = narrator.get_married_string(family) if text: sd.paragraph(text) sd.paragraph('') # Death Details text = narrator.get_died_string(True) if text: sd.paragraph(text) text = narrator.get_buried_string() if text: sd.paragraph(text) sd.paragraph('') # Sources sd.header1(_('Sources')) for source in get_sources(database, person): sd.paragraph(source)
def __init__(self, dbstate, uistate, track, url, callback): self.url = url self.dbstate = dbstate self.simple_access = SimpleAccess(self.dbstate.db) self.callback = callback ManagedWindow.__init__(self, uistate, track, url) self._local_init() self._connect_signals() self.show()
def run(database, document, person): """ Output a text biography of active person """ sa = SimpleAccess(database) sd = SimpleDoc(document) sd.title("Biography for %s" % sa.name(person)) sd.paragraph('') narrator = Narrator(database, verbose=True, use_call_name=True, use_fulldate=True) narrator.set_subject(person) # Birth Details text = narrator.get_born_string() if text: sd.paragraph(text) text = narrator.get_baptised_string() if text: sd.paragraph(text) text = narrator.get_christened_string() if text: sd.paragraph(text) text = get_parents_desc(database, person) if text: sd.paragraph(text) sd.paragraph('') # Family Details for family in sa.parent_in(person): text = narrator.get_married_string(family) if text: sd.paragraph(text) sd.paragraph('') # Death Details text = narrator.get_died_string(True) if text: sd.paragraph(text) text = narrator.get_buried_string() if text: sd.paragraph(text) sd.paragraph('') # Sources sd.header1('Sources') for source in get_sources(database, person): sd.paragraph(source)
def run(database, document, date): """ Display people probably alive and their ages on a particular date. """ # setup the simple access functions sdb = SimpleAccess(database) sdoc = SimpleDoc(document) stab = QuickTable(sdb) if not date.get_valid(): sdoc.paragraph("Date is not a valid date.") return # display the title if date.get_day_valid(): sdoc.title(_("People and their ages the %s") % displayer.display(date)) else: sdoc.title(_("People and their ages on %s") % displayer.display(date)) stab.columns(_("Person"), _("Age"), _("Status")) # Actual Date makes column unicode alive_matches = 0 dead_matches = 0 for person in sdb.all_people(): alive, birth, death, explain, relative = \ probably_alive(person, database, date, return_range=True) # Doesn't show people probably alive but no way of figuring an age: if alive: if birth: diff_span = (date - birth) stab.row(person, str(diff_span), _("Alive: %s") % explain) stab.row_sort_val(1, int(diff_span)) else: stab.row(person, "", _("Alive: %s") % explain) stab.row_sort_val(1, 0) alive_matches += 1 else: # not alive if birth: diff_span = (date - birth) stab.row(person, str(diff_span), _("Deceased: %s") % explain) stab.row_sort_val(1, int(diff_span)) else: stab.row(person, "", _("Deceased: %s") % explain) stab.row_sort_val(1, 1) dead_matches += 1 document.has_data = (alive_matches + dead_matches) > 0 sdoc.paragraph( _("\nLiving matches: %(alive)d, " "Deceased matches: %(dead)d\n") % { 'alive': alive_matches, 'dead': dead_matches }) if document.has_data: stab.write(sdoc) sdoc.paragraph("")
def run(database, document, date): """ Display people probably alive and their ages on a particular date. """ # setup the simple access functions sdb = SimpleAccess(database) sdoc = SimpleDoc(document) stab = QuickTable(sdb) if not date.get_valid(): sdoc.paragraph("Date is not a valid date.") return # display the title if date.get_day_valid(): sdoc.title(_("People and their ages the %s") % displayer.display(date)) else: sdoc.title(_("People and their ages on %s") % displayer.display(date)) stab.columns(_("Person"), _("Age"), _("Status")) # Actual Date makes column unicode alive_matches = 0 dead_matches = 0 for person in sdb.all_people(): alive, birth, death, explain, relative = \ probably_alive(person, database, date, return_range=True) # Doesn't show people probably alive but no way of figuring an age: if alive: if birth: diff_span = (date - birth) stab.row(person, str(diff_span), _("Alive: %s") % explain) stab.row_sort_val(1, int(diff_span)) else: stab.row(person, "", _("Alive: %s") % explain) stab.row_sort_val(1, 0) alive_matches += 1 else: # not alive if birth: diff_span = (date - birth) stab.row(person, str(diff_span), _("Deceased: %s") % explain) stab.row_sort_val(1, int(diff_span)) else: stab.row(person, "", _("Deceased: %s") % explain) stab.row_sort_val(1, 1) dead_matches += 1 document.has_data = (alive_matches + dead_matches) > 0 sdoc.paragraph(_("\nLiving matches: %(alive)d, " "Deceased matches: %(dead)d\n") % {'alive' : alive_matches, 'dead' : dead_matches}) if document.has_data: stab.write(sdoc) sdoc.paragraph("")
def make_tooltip_from_link(self, link_tag): """ Return a string useful for a tooltip given a LinkTag object. """ from gramps.gen.simple import SimpleAccess win_obj = find_parent_with_attr(self, attr="dbstate") display = link_tag.data if win_obj: simple_access = SimpleAccess(win_obj.dbstate.db) url = link_tag.data if url.startswith("gramps://"): obj_class, prop, value = url[9:].split("/") display = simple_access.display(obj_class, prop, value) or url return display
def run(database, document, person): """ Loops through the person events and the family events of any family in which the person is a parent (to catch Marriage events), displaying the basic details of the event """ sdb = SimpleAccess(database) sdoc = SimpleDoc(document) stab = QuickTable(sdb) # get the personal events event_list = sdb.events(person) # get the events of each family in which the person is # a parent for family in sdb.parent_in(person): event_list += sdb.events(family) # Sort the events by their date event_list.sort(key=lambda x: x.get_date_object()) # display the results # feature request 2356: avoid genitive form sdoc.title(_("Sorted events of %s") % sdb.name(person)) sdoc.paragraph("") stab.columns(_("Event Type"), _("Event Date"), _("Event Place")) document.has_data = False for event in event_list: stab.row(event, sdb.event_date_obj(event), sdb.event_place(event)) document.has_data = True stab.write(sdoc)
def make_tooltip_from_link(self, link_tag): """ Return a string useful for a tooltip given a LinkTag object. """ from gramps.gen.simple import SimpleAccess win_obj = find_parent_with_attr(self, attr="dbstate") display = link_tag.data if win_obj: simple_access = SimpleAccess(win_obj.dbstate.db) url = link_tag.data if url.startswith("gramps://"): obj_class, prop, value = url[9:].split("/") display = simple_access.display(obj_class, prop, value) or url return display + ((_("\nCommand-Click to follow link") if mac() else _( "\nCtrl-Click to follow link")) if self.get_editable() else '')
def query(self, query): self.parse(query) self.select = 0 start_time = time.time() class Table(): results = [] def row(self, *args, **kwargs): self.results.append([args, kwargs]) def get_rows(self): return [list(item[0]) for item in self.results] table = Table() self.sdb = SimpleAccess(self.database) self.process_table(table) # a class that has .row(1, 2, 3, ...) print(_("%d rows processed in %s seconds.\n") % (self.select, time.time() - start_time)) return table
def main(self): database = self.dbstate.db simple_a = SimpleAccess(database) # stime = time.perf_counter() counts_list = {} count = 0 self.model.clear() for person in database.iter_people(): if count == 200: count = 0 yield True count += 1 result = len(countem(database, person, counts_list)) self.model.append( (simple_a.describe(person), result, person.handle)) self.set_has_data(len(self.model) > 0)
def run(database, document, person): """ Loops through the families that the person is a child in, and display the information about the other children. """ global cache cache = {} # setup the simple access functions sdb = SimpleAccess(database) sdoc = SimpleDoc(document) stab = QuickTable(sdb) # display the title sdoc.title(_("Descendant Count")) sdoc.paragraph("") stab.columns(_("Person"), _("Number of Descendants")) people = database.get_person_handles(sort_handles=True) for person_handle in people: result = countem(database, handle2internal(person_handle)) cache[person_handle] = len(result) matches = 0 for person_handle in cache: person = database.get_person_from_handle(person_handle) stab.row(person, cache[person_handle]) matches += 1 sdoc.paragraph(_("There are %d people.\n") % matches) stab.write(sdoc)
def run(database, document, *args, **kwargs): """ Loops through the families that the person is a child in, and display the information about the other children. """ # setup the simple access functions sdb = SimpleAccess(database) sdoc = SimpleDoc(document) stab = QuickTable(sdb) # display the title sdoc.title(_("All Names of All People")) sdoc.paragraph("") matches = 0 stab.columns(_("Name"), _("Primary Name"), _("Name Type")) names = [] # name, person for person in database.iter_people(): primary_name = person.get_primary_name() if primary_name: names += [(nd.display_name(primary_name), person, str(primary_name.get_type()))] names += [(nd.display_name(name), person, str(name.get_type())) for name in person.get_alternate_names()] matches = 0 for (name, person, name_type) in sorted(names, key=lambda x: x[0]): stab.row(name, person, name_type) matches += 1 sdoc.paragraph(_("Total names %d") % matches) sdoc.paragraph("") stab.write(sdoc)
def run(database, document, object, item, trans): """ Display back-references for this object. """ # setup the simple access functions sdb = SimpleAccess(database) sdoc = SimpleDoc(document) stab = QuickTable(sdb) # display the title sdoc.title(_("References for this %s") % trans) sdoc.paragraph("\n") stab.columns(_("Type"), _("Reference")) for (objclass, handle) in database.find_backlink_handles(object.handle): ref = get_ref(database, objclass, handle) stab.row(_(objclass), ref) # translation are explicit (above) if stab.get_row_count() > 0: document.has_data = True stab.write(sdoc) else: document.has_data = False sdoc.paragraph(_("No references for this %s") % trans) sdoc.paragraph("") sdoc.paragraph("")
def main(self): database = self.dbstate.db simple_a = SimpleAccess(database) # stime = time.perf_counter() counts_list = {} count = 0 self.model.clear() for person in database.iter_people(): if count == 200: count = 0 yield True count += 1 result = len(countem(database, person, counts_list)) self.model.append((simple_a.describe(person), result, person.handle)) self.set_has_data(len(self.model) > 0)
def eval(self): """ Execute the query. """ self.sdb = SimpleAccess(self.database) self.stab = QuickTable(self.sdb) self.select = 0 start_time = time.time() self.process_table(self.stab) # a class that has .row(1, 2, 3, ...) if self.select > 0: self.stab.columns(*self.clean_titles(self.columns)) self.sdoc = SimpleDoc(self.document) self.sdoc.title(self.query_text) self.sdoc.paragraph("\n") self.sdoc.paragraph("%d rows processed in %s seconds.\n" % (self.select, time.time() - start_time)) self.stab.write(self.sdoc) self.sdoc.paragraph("") return _("%d rows processed in %s seconds.\n") % (self.select, time.time() - start_time)
def run(database, document, person): """ Loops through the families that the person is a child in, and displays the information about the other children. """ # setup the simple access functions sdb = SimpleAccess(database) sdoc = SimpleDoc(document) stab = QuickTable(sdb) if isinstance(person, Person): surname = sdb.surname(person) rsurname = person.get_primary_name().get_group_name() else: surname = person rsurname = person # display the title sdoc.title(_("People sharing the surname '%s'") % surname) sdoc.paragraph("") stab.columns(_("Person"), _("Birth Date"), _("Name type")) filter = GenericFilterFactory('Person')() if rsurname != '': rule = SameSurname([rsurname]) else: rule = IncompleteSurname([]) filter.add_rule(rule) people = filter.apply(database, database.iter_person_handles()) matches = 0 for person_handle in people: person = database.get_person_from_handle(person_handle) stab.row(person, sdb.birth_or_fallback(person), str(person.get_primary_name().get_type())) matches += 1 document.has_data = matches > 0 sdoc.paragraph( # translators: leave all/any {...} untranslated ngettext("There is {number_of} person " "with a matching name, or alternate name.\n", "There are {number_of} people " "with a matching name, or alternate name.\n", matches ).format(number_of=matches) ) stab.write(sdoc)
def run_given(database, document, person): """ Loops through the families that the person is a child in, and displays the information about the other children. """ # setup the simple access functions sdb = SimpleAccess(database) sdoc = SimpleDoc(document) stab = QuickTable(sdb) if isinstance(person, Person): rgivenname = person.get_primary_name().get_first_name() else: rgivenname = person if " " in rgivenname.strip(): rgivenname, second = rgivenname.strip().split(" ", 1) # display the title sdoc.title(_("People with the given name '%s'") % rgivenname) sdoc.paragraph("") stab.columns(_("Person"), _("Birth Date"), _("Name type")) filter = GenericFilterFactory('Person')() if rgivenname != '': rule = SameGiven([rgivenname]) else: rule = IncompleteGiven([]) filter.add_rule(rule) people = filter.apply(database, database.iter_person_handles()) matches = 0 for person_handle in people: person = database.get_person_from_handle(person_handle) stab.row(person, sdb.birth_or_fallback(person), str(person.get_primary_name().get_type())) matches += 1 document.has_data = matches > 0 sdoc.paragraph( # Translators: leave all/any {...} untranslated ngettext( "There is {number_of} person " "with a matching name, or alternate name.\n", "There are {number_of} people " "with a matching name, or alternate name.\n", matches).format(number_of=matches)) stab.write(sdoc)
def run(database, document, obj): """ Display link references for this note. """ # setup the simple access functions sdb = SimpleAccess(database) sdoc = SimpleDoc(document) stab = QuickTable(sdb) # display the title sdoc.title(_("Link References for this note")) sdoc.paragraph("\n") stab.columns(_("Type"), _("Reference"), _("Link check")) for (ldomain, ltype, lprop, lvalue) in obj.get_links(): if ldomain == "gramps": tagtype = _(ltype) ref_obj = sdb.get_link(ltype, lprop, lvalue) if ref_obj: tagvalue = ref_obj tagcheck = _("Ok") else: tagvalue = lvalue tagcheck = _("Failed: missing object") else: tagtype = _("Internet") tagvalue = lvalue tagcheck = "" stab.row(tagtype, tagvalue, tagcheck) if stab.get_row_count() > 0: stab.write(sdoc) document.has_data = True else: sdoc.paragraph(_("No link references for this note")) sdoc.paragraph("") document.has_data = False sdoc.paragraph("")
def run(database, document, obj): """ Display link references for this note. """ # setup the simple access functions sdb = SimpleAccess(database) sdoc = SimpleDoc(document) stab = QuickTable(sdb) # display the title sdoc.title(_("Link References for this note")) sdoc.paragraph("\n") stab.columns(_("Type"), _("Reference"), _("Link check")) for (ldomain, ltype, lprop, lvalue) in obj.get_links(): if ldomain == "gramps": tagtype = _(ltype) ref_obj = sdb.get_link(ltype, lprop, lvalue) if ref_obj: tagvalue = ref_obj tagcheck = _("Ok") else: tagvalue = styledtext_tag.value tagcheck = _("Failed: missing object") else: tagtype = _("Internet") tagvalue = lvalue tagcheck = "" stab.row(tagtype, tagvalue, tagcheck) if stab.get_row_count() > 0: stab.write(sdoc) document.has_data = True else: sdoc.paragraph(_("No link references for this note")) sdoc.paragraph("") document.has_data = False sdoc.paragraph("")
def __init__(self, *args, **kwargs): self.dbi = DBI(SelectTest.DB, None) # no document here self.dbi.flat = True self.dbi.sdb = SimpleAccess(SelectTest.DB) self.pcount = len(SelectTest.DB._tables["Person"]["handles_func"]()) self.john_count = 0 with SelectTest.DB._tables["Person"]["cursor_func"]() as cursor: for handle, person in cursor: name = SelectTest.DB._tables["Person"]["class_func"]( person).get_primary_name() if name and "John" in name.first_name: self.john_count += 1 unittest.TestCase.__init__(self, *args, **kwargs)
def run(database, document, repo): """ Display back-references (sources) for this repository. """ # setup the simple access functions sdb = SimpleAccess(database) sdoc = SimpleDoc(document) stab = QuickTable(sdb) # First we find repository and add its text sdoc.title('%s\n' % repo.get_name()) # Go over all the sources that refer to this repository repo_handle = repo.handle source_list = [item[1] for item in database.find_backlink_handles(repo_handle, ['Source' ])] stab.columns(_("Source"), _("Type of media"), _("Call number")) document.has_data = False for source_handle in source_list: src = database.get_source_from_handle(source_handle) # Get the list of references from this source to our repo # (can be more than one, technically) for reporef in src.get_reporef_list(): if reporef.ref == repo_handle: # Determine the text for this source media = str(reporef.get_media_type()) call = reporef.get_call_number() stab.row(src.get_title(), media, call) document.has_data = True if document.has_data: stab.write(sdoc) else: sdoc.header1(_("Not found"))
def run(database, document, person): """ Loops through the families that the person is a child in, and display the information about the other children. """ # setup the simple access functions sdb = SimpleAccess(database) sdoc = SimpleDoc(document) stab = QuickTable(sdb) rel_class = get_relationship_calculator(glocale) # display the title # feature request 2356: avoid genitive form sdoc.title(_("Siblings of %s") % sdb.name(person)) sdoc.paragraph("") stab.columns(_("Sibling"), _("Gender"), _("Birth Date"), _("Type")) # grab our current id (self): gid = sdb.gid(person) # loop through each family in which the person is a child document.has_data = False for family in sdb.child_in(person): # loop through each child in the family for child in sdb.children(family): # only display if this child is not the active person if sdb.gid(child) != gid: rel_str = rel_class.get_sibling_relationship_string( rel_class.get_sibling_type(database, person, child), person.get_gender(), child.get_gender()) else: rel_str = _('self') # pass row the child object to make link: stab.row(child, sdb.gender(child), sdb.birth_or_fallback(child), rel_str) document.has_data = True if document.has_data: stab.write(sdoc) else: sdoc.header1(_("Not found") + "\n")
def run(database, document, attribute, value=None): sdb = SimpleAccess(database) sdoc = SimpleDoc(document) stab = QuickTable(sdb) sdoc.title(_("People who have the '%s' Attribute") % attribute) sdoc.paragraph("") stab.columns(_("Person"), str(attribute)) matches = 0 for person_handle in database.iter_person_handles(): person = database.get_person_from_handle(person_handle) matched = False for attr in person.attribute_list: if str(attr.type) == attribute: stab.row(person, str(attr.get_value())) matched = True if matched: matches += 1 document.has_data = matches > 0 sdoc.paragraph( _("There are %d people with a matching attribute name.\n") % matches) stab.write(sdoc)
def run(database, document, person): """ Loops through the person events and the family events of any family in which the person is a parent (to catch Marriage events), displaying the basic details of the event """ sdb = SimpleAccess(database) sdoc = SimpleDoc(document) stab = QuickTable(sdb) # get the personal events event_list = sdb.events(person) # get the events of each family in which the person is # a parent for family in sdb.parent_in(person): event_list += sdb.events(family) # Sort the events by their date event_list.sort(key=lambda x: x.get_date_object()) # display the results # feature request 2356: avoid genitive form sdoc.title(_("Sorted events of %s") % sdb.name(person)) sdoc.paragraph("") stab.columns(_("Event Type"), _("Event Date"), _("Event Place")) document.has_data = False for event in event_list: stab.row(event, sdb.event_date_obj(event), sdb.event_place(event)) document.has_data = True if document.has_data: stab.write(sdoc) else: sdoc.header1(_("Not found"))
class AllRelReport: """ Obtains all relationships, displays the relations, and in details, the relation path """ def __init__(self, database, document, person): self.database = database self.person = person self.sdb = SimpleAccess(database) self.sdoc = SimpleDoc(document) self.rel_class = get_relationship_calculator(glocale) self.msg_list = [] def run(self): # get home_person self.home_person = self.database.get_default_person() if not self.home_person: self.sdoc.paragraph(_("Home person not set.")) return self.print_title() p2 = self.sdb.name(self.home_person) p1 = self.sdb.name(self.person) if self.person.handle == self.home_person.handle: self.sdoc.paragraph( _FMT_VOID % (_("%(person)s and %(active_person)s are the same person.")) % {"person": p1, "active_person": p2} ) return # check if not a family too: is_spouse = self.rel_class.is_spouse(self.database, self.home_person, self.person) if is_spouse: rel_string = is_spouse rstr = _("%(person)s is the %(relationship)s of %(active_person)s.") % { "person": p1, "relationship": rel_string, "active_person": p2, } self.sdoc.paragraph(_FMT_VOID % (rstr)) self.sdoc.paragraph("") # obtain all relationships, assume home person has largest tree common, self.msg_list = self.rel_class.get_relationship_distance_new( self.database, self.person, self.home_person, all_families=True, all_dist=True, only_birth=False ) # all relations if (not common or common[0][0] == -1) and not is_spouse: rstr = _("%(person)s and %(active_person)s are not " "directly related.") % { "person": p2, "active_person": p1, } self.sdoc.paragraph(_FMT_VOID % (rstr)) self.sdoc.paragraph("") # collapse common so parents of same fam in common are one line commonnew = self.rel_class.collapse_relations(common) self.print_details_header(commonnew, self.home_person, self.person, skip_list_text=None) self.print_details_path(commonnew, self.home_person, self.person) self.print_details_path(commonnew, self.home_person, self.person, first=False) if not common or common[0][0] == -1: self.remarks(self.msg_list) self.msg_list = [] # check inlaw relation next else: # stop return # we check the inlaw relationships if not partners. if is_spouse: return handles_done = [(self.person.handle, self.home_person.handle)] inlaws_pers = [self.person] + self.get_inlaws(self.person) inlaws_home = [self.home_person] + self.get_inlaws(self.home_person) # remove overlap: inlaws_home = [x for x in inlaws_home if x not in inlaws_pers] inlawwritten = False skiplist = [] commonnew = [] for inlawpers in inlaws_pers: for inlawhome in inlaws_home: if (inlawpers, inlawhome) in handles_done: continue else: handles_done.append((inlawpers, inlawhome)) common, msg = self.rel_class.get_relationship_distance_new( self.database, inlawpers, inlawhome, all_families=True, all_dist=True, only_birth=False ) if msg: self.msg_list += msg if common and not common[0][0] == -1: if not inlawwritten: rstr = _("%(person)s and %(active_person)s have " "following in-law relations:") % { "person": p2, "active_person": p1, } self.sdoc.paragraph(_FMT_VOID % (rstr)) self.sdoc.paragraph("") inlawwritten = True else: continue inlawb = not inlawpers.handle == self.person.handle inlawa = not inlawhome.handle == self.home_person.handle commonnew.append((inlawa, inlawb, inlawhome, inlawpers, self.rel_class.collapse_relations(common))) skip = [] skip_text = [] count = 1 for inlawa, inlawb, inlawhome, inlawpers, commonrel in commonnew: count = self.print_details_header( commonrel, inlawhome, inlawpers, inlawa=inlawa, inlawb=inlawb, count=count, skip_list=skip, skip_list_text=skip_text, ) count = 1 for inlawa, inlawb, inlawhome, inlawpers, commonrel in commonnew: self.print_details_path( commonrel, inlawhome, inlawpers, inlawa=inlawa, inlawb=inlawb, count=count, skip_list=skip ) count = self.print_details_path( commonrel, inlawhome, inlawpers, inlawa=inlawa, inlawb=inlawb, count=count, skip_list=skip, first=False ) self.remarks(self.msg_list, True) def get_inlaws(self, person): inlaws = [] family_handles = person.get_family_handle_list() for handle in family_handles: fam = self.database.get_family_from_handle(handle) if fam.father_handle and not fam.father_handle == person.handle: inlaws.append(self.database.get_person_from_handle(fam.father_handle)) elif fam.mother_handle and not fam.mother_handle == person.handle: inlaws.append(self.database.get_person_from_handle(fam.mother_handle)) return inlaws def print_title(self): """ print the title """ p2 = self.sdb.name(self.home_person) p1 = self.sdb.name(self.person) self.sdoc.title(_("Relationships of %(person)s to %(active_person)s") % {"person": p1, "active_person": p2}) self.sdoc.paragraph("") def print_details_header( self, relations, pers1, pers2, inlawa=False, inlawb=False, count=1, skip_list=[], skip_list_text=[] ): if not relations or relations[0][0] == -1: return count sdoc = self.sdoc rel_class = self.rel_class for relation in relations: birth = self.rel_class.only_birth(relation[2]) and self.rel_class.only_birth(relation[4]) distorig = len(relation[4]) distother = len(relation[2]) if distorig == distother == 1 and not inlawa and not inlawb: rel_str = self.rel_class.get_sibling_relationship_string( self.rel_class.get_sibling_type(self.database, pers1, pers2), self.home_person.get_gender(), self.person.get_gender(), ) else: rel_str = self.rel_class.get_single_relationship_string( distorig, distother, self.home_person.get_gender(), self.person.get_gender(), relation[4], relation[2], only_birth=birth, in_law_a=inlawa, in_law_b=inlawb, ) if not skip_list_text is None: if rel_str in skip_list_text: skip_list.append(count) else: skip_list_text.append(rel_str) sdoc.paragraph(_FMT % (count - len(skip_list), rel_str)) else: sdoc.paragraph(_FMT % (count, rel_str)) count += 1 return count def print_details_path( self, relations, pers1, pers2, inlawa=False, inlawb=False, count=1, skip_list=[], first=True ): if not relations or relations[0][0] == -1: return count sdoc = self.sdoc rel_class = self.rel_class p2 = self.sdb.name(self.home_person) p1 = self.sdb.name(self.person) pers = p2 inlaw = inlawa if first: pers = p1 inlaw = inlawb if count == 1: sdoc.paragraph("") sdoc.header1(_("Detailed path from %(person)s to common ancestor") % {"person": pers}) sdoc.paragraph("") sdoc.header2(_FMT_DET1 % (" ", _("Name Common ancestor"))) sdoc.header2(_FMT_DET2 % (" ", _("Parent"), _("Birth"), _("Family"))) sdoc.paragraph("") for relation in relations: if count in skip_list: count += 1 continue counter = str(count - len([x for x in range(count) if x + 1 in skip_list])) name = _("Unknown") if relation[1]: name = self.sdb.name(self.database.get_person_from_handle(relation[1][0])) for handle in relation[1][1:]: name += " " + _("and") + " " + self.sdb.name(self.database.get_person_from_handle(handle)) sdoc.paragraph(_FMT_DET1 % (counter, name)) if inlaw: sdoc.paragraph(_FMT_DET2 % (" ", _("Partner"), " ", " ")) if first: ind1 = 2 ind2 = 3 else: ind1 = 4 ind2 = 5 for rel, fam in zip(relation[ind1], relation[ind2]): par_str = _("Unknown") # when sibling, parent is unknown if rel == rel_class.REL_MOTHER or rel == rel_class.REL_MOTHER_NOTBIRTH: par_str = _("Mother") if rel == rel_class.REL_FATHER or rel == rel_class.REL_FATHER_NOTBIRTH: par_str = _("Father") if ( rel == rel_class.REL_FAM_BIRTH or rel == rel_class.REL_FAM_NONBIRTH or rel == rel_class.REL_FAM_BIRTH_MOTH_ONLY or rel == rel_class.REL_FAM_BIRTH_FATH_ONLY ): par_str = _("Parents") birth_str = _("Yes") if ( rel == rel_class.REL_MOTHER_NOTBIRTH or rel == rel_class.REL_FATHER_NOTBIRTH or rel == rel_class.REL_FAM_NONBIRTH ): birth_str = _("No") elif rel == rel_class.REL_FAM_BIRTH_FATH_ONLY or rel == rel_class.REL_FAM_BIRTH_MOTH_ONLY: birth_str = _("Partial") famstr = "" if isinstance(fam, list): famstr = str(fam[0] + 1) for val in fam[1:]: famstr += ", " + str(val + 1) else: famstr = str(fam + 1) sdoc.paragraph(_FMT_DET2 % (" ", par_str, birth_str, famstr)) counter = "" name = "" count += 1 return count def remarks(self, msg_list, inlaw=False): if msg_list: sdoc = self.sdoc sdoc.paragraph("") if inlaw: sdoc.header1(_("Remarks with inlaw family")) else: sdoc.header1(_("Remarks")) sdoc.paragraph("") sdoc.paragraph(_("The following problems were encountered:")) list(map(sdoc.paragraph, msg_list)) sdoc.paragraph("") sdoc.paragraph("")
def run(database, document, filter_name, *args, **kwargs): """ Loops through the families that the person is a child in, and display the information about the other children. """ # setup the simple access functions sdb = SimpleAccess(database) sdoc = SimpleDoc(document) stab = QuickTable(sdb) if (filter_name == 'all'): sdoc.title(_("Summary counts of current selection")) sdoc.paragraph("") sdoc.paragraph(_("Right-click row (or press ENTER) to see selected items.")) sdoc.paragraph("") stab.columns(_("Object"), _("Count/Total")) if hasattr(database, "db"): stab.row([_("People"), "Filter", "Person"], "%d/%d" % (len(database.get_person_handles()), len(database.db.get_person_handles()))) stab.row([_("Families"), "Filter", "Family"], "%d/%d" % (len(database.get_family_handles()), len(database.db.get_family_handles()))) stab.row([_("Events"), "Filter", "Event"], "%d/%d" % (len(database.get_event_handles()), len(database.db.get_event_handles()))) stab.row([_("Places"), "Filter", "Place"], "%d/%d" % (len(database.get_place_handles()), len(database.db.get_place_handles()))) stab.row([_("Sources"), "Filter", "Source"], "%d/%d" % (len(database.get_source_handles()), len(database.db.get_source_handles()))) stab.row([_("Repositories"), "Filter", "Repository"], "%d/%d" % (len(database.get_repository_handles()), len(database.db.get_repository_handles()))) stab.row([_("Media"), "Filter", "MediaObject"], "%d/%d" % (len(database.get_media_object_handles()), len(database.db.get_media_object_handles()))) stab.row([_("Notes"), "Filter", "Note"], "%d/%d" % (len(database.get_note_handles()), len(database.db.get_note_handles()))) else: stab.row([_("People"), "Filter", "Person"], "%d/%d" % (len(database.get_person_handles()), len(database.basedb.get_person_handles()))) stab.row([_("Families"), "Filter", "Family"], "%d/%d" % (len(database.get_family_handles()), len(database.basedb.get_family_handles()))) stab.row([_("Events"), "Filter", "Event"], "%d/%d" % (len(database.get_event_handles()), len(database.basedb.get_event_handles()))) stab.row([_("Places"), "Filter", "Place"], "%d/%d" % (len(database.get_place_handles()), len(database.basedb.get_place_handles()))) stab.row([_("Sources"), "Filter", "Source"], "%d/%d" % (len(database.get_source_handles()), len(database.basedb.get_source_handles()))) stab.row([_("Repositories"), "Filter", "Repository"], "%d/%d" % (len(database.get_repository_handles()), len(database.basedb.get_repository_handles()))) stab.row([_("Media"), "Filter", "MediaObject"], "%d/%d" % (len(database.get_media_object_handles()), len(database.basedb.get_media_object_handles()))) stab.row([_("Notes"), "Filter", "Note"], "%d/%d" % (len(database.get_note_handles()), len(database.basedb.get_note_handles()))) sdoc.paragraph("") stab.write(sdoc) return # display the title if filter_name in fname_map: sdoc.title(_("Filtering on %s") % fname_map[filter_name]) # listed above else: sdoc.title(_("Filtering on %s") % _(filter_name)) sdoc.paragraph("") matches = 0 if (filter_name == 'Inverse Person'): sdb.dbase = database.db stab.columns(_("Person"), _("Gramps ID"), _("Birth Date")) proxy_handles = set(database.iter_person_handles()) for person in database.db.iter_people(): if person.handle not in proxy_handles: stab.row(person, person.gramps_id, sdb.birth_or_fallback(person)) matches += 1 elif (filter_name == 'Inverse Family'): sdb.dbase = database.db stab.columns(_("Family"), _("Gramps ID")) proxy_handles = set(database.iter_family_handles()) for family in database.db.iter_families(): if family.handle not in proxy_handles: stab.row(family, family.gramps_id) matches += 1 elif (filter_name == 'Inverse Event'): sdb.dbase = database.db stab.columns(_("Event"), _("Gramps ID")) proxy_handles = set(database.iter_event_handles()) for event in database.db.iter_events(): if event.handle not in proxy_handles: stab.row(event, event.gramps_id) matches += 1 elif (filter_name == 'Inverse Place'): sdb.dbase = database.db stab.columns(_("Place"), _("Gramps ID")) proxy_handles = set(database.iter_place_handles()) for place in database.db.iter_places(): if place.handle not in proxy_handles: stab.row(place, place.gramps_id) matches += 1 elif (filter_name == 'Inverse Source'): sdb.dbase = database.db stab.columns(_("Source"), _("Gramps ID")) proxy_handles = set(database.iter_source_handles()) for source in database.db.iter_sources(): if source.handle not in proxy_handles: stab.row(source, source.gramps_id) matches += 1 elif (filter_name == 'Inverse Repository'): sdb.dbase = database.db stab.columns(_("Repository"), _("Gramps ID")) proxy_handles = set(database.iter_repository_handles()) for repository in database.db.iter_repositories(): if repository.handle not in proxy_handles: stab.row(repository, repository.gramps_id) matches += 1 elif (filter_name == 'Inverse MediaObject'): sdb.dbase = database.db stab.columns(_("Media"), _("Gramps ID")) proxy_handles = set(database.iter_media_object_handles()) for media in database.db.iter_media_objects(): if media.handle not in proxy_handles: stab.row(media, media.gramps_id) matches += 1 elif (filter_name == 'Inverse Note'): sdb.dbase = database.db stab.columns(_("Note"), _("Gramps ID")) proxy_handles = set(database.iter_note_handles()) for note in database.db.iter_notes(): if note.handle not in proxy_handles: stab.row(note, note.gramps_id) matches += 1 elif (filter_name in ['all people', 'Person']): stab.columns(_("Person"), _("Gramps ID"), _("Birth Date")) for person in database.iter_people(): stab.row(person, person.gramps_id, sdb.birth_or_fallback(person)) matches += 1 elif (filter_name in ['all families', 'Family']): stab.columns(_("Family"), _("Gramps ID")) for family in database.iter_families(): stab.row(family, family.gramps_id) matches += 1 elif (filter_name in ['all events', 'Event']): stab.columns(_("Event"), _("Gramps ID")) for obj in database.iter_events(): stab.row(obj, obj.gramps_id) matches += 1 elif (filter_name in ['all places', 'Place']): stab.columns(_("Place"), _("Gramps ID")) for obj in database.iter_places(): stab.row(obj, obj.gramps_id) matches += 1 elif (filter_name in ['all sources', 'Source']): stab.columns(_("Source"), _("Gramps ID")) for obj in database.iter_sources(): stab.row(obj, obj.gramps_id) matches += 1 elif (filter_name in ['all repositories', 'Repository']): stab.columns(_("Repository"), _("Gramps ID")) for obj in database.iter_repositories(): stab.row(obj, obj.gramps_id) matches += 1 elif (filter_name in ['all media', 'MediaObject']): stab.columns(_("Media"), _("Gramps ID")) for obj in database.iter_media_objects(): stab.row(obj, obj.gramps_id) matches += 1 elif (filter_name in ['all notes', 'Note']): stab.columns(_("Note"), _("Gramps ID")) for obj in database.iter_notes(): stab.row(obj, obj.gramps_id) matches += 1 elif (filter_name == 'males'): stab.columns(_("Person"), _("Birth Date"), _("Name type")) for person in database.iter_people(): if person.gender == Person.MALE: stab.row(person, sdb.birth_or_fallback(person), str(person.get_primary_name().get_type())) matches += 1 elif (filter_name == 'females'): stab.columns(_("Person"), _("Birth Date"), _("Name type")) for person in database.iter_people(): if person.gender == Person.FEMALE: stab.row(person, sdb.birth_or_fallback(person), str(person.get_primary_name().get_type())) matches += 1 elif (filter_name == 'people with unknown gender'): stab.columns(_("Person"), _("Birth Date"), _("Name type")) for person in database.iter_people(): if person.gender not in [Person.FEMALE, Person.MALE]: stab.row(person, sdb.birth_or_fallback(person), str(person.get_primary_name().get_type())) matches += 1 elif (filter_name == 'incomplete names'): stab.columns(_("Name"), _("Birth Date"), _("Name type")) for person in database.iter_people(): for name in [person.get_primary_name()] + person.get_alternate_names(): if name.get_first_name().strip() == "": stab.row([name.get_name(), "Person", person.handle], sdb.birth_or_fallback(person), str(name.get_type())) matches += 1 else: if name.get_surname_list(): for surname in name.get_surname_list(): if surname.get_surname().strip() == "": stab.row([name.get_first_name(), "Person", person.handle], sdb.birth_or_fallback(person), str(name.get_type())) matches += 1 else: stab.row([name.get_first_name(), "Person", person.handle], sdb.birth_or_fallback(person), str(name.get_type())) matches += 1 elif (filter_name == 'people with missing birth dates'): stab.columns(_("Person"), _("Type")) for person in database.iter_people(): birth_ref = person.get_birth_ref() if birth_ref: birth = database.get_event_from_handle(birth_ref.ref) if not get_date(birth): stab.row(person, _("birth event but no date")) matches += 1 else: stab.row(person, _("missing birth event")) matches += 1 elif (filter_name == 'disconnected people'): stab.columns(_("Person"), _("Birth Date"), _("Name type")) for person in database.iter_people(): if ((not person.get_main_parents_family_handle()) and (not len(person.get_family_handle_list()))): stab.row(person, sdb.birth_or_fallback(person), str(person.get_primary_name().get_type())) matches += 1 elif (filter_name == 'unique surnames'): namelist = defaultdict(int) for person in database.iter_people(): names = [person.get_primary_name()] + person.get_alternate_names() surnames = list(set([name.get_group_name() for name in names])) for surname in surnames: namelist[surname] += 1 stab.columns(_("Surname"), _("Count")) for name in sorted(namelist): stab.row(name, namelist[name]) matches += 1 stab.set_callback("leftdouble", lambda name: run_quick_report_by_name_direct("samesurnames", database, document, name)) elif (filter_name == 'people with media'): stab.columns(_("Person"), _("Media count")) for person in database.iter_people(): length = len(person.get_media_list()) if length > 0: stab.row(person, str(length)) matches += 1 elif (filter_name == 'media references'): stab.columns(_("Person"), _("Reference")) for person in database.iter_people(): medialist = person.get_media_list() for item in medialist: stab.row(person, _("media")) matches += 1 elif (filter_name == 'unique media'): stab.columns(_("Unique Media")) for photo in database.iter_media_objects(): fullname = media_path_full(database, photo.get_path()) stab.row(fullname) matches += 1 elif (filter_name == 'missing media'): stab.columns(_("Missing Media")) for photo in database.iter_media_objects(): fullname = media_path_full(database, photo.get_path()) try: posixpath.getsize(fullname) except: stab.row(fullname) matches += 1 elif (filter_name == 'media by size'): stab.columns(_("Media"), _("Size in bytes")) for photo in database.iter_media_objects(): fullname = media_path_full(database, photo.get_path()) try: bytes = posixpath.getsize(fullname) stab.row(fullname, str(bytes)) matches += 1 except: pass elif (filter_name == 'list of people'): stab.columns(_("Person"), _("Birth Date"), _("Name type")) handles = kwargs["handles"] for person_handle in handles: person = database.get_person_from_handle(person_handle) stab.row(person, sdb.birth_or_fallback(person), str(person.get_primary_name().get_type())) matches += 1 else: raise AttributeError("invalid filter name: '%s'" % filter_name) # translators: leave all/any {...} untranslated sdoc.paragraph(ngettext("Filter matched {number_of} record.", "Filter matched {number_of} records.", matches ).format(number_of=matches) ) sdoc.paragraph("") document.has_data = matches > 0 if matches > 0: stab.write(sdoc)
def run(database, document, main_event): """ Displays events on a specific date of an event (or date) Takes an Event or Date object """ if isinstance(main_event, Date): main_date = main_event else: main_date = main_event.get_date_object() cal = main_date.get_calendar(); # setup the simple access functions sdb = SimpleAccess(database) sdoc = SimpleDoc(document) stab = QuickTable(sdb) stab.set_link_col(3) yeartab = QuickTable(sdb) yeartab.set_link_col(3) histab = QuickTable(sdb) histab.set_link_col(3) # display the title sdoc.title(_("Events of %(date)s") % {"date": sdb.date_string(main_date)}) sdoc.paragraph("") stab.columns(_("Date"), _("Type"), _("Place"), _("Reference")) yeartab.columns(_("Date"), _("Type"), _("Place"), _("Reference")) histab.columns(_("Date"), _("Type"), _("Place"), _("Reference")) for event in database.iter_events(): date = event.get_date_object() date.convert_calendar(cal) if date.get_year() == 0: continue if (date.get_year() == main_date.get_year() and date.get_month() == main_date.get_month() and date.get_day() == main_date.get_day()): for (objclass, handle) in database.find_backlink_handles(event.handle): ref = get_ref(database, objclass, handle) stab.row(date, sdb.event_type(event), sdb.event_place(event), ref) elif (date.get_month() == main_date.get_month() and date.get_day() == main_date.get_day() and date.get_month() != 0): for (objclass, handle) in database.find_backlink_handles(event.handle): ref = get_ref(database, objclass, handle) histab.row(date, sdb.event_type(event), sdb.event_place(event), ref) elif (date.get_year() == main_date.get_year()): for (objclass, handle) in database.find_backlink_handles(event.handle): ref = get_ref(database, objclass, handle) yeartab.row(date, sdb.event_type(event), sdb.event_place(event), ref) document.has_data = False if stab.get_row_count() > 0: document.has_data = True sdoc.paragraph(_("Events on this exact date")) stab.write(sdoc) else: sdoc.paragraph(_("No events on this exact date")) sdoc.paragraph("") sdoc.paragraph("") if histab.get_row_count() > 0: document.has_data = True sdoc.paragraph(_("Other events on this month/day in history")) histab.write(sdoc) else: sdoc.paragraph(_("No other events on this month/day in history")) sdoc.paragraph("") sdoc.paragraph("") if yeartab.get_row_count() > 0: document.has_data = True sdoc.paragraph(_("Other events in %(year)d") % {"year":main_date.get_year()}) yeartab.write(sdoc) else: sdoc.paragraph(_("No other events in %(year)d") % {"year":main_date.get_year()}) sdoc.paragraph("") sdoc.paragraph("")
class DBI(object): """ The SQL-like interface to the database and document instances. """ def __init__(self, database, document=None): self.database = database self.document = document self.data = {} self.select = 0 self.flat = False self.raw = False if self.database: for name in self.database.get_table_names(): d = self.database._tables[name]["class_func"]().to_struct() self.data[name.lower()] = d.keys() # The macros: self.shortcuts = { "SURNAME": "primary_name.surname_list[0].surname", "GIVEN": "primary_name.first_name", } def parse(self, query): """ Parse the query. """ self.query_text = query.replace("\n", " ").strip() lexed = self.lexer(self.query_text) #print(lexed) self.parser(lexed) for col_name in self.columns[:]: # copy if col_name == "*": self.columns.remove('*') # this is useful to see what _class it is: self.columns.extend(self.get_columns(self.table)) # otherwise remove metadata: #self.columns.extend([col for col in self.get_columns(self.table) if not col.startswith("_")) def lexer(self, string): """ Given a string, break into a list of chunks. """ retval = [] state = None current = "" stack = [] i = 0 # Handle macros: for key in self.shortcuts.keys(): string = string.replace(key, self.shortcuts[key]) # (some "expression" in ok) # func(some "expression" in (ok)) # list[1][0] # [x for x in list] while i < len(string): ch = string[i] #print("lex:", i, ch, state, retval, current) if state == "in-double-quote": if ch == '"': state = stack.pop() current += ch elif state == "in-single-quote": if ch == "'": state = stack.pop() current += ch elif state == "in-expr": if ch == ")": state = stack.pop() elif ch == "(": stack.append("in-expr") current += ch elif state == "in-square-bracket": if ch == "]": state = stack.pop() elif ch == "[": stack.append("in-square-bracket") current += ch elif ch == '"': stack.append(state) state = "in-double-quote" current += ch elif ch == "'": stack.append(state) state = "in-single-quote" current += ch elif ch == "(": stack.append(state) state = "in-expr" current += "(" elif ch == "[": stack.append(state) state = "in-square-bracket" current += "[" elif ch == ",": if current: retval.append(current) retval.append(",") current = "" elif ch == "=": if current: retval.append(current) retval.append("=") current = "" elif ch in [' ', '\t', '\n', ";"]: # break if current: retval.append(current) if current.upper() == "WHERE": # HACK: get rest of string: if string[-1] == ";": retval.append(string[i + 1:-1]) i = len(string) - 2 else: retval.append(string[i + 1:]) i = len(string) - 1 current = "" else: pass # ignore whitespace else: current += ch i += 1 if current: retval.append(current) #print("lexed:", retval) return retval def parser(self, lex): """ Takes output of lexer, and sets the values. After parser, the DBI will be ready to process query. """ self.action = None self.table = None self.columns = [] self.setcolumns = [] self.values = [] self.aliases = {} self.limit = None self.where = None self.index = 0 while self.index < len(lex): symbol = lex[self.index] if symbol.upper() == "FROM": # from table select *; self.index += 1 if self.index < len(lex): self.table = lex[self.index] elif symbol.upper() == "SELECT": # select a, b from table; self.action = "SELECT" self.index += 1 self.columns.append(lex[self.index]) self.index += 1 while self.index < len(lex) and lex[self.index].upper() in [",", "AS"]: sep = lex[self.index] if sep == ",": self.index += 1 self.columns.append(lex[self.index]) self.index += 1 elif sep.upper() == "AS": self.index += 1 # alias self.aliases[self.columns[-1]] = lex[self.index] self.index += 1 self.index -= 1 elif symbol.upper() == "DELETE": # delete from table where item == 1; self.action = "DELETE" self.columns = ["gramps_id"] elif symbol.upper() == "SET": # SET x=1, y=2 self.index += 1 self.setcolumns.append(lex[self.index]) # first column self.index += 1 # equal sign # = self.index += 1 # value self.values.append(lex[self.index]) self.index += 1 # comma while self.index < len(lex) and lex[self.index] == ",": self.index += 1 # next column self.setcolumns.append(lex[self.index]) self.index += 1 # equal # = self.index += 1 # value self.values.append(lex[self.index]) self.index += 1 # comma? self.index -= 1 elif symbol.upper() == "LIMIT": self.index += 1 # after LIMIT number = lex[self.index] self.index += 1 # maybe a comma if self.index < len(lex) and lex[self.index] == ",": self.index += 1 # after "," stop = lex[self.index] self.limit = (int(number), int(stop)) else: self.limit = (0, int(number)) self.index -= 1 elif symbol.upper() == "WHERE": # how can we get all of Python expressions? # this assumes all by ; self.index += 1 self.where = lex[self.index] elif symbol.upper() == "UPDATE": # update table set x=1, y=2 where condition; # UPDATE gramps_id set tag_list = Tag("Betty") from person where "Betty" in primary_name.first_name self.columns = ["gramps_id"] self.action = "UPDATE" if self.index < len(lex): self.index += 1 self.table = lex[self.index] elif symbol.upper() == "FLAT": self.flat = True elif symbol.upper() == "EXPAND": self.flat = False elif symbol.upper() == "RAW": self.raw = True elif symbol.upper() == "NORAW": self.raw = False else: raise AttributeError("invalid SQL expression: '... %s ...'" % symbol) self.index += 1 def close(self): """ Close up any progress widgets or dialogs. """ #try: # self.progress.close() #except: pass def clean_titles(self, columns): """ Take the columns and turn them into strings for the table. """ retval = [] for column in columns: if column in self.aliases: column = self.aliases[column] retval.append(column.replace("_", "__")) return retval def query(self, query): self.parse(query) self.select = 0 start_time = time.time() class Table(): results = [] def row(self, *args, **kwargs): self.results.append([args, kwargs]) def get_rows(self): return [list(item[0]) for item in self.results] table = Table() self.sdb = SimpleAccess(self.database) self.process_table(table) # a class that has .row(1, 2, 3, ...) print(_("%d rows processed in %s seconds.\n") % (self.select, time.time() - start_time)) return table def eval(self): """ Execute the query. """ self.sdb = SimpleAccess(self.database) self.stab = QuickTable(self.sdb) self.select = 0 start_time = time.time() self.process_table(self.stab) # a class that has .row(1, 2, 3, ...) if self.select > 0: self.stab.columns(*self.clean_titles(self.columns)) self.sdoc = SimpleDoc(self.document) self.sdoc.title(self.query_text) self.sdoc.paragraph("\n") self.sdoc.paragraph("%d rows processed in %s seconds.\n" % (self.select, time.time() - start_time)) self.stab.write(self.sdoc) self.sdoc.paragraph("") return _("%d rows processed in %s seconds.\n") % (self.select, time.time() - start_time) def get_columns(self, table): """ Get the columns for the given table. """ if self.database: retval = self.data[table.lower()] return retval # [self.name] + retval else: return ["*"] def process_table(self, table): """ Given a table name, process the query on the elements of the table. """ # 'Person', 'Family', 'Source', 'Citation', 'Event', 'Media', # 'Place', 'Repository', 'Note', 'Tag' # table: a class that has .row(1, 2, 3, ...) if self.table == "person": self.do_query(self.sdb.all_people(), table) elif self.table == "family": self.do_query(self.sdb.all_families(), table) elif self.table == "event": self.do_query(self.sdb.all_events(), table) elif self.table == "source": self.do_query(self.sdb.all_sources(), table) elif self.table == "tag": self.do_query(self.sdb.all_tags(), table) elif self.table == "citation": self.do_query(self.sdb.all_citations(), table) elif self.table == "media": self.do_query(self.sdb.all_media(), table) elif self.table == "place": self.do_query(self.sdb.all_places(), table) elif self.table == "repository": self.do_query(self.sdb.all_repositories(), table) elif self.table == "note": self.do_query(self.sdb.all_notes(), table) else: raise AttributeError("no such table: '%s'" % self.table) def get_tag(self, name): tag = self.database.get_tag_from_name(name) if tag is None: tag = gramps.gen.lib.Tag() tag.set_name(name) trans_class = self.database.get_transaction_class() with trans_class("QueryQuickview new Tag", self.database, batch=False) as trans: self.database.add_tag(tag, trans) return Handle("Tag", tag.handle) def make_env(self, **kwargs): """ An environment with which to eval elements. """ retval= Environment({ _("Date"): gramps.gen.lib.date.Date, _("Today"): gramps.gen.lib.date.Today(), "random": random, "re": re, "db": self.database, "sdb": self.sdb, "lib": gramps.gen.lib, "_": _, "Tag": self.get_tag, }) retval.update(__builtins__) retval.update(kwargs) return retval def stringify(self, value): """ Turn the value into an appropriate string representation. """ if self.raw: return value if isinstance(value, Struct): return self.stringify(value.struct) elif isinstance(value, (list, tuple)): if len(value) == 0 and not self.flat: return "" elif len(value) == 1 and not self.flat: return self.stringify(value[0]) else: return "[%s]" % (", ".join(map(self.stringify, value))) elif isinstance(value, PrimaryObject): return value else: return str(value) def clean(self, values, names): """ Given the values and names of columns, change the values into string versions for the display table. """ if self.raw: return values retval = [] for i in range(len(values)): if names[i].endswith("handle"): retval.append(repr(values[i].struct["handle"])) else: retval.append(self.stringify(values[i])) return retval def do_query(self, items, table): """ Perform the query on the items in the named table. """ # table: a class that has .row(1, 2, 3, ...) with self.database.get_transaction_class()("QueryQuickview", self.database, batch=True) as trans: ROWNUM = 0 env = self.make_env() for item in items: if item is None: continue row = [] row_env = [] # "col[0]" in WHERE clause will return first column of selection: env["col"] = row_env env["ROWNUM"] = ROWNUM env["object"] = item struct = Struct(item.to_struct(), self.database) env.set_struct(struct) for col in self.columns: try: value = eval(col, env) except: value = None row.append(value) # allow col[#] reference: row_env.append(value) # an alias? if col in self.aliases: env[self.aliases[col]] = value # Should we include this row? if self.where: try: result = eval(self.where, env) except: continue else: if self.action in ["DELETE", "UPDATE"]: result = True else: result = any([col != None for col in row]) # are they all None? # If result, then append the row if result: if (self.limit is None) or (self.limit[0] <= ROWNUM < self.limit[1]): if self.action == "SELECT": if not self.flat: # Join by rows: products = [] columns = [] count = 0 for col in row: if ((isinstance(col, Struct) and isinstance(col.struct, list) and len(col.struct) > 0) or (isinstance(col, list) and len(col) > 0)): products.append(col) columns.append(count) count += 1 if len(products) > 0: current = self.clean(row, self.columns) for items in itertools.product(*products): for i in range(len(items)): current[columns[i]] = self.stringify(items[i]) table.row(*current, link=(item.__class__.__name__, item.handle)) self.select += 1 else: table.row(*self.clean(row, self.columns), link=(item.__class__.__name__, item.handle)) self.select += 1 else: table.row(*self.clean(row, self.columns), link=(item.__class__.__name__, item.handle)) self.select += 1 elif self.action == "UPDATE": # update table set col=val, col=val where expr; table.row(*self.clean(row, self.columns), link=(item.__class__.__name__, item.handle)) self.select += 1 for i in range(len(self.setcolumns)): struct.setitem(self.setcolumns[i], eval(self.values[i], env), trans=trans) elif self.action == "DELETE": table.row(*self.clean(row, self.columns)) self.select += 1 self.database.remove_instance(item, trans) else: raise AttributeError("unknown command: '%s'", self.action) ROWNUM += 1 if (self.limit is not None) and (ROWNUM >= self.limit[1]): break
def run_fam(database, document, family): """ Loops through the family events and the events of all parents, displaying the basic details of the event """ sdb = SimpleAccess(database) sdoc = SimpleDoc(document) stab = QuickTable(sdb) # get the family events event_list = [(_('Family'), x) for x in sdb.events(family)] # get the events of father and mother #fathername = sdb.first_name(sdb.father(family)) event_list += [(sdb.father(family), x) for x in sdb.events(sdb.father(family))] #mothername = sdb.first_name(sdb.mother(family)) event_list += [(sdb.mother(family), x) for x in sdb.events(sdb.mother(family))] # children events event_list_children = [] for child in sdb.children(family) : #name = sdb.first_name(child) event_list_children += [(child, x) for x in sdb.events(child)] # Sort the events by their date event_list.sort(key=lambda x: x[1].get_date_object()) event_list_children.sort(key=lambda x: x[1].get_date_object()) # display the results sdoc.title(_("Sorted events of family\n %(father)s - %(mother)s") % { 'father' : sdb.name(sdb.father(family)), 'mother' : sdb.name(sdb.mother(family)) }) sdoc.paragraph("") document.has_data = False stab.columns(_("Family Member"), _("Event Type"), _("Event Date"), _("Event Place")) for (person, event) in event_list: stab.row(person, sdb.event_type(event), sdb.event_date_obj(event), sdb.event_place(event)) document.has_data = True stab.write(sdoc) stab = QuickTable(sdb) sdoc.header1(_("Personal events of the children")) stab.columns(_("Family Member"), _("Event Type"), _("Event Date"), _("Event Place")) for (person, event) in event_list_children: stab.row(person, sdb.event_type(event), sdb.event_date_obj(event), sdb.event_place(event)) document.has_data = True stab.write(sdoc)
class AllRelReport: """ Obtains all relationships, displays the relations, and in details, the relation path """ def __init__(self, database, document, person): self.database = database self.person = person self.sdb = SimpleAccess(database) self.sdoc = SimpleDoc(document) self.rel_class = get_relationship_calculator(glocale) self.msg_list = [] def run(self): #get home_person self.home_person = self.database.get_default_person() if not self.home_person : self.sdoc.paragraph(_("Home person not set.")) return self.print_title() p2 = self.sdb.name(self.home_person) p1 = self.sdb.name(self.person) if self.person.handle == self.home_person.handle : self.sdoc.paragraph(_FMT_VOID % ( _("%(person)s and %(active_person)s are the same person.")) % { 'person' : p1, 'active_person' : p2 }) return #check if not a family too: is_spouse = self.rel_class.is_spouse(self.database, self.home_person, self.person) if is_spouse: rel_string = is_spouse rstr = _("%(person)s is the %(relationship)s of %(active_person)s." ) % {'person' : p1, 'relationship' : rel_string, 'active_person' : p2 } self.sdoc.paragraph(_FMT_VOID % (rstr)) self.sdoc.paragraph("") #obtain all relationships, assume home person has largest tree common, self.msg_list = self.rel_class.get_relationship_distance_new( self.database, self.person, self.home_person, all_families=True, all_dist=True, only_birth=False) #all relations if (not common or common[0][0]== -1 ) and not is_spouse: rstr = _("%(person)s and %(active_person)s are not " "directly related.") % {'person' : p2, 'active_person' : p1 } self.sdoc.paragraph(_FMT_VOID % (rstr)) self.sdoc.paragraph("") #collapse common so parents of same fam in common are one line commonnew = self.rel_class.collapse_relations(common) self.print_details_header(commonnew, self.home_person, self.person, skip_list_text=None) self.print_details_path(commonnew, self.home_person, self.person) self.print_details_path(commonnew, self.home_person, self.person, first=False) if not common or common[0][0]== -1 : self.remarks(self.msg_list) self.msg_list = [] #check inlaw relation next else: #stop return #we check the inlaw relationships if not partners. if is_spouse: return handles_done = [(self.person.handle, self.home_person.handle)] inlaws_pers = [self.person] + self.get_inlaws(self.person) inlaws_home = [self.home_person] + self.get_inlaws(self.home_person) #remove overlap: inlaws_home = [x for x in inlaws_home if x not in inlaws_pers] inlawwritten = False skiplist = [] commonnew = [] for inlawpers in inlaws_pers: for inlawhome in inlaws_home: if (inlawpers, inlawhome) in handles_done : continue else: handles_done.append((inlawpers, inlawhome)) common, msg = \ self.rel_class.get_relationship_distance_new( self.database, inlawpers, inlawhome, all_families=True, all_dist=True, only_birth=False) if msg: self.msg_list += msg if common and not common[0][0] == -1: if not inlawwritten: rstr = _("%(person)s and %(active_person)s have " "following in-law relations:" ) % {'person' : p2, 'active_person' : p1 } self.sdoc.paragraph(_FMT_VOID % (rstr)) self.sdoc.paragraph("") inlawwritten = True else: continue inlawb = not inlawpers.handle == self.person.handle inlawa = not inlawhome.handle == self.home_person.handle commonnew.append((inlawa, inlawb, inlawhome, inlawpers, self.rel_class.collapse_relations(common))) skip=[] skip_text = [] count = 1 for inlawa, inlawb, inlawhome, inlawpers, commonrel in commonnew: count = self.print_details_header(commonrel, inlawhome, inlawpers, inlawa = inlawa, inlawb = inlawb, count=count, skip_list=skip, skip_list_text = skip_text) count = 1 for inlawa, inlawb, inlawhome, inlawpers, commonrel in commonnew: self.print_details_path(commonrel, inlawhome, inlawpers, inlawa = inlawa, inlawb = inlawb, count = count, skip_list = skip) count = self.print_details_path(commonrel, inlawhome, inlawpers, inlawa = inlawa, inlawb = inlawb, count = count, skip_list = skip, first = False) self.remarks(self.msg_list, True) def get_inlaws(self, person): inlaws = [] family_handles = person.get_family_handle_list() for handle in family_handles: fam = self.database.get_family_from_handle(handle) if fam.father_handle and \ not fam.father_handle == person.handle: inlaws.append(self.database.get_person_from_handle( fam.father_handle)) elif fam.mother_handle and \ not fam.mother_handle == person.handle: inlaws.append(self.database.get_person_from_handle( fam.mother_handle)) return inlaws def print_title(self): """ print the title """ p2 = self.sdb.name(self.home_person) p1 = self.sdb.name(self.person) self.sdoc.title(_("Relationships of %(person)s to %(active_person)s") % { 'person' : p1 ,'active_person' : p2 }) self.sdoc.paragraph("") def print_details_header(self, relations, pers1, pers2, inlawa=False, inlawb=False, count=1, skip_list=[], skip_list_text = []): if not relations or relations[0][0] == -1: return count sdoc = self.sdoc rel_class = self.rel_class for relation in relations: birth = self.rel_class.only_birth(relation[2])\ and self.rel_class.only_birth(relation[4]) distorig = len(relation[4]) distother = len(relation[2]) if distorig == distother == 1 and not inlawa \ and not inlawb: rel_str = self.rel_class.get_sibling_relationship_string( self.rel_class.get_sibling_type( self.database, pers1, pers2), self.home_person.get_gender(), self.person.get_gender()) else: rel_str = self.rel_class.get_single_relationship_string( distorig, distother, self.home_person.get_gender(), self.person.get_gender(), relation[4], relation[2], only_birth = birth, in_law_a = inlawa, in_law_b = inlawb) if skip_list_text is not None: if rel_str in skip_list_text: skip_list.append(count) else: skip_list_text.append(rel_str) sdoc.paragraph(_FMT % (count-len(skip_list), rel_str)) else: sdoc.paragraph(_FMT % (count, rel_str)) count += 1 return count def print_details_path(self, relations, pers1, pers2, inlawa=False, inlawb=False, count = 1, skip_list = [], first=True): if not relations or relations[0][0] == -1: return count sdoc = self.sdoc rel_class = self.rel_class p2 = self.sdb.name(self.home_person) p1 = self.sdb.name(self.person) pers = p2 inlaw = inlawa if first: pers = p1 inlaw = inlawb if count == 1: sdoc.paragraph("") sdoc.header1(_("Detailed path from %(person)s to common ancestor" ) % {'person':pers}) sdoc.paragraph("") sdoc.header2(_FMT_DET1 % (' ', _('Name Common ancestor'))) sdoc.header2(_FMT_DET2 % (' ', _('Parent'), _('Birth'), _('Family'))) sdoc.paragraph("") for relation in relations: if count in skip_list: count += 1 continue counter = str(count - len([x for x in range(count) if x+1 in skip_list])) name = _('Unknown') if relation[1]: name = self.sdb.name(self.database.get_person_from_handle( relation[1][0])) for handle in relation[1][1:]: name += ' ' + _('and') + ' ' + self.sdb.name( self.database.get_person_from_handle(handle)) sdoc.paragraph(_FMT_DET1 % (counter, name)) if inlaw: sdoc.paragraph(_FMT_DET2 % (' ', _('Partner'), ' ', ' ')) if first: ind1 = 2 ind2 = 3 else: ind1 = 4 ind2 = 5 for rel,fam in zip(relation[ind1],relation[ind2]): par_str = _('Unknown') #when sibling, parent is unknown if rel == rel_class.REL_MOTHER \ or rel == rel_class.REL_MOTHER_NOTBIRTH: par_str = _('Mother') if rel == rel_class.REL_FATHER \ or rel == rel_class.REL_FATHER_NOTBIRTH: par_str = _('Father') if (rel == rel_class.REL_FAM_BIRTH or rel == rel_class.REL_FAM_NONBIRTH or rel == rel_class.REL_FAM_BIRTH_MOTH_ONLY or rel == rel_class.REL_FAM_BIRTH_FATH_ONLY): par_str = _('Parents') birth_str = _('Yes') if (rel == rel_class.REL_MOTHER_NOTBIRTH or rel == rel_class.REL_FATHER_NOTBIRTH or rel == rel_class.REL_FAM_NONBIRTH): birth_str = _('No') elif (rel == rel_class.REL_FAM_BIRTH_FATH_ONLY or rel == rel_class.REL_FAM_BIRTH_MOTH_ONLY): birth_str = _('Partial') famstr = '' if isinstance(fam, list): famstr = str(fam[0]+1) for val in fam[1:] : # TODO for Arabic, should the next comma be translated? famstr += ', ' + str(val+1) else: famstr = str(fam+1) sdoc.paragraph(_FMT_DET2 % (' ', par_str, birth_str, famstr)) counter='' name = '' count += 1 return count def remarks(self, msg_list, inlaw=False): if msg_list : sdoc = self.sdoc sdoc.paragraph("") if inlaw: sdoc.header1(_("Remarks with inlaw family")) else: sdoc.header1(_("Remarks")) sdoc.paragraph("") sdoc.paragraph(_("The following problems were encountered:")) list(map(sdoc.paragraph, msg_list)) sdoc.paragraph("") sdoc.paragraph("")
class EditLink(ManagedWindow): def __init__(self, dbstate, uistate, track, url, callback): self.url = url self.dbstate = dbstate self.simple_access = SimpleAccess(self.dbstate.db) self.callback = callback ManagedWindow.__init__(self, uistate, track, url) self._local_init() self._connect_signals() self.show() def _local_init(self): self.top = Glade() self.set_window(self.top.toplevel, self.top.get_object("title"), _('Link Editor')) self.uri_list = self.top.get_object('link_type') for text in [_("Internet Address"), # 0 this order range above _("Event"), # 1 _("Family"), # 2 _("Media"), # 3 _("Note"), # 4 _("Person"), # 5 _("Place"), # 6 _("Repository"), # 7 _("Source"), # 8 ]: self.uri_list.append_text(text) self.pick_item = self.top.get_object('button1') self.new_button = self.top.get_object('new') self.edit_button = self.top.get_object('edit') self.selected = self.top.get_object('label1') self.url_link = self.top.get_object('entry1') self.uri_list.connect("changed", self._on_type_changed) self.pick_item.connect("clicked", self._on_pick_one) self.new_button.connect("clicked", self._on_new) self.edit_button.connect("clicked", self._on_edit_one) if self.url.startswith("gramps://"): object_class, prop, value = self.url[9:].split("/", 2) if object_class == "Event": self.uri_list.set_active(EVENT) elif object_class == "Family": self.uri_list.set_active(FAMILY) elif object_class == "Media": self.uri_list.set_active(MEDIA) elif object_class == "Note": self.uri_list.set_active(NOTE) elif object_class == "Person": self.uri_list.set_active(PERSON) elif object_class == "Place": self.uri_list.set_active(PLACE) elif object_class == "Repository": self.uri_list.set_active(REPOSITORY) elif object_class == "Source": self.uri_list.set_active(SOURCE) # set texts: self.selected.set_text(self.display_link( object_class, prop, value)) self.url_link.set_text("gramps://%s/%s/%s" % (object_class, prop, value)) else: self.uri_list.set_active(WEB) self.url_link.set_text(self.url) self.url_link.connect("changed", self.update_ui) def update_ui(self, widget): url = self.url_link.get_text() # text needs to have 3 or more chars://and at least one char match = re.match("\w{3,}://\w+", url) if match: self.ok_button.set_sensitive(True) else: self.ok_button.set_sensitive(False) def display_link(self, obj_class, prop, value): return self.simple_access.display(obj_class, prop, value) def _on_new_callback(self, obj): object_class = obj.__class__.__name__ self.selected.set_text(self.display_link( object_class, "handle", obj.handle)) self.url_link.set_text("gramps://%s/%s/%s" % (object_class, "handle", obj.handle)) def _on_new(self, widget): from ..editors import EditObject object_class = OBJECT_MAP[self.uri_list.get_active()] EditObject(self.dbstate, self.uistate, self.track, object_class, callback=self._on_new_callback) def _on_edit_one(self, widget): from ..editors import EditObject uri = self.url_link.get_text() if uri.startswith("gramps://"): obj_class, prop, value = uri[9:].split("/", 2) EditObject(self.dbstate, self.uistate, self.track, obj_class, prop, value) def _on_pick_one(self, widget): from ..selectors import SelectorFactory object_class = OBJECT_MAP[self.uri_list.get_active()] Select = SelectorFactory(object_class) uri = self.url_link.get_text() default = None if uri.startswith("gramps://"): obj_class, prop, value = uri[9:].split("/", 2) if object_class == obj_class: if prop == "handle": default = value elif (prop == "gramps_id" and object_class in self.dbstate.db.get_table_names()): person = self.dbstate.db.get_table_metadata(object_class)["gramps_id_func"](value) if person: default = person.handle d = Select(self.dbstate, self.uistate, self.track, default=default) result = d.run() if result: prop = "handle" value = result.handle self.selected.set_text(self.display_link( object_class, prop, value)) self.url_link.set_text("gramps://%s/%s/%s" % (object_class, prop, value)) def _on_type_changed(self, widget): self.selected.set_text("") if self.uri_list.get_active() == WEB: self.url_link.set_sensitive(True) self.pick_item.set_sensitive(False) self.new_button.set_sensitive(False) self.edit_button.set_sensitive(False) else: self.url_link.set_sensitive(False) self.pick_item.set_sensitive(True) self.new_button.set_sensitive(True) self.edit_button.set_sensitive(True) def get_uri(self): if self.uri_list.get_active() == WEB: return self.url_link.get_text() else: return self.url_link.get_text() def _connect_signals(self): self.define_cancel_button(self.top.get_object('button125')) self.ok_button = self.top.get_object('button124') self.define_ok_button(self.ok_button, self.save) # TODO help button (rename glade button name) self.define_help_button(self.top.get_object('button130'), WIKI_HELP_PAGE, WIKI_HELP_SEC) self.update_ui(self.url_link) def build_menu_names(self, obj): etitle =_('Link Editor') return (etitle, etitle) def define_ok_button(self,button,function): button.connect('clicked',function) def save(self, widget): self.callback(self.get_uri()) self.close() def define_cancel_button(self,button): button.connect('clicked',self.close) def define_help_button(self, button, webpage='', section=''): button.connect('clicked', lambda x: display_help(webpage, section))
def run(self): BUTTONS = ((_("Select All"), self.select_all), (_("Select None"), self.select_none), (_("Toggle Selection"), self.toggle_select), (_("Add Selected Events"), self.apply_selection), ) if hasattr(self, "table") and self.table: self.reselect = False if self.options.handler.options_dict['remove']: QuestionDialog(_("Remove Events, Notes, and Source and Reselect Data"), _("Are you sure you want to remove previous events, notes, and source and reselect data?"), _("Remove and Run Select Again"), self.set_reselect, self.window) else: QuestionDialog(_("Reselect Data"), _("Are you sure you want to reselect data?"), _("Run Select Again"), self.set_reselect, self.window) if not self.reselect: return current_date = Date() current_date.set_yr_mon_day(*time.localtime(time.time())[0:3]) self.action = {} widget = self.add_results_frame(_("Select")) document = TextBufDoc(make_basic_stylesheet(), None) document.dbstate = self.dbstate document.uistate = self.uistate document.open("", container=widget) self.sdb = SimpleAccess(self.db) sdoc = SimpleDoc(document) stab = QuickTable(self.sdb) self.table = stab stab.columns(_("Select"), _("Person"), _("Action"), _("Birth Date"), _("Death Date"), _("Evidence"), _("Relative")) self.results_write(_("Processing...\n")) self.filter_option = self.options.menu.get_option_by_name('filter') self.filter = self.filter_option.get_filter() # the actual filter people = self.filter.apply(self.db, self.db.iter_person_handles()) num_people = self.db.get_number_of_people() source_text = self.options.handler.options_dict['source_text'] source = None add_birth = self.options.handler.options_dict['add_birth'] add_death = self.options.handler.options_dict['add_death'] remove_old = self.options.handler.options_dict['remove'] self.MAX_SIB_AGE_DIFF = self.options.handler.options_dict['MAX_SIB_AGE_DIFF'] self.MAX_AGE_PROB_ALIVE = self.options.handler.options_dict['MAX_AGE_PROB_ALIVE'] self.AVG_GENERATION_GAP = self.options.handler.options_dict['AVG_GENERATION_GAP'] if remove_old: with DbTxn("", self.db, batch=True) as self.trans: self.db.disable_signals() self.results_write(_("Removing old estimations... ")) self.progress.set_pass((_("Removing '%s'...") % source_text), num_people) supdate = None for person_handle in people: self.progress.step() pupdate = 0 person = self.db.get_person_from_handle(person_handle) birth_ref = person.get_birth_ref() if birth_ref: birth = self.db.get_event_from_handle(birth_ref.ref) for citation_handle in birth.get_citation_list(): citation = self.db.get_citation_from_handle(citation_handle) source_handle = citation.get_reference_handle() #print "birth handle:", source_handle source = self.db.get_source_from_handle(source_handle) if source: if source.get_title() == source_text: #print("birth event removed from:", # person.gramps_id) person.set_birth_ref(None) person.remove_handle_references('Event',[birth_ref.ref]) # remove note note_list = birth.get_referenced_note_handles() birth.remove_handle_references('Note', [note_handle for (obj_type, note_handle) in note_list]) for (obj_type, note_handle) in note_list: self.db.remove_note(note_handle, self.trans) self.db.remove_event(birth_ref.ref, self.trans) self.db.remove_citation(citation_handle, self.trans) pupdate = 1 supdate = source # found the source. break death_ref = person.get_death_ref() if death_ref: death = self.db.get_event_from_handle(death_ref.ref) for citation_handle in death.get_citation_list(): citation = self.db.get_citation_from_handle(citation_handle) source_handle = citation.get_reference_handle() #print "death handle:", source_handle source = self.db.get_source_from_handle(source_handle) if source: if source.get_title() == source_text: #print("death event removed from:", # person.gramps_id) person.set_death_ref(None) person.remove_handle_references('Event',[death_ref.ref]) # remove note note_list = death.get_referenced_note_handles() death.remove_handle_references('Note', [note_handle for (obj_type, note_handle) in note_list]) for (obj_type, note_handle) in note_list: self.db.remove_note(note_handle, self.trans) self.db.remove_event(death_ref.ref, self.trans) self.db.remove_citation(citation_handle, self.trans) pupdate = 1 supdate = source # found the source. break if pupdate == 1: self.db.commit_person(person, self.trans) if supdate: self.db.remove_source(supdate.handle, self.trans) self.results_write(_("done!\n")) self.db.enable_signals() self.db.request_rebuild() if add_birth or add_death: self.results_write(_("Selecting... \n\n")) self.progress.set_pass(_('Selecting...'), num_people) row = 0 for person_handle in people: self.progress.step() person = self.db.get_person_from_handle(person_handle) birth_ref = person.get_birth_ref() death_ref = person.get_death_ref() add_birth_event, add_death_event = False, False if not birth_ref or not death_ref: date1, date2, explain, other = self.calc_estimates(person) if birth_ref: ev = self.db.get_event_from_handle(birth_ref.ref) date1 = ev.get_date_object() elif not birth_ref and add_birth and date1: if date1.match( current_date, "<"): add_birth_event = True date1.make_vague() else: date1 = Date() else: date1 = Date() if death_ref: ev = self.db.get_event_from_handle(death_ref.ref) date2 = ev.get_date_object() elif not death_ref and add_death and date2: if date2.match( current_date, "<"): add_death_event = True date2.make_vague() else: date2 = Date() else: date2 = Date() # Describe if add_birth_event and add_death_event: action = _("Add birth and death events") elif add_birth_event: action = _("Add birth event") elif add_death_event: action = _("Add death event") else: continue #stab.columns(_("Select"), _("Person"), _("Action"), # _("Birth Date"), _("Death Date"), _("Evidence"), _("Relative")) if add_birth == 1 and not birth_ref: # no date date1 = Date() if add_death == 1 and not death_ref: # no date date2 = Date() if person == other: other = None stab.row("checkbox", person, action, date1, date2, explain or "", other or "") if add_birth_event: stab.set_cell_markup(3, row, "<b>%s</b>" % date_displayer.display(date1)) if add_death_event: stab.set_cell_markup(4, row, "<b>%s</b>" % date_displayer.display(date2)) self.action[person.handle] = (add_birth_event, add_death_event) row += 1 if row > 0: self.results_write(" ") for text, function in BUTTONS: self.make_button(text, function, widget) self.results_write("\n") stab.write(sdoc) self.results_write(" ") for text, function in BUTTONS: self.make_button(text, function, widget) self.results_write("\n") else: self.results_write(_("No events to be added.")) self.results_write("\n") self.results_write("\n") self.set_current_frame(_("Select"))
class CalcToolManagedWindow(PluginWindows.ToolManagedWindowBatch): def __init__(self, *args, **kwargs): PluginWindows.ToolManagedWindowBatch.__init__(self, *args, **kwargs) if self.fail: return self.help_page = self.add_page(_("Help")) self.write_to_page(self.help_page, _("The Calculate Estimated Dates Tool is used to add and remove " "birth and death events for people that are missing these " "events.\n\n" "To use:\n" "1. Go to the Options tab\n" "2. Check the [ ] Remove option to remove previous estimates\n" "3. Select the Add date options to date events with or without dates\n" "4. Click on Execute\n" "5. Select the people with which to add events\n" "6. Click on 'Add Selected Events' button to create\n\n" "NOTES: if you decide to make an event permanent, remove it from " "the Source. Otherwise, it will get removed the next time you " "automatically remove these events.\n\n" "You may have to run the tool repeatedly (without removing previous " "events) to add all of the events possible.")) self.set_current_frame(_("Help")) def get_title(self): return _("Calculate Estimated Dates") def initial_frame(self): return _("Options") def set_reselect(self): self.reselect = True def run(self): BUTTONS = ((_("Select All"), self.select_all), (_("Select None"), self.select_none), (_("Toggle Selection"), self.toggle_select), (_("Add Selected Events"), self.apply_selection), ) if hasattr(self, "table") and self.table: self.reselect = False if self.options.handler.options_dict['remove']: QuestionDialog(_("Remove Events, Notes, and Source and Reselect Data"), _("Are you sure you want to remove previous events, notes, and source and reselect data?"), _("Remove and Run Select Again"), self.set_reselect, self.window) else: QuestionDialog(_("Reselect Data"), _("Are you sure you want to reselect data?"), _("Run Select Again"), self.set_reselect, self.window) if not self.reselect: return current_date = Date() current_date.set_yr_mon_day(*time.localtime(time.time())[0:3]) self.action = {} widget = self.add_results_frame(_("Select")) document = TextBufDoc(make_basic_stylesheet(), None) document.dbstate = self.dbstate document.uistate = self.uistate document.open("", container=widget) self.sdb = SimpleAccess(self.db) sdoc = SimpleDoc(document) stab = QuickTable(self.sdb) self.table = stab stab.columns(_("Select"), _("Person"), _("Action"), _("Birth Date"), _("Death Date"), _("Evidence"), _("Relative")) self.results_write(_("Processing...\n")) self.filter_option = self.options.menu.get_option_by_name('filter') self.filter = self.filter_option.get_filter() # the actual filter people = self.filter.apply(self.db, self.db.iter_person_handles()) num_people = self.db.get_number_of_people() source_text = self.options.handler.options_dict['source_text'] source = None add_birth = self.options.handler.options_dict['add_birth'] add_death = self.options.handler.options_dict['add_death'] remove_old = self.options.handler.options_dict['remove'] self.MAX_SIB_AGE_DIFF = self.options.handler.options_dict['MAX_SIB_AGE_DIFF'] self.MAX_AGE_PROB_ALIVE = self.options.handler.options_dict['MAX_AGE_PROB_ALIVE'] self.AVG_GENERATION_GAP = self.options.handler.options_dict['AVG_GENERATION_GAP'] if remove_old: with DbTxn("", self.db, batch=True) as self.trans: self.db.disable_signals() self.results_write(_("Removing old estimations... ")) self.progress.set_pass((_("Removing '%s'...") % source_text), num_people) supdate = None for person_handle in people: self.progress.step() pupdate = 0 person = self.db.get_person_from_handle(person_handle) birth_ref = person.get_birth_ref() if birth_ref: birth = self.db.get_event_from_handle(birth_ref.ref) for citation_handle in birth.get_citation_list(): citation = self.db.get_citation_from_handle(citation_handle) source_handle = citation.get_reference_handle() #print "birth handle:", source_handle source = self.db.get_source_from_handle(source_handle) if source: if source.get_title() == source_text: #print("birth event removed from:", # person.gramps_id) person.set_birth_ref(None) person.remove_handle_references('Event',[birth_ref.ref]) # remove note note_list = birth.get_referenced_note_handles() birth.remove_handle_references('Note', [note_handle for (obj_type, note_handle) in note_list]) for (obj_type, note_handle) in note_list: self.db.remove_note(note_handle, self.trans) self.db.remove_event(birth_ref.ref, self.trans) self.db.remove_citation(citation_handle, self.trans) pupdate = 1 supdate = source # found the source. break death_ref = person.get_death_ref() if death_ref: death = self.db.get_event_from_handle(death_ref.ref) for citation_handle in death.get_citation_list(): citation = self.db.get_citation_from_handle(citation_handle) source_handle = citation.get_reference_handle() #print "death handle:", source_handle source = self.db.get_source_from_handle(source_handle) if source: if source.get_title() == source_text: #print("death event removed from:", # person.gramps_id) person.set_death_ref(None) person.remove_handle_references('Event',[death_ref.ref]) # remove note note_list = death.get_referenced_note_handles() death.remove_handle_references('Note', [note_handle for (obj_type, note_handle) in note_list]) for (obj_type, note_handle) in note_list: self.db.remove_note(note_handle, self.trans) self.db.remove_event(death_ref.ref, self.trans) self.db.remove_citation(citation_handle, self.trans) pupdate = 1 supdate = source # found the source. break if pupdate == 1: self.db.commit_person(person, self.trans) if supdate: self.db.remove_source(supdate.handle, self.trans) self.results_write(_("done!\n")) self.db.enable_signals() self.db.request_rebuild() if add_birth or add_death: self.results_write(_("Selecting... \n\n")) self.progress.set_pass(_('Selecting...'), num_people) row = 0 for person_handle in people: self.progress.step() person = self.db.get_person_from_handle(person_handle) birth_ref = person.get_birth_ref() death_ref = person.get_death_ref() add_birth_event, add_death_event = False, False if not birth_ref or not death_ref: date1, date2, explain, other = self.calc_estimates(person) if birth_ref: ev = self.db.get_event_from_handle(birth_ref.ref) date1 = ev.get_date_object() elif not birth_ref and add_birth and date1: if date1.match( current_date, "<"): add_birth_event = True date1.make_vague() else: date1 = Date() else: date1 = Date() if death_ref: ev = self.db.get_event_from_handle(death_ref.ref) date2 = ev.get_date_object() elif not death_ref and add_death and date2: if date2.match( current_date, "<"): add_death_event = True date2.make_vague() else: date2 = Date() else: date2 = Date() # Describe if add_birth_event and add_death_event: action = _("Add birth and death events") elif add_birth_event: action = _("Add birth event") elif add_death_event: action = _("Add death event") else: continue #stab.columns(_("Select"), _("Person"), _("Action"), # _("Birth Date"), _("Death Date"), _("Evidence"), _("Relative")) if add_birth == 1 and not birth_ref: # no date date1 = Date() if add_death == 1 and not death_ref: # no date date2 = Date() if person == other: other = None stab.row("checkbox", person, action, date1, date2, explain or "", other or "") if add_birth_event: stab.set_cell_markup(3, row, "<b>%s</b>" % date_displayer.display(date1)) if add_death_event: stab.set_cell_markup(4, row, "<b>%s</b>" % date_displayer.display(date2)) self.action[person.handle] = (add_birth_event, add_death_event) row += 1 if row > 0: self.results_write(" ") for text, function in BUTTONS: self.make_button(text, function, widget) self.results_write("\n") stab.write(sdoc) self.results_write(" ") for text, function in BUTTONS: self.make_button(text, function, widget) self.results_write("\n") else: self.results_write(_("No events to be added.")) self.results_write("\n") self.results_write("\n") self.set_current_frame(_("Select")) def make_button(self, text, function, widget): from gi.repository import Gtk button = Gtk.Button(text) buffer = widget.get_buffer() iter = buffer.get_end_iter() anchor = buffer.create_child_anchor(iter) widget.add_child_at_anchor(button, anchor) button.connect("clicked", function) button.show() self.results_write(" ") def select_all(self, obj): select_col = self.table.model_index_of_column[_("Select")] for row in self.table.treeview.get_model(): row[select_col] = True def select_none(self, obj): select_col = self.table.model_index_of_column[_("Select")] for row in self.table.treeview.get_model(): row[select_col] = False def toggle_select(self, obj): select_col = self.table.model_index_of_column[_("Select")] for row in self.table.treeview.get_model(): row[select_col] = not row[select_col] def apply_selection(self, *args, **kwargs): # Do not add birth or death event if one exists, no matter what if self.table.treeview.get_model() is None: return with DbTxn("", self.db, batch=True) as self.trans: self.pre_run() source_text = self.options.handler.options_dict['source_text'] select_col = self.table.model_index_of_column[_("Select")] source = self.get_or_create_source(source_text) self.db.disable_signals() self.results_write(_("Selecting... ")) self.progress.set_pass((_("Adding events '%s'...") % source_text), len(self.table.treeview.get_model())) count = 0 for row in self.table.treeview.get_model(): self.progress.step() select = row[select_col] # live select value if not select: continue pupdate = False index = row[0] # order put in row_data = self.table.get_raw_data(index) person = row_data[1] # check, person, action, date1, date2 date1 = row_data[3] # date date2 = row_data[4] # date evidence = row_data[5] # evidence other = row_data[6] # other person if other: other_name = self.sdb.name(other) else: other_name = None add_birth_event, add_death_event = self.action[person.handle] birth_ref = person.get_birth_ref() death_ref = person.get_death_ref() if not birth_ref and add_birth_event: if other_name: explanation = _("Added birth event based on %(evidence)s, from %(name)s") % { 'evidence' : evidence, 'name' : other_name } else: explanation = _("Added birth event based on %s") % evidence modifier = self.get_modifier("birth") birth = self.create_event(_("Estimated birth date"), EventType.BIRTH, date1, source, explanation, modifier) event_ref = EventRef() event_ref.set_reference_handle(birth.get_handle()) person.set_birth_ref(event_ref) pupdate = True count += 1 if not death_ref and add_death_event: if other_name: explanation = _("Added death event based on %(evidence)s, from %(person)s") % { 'evidence' : evidence, 'person' : other_name } else: explanation = _("Added death event based on %s") % evidence modifier = self.get_modifier("death") death = self.create_event(_("Estimated death date"), EventType.DEATH, date2, source, explanation, modifier) event_ref = EventRef() event_ref.set_reference_handle(death.get_handle()) person.set_death_ref(event_ref) pupdate = True count += 1 if pupdate: self.db.commit_person(person, self.trans) self.results_write(_(" Done! Committing...")) self.results_write("\n") self.db.enable_signals() self.db.request_rebuild() self.results_write(_("Added %d events.") % count) self.results_write("\n\n") self.progress.close() def get_modifier(self, event_type): setting = self.options.handler.options_dict['dates'] if event_type == "birth": if setting == 0: return Date.MOD_ABOUT else: return Date.MOD_AFTER else: if setting == 0: return Date.MOD_ABOUT else: return Date.MOD_BEFORE def get_or_create_source(self, source_text): source_list = self.db.get_source_handles() for source_handle in source_list: source = self.db.get_source_from_handle(source_handle) if source.get_title() == source_text: return source source = Source() source.set_title(source_text) self.db.add_source(source, self.trans) return source def create_event(self, description=_("Estimated date"), type=None, date=None, source=None, note_text="", modifier=None): event = Event() event.set_description(description) note = Note() note.handle = create_id() note.type.set(NoteType.EVENT) note.set(note_text) self.db.add_note(note, self.trans) event.add_note(note.handle) if type: event.set_type(EventType(type)) if date: if modifier: date.set_modifier(modifier) date.set_quality(Date.QUAL_ESTIMATED) date.set_yr_mon_day(date.get_year(), 0, 0) event.set_date_object(date) if source: citation = Citation() citation.set_reference_handle(source.get_handle()) self.db.add_citation(citation, self.trans) event.add_citation(citation.get_handle()) self.db.commit_source(source, self.trans) self.db.add_event(event, self.trans) return event def calc_estimates(self, person): return probably_alive_range(person, self.db, self.MAX_SIB_AGE_DIFF, self.MAX_AGE_PROB_ALIVE, self.AVG_GENERATION_GAP)
def write_report(self): """ The routine that actually creates the report. At this point, the document is opened and ready for writing. """ sdb = SimpleAccess(self.database) self.doc.start_paragraph("NoteLink-Title") title = _("Note Link Check Report") mark = IndexMark(title, INDEX_TYPE_TOC, 1) self.doc.write_text(title, mark) self.doc.end_paragraph() self.doc.start_table('NoteLinkTable','NoteLink-Table') self.doc.start_row() self.doc.start_cell('NoteLink-TableCell') self.doc.start_paragraph('NoteLink-Normal-Bold') self.doc.write_text(_("Note ID")) self.doc.end_paragraph() self.doc.end_cell() self.doc.start_cell('NoteLink-TableCell') self.doc.start_paragraph('NoteLink-Normal-Bold') self.doc.write_text(_("Link Type")) self.doc.end_paragraph() self.doc.end_cell() self.doc.start_cell('NoteLink-TableCell') self.doc.start_paragraph('NoteLink-Normal-Bold') self.doc.write_text(_("Links To")) self.doc.end_paragraph() self.doc.end_cell() self.doc.start_cell('NoteLink-TableCell') self.doc.start_paragraph('NoteLink-Normal-Bold') self.doc.write_text(_("Status")) self.doc.end_paragraph() self.doc.end_cell() self.doc.end_row() for note in self.database.iter_notes(): for (ldomain, ltype, lprop, lvalue) in note.get_links(): if ldomain == "gramps": tagtype = _(ltype) ref_obj = sdb.get_link(ltype, lprop, lvalue) if ref_obj: tagvalue = sdb.describe(ref_obj) tagcheck = _("Ok") else: tagvalue = "%s://%s/%s/%s" % (ldomain, ltype, lprop, lvalue) tagcheck = _("Failed") else: tagtype = _("Internet") tagvalue = lvalue tagcheck = "" self.doc.start_row() self.doc.start_cell('NoteLink-TableCell') self.doc.start_paragraph('NoteLink-Normal') self.doc.write_text(note.gramps_id) self.doc.end_paragraph() self.doc.end_cell() self.doc.start_cell('NoteLink-TableCell') self.doc.start_paragraph('NoteLink-Normal') self.doc.write_text(tagtype) self.doc.end_paragraph() self.doc.end_cell() self.doc.start_cell('NoteLink-TableCell') self.doc.start_paragraph('NoteLink-Normal') self.doc.write_text(tagvalue) self.doc.end_paragraph() self.doc.end_cell() self.doc.start_cell('NoteLink-TableCell') self.doc.start_paragraph('NoteLink-Normal') self.doc.write_text(tagcheck) self.doc.end_paragraph() self.doc.end_cell() self.doc.end_row() self.doc.end_table()
class EditLink(ManagedWindow): def __init__(self, dbstate, uistate, track, url, callback): self.url = url self.dbstate = dbstate self.simple_access = SimpleAccess(self.dbstate.db) self.callback = callback ManagedWindow.__init__(self, uistate, track, url) self._local_init() self._connect_signals() self.show() def _local_init(self): self.top = Glade() self.set_window(self.top.toplevel, self.top.get_object("title"), _('Link Editor')) self.setup_configs('interface.editlink', 600, 160) self.uri_list = self.top.get_object('link_type') for text in [ _("Internet Address"), # 0 this order range above _("Event"), # 1 _("Family"), # 2 _("Media"), # 3 _("Note"), # 4 _("Person"), # 5 _("Place"), # 6 _("Repository"), # 7 _("Source"), # 8 _("Citation"), # 9 ]: self.uri_list.append_text(text) self.pick_item = self.top.get_object('button1') self.new_button = self.top.get_object('new') self.edit_button = self.top.get_object('edit') self.selected = self.top.get_object('label1') self.url_link = self.top.get_object('entry1') self.uri_list.connect("changed", self._on_type_changed) self.pick_item.connect("clicked", self._on_pick_one) self.new_button.connect("clicked", self._on_new) self.edit_button.connect("clicked", self._on_edit_one) if self.url.startswith("gramps://"): object_class, prop, value = self.url[9:].split("/", 2) if object_class == "Event": self.uri_list.set_active(EVENT) elif object_class == "Family": self.uri_list.set_active(FAMILY) elif object_class == "Media": self.uri_list.set_active(MEDIA) elif object_class == "Note": self.uri_list.set_active(NOTE) elif object_class == "Person": self.uri_list.set_active(PERSON) elif object_class == "Place": self.uri_list.set_active(PLACE) elif object_class == "Repository": self.uri_list.set_active(REPOSITORY) elif object_class == "Source": self.uri_list.set_active(SOURCE) elif object_class == "Citation": self.uri_list.set_active(CITATION) # set texts: self.selected.set_text(self.display_link(object_class, prop, value)) self.url_link.set_text("gramps://%s/%s/%s" % (object_class, prop, value)) else: self.uri_list.set_active(WEB) self.url_link.set_text(self.url) self.url_link.connect("changed", self.update_ui) def update_ui(self, widget): url = self.url_link.get_text() # text needs to have 3 or more chars://and at least one char match = re.match(r"\w{3,}://\w+", url) if match: self.ok_button.set_sensitive(True) else: self.ok_button.set_sensitive(False) def display_link(self, obj_class, prop, value): return self.simple_access.display(obj_class, prop, value) def _on_new_callback(self, obj): object_class = obj.__class__.__name__ self.selected.set_text( self.display_link(object_class, "handle", obj.handle)) self.url_link.set_text("gramps://%s/%s/%s" % (object_class, "handle", obj.handle)) def _on_new(self, widget): from ..editors import EditObject object_class = OBJECT_MAP[self.uri_list.get_active()] EditObject(self.dbstate, self.uistate, self.track, object_class, callback=self._on_new_callback) def _on_edit_one(self, widget): from ..editors import EditObject uri = self.url_link.get_text() if uri.startswith("gramps://"): obj_class, prop, value = uri[9:].split("/", 2) EditObject(self.dbstate, self.uistate, self.track, obj_class, prop, value) def _on_pick_one(self, widget): from ..selectors import SelectorFactory object_class = OBJECT_MAP[self.uri_list.get_active()] Select = SelectorFactory(object_class) uri = self.url_link.get_text() default = None if uri.startswith("gramps://"): obj_class, prop, value = uri[9:].split("/", 2) if object_class == obj_class: if prop == "handle": default = value elif (prop == "gramps_id" and object_class in OBJECT_MAP.values()): person = self.dbstate.db.method('get_%s_from_gramps_id', object_class)(value) if person: default = person.handle d = Select(self.dbstate, self.uistate, self.track, default=default) result = d.run() if result: prop = "handle" value = result.handle self.selected.set_text(self.display_link(object_class, prop, value)) self.url_link.set_text("gramps://%s/%s/%s" % (object_class, prop, value)) def _on_type_changed(self, widget): self.selected.set_text("") if self.uri_list.get_active() == WEB: self.url_link.set_sensitive(True) self.pick_item.set_sensitive(False) self.new_button.set_sensitive(False) self.edit_button.set_sensitive(False) else: self.url_link.set_sensitive(False) self.pick_item.set_sensitive(True) self.new_button.set_sensitive(True) self.edit_button.set_sensitive(True) def get_uri(self): if self.uri_list.get_active() == WEB: return self.url_link.get_text() else: return self.url_link.get_text() def _connect_signals(self): self.define_cancel_button(self.top.get_object('button125')) self.ok_button = self.top.get_object('button124') self.define_ok_button(self.ok_button, self.save) # TODO help button (rename glade button name) self.define_help_button(self.top.get_object('button130'), WIKI_HELP_PAGE, WIKI_HELP_SEC) self.update_ui(self.url_link) def build_menu_names(self, obj): etitle = _('Link Editor') return (etitle, etitle) def define_ok_button(self, button, function): button.connect('clicked', function) def save(self, widget): self.callback(self.get_uri()) self.close() def define_cancel_button(self, button): button.connect('clicked', self.close) def define_help_button(self, button, webpage='', section=''): button.connect('clicked', lambda x: display_help(webpage, section))
def write_report(self): """ The short method that runs through each month and creates a page. """ self.doc.start_paragraph('DIFF-Title') self.doc.write_text(_("Database Differences Report")) self.doc.end_paragraph() self.doc.start_table('DiffTable', 'DIFF-Table2') self.doc.start_row() self.doc.start_cell('DIFF-TableCellNoBorder') self.doc.start_paragraph('DIFF-TableHeading') self.doc.write_text("Database:") self.doc.end_paragraph() self.doc.end_cell() self.doc.start_cell('DIFF-TableCellNoBorder') self.doc.start_paragraph('DIFF-Text') self.doc.write_text(str(self.database.get_dbname())) self.doc.end_paragraph() self.doc.end_cell() self.doc.end_row() self.doc.start_row() self.doc.start_cell('DIFF-TableCellNoBorder') self.doc.start_paragraph('DIFF-TableHeading') self.doc.write_text(_("File:")) self.doc.end_paragraph() self.doc.end_cell() self.doc.start_cell('DIFF-TableCellNoBorder') self.doc.start_paragraph('DIFF-Text') self.doc.write_text(self.filename) self.doc.end_paragraph() self.doc.end_cell() self.doc.end_row() self.doc.end_table() self.doc.start_paragraph('DIFF-Heading') self.doc.write_text("") self.doc.end_paragraph() self.database2 = import_as_dict(self.filename, self._user) if self.database2 is None: return self.sa = [SimpleAccess(self.database), SimpleAccess(self.database2)] diffs, added, missing = diff_dbs(self.database, self.database2, self._user) if self.show_diff: self.doc.start_paragraph('DIFF-Heading') self.doc.write_text(_("Differences between Database and File")) self.doc.end_paragraph() last_object = None if diffs: self._user.begin_progress(_('Family Tree Differences'), _('Processing...'), len(diffs)) for diff in diffs: self._user.step_progress() obj_type, item1, item2 = diff if last_object != item1: if last_object != None: self.doc.end_table() self.doc.start_paragraph('DIFF-Heading') self.doc.write_text("") self.doc.end_paragraph() self.doc.start_table('DiffTable', 'DIFF-Table3') last_object = item1 if hasattr(item1, "gramps_id"): self.start_list(self.doc, "%s: %s" % (obj_type, item1.gramps_id), "Database", "File") else: self.start_list( self.doc, "%s: %s" % (obj_type, item1.get_name()), "Database", "File") self.report_diff(obj_type, to_struct(item1), to_struct(item2), self.doc) self.doc.end_table() else: self.doc.start_table('DiffTable', 'DIFF-Table3') self.start_list(self.doc, _("No differences"), "", "") self.doc.end_table() self.doc.start_paragraph('DIFF-Heading') self.doc.write_text("") self.doc.end_paragraph() if self.show_missing: self.doc.start_paragraph('DIFF-Heading') self.doc.write_text( _("Missing items in File that are added in Database")) self.doc.end_paragraph() if missing: for pair in missing: obj_type, item = pair self.doc.start_paragraph('DIFF-Text') self.doc.write_text( _("Missing %s: %s") % (obj_type, self.sa[0].describe(item))) self.doc.end_paragraph() else: self.doc.start_paragraph('DIFF-Text') self.doc.write_text(_("Nothing missing")) self.doc.end_paragraph() self.doc.start_paragraph('DIFF-Heading') self.doc.write_text("") self.doc.end_paragraph() if self.show_added: self.doc.start_paragraph('DIFF-Heading') self.doc.write_text( _("Added items in File that are missing in Database")) self.doc.end_paragraph() if added: for pair in added: obj_type, item = pair self.doc.start_paragraph('DIFF-Text') self.doc.write_text( _("Added %s: %s ") % (obj_type, self.sa[1].describe(item))) self.doc.end_paragraph() else: self.doc.start_paragraph('DIFF-Text') self.doc.write_text(_("Nothing added")) self.doc.end_paragraph() self.doc.start_paragraph('DIFF-Heading') self.doc.write_text("") self.doc.end_paragraph() self._user.end_progress()
class DBI(object): """ The SQL-like interface to the database and document instances. """ def __init__(self, database, document=None): self.database = database self.document = document self.data = {} self.select = 0 self.flat = False self.raw = False if self.database: for name in ('Person', 'Family', 'Event', 'Place', 'Repository', 'Source', 'Citation', 'Media', 'Note', 'Tag'): d = self.database._tables[name]["class_func"]().to_struct() self.data[name.lower()] = d.keys() # The macros: self.shortcuts = { "SURNAME": "primary_name.surname_list[0].surname", "GIVEN": "primary_name.first_name", } def parse(self, query): """ Parse the query. """ self.query_text = query.replace("\n", " ").strip() lexed = self.lexer(self.query_text) #print(lexed) self.parser(lexed) for col_name in self.columns[:]: # copy if col_name == "*": self.columns.remove('*') # this is useful to see what _class it is: self.columns.extend(self.get_columns(self.table)) # otherwise remove metadata: #self.columns.extend([col for col in self.get_columns(self.table) if not col.startswith("_")) def lexer(self, string): """ Given a string, break into a list of chunks. """ retval = [] state = None current = "" stack = [] i = 0 # Handle macros: for key in self.shortcuts.keys(): string = string.replace(key, self.shortcuts[key]) # (some "expression" in ok) # func(some "expression" in (ok)) # list[1][0] # [x for x in list] while i < len(string): ch = string[i] #print("lex:", i, ch, state, retval, current) if state == "in-double-quote": if ch == '"': state = stack.pop() current += ch elif state == "in-single-quote": if ch == "'": state = stack.pop() current += ch elif state == "in-expr": if ch == ")": state = stack.pop() elif ch == "(": stack.append("in-expr") current += ch elif state == "in-square-bracket": if ch == "]": state = stack.pop() elif ch == "[": stack.append("in-square-bracket") current += ch elif ch == '"': stack.append(state) state = "in-double-quote" current += ch elif ch == "'": stack.append(state) state = "in-single-quote" current += ch elif ch == "(": stack.append(state) state = "in-expr" current += "(" elif ch == "[": stack.append(state) state = "in-square-bracket" current += "[" elif ch == ",": if current: retval.append(current) retval.append(",") current = "" elif ch == "=": if current: retval.append(current) retval.append("=") current = "" elif ch in [' ', '\t', '\n', ";"]: # break if current: retval.append(current) if current.upper() == "WHERE": # HACK: get rest of string: if string[-1] == ";": retval.append(string[i + 1:-1]) i = len(string) - 2 else: retval.append(string[i + 1:]) i = len(string) - 1 current = "" else: pass # ignore whitespace else: current += ch i += 1 if current: retval.append(current) #print("lexed:", retval) return retval def parser(self, lex): """ Takes output of lexer, and sets the values. After parser, the DBI will be ready to process query. """ self.action = None self.table = None self.columns = [] self.setcolumns = [] self.values = [] self.aliases = {} self.limit = None self.where = None self.index = 0 while self.index < len(lex): symbol = lex[self.index] if symbol.upper() == "FROM": # from table select *; self.index += 1 if self.index < len(lex): self.table = lex[self.index] elif symbol.upper() == "SELECT": # select a, b from table; self.action = "SELECT" self.index += 1 self.columns.append(lex[self.index]) self.index += 1 while self.index < len(lex) and lex[self.index].upper() in [ ",", "AS" ]: sep = lex[self.index] if sep == ",": self.index += 1 self.columns.append(lex[self.index]) self.index += 1 elif sep.upper() == "AS": self.index += 1 # alias self.aliases[self.columns[-1]] = lex[self.index] self.index += 1 self.index -= 1 elif symbol.upper() == "DELETE": # delete from table where item == 1; self.action = "DELETE" self.columns = ["gramps_id"] elif symbol.upper() == "SET": # SET x=1, y=2 self.index += 1 self.setcolumns.append(lex[self.index]) # first column self.index += 1 # equal sign # = self.index += 1 # value self.values.append(lex[self.index]) self.index += 1 # comma while self.index < len(lex) and lex[self.index] == ",": self.index += 1 # next column self.setcolumns.append(lex[self.index]) self.index += 1 # equal # = self.index += 1 # value self.values.append(lex[self.index]) self.index += 1 # comma? self.index -= 1 elif symbol.upper() == "LIMIT": self.index += 1 # after LIMIT number = lex[self.index] self.index += 1 # maybe a comma if self.index < len(lex) and lex[self.index] == ",": self.index += 1 # after "," stop = lex[self.index] self.limit = (int(number), int(stop)) else: self.limit = (0, int(number)) self.index -= 1 elif symbol.upper() == "WHERE": # how can we get all of Python expressions? # this assumes all by ; self.index += 1 self.where = lex[self.index] elif symbol.upper() == "UPDATE": # update table set x=1, y=2 where condition; # UPDATE gramps_id set tag_list = Tag("Betty") from person where "Betty" in primary_name.first_name self.columns = ["gramps_id"] self.action = "UPDATE" if self.index < len(lex): self.index += 1 self.table = lex[self.index] elif symbol.upper() == "FLAT": self.flat = True elif symbol.upper() == "EXPAND": self.flat = False elif symbol.upper() == "RAW": self.raw = True elif symbol.upper() == "NORAW": self.raw = False else: raise AttributeError("invalid SQL expression: '... %s ...'" % symbol) self.index += 1 def close(self): """ Close up any progress widgets or dialogs. """ #try: # self.progress.close() #except: pass def clean_titles(self, columns): """ Take the columns and turn them into strings for the table. """ retval = [] for column in columns: if column in self.aliases: column = self.aliases[column] retval.append(column.replace("_", "__")) return retval def query(self, query): self.parse(query) self.select = 0 start_time = time.time() class Table(): results = [] def row(self, *args, **kwargs): self.results.append([args, kwargs]) def get_rows(self): return [list(item[0]) for item in self.results] table = Table() self.sdb = SimpleAccess(self.database) self.process_table(table) # a class that has .row(1, 2, 3, ...) print( _("%d rows processed in %s seconds.\n") % (self.select, time.time() - start_time)) return table def eval(self): """ Execute the query. """ self.sdb = SimpleAccess(self.database) self.stab = QuickTable(self.sdb) self.select = 0 start_time = time.time() self.process_table(self.stab) # a class that has .row(1, 2, 3, ...) if self.select > 0: self.stab.columns(*self.clean_titles(self.columns)) self.sdoc = SimpleDoc(self.document) self.sdoc.title(self.query_text) self.sdoc.paragraph("\n") self.sdoc.paragraph("%d rows processed in %s seconds.\n" % (self.select, time.time() - start_time)) self.stab.write(self.sdoc) self.sdoc.paragraph("") return _("%d rows processed in %s seconds.\n") % ( self.select, time.time() - start_time) def get_columns(self, table): """ Get the columns for the given table. """ if self.database: retval = self.data[table.lower()] return retval # [self.name] + retval else: return ["*"] def process_table(self, table): """ Given a table name, process the query on the elements of the table. """ # 'Person', 'Family', 'Source', 'Citation', 'Event', 'Media', # 'Place', 'Repository', 'Note', 'Tag' # table: a class that has .row(1, 2, 3, ...) if self.table == "person": self.do_query(self.sdb.all_people(), table) elif self.table == "family": self.do_query(self.sdb.all_families(), table) elif self.table == "event": self.do_query(self.sdb.all_events(), table) elif self.table == "source": self.do_query(self.sdb.all_sources(), table) elif self.table == "tag": self.do_query(self.sdb.all_tags(), table) elif self.table == "citation": self.do_query(self.sdb.all_citations(), table) elif self.table == "media": self.do_query(self.sdb.all_media(), table) elif self.table == "place": self.do_query(self.sdb.all_places(), table) elif self.table == "repository": self.do_query(self.sdb.all_repositories(), table) elif self.table == "note": self.do_query(self.sdb.all_notes(), table) else: raise AttributeError("no such table: '%s'" % self.table) def get_tag(self, name): tag = self.database.get_tag_from_name(name) if tag is None: tag = gramps.gen.lib.Tag() tag.set_name(name) trans_class = self.database.get_transaction_class() with trans_class("QueryQuickview new Tag", self.database, batch=False) as trans: self.database.add_tag(tag, trans) return Handle("Tag", tag.handle) def make_env(self, **kwargs): """ An environment with which to eval elements. """ retval = Environment({ _("Date"): gramps.gen.lib.date.Date, _("Today"): gramps.gen.lib.date.Today(), "random": random, "re": re, "db": self.database, "sdb": self.sdb, "lib": gramps.gen.lib, "_": _, "Tag": self.get_tag, }) retval.update(__builtins__) retval.update(kwargs) return retval def stringify(self, value): """ Turn the value into an appropriate string representation. """ if self.raw: return value if isinstance(value, Struct): return self.stringify(value.struct) elif isinstance(value, (list, tuple)): if len(value) == 0 and not self.flat: return "" elif len(value) == 1 and not self.flat: return self.stringify(value[0]) else: return "[%s]" % (", ".join(map(self.stringify, value))) elif isinstance(value, PrimaryObject): return value else: return str(value) def clean(self, values, names): """ Given the values and names of columns, change the values into string versions for the display table. """ if self.raw: return values retval = [] for i in range(len(values)): if names[i].endswith("handle"): retval.append(repr(values[i].struct["handle"])) else: retval.append(self.stringify(values[i])) return retval def do_query(self, items, table): """ Perform the query on the items in the named table. """ # table: a class that has .row(1, 2, 3, ...) with self.database.get_transaction_class()("QueryQuickview", self.database, batch=True) as trans: ROWNUM = 0 env = self.make_env() for item in items: if item is None: continue row = [] row_env = [] # "col[0]" in WHERE clause will return first column of selection: env["col"] = row_env env["ROWNUM"] = ROWNUM env["object"] = item struct = Struct(item.to_struct(), self.database) env.set_struct(struct) for col in self.columns: try: value = eval(col, env) except: value = None row.append(value) # allow col[#] reference: row_env.append(value) # an alias? if col in self.aliases: env[self.aliases[col]] = value # Should we include this row? if self.where: try: result = eval(self.where, env) except: continue else: if self.action in ["DELETE", "UPDATE"]: result = True else: result = any([col != None for col in row]) # are they all None? # If result, then append the row if result: if (self.limit is None) or (self.limit[0] <= ROWNUM < self.limit[1]): if self.action == "SELECT": if not self.flat: # Join by rows: products = [] columns = [] count = 0 for col in row: if ((isinstance(col, Struct) and isinstance(col.struct, list) and len(col.struct) > 0) or (isinstance(col, list) and len(col) > 0)): products.append(col) columns.append(count) count += 1 if len(products) > 0: current = self.clean(row, self.columns) for items in itertools.product(*products): for i in range(len(items)): current[ columns[i]] = self.stringify( items[i]) table.row( *current, link=(item.__class__.__name__, item.handle)) self.select += 1 else: table.row(*self.clean(row, self.columns), link=(item.__class__.__name__, item.handle)) self.select += 1 else: table.row(*self.clean(row, self.columns), link=(item.__class__.__name__, item.handle)) self.select += 1 elif self.action == "UPDATE": # update table set col=val, col=val where expr; table.row(*self.clean(row, self.columns), link=(item.__class__.__name__, item.handle)) self.select += 1 for i in range(len(self.setcolumns)): struct.setitem(self.setcolumns[i], eval(self.values[i], env), trans=trans) elif self.action == "DELETE": table.row(*self.clean(row, self.columns)) self.select += 1 self.database.remove_instance(item, trans) else: raise AttributeError("unknown command: '%s'", self.action) ROWNUM += 1 if (self.limit is not None) and (ROWNUM >= self.limit[1]): break
def write_report(self): """ The routine that actually creates the report. At this point, the document is opened and ready for writing. """ sdb = SimpleAccess(self.database) self.doc.start_paragraph("NoteLink-Title") title = _("Note Link Check Report") mark = IndexMark(title, INDEX_TYPE_TOC, 1) self.doc.write_text(title, mark) self.doc.end_paragraph() self.doc.start_table('NoteLinkTable', 'NoteLink-Table') self.doc.start_row() self.doc.start_cell('NoteLink-TableCell') self.doc.start_paragraph('NoteLink-Normal-Bold') self.doc.write_text(_("Note ID")) self.doc.end_paragraph() self.doc.end_cell() self.doc.start_cell('NoteLink-TableCell') self.doc.start_paragraph('NoteLink-Normal-Bold') self.doc.write_text(_("Link Type")) self.doc.end_paragraph() self.doc.end_cell() self.doc.start_cell('NoteLink-TableCell') self.doc.start_paragraph('NoteLink-Normal-Bold') self.doc.write_text(_("Links To")) self.doc.end_paragraph() self.doc.end_cell() self.doc.start_cell('NoteLink-TableCell') self.doc.start_paragraph('NoteLink-Normal-Bold') self.doc.write_text(_("Status")) self.doc.end_paragraph() self.doc.end_cell() self.doc.end_row() for note in self.database.iter_notes(): for (ldomain, ltype, lprop, lvalue) in note.get_links(): if ldomain == "gramps": tagtype = _(ltype) ref_obj = sdb.get_link(ltype, lprop, lvalue) if ref_obj: tagvalue = sdb.describe(ref_obj) tagcheck = _("Ok") else: tagvalue = "%s://%s/%s/%s" % (ldomain, ltype, lprop, lvalue) tagcheck = _("Failed") else: tagtype = _("Internet") tagvalue = lvalue tagcheck = "" self.doc.start_row() self.doc.start_cell('NoteLink-TableCell') self.doc.start_paragraph('NoteLink-Normal') self.doc.write_text(note.gramps_id) self.doc.end_paragraph() self.doc.end_cell() self.doc.start_cell('NoteLink-TableCell') self.doc.start_paragraph('NoteLink-Normal') self.doc.write_text(tagtype) self.doc.end_paragraph() self.doc.end_cell() self.doc.start_cell('NoteLink-TableCell') self.doc.start_paragraph('NoteLink-Normal') self.doc.write_text(tagvalue) self.doc.end_paragraph() self.doc.end_cell() self.doc.start_cell('NoteLink-TableCell') self.doc.start_paragraph('NoteLink-Normal') self.doc.write_text(tagcheck) self.doc.end_paragraph() self.doc.end_cell() self.doc.end_row() self.doc.end_table()
def run(database, document, main_event): """ Displays events on a specific date of an event (or date) Takes an Event or Date object """ if isinstance(main_event, Date): main_date = main_event else: main_date = main_event.get_date_object() cal = main_date.get_calendar() # setup the simple access functions sdb = SimpleAccess(database) sdoc = SimpleDoc(document) stab = QuickTable(sdb) stab.set_link_col(3) yeartab = QuickTable(sdb) yeartab.set_link_col(3) histab = QuickTable(sdb) histab.set_link_col(3) # display the title sdoc.title(_("Events of %(date)s") % {"date": sdb.date_string(main_date)}) sdoc.paragraph("") stab.columns(_("Date"), _("Type"), _("Place"), _("Reference")) yeartab.columns(_("Date"), _("Type"), _("Place"), _("Reference")) histab.columns(_("Date"), _("Type"), _("Place"), _("Reference")) for event in database.iter_events(): date = event.get_date_object() date.convert_calendar(cal) if date.get_year() == 0: continue if (date.get_year() == main_date.get_year() and date.get_month() == main_date.get_month() and date.get_day() == main_date.get_day()): for (objclass, handle) in database.find_backlink_handles(event.handle): ref = get_ref(database, objclass, handle) stab.row(date, sdb.event_type(event), sdb.event_place(event), ref) elif (date.get_month() == main_date.get_month() and date.get_day() == main_date.get_day() and date.get_month() != 0): for (objclass, handle) in database.find_backlink_handles(event.handle): ref = get_ref(database, objclass, handle) histab.row(date, sdb.event_type(event), sdb.event_place(event), ref) elif (date.get_year() == main_date.get_year()): for (objclass, handle) in database.find_backlink_handles(event.handle): ref = get_ref(database, objclass, handle) yeartab.row(date, sdb.event_type(event), sdb.event_place(event), ref) document.has_data = False if stab.get_row_count() > 0: document.has_data = True sdoc.paragraph(_("Events on this exact date")) stab.write(sdoc) else: sdoc.paragraph(_("No events on this exact date")) sdoc.paragraph("") sdoc.paragraph("") if histab.get_row_count() > 0: document.has_data = True sdoc.paragraph(_("Other events on this month/day in history")) histab.write(sdoc) else: sdoc.paragraph(_("No other events on this month/day in history")) sdoc.paragraph("") sdoc.paragraph("") if yeartab.get_row_count() > 0: document.has_data = True sdoc.paragraph( _("Other events in %(year)d") % {"year": main_date.get_year()}) yeartab.write(sdoc) else: sdoc.paragraph( _("No other events in %(year)d") % {"year": main_date.get_year()}) sdoc.paragraph("") sdoc.paragraph("")