Пример #1
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)
Пример #2
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)
Пример #3
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)
Пример #4
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)
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("")
Пример #6
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)
Пример #7
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)
Пример #8
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
    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 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)
Пример #11
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)
Пример #12
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")
Пример #13
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("")
Пример #14
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"))
Пример #15
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("")
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)
Пример #17
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("")
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)
                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:
                                #print "birth source:", source, source.get_title()
                                if source.get_title() == source_text:
                                    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.commit_source(source, self.trans)
                                    pupdate = 1
                                    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:
                                #print "death source:", source, source.get_title()
                                if source.get_title() == source_text:
                                    person.set_death_ref(None)
                                    person.remove_handle_references('Event',[death_ref.ref])
                                    # remove note
                                    note_list = death.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(death_ref.ref, self.trans)
                                    self.db.commit_source(source, self.trans)
                                    pupdate = 1
                                    break
                    if pupdate == 1:
                        self.db.commit_person(person, self.trans)
                if source:
                    self.db.remove_source(source.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.progress.close()
        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
                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:
                    other_name = self.sdb.name(other)
                    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:
                    other_name = self.sdb.name(other)
                    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)