diff --git a/ChangeLog b/ChangeLog index 59a97a9ff..4bdd21a79 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2007-10-31 Benny Malengier + * src/plugins/all_relations.py: use collapse family + * src/Relationship.py: add collopse equal family + 2007-10-30 Douglas S. Blank * src/plugins/Calendar.py: added Peter Landgren's locale suggestions diff --git a/src/Relationship.py b/src/Relationship.py index a680905f2..5ec37e9c1 100644 --- a/src/Relationship.py +++ b/src/Relationship.py @@ -526,7 +526,6 @@ class RelationshipCalculator: common.append( common_anc[1] ) return (firstRel, secondRel, common) - def get_relationship_distance_new(self, db, orig_person, other_person, @@ -535,7 +534,7 @@ class RelationshipCalculator: only_birth=True, max_depth = MAX_DEPTH): """ - Returns if all_dist == First a 'tuple, string': + Returns if all_dist == True a 'tuple, string': (rank, person handle, firstRel_str, firstRel_fam, secondRel_str, secondRel_fam), msg or if all_dist == True a 'list of tuple, string': @@ -810,8 +809,195 @@ class RelationshipCalculator: import traceback print traceback.print_exc() return - - def get_relationship(self,db,orig_person,other_person): + + def collapse_relations(self, relations): + """ Internal method to condense the relationships as returned by + get_relationship_distance_new. + Common ancestors in the same family are collapsed to one entry, + changing the person paths to family paths, eg 'mf' and 'mm' become + 'ma' + + relations : list of relations as returned by + get_relationship_distance_new with all_dist = True + + returns : the same data as relations, but collapsed, hence the + handle entry is now a list of handles, and the + path to common ancestors can now contain family + identifiers (eg 'a', ...) + In the case of sibling, this is replaced by family + with common ancestor handles empty list []! + """ + if relations[0][0] == -1 : + return relations + commonnew = [] + existing_path = [] + for relation in relations: + relstrfirst = None + commonhandle = [relation[1]] + if relation[2] : + relstrfirst = relation[2][:-1] + relstrsec = None + if relation[4] : + relstrsec = relation[4][:-1] + relfamfirst = relation[3][:] + relfamsec = relation[5][:] + #handle pure sibling: + if relation[2] and relation[2][-1] == self.REL_SIBLING: + #sibling will be the unique common ancestor, + #change to a family with unknown handle for common ancestor + relation[2] = relation[2][:-1] + self.REL_FAM_BIRTH + relation[4] = relation[4] + self.REL_FAM_BIRTH + relfamsec = relfamsec + [relfamfirst[-1]] + relstrsec = relation[4][:-1] + commonhandle = [] + + # a unique path to family: + familypath = (relstrfirst, relstrsec, relfamfirst, relfamsec) + try: + posfam = existing_path.index(familypath) + except ValueError: + posfam = None + #if relstr is '', the ancestor is unique, if posfam None, + # first time we see this family path + if (posfam is not None and relstrfirst is not None and + relstrsec is not None): + #we already have a common ancestor of this family, just add the + #other, setting correct family relation + tmp = commonnew[posfam] + frstcomstr = relation[2][-1] + scndcomstr = tmp[2][-1] + newcomstra = self.famrel_from_persrel(frstcomstr, scndcomstr) + frstcomstr = relation[4][-1] + scndcomstr = tmp[4][-1] + newcomstrb = self.famrel_from_persrel(frstcomstr, scndcomstr) + + commonnew[posfam] = (tmp[0], tmp[1]+commonhandle, + relation[2][:-1]+newcomstra, + tmp[3], relation[4][:-1]+newcomstrb, + tmp[5]) + + else : + existing_path.append(familypath) + commonnew.append((relation[0], commonhandle, relation[2], + relfamfirst, relation[4], relfamsec) + ) + return commonnew + + def famrel_from_persrel(self, persrela, persrelb): + """ Conversion from eg 'f' and 'm' to 'a', so relation to the two + persons of a common family is converted to a family relation + """ + if persrela == persrelb: + #should not happen, procedure called in error, just return value + return persrela + if (persrela == self.REL_MOTHER and persrelb == self.REL_FATHER) or \ + (persrelb == self.REL_MOTHER and persrela == self.REL_FATHER): + return self.REL_FAM_BIRTH + if (persrela == self.REL_MOTHER and persrelb == self.REL_FATHER_NOTBIRTH) or \ + (persrelb == self.REL_MOTHER and persrela == self.REL_FATHER_NOTBIRTH): + return self.REL_FAM_BIRTH_MOTH_ONLY + if (persrela == self.REL_FATHER and persrelb == self.REL_MOTHER_NOTBIRTH) or \ + (persrelb == self.REL_FATHER and persrela == self.REL_MOTHER_NOTBIRTH): + return self.REL_FAM_BIRTH_FATH_ONLY + #catch calling with family relations already, return val + if (persrela == self.REL_FAM_BIRTH or + persrela == self.REL_FAM_BIRTH_FATH_ONLY or + persrela == self.REL_FAM_BIRTH_MOTH_ONLY or + persrela == REL_FAM_NONBIRTH): + return persrela + if (persrelb == self.REL_FAM_BIRTH or + persrelb == self.REL_FAM_BIRTH_FATH_ONLY or + persrelb == self.REL_FAM_BIRTH_MOTH_ONLY or + persrelb == REL_FAM_NONBIRTH): + return persrelb + return self.REL_FAM_NONBIRTH + + def only_birth(self, path): + """ given a path to common ancestor. Return True if only birth + relations, False otherwise + """ + only_birth = True + for str in path: + only_birth = only_birth and (str not in [self.REL_FAM_NONBIRTH, + self.REL_FATHER_NOTBIRTH, self.REL_MOTHER_NOTBIRTH]) + return only_birth + + def get_one_relationship(self, db, orig_person, other_person): + """ + returns a string representing the most relevant relationship between + the two people + """ + if orig_person == None: + return (_("undefined"),[]) + + if orig_person.get_handle() == other_person.get_handle(): + return ('', []) + + is_spouse = self.is_spouse(db,orig_person,other_person) + if is_spouse: + return is_spouse + + data, msg = self.get_relationship_distance_new( + db, orig_person, other_person, + all_dist=True, + all_families=True, only_birth=False) + if data[0][0] == -1: + return '' + + data = self.collapse_relations(data) + #most relevant relationship is a birth family relation of lowest rank + databest = [data[0]] + rankbest = data[0][0] + for rel in data : + if rel[0] == rankbest: + databest.append(rel) + if len(databest) == 1: + rel = databest[0] + dist_orig = len(rel[2]) + dist_other= len(rel[4]) + birth = self.only_birth(rel[2]) and self.only_birth(rel[4]) + return get_single_relationship_string(dist_orig, + dist_other, + orig_person.get_gender(), + other_person.get_gender(), + rel[2], rel[4], + only_birth=birth, + in_law_a=False, + in_law_b=False) + else: + rel = databest[0] + order = [self.REL_FAM_BIRTH, self.REL_FAM_BIRTH_MOTH_ONLY, + self.REL_FAM_BIRTH_FATH_ONLY, self.REL_MOTHER, + self.REL_FATHER, self.REL_SIBLING, self.REL_FAM_NONBIRTH, + self.REL_MOTHER_NOTBIRTH, self.REL_MOTHER_NOTBIRTH] + for relother in databest: + relbirth = self.only_birth(rel[2]) and self.only_birth(rel[4]) + if relother[2] == '' or relother[4]== '': + #direct relation, take that + rel = relother + break + if not relbirth and self.only_birth(relother[2]) \ + and self.only_birth(relother[4]) : + #birth takes precedence + rel = relother + continue + if order.index(relother[2][-1]) < order.index(rel[2][-1]): + rel = relother + continue + if order.index(relother[2][-1]) == order.index(rel[2][-1]) and\ + order.index(relother[4][-1]) < order.index(rel[4][-1]): + rel = relother + continue + return get_single_relationship_string(dist_orig, + dist_other, + orig_person.get_gender(), + other_person.get_gender(), + rel[2], rel[4], + only_birth=birth, + in_law_a=False, + in_law_b=False) + + def get_relationship(self, db, orig_person, other_person): """ returns a string representing the relationshp between the two people, along with a list of common ancestors (typically father,mother) diff --git a/src/plugins/all_relations.py b/src/plugins/all_relations.py index d6b5bbae6..2925f46d7 100644 --- a/src/plugins/all_relations.py +++ b/src/plugins/all_relations.py @@ -101,63 +101,11 @@ def run(database, document, person): count = 1 #collapse common so parents of same fam in common are one line - commonnew = [] - existing_path = [] - for relation in common: - relstrfirst = None - if relation[2] : - relstrfirst = relation[2][:-1] - relstrsec = None - if relation[4] : - relstrsec = relation[4][:-1] - familypath = (relstrfirst, relstrsec, relation[3], relation[5]) - try: - posfam = existing_path.index(familypath) - except ValueError: - posfam = None - #if relstr is '', the ancestor is unique, if posfam None, first time - # we see this family path - if (posfam is not None and relstrfirst is not None and - relstrsec is not None): - #we already have a common ancestor of this family, just add the - #other - tmp = commonnew[posfam] - if (relation[2][-1]== rel_class.REL_MOTHER or - relation[2][-1] == rel_class.REL_FATHER or - tmp[2][-1] == rel_class.REL_MOTHER or - tmp[2][-1] == rel_class.REL_FATHER or - tmp[2][-1] == rel_class.REL_SIBLING) : - #we consider the relation to parents by birth - reltofirst = 'p' - else: - reltofirst = 'P' - if (relation[4][-1]== rel_class.REL_MOTHER or - relation[4][-1] == rel_class.REL_FATHER or - tmp[4][-1] == rel_class.REL_MOTHER or - tmp[4][-1] == rel_class.REL_FATHER or - tmp[4][-1] == rel_class.REL_SIBLING) : - #we consider the relation to parents by birth - reltosec = 'p' - else: - reltosec = 'P' - commonnew[posfam] = (tmp[0], tmp[1]+[relation[1]], - relation[2][:-1]+reltofirst, - tmp[3], relation[4][:-1]+reltosec, - tmp[5]) - else : - existing_path.append(familypath) - commonnew.append((relation[0], [relation[1]], relation[2], - relation[3], relation[4], relation[5] ) - ) - + commonnew = rel_class.collapse_relations(common) + for relation in commonnew: - birth = not (rel_class.REL_MOTHER_NOTBIRTH in relation[2] or - rel_class.REL_FATHER_NOTBIRTH in relation[2] or - 'P' in relation[2] or - rel_class.REL_MOTHER_NOTBIRTH in relation[4] or - rel_class.REL_FATHER_NOTBIRTH in relation[4] or - 'P' in relation[4] - ) + birth = rel_class.only_birth(relation[2])\ + and rel_class.only_birth(relation[4]) rel_str = rel_class.get_single_relationship_string( len(relation[4]), len(relation[2]), home_person.get_gender(), person.get_gender(), @@ -177,10 +125,12 @@ def run(database, document, person): count = 1 for relation in commonnew: counter = str(count) - name = sdb.name(database.get_person_from_handle(relation[1][0])) - for handle in relation[1][1:]: - name += ' ' + _('and') + ' ' + \ - sdb.name(database.get_person_from_handle(handle)) + name = _('Unknown') + if relation[1]: + name = sdb.name(database.get_person_from_handle(relation[1][0])) + for handle in relation[1][1:]: + name += ' ' + _('and') + ' ' + \ + sdb.name(database.get_person_from_handle(handle)) sdoc.paragraph(__FMT_DET1 % (counter, name)) for rel,fam in zip(relation[2],relation[3]) : par_str = _('Unknown') #when sibling, parent is unknown @@ -190,12 +140,19 @@ def run(database, document, person): if rel == rel_class.REL_FATHER \ or rel == rel_class.REL_FATHER_NOTBIRTH: par_str = _('Father') - if rel == 'p' or rel == 'P': + 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 == 'P': + 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') sdoc.paragraph(__FMT_DET2 % (' ', par_str, birth_str, str(fam+1))) counter='' name = '' @@ -210,10 +167,12 @@ def run(database, document, person): count = 1 for relation in commonnew: counter = str(count) - name = sdb.name(database.get_person_from_handle(relation[1][0])) - for handle in relation[1][1:]: - name += ' ' + _('and') + ' ' + \ - sdb.name(database.get_person_from_handle(handle)) + name = _('Unknown') + if relation[1]: + name = sdb.name(database.get_person_from_handle(relation[1][0])) + for handle in relation[1][1:]: + name += ' ' + _('and') + ' ' + \ + sdb.name(database.get_person_from_handle(handle)) sdoc.paragraph(__FMT_DET1 % (counter, name)) for rel,fam in zip(relation[4],relation[5]) : par_str = _('Unknown') @@ -223,12 +182,19 @@ def run(database, document, person): if rel == rel_class.REL_FATHER \ or rel == rel_class.REL_FATHER_NOTBIRTH: par_str = _('Father') - if rel == 'p' or rel == 'P': + 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 == 'P': + 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') sdoc.paragraph(__FMT_DET2 % (' ', par_str, birth_str, str(fam+1))) counter='' name = ''