示例#1
0
文件: lineage.py 项目: vperic/gramps
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)
示例#2
0
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)
示例#3
0
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)
示例#4
0
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 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("")
示例#7
0
    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 = []
示例#8
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.
    """
    # 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)
示例#9
0
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)
示例#10
0
    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)
示例#12
0
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("")
示例#13
0
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("")
示例#14
0
 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
示例#15
0
文件: all_events.py 项目: wmbr/gramps
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)
示例#16
0
 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
示例#17
0
 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 '')
示例#18
0
 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)
示例#20
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)
示例#21
0
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)
示例#22
0
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("")
示例#23
0
 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)
示例#24
0
    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 = []
示例#25
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)
示例#26
0
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)
示例#27
0
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)
示例#28
0
    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()
示例#29
0
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("")
示例#30
0
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("")
示例#31
0
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("")
示例#32
0
 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)
示例#33
0
 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 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)
示例#35
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)
示例#36
0
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"))
示例#37
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.
    """
    # 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")
示例#38
0
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)
示例#39
0
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"))
示例#40
0
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("")
示例#41
0
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)
示例#42
0
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("")
示例#43
0
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
示例#44
0
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)
示例#45
0
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("")
示例#46
0
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)
示例#49
0
    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()
示例#50
0
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))
示例#51
0
    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()
示例#52
0
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
示例#53
0
    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()
示例#54
0
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("")