2007-10-23 Benny Malengier <benny.malengier@gramps-project.org>
* src/Relationship.py: new algorithm to calculate relation * src/plugins/all_relations.py: begin of quick report to show extended relationship. svn: r9237
This commit is contained in:
		@@ -1,3 +1,7 @@
 | 
			
		||||
2007-10-23 Benny Malengier <benny.malengier@gramps-project.org>
 | 
			
		||||
	* src/Relationship.py: new algorithm to calculate relation
 | 
			
		||||
	* src/plugins/all_relations.py: begin of quick report to show extended relationship.
 | 
			
		||||
 | 
			
		||||
2007-10-22 Benny Malengier <benny.malengier@gramps-project.org>
 | 
			
		||||
	* src/DisplayTabs/_GalleryTab.py: correctly update displaytab
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -41,12 +41,18 @@ _level_name = [ "", "first", "second", "third", "fourth", "fifth", "sixth",
 | 
			
		||||
                "thirteenth", "fourteenth", "fifteenth", "sixteenth",
 | 
			
		||||
                "seventeenth", "eighteenth", "nineteenth", "twentieth" ]
 | 
			
		||||
 | 
			
		||||
_removed_level = [ "", " once removed", " twice removed", " three times removed",
 | 
			
		||||
                   " four times removed", " five times removed", " six times removed",
 | 
			
		||||
                  " sevent times removed", " eight times removed", " nine times removed",
 | 
			
		||||
                   " ten times removed", " eleven times removed", " twelve times removed",
 | 
			
		||||
                   " thirteen times removed", " fourteen times removed", " fifteen times removed",
 | 
			
		||||
                   " sixteen times removed", " seventeen times removed", " eighteen times removed",
 | 
			
		||||
_removed_level = [ "", " once removed", " twice removed", 
 | 
			
		||||
                   " three times removed",
 | 
			
		||||
                   " four times removed", " five times removed", 
 | 
			
		||||
                    " six times removed",
 | 
			
		||||
                   " sevent times removed", " eight times removed", 
 | 
			
		||||
                   " nine times removed",
 | 
			
		||||
                   " ten times removed", " eleven times removed", 
 | 
			
		||||
                   " twelve times removed",
 | 
			
		||||
                   " thirteen times removed", " fourteen times removed", 
 | 
			
		||||
                   " fifteen times removed",
 | 
			
		||||
                   " sixteen times removed", " seventeen times removed", 
 | 
			
		||||
                   " eighteen times removed",
 | 
			
		||||
                   " nineteen times removed", " twenty times removed" ]
 | 
			
		||||
 | 
			
		||||
_parents_level = [ "", "parents", "grandparents", "great grandparents", "second great grandparents",
 | 
			
		||||
@@ -175,6 +181,20 @@ _siblings_level = [ "",
 | 
			
		||||
    "sixteenth great granduncles/aunts",  "seventeenth great granduncles/aunts", 
 | 
			
		||||
    "eighteenth great granduncles/aunts", "nineteenth great granduncles/aunts", 
 | 
			
		||||
    "twentieth great granduncles/aunts", ]
 | 
			
		||||
    
 | 
			
		||||
_sibling_level = [ "",
 | 
			
		||||
    "sibling",                          "uncle/aunt", 
 | 
			
		||||
    "granduncle/aunt",                  "great granduncle/aunt", 
 | 
			
		||||
    "second great granduncle/aunt",     "third great granduncle/aunt",  
 | 
			
		||||
    "fourth great granduncle/aunt",     "fifth great granduncle/aunt",  
 | 
			
		||||
    "sixth great granduncle/aunt",      "seventh great granduncle/aunt", 
 | 
			
		||||
    "eighth great granduncle/aunt",     "ninth great granduncle/aunt", 
 | 
			
		||||
    "tenth great granduncle/aunt",      "eleventh great granduncle/aunt",  
 | 
			
		||||
    "twelfth great granduncle/aunt",    "thirteenth great granduncle/aunt", 
 | 
			
		||||
    "fourteenth great granduncle/aunt", "fifteenth great granduncle/aunt", 
 | 
			
		||||
    "sixteenth great granduncle/aunt",  "seventeenth great granduncle/aunt", 
 | 
			
		||||
    "eighteenth great granduncle/aunt", "nineteenth great granduncle/aunt", 
 | 
			
		||||
    "twentieth great granduncle/aunt", ]
 | 
			
		||||
 | 
			
		||||
_nephews_nieces_level = [   "", 
 | 
			
		||||
                            "siblings",
 | 
			
		||||
@@ -211,93 +231,78 @@ _nephews_nieces_level = [   "",
 | 
			
		||||
MAX_DEPTH = 15
 | 
			
		||||
 | 
			
		||||
class RelationshipCalculator:
 | 
			
		||||
    
 | 
			
		||||
    REL_MOTHER           = 'm'
 | 
			
		||||
    REL_FATHER           = 'f'
 | 
			
		||||
    REL_MOTHER_NOTBIRTH  = 'M'
 | 
			
		||||
    REL_FATHER_NOTBIRTH  = 'F'
 | 
			
		||||
    REL_SIBLING          = 's'
 | 
			
		||||
 | 
			
		||||
    def __init__(self):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def __apply_filter(self,db,person,rel_str,plist,pmap,gen=1):
 | 
			
		||||
        if person == None or gen > MAX_DEPTH:
 | 
			
		||||
            return
 | 
			
		||||
        gen += 1
 | 
			
		||||
        plist.append(person.handle)
 | 
			
		||||
        pmap[person.handle] = rel_str
 | 
			
		||||
 | 
			
		||||
        family_handle = person.get_main_parents_family_handle()
 | 
			
		||||
        try:
 | 
			
		||||
            if family_handle:
 | 
			
		||||
                family = db.get_family_from_handle(family_handle)
 | 
			
		||||
                fhandle = family.father_handle
 | 
			
		||||
                if fhandle:
 | 
			
		||||
                    father = db.get_person_from_handle(fhandle)
 | 
			
		||||
                    self.__apply_filter(db,father,rel_str+'f',plist,pmap,gen)
 | 
			
		||||
                mhandle = family.mother_handle
 | 
			
		||||
                if mhandle:
 | 
			
		||||
                    mother = db.get_person_from_handle(mhandle)
 | 
			
		||||
                    self.__apply_filter(db,mother,rel_str+'m',plist,pmap,gen)
 | 
			
		||||
        except:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
    def get_cousin(self,level,removed):
 | 
			
		||||
    def get_cousin(self, level, removed):
 | 
			
		||||
        if removed > len(_removed_level)-1 or level>len(_level_name)-1:
 | 
			
		||||
            return "distant relative"
 | 
			
		||||
        else:
 | 
			
		||||
            return "%s cousin%s" % (_level_name[level],_removed_level[removed])
 | 
			
		||||
            return "%s cousin%s" % (_level_name[level], 
 | 
			
		||||
                                    _removed_level[removed])
 | 
			
		||||
 | 
			
		||||
    def get_parents(self,level):
 | 
			
		||||
    def get_parents(self, level):
 | 
			
		||||
        if level>len(_parents_level)-1:
 | 
			
		||||
            return "distant ancestors"
 | 
			
		||||
        else:
 | 
			
		||||
            return _parents_level[level]
 | 
			
		||||
 | 
			
		||||
    def get_father(self,level):
 | 
			
		||||
    def get_father(self, level):
 | 
			
		||||
        if level>len(_father_level)-1:
 | 
			
		||||
            return "distant ancestor"
 | 
			
		||||
        else:
 | 
			
		||||
            return _father_level[level]
 | 
			
		||||
 | 
			
		||||
    def get_son(self,level):
 | 
			
		||||
    def get_son(self, level):
 | 
			
		||||
        if level>len(_son_level)-1:
 | 
			
		||||
            return "distant descendant"
 | 
			
		||||
        else:
 | 
			
		||||
            return _son_level[level]
 | 
			
		||||
 | 
			
		||||
    def get_mother(self,level):
 | 
			
		||||
    def get_mother(self, level):
 | 
			
		||||
        if level>len(_mother_level)-1:
 | 
			
		||||
            return "distant ancestor"
 | 
			
		||||
        else:
 | 
			
		||||
            return _mother_level[level]
 | 
			
		||||
 | 
			
		||||
    def get_daughter(self,level):
 | 
			
		||||
    def get_daughter(self, level):
 | 
			
		||||
        if level>len(_daughter_level)-1:
 | 
			
		||||
            return "distant descendant"
 | 
			
		||||
        else:
 | 
			
		||||
            return _daughter_level[level]
 | 
			
		||||
 | 
			
		||||
    def get_aunt(self,level):
 | 
			
		||||
    def get_aunt(self, level):
 | 
			
		||||
        if level>len(_sister_level)-1:
 | 
			
		||||
            return "distant ancestor"
 | 
			
		||||
        else:
 | 
			
		||||
            return _sister_level[level]
 | 
			
		||||
 | 
			
		||||
    def get_uncle(self,level):
 | 
			
		||||
    def get_uncle(self, level):
 | 
			
		||||
        if level>len(_brother_level)-1:
 | 
			
		||||
            return "distant ancestor"
 | 
			
		||||
        else:
 | 
			
		||||
            return _brother_level[level]
 | 
			
		||||
 | 
			
		||||
    def get_nephew(self,level):
 | 
			
		||||
    def get_nephew(self, level):
 | 
			
		||||
        if level>len(_nephew_level)-1:
 | 
			
		||||
            return "distant descendant"
 | 
			
		||||
        else:
 | 
			
		||||
            return _nephew_level[level]
 | 
			
		||||
 | 
			
		||||
    def get_niece(self,level):
 | 
			
		||||
    def get_niece(self, level):
 | 
			
		||||
        if level>len(_niece_level)-1:
 | 
			
		||||
            return "distant descendant"
 | 
			
		||||
        else:
 | 
			
		||||
            return _niece_level[level]
 | 
			
		||||
        
 | 
			
		||||
    def is_spouse(self,db,orig,other):
 | 
			
		||||
    def is_spouse(self, db, orig, other):
 | 
			
		||||
        for f in orig.get_family_handle_list():
 | 
			
		||||
            family = db.get_family_from_handle(f)
 | 
			
		||||
            if family and other.get_handle() in [family.get_father_handle(),
 | 
			
		||||
@@ -354,18 +359,25 @@ class RelationshipCalculator:
 | 
			
		||||
                return None
 | 
			
		||||
        return None
 | 
			
		||||
 | 
			
		||||
    def get_relationship_distance(self,db,orig_person,other_person):
 | 
			
		||||
    def get_relationship_distance_old(self, db, orig_person, other_person):
 | 
			
		||||
        """
 | 
			
		||||
        Returns a tuple (firstRel,secondRel,common):
 | 
			
		||||
           ** DEPRECATED  -- USE NEW **
 | 
			
		||||
        
 | 
			
		||||
        NOTE: CHANGED ORDER OF RETURN, now first is rel to orig, second to other
 | 
			
		||||
                (as it should, but wasn't !! )
 | 
			
		||||
 | 
			
		||||
        Returns a tuple (firstRel, secondRel, common):
 | 
			
		||||
        
 | 
			
		||||
        firstRel    Number of generations from the orig_person to their
 | 
			
		||||
                    closest common ancestor
 | 
			
		||||
        secondRel   Number of generations from the other_person to their
 | 
			
		||||
                    closest common ancestor
 | 
			
		||||
        common      list of their common ancestors, the closest is the first
 | 
			
		||||
        
 | 
			
		||||
        is returned
 | 
			
		||||
                    closest common ancestors, as eg 'ffmm'
 | 
			
		||||
        secondRel   Number of generations from the other_person to that
 | 
			
		||||
                    firstRel closest common ancestors, as eg 'ffmm'
 | 
			
		||||
        common      list of all these common ancestors (so same generation
 | 
			
		||||
                    difference with firstRel), no specific order !!
 | 
			
		||||
                    
 | 
			
		||||
        in the Rel, f is father, m is mother
 | 
			
		||||
        """
 | 
			
		||||
        print "get_relationship_distance_old is deprecated, use new instead!"
 | 
			
		||||
        
 | 
			
		||||
        firstRel = -1
 | 
			
		||||
        secondRel = -1
 | 
			
		||||
@@ -378,10 +390,10 @@ class RelationshipCalculator:
 | 
			
		||||
        rank = 9999999
 | 
			
		||||
 | 
			
		||||
        try:
 | 
			
		||||
            self.__apply_filter(db,orig_person,'',firstList,firstMap)
 | 
			
		||||
            self.__apply_filter(db,other_person,'',secondList,secondMap)
 | 
			
		||||
            self.__apply_filter(db, orig_person, '', firstList, firstMap)
 | 
			
		||||
            self.__apply_filter(db, other_person, '', secondList, secondMap)
 | 
			
		||||
        except RuntimeError:
 | 
			
		||||
            return (firstRel,secondRel,_("Relationship loop detected"))
 | 
			
		||||
            return (firstRel, secondRel, _("Relationship loop detected"))
 | 
			
		||||
 | 
			
		||||
        for person_handle in firstList:
 | 
			
		||||
            if person_handle in secondList:
 | 
			
		||||
@@ -394,68 +406,441 @@ class RelationshipCalculator:
 | 
			
		||||
 | 
			
		||||
        if common:
 | 
			
		||||
            person_handle = common[0]
 | 
			
		||||
            secondRel = firstMap[person_handle]
 | 
			
		||||
            firstRel = secondMap[person_handle]
 | 
			
		||||
            firstRel = firstMap[person_handle]
 | 
			
		||||
            secondRel = secondMap[person_handle]
 | 
			
		||||
 | 
			
		||||
        return (firstRel,secondRel,common)
 | 
			
		||||
 | 
			
		||||
    def __apply_filter(self, db, person, rel_str, plist, pmap, depth=1):
 | 
			
		||||
        if person == None or depth > MAX_DEPTH:
 | 
			
		||||
            return
 | 
			
		||||
        depth += 1
 | 
			
		||||
        plist.append(person.handle)
 | 
			
		||||
        pmap[person.handle] = rel_str  # ?? this overwrites if person is double!
 | 
			
		||||
 | 
			
		||||
        family_handle = person.get_main_parents_family_handle()
 | 
			
		||||
        try:
 | 
			
		||||
            if family_handle:
 | 
			
		||||
                family = db.get_family_from_handle(family_handle)
 | 
			
		||||
                fhandle = family.father_handle
 | 
			
		||||
                if fhandle:
 | 
			
		||||
                    father = db.get_person_from_handle(fhandle)
 | 
			
		||||
                    self.__apply_filter(db, father, rel_str+'f', plist, pmap,
 | 
			
		||||
                                        depth)
 | 
			
		||||
                mhandle = family.mother_handle
 | 
			
		||||
                if mhandle:
 | 
			
		||||
                    mother = db.get_person_from_handle(mhandle)
 | 
			
		||||
                    self.__apply_filter(db, mother, rel_str+'m', plist, pmap,
 | 
			
		||||
                                        depth)
 | 
			
		||||
        except:
 | 
			
		||||
            return
 | 
			
		||||
        
 | 
			
		||||
    def get_relationship_distance(self, db, orig_person, other_person):
 | 
			
		||||
        """
 | 
			
		||||
        wrapper around get_relationship_distance_new to return a value like
 | 
			
		||||
        the old method (note, firstRel is now to orig person, not to other as
 | 
			
		||||
            it was in 2.2.x series !!!)
 | 
			
		||||
            
 | 
			
		||||
            *** DO NOT USE, IS INCORRECT IN SOME CASES, eg person common 
 | 
			
		||||
                ancestor along two paths, only one returned,
 | 
			
		||||
                however this should not matter for number of generation or 
 | 
			
		||||
                last gender, eg firstRel is 'ffffm' or 'mmfmm', only one 
 | 
			
		||||
                returned ***
 | 
			
		||||
        
 | 
			
		||||
        Returns a tuple (firstRel, secondRel, common):
 | 
			
		||||
        
 | 
			
		||||
        firstRel    Number of generations from the orig_person to their
 | 
			
		||||
                    closest common ancestors, as eg 'ffmm'
 | 
			
		||||
        secondRel   Number of generations from the other_person to that 
 | 
			
		||||
                    firstRel closest common ancestors, as eg 'ffmm'
 | 
			
		||||
        common      list of all these common ancestors (so same generation
 | 
			
		||||
                    difference with firstRel), no specific order !!
 | 
			
		||||
                    
 | 
			
		||||
        in the Rel, f is father, m is mother
 | 
			
		||||
        """
 | 
			
		||||
        
 | 
			
		||||
        firstRel = -1
 | 
			
		||||
        secondRel = -1
 | 
			
		||||
        common = []
 | 
			
		||||
        rank = 9999999
 | 
			
		||||
        
 | 
			
		||||
        data, msg = self.get_relationship_distance_new(
 | 
			
		||||
                                db, orig_person, other_person,
 | 
			
		||||
                                all_dist=True,
 | 
			
		||||
                                all_families=False, only_birth=True)
 | 
			
		||||
        #data is sorted on rank, we need closest to orig instead
 | 
			
		||||
        if data[0][0] == -1 :
 | 
			
		||||
            return firstRel, secondRel, common
 | 
			
		||||
        for common_anc in data :
 | 
			
		||||
            # common_anc looks like:
 | 
			
		||||
            #(total dist, handle_common, 'ffffff', [0,0,0,0,0,0],'ff',[0, 0])
 | 
			
		||||
            #where 2&3 are related to orig_pers, 4&5 other_pers
 | 
			
		||||
            new_rank = len(common_anc[2])
 | 
			
		||||
            if new_rank < rank:
 | 
			
		||||
                    rank = new_rank
 | 
			
		||||
                    common = [ common_anc[1] ]
 | 
			
		||||
                    firstRel = common_anc[2]
 | 
			
		||||
                    secondRel = common_anc[4]
 | 
			
		||||
            elif new_rank == rank:
 | 
			
		||||
                common.append( common_anc[1] )
 | 
			
		||||
            
 | 
			
		||||
        return (firstRel, secondRel, common)
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
    def get_relationship_distance_new(self, db, orig_person,
 | 
			
		||||
                                      other_person,
 | 
			
		||||
                                      all_families=False, 
 | 
			
		||||
                                      all_dist=False, 
 | 
			
		||||
                                      only_birth=True,
 | 
			
		||||
                                      max_depth = MAX_DEPTH):
 | 
			
		||||
        """
 | 
			
		||||
        Returns if all_dist == First 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': 
 | 
			
		||||
            [.....], msg:
 | 
			
		||||
        
 | 
			
		||||
        The tuple or list of tuples consists of:
 | 
			
		||||
         
 | 
			
		||||
        *rank           Total number of generations from common ancestor to 
 | 
			
		||||
                        the two persons, rank is -1 if no relations found
 | 
			
		||||
        *person_handle  The Common ancestor
 | 
			
		||||
        *firstRel_str   String with the path to the common ancestor 
 | 
			
		||||
                        from orig Person
 | 
			
		||||
        *firstRel_fam   Family numbers along the path
 | 
			
		||||
        *secondRel_str  String with the path to the common ancestor 
 | 
			
		||||
                        from otherPerson
 | 
			
		||||
        *secondRel_fam  Family numbers along the path
 | 
			
		||||
        *msg            List of messages indicating errors. Empyt list if no
 | 
			
		||||
                        errors.
 | 
			
		||||
                        
 | 
			
		||||
        Example:
 | 
			
		||||
                firstRel_str = 'ffm' and firstRel_fam = [2,0,1] means 
 | 
			
		||||
                common ancestor is mother of the second family of the 
 | 
			
		||||
                father of the first family of the father of the third 
 | 
			
		||||
                family.
 | 
			
		||||
        Note that the same person might be present twice if the person is
 | 
			
		||||
        reached via a different branch too. Path (firstRel_str and 
 | 
			
		||||
        secondRel_str) will of course be different
 | 
			
		||||
        
 | 
			
		||||
        @param db: database to work on
 | 
			
		||||
        @param orig_person: first person 
 | 
			
		||||
        @type orig_person:  Person Obj
 | 
			
		||||
        @param other_person: second person, relation is sought between
 | 
			
		||||
                             first and second person
 | 
			
		||||
        @type other_person:  Person Obj
 | 
			
		||||
        @param all_families: if False only Main family is searched, otherwise
 | 
			
		||||
                             all families are used
 | 
			
		||||
        @type all_families:  bool
 | 
			
		||||
        @param all_dist: if False only the shortest distance is returned, 
 | 
			
		||||
                         otherwise all relationships
 | 
			
		||||
        @type all_dist:  bool
 | 
			
		||||
        @param only_birth: if True only parents with birth relation are 
 | 
			
		||||
                           considered
 | 
			
		||||
        @type only_birth:  bool
 | 
			
		||||
        @param max_depth: how many generations deep do we search?
 | 
			
		||||
        @type max_depth: int
 | 
			
		||||
        """
 | 
			
		||||
        #data storage to communicate with recursive functions
 | 
			
		||||
        self.__maxDepthReached = False
 | 
			
		||||
        self.__loopDetected = False
 | 
			
		||||
        self.__max_depth = max_depth
 | 
			
		||||
        self.__all_families = all_families
 | 
			
		||||
        self.__all_dist = all_dist
 | 
			
		||||
        self.__only_birth = only_birth
 | 
			
		||||
        
 | 
			
		||||
        firstRel   = -1
 | 
			
		||||
        secondRel  = -1
 | 
			
		||||
        common_str = []
 | 
			
		||||
        common_fam = []
 | 
			
		||||
        self.__msg = []
 | 
			
		||||
        
 | 
			
		||||
        common = []
 | 
			
		||||
        firstMap = {}
 | 
			
		||||
        firstList = []
 | 
			
		||||
        secondMap = {}
 | 
			
		||||
        secondList = []
 | 
			
		||||
        rank = 9999999
 | 
			
		||||
 | 
			
		||||
        try:
 | 
			
		||||
            self.__apply_filter_new(db, orig_person, '', [], firstMap)
 | 
			
		||||
            self.__apply_filter_new(db, other_person, '', [], secondMap,
 | 
			
		||||
                                    stoprecursemap = firstMap, 
 | 
			
		||||
                                    store_all=False)
 | 
			
		||||
##            print firstMap
 | 
			
		||||
##            print secondMap
 | 
			
		||||
        except RuntimeError:
 | 
			
		||||
            return (-1,None,-1,[],-1,[] ) , \
 | 
			
		||||
                            [_("Relationship loop detected")] + self.__msg
 | 
			
		||||
 | 
			
		||||
        for person_handle in secondMap.keys() :
 | 
			
		||||
            if firstMap.has_key(person_handle) :
 | 
			
		||||
                com = []
 | 
			
		||||
                #a common ancestor
 | 
			
		||||
                for rel1,fam1 in zip(firstMap[person_handle][0],
 | 
			
		||||
                                        firstMap[person_handle][1]):
 | 
			
		||||
                    l1 = len(rel1)
 | 
			
		||||
                    for rel2,fam2 in zip(secondMap[person_handle][0], 
 | 
			
		||||
                                        secondMap[person_handle][1]):
 | 
			
		||||
                        l2 = len(rel2)
 | 
			
		||||
                        #collect paths to arrive at common ancestor
 | 
			
		||||
                        com.append((l1+l2,person_handle,rel1,fam1,
 | 
			
		||||
                                                        rel2,fam2))
 | 
			
		||||
                #insert common ancestor in correct position,
 | 
			
		||||
                #  if shorter links, check if not subset
 | 
			
		||||
                #  if longer links, check if not superset
 | 
			
		||||
                pos=0
 | 
			
		||||
                for ranknew,handlenew,rel1new,fam1new,rel2new,fam2new in com :
 | 
			
		||||
                    insert = True
 | 
			
		||||
                    for rank, handle, rel1, fam1, rel2, fam2 in common :
 | 
			
		||||
                        if ranknew < rank : 
 | 
			
		||||
                            break
 | 
			
		||||
                        elif ranknew >= rank :
 | 
			
		||||
                            #check subset
 | 
			
		||||
                            if rel1 == rel1new[:len(rel1)] and \
 | 
			
		||||
                                    rel2 == rel2new[:len(rel2)] :
 | 
			
		||||
                                #subset relation exists already
 | 
			
		||||
                                insert = False
 | 
			
		||||
                                break
 | 
			
		||||
                        pos += 1
 | 
			
		||||
                    if insert :
 | 
			
		||||
                        if common :
 | 
			
		||||
                            common.insert(pos, (ranknew, handlenew,
 | 
			
		||||
                                    rel1new, fam1new,rel2new,fam2new))
 | 
			
		||||
                        else:
 | 
			
		||||
                            common = [(ranknew, handlenew,
 | 
			
		||||
                                    rel1new, fam1new, rel2new, fam2new)]
 | 
			
		||||
                        #now check if superset must be deleted from common
 | 
			
		||||
                        deletelist=[]
 | 
			
		||||
                        index = pos+1
 | 
			
		||||
                        for rank,handle,rel1,fam1,rel2,fam2 in common[pos+1:]:
 | 
			
		||||
                            if rel1new == rel1[:len(rel1new)] and \
 | 
			
		||||
                                    rel2new == rel2[:len(rel2new)] :
 | 
			
		||||
                                deletelist.append(index)
 | 
			
		||||
                                index += 1
 | 
			
		||||
                        deletelist.reverse()
 | 
			
		||||
                        for index in deletelist:
 | 
			
		||||
                            del common[index]  
 | 
			
		||||
        #check for extra messages
 | 
			
		||||
        if self.__maxDepthReached :
 | 
			
		||||
            self.__msg += [_('Family tree reaches back more than the maximum '
 | 
			
		||||
                        '%d generations searched.\nIt is possible that '
 | 
			
		||||
                        'relationships have been missed') % (max_depth)]
 | 
			
		||||
        
 | 
			
		||||
##        print 'common list :', common
 | 
			
		||||
 | 
			
		||||
        if common and not self.__all_dist :
 | 
			
		||||
            rank          = common[0][0]
 | 
			
		||||
            person_handle = common[0][1]
 | 
			
		||||
            firstRel      = common[0][2]
 | 
			
		||||
            firstFam      = common[0][3]
 | 
			
		||||
            secondRel     = common[0][4]
 | 
			
		||||
            secondFam     = common[0][5]
 | 
			
		||||
            return (rank,person_handle,firstRel,firstFam,secondRel,secondFam),\
 | 
			
		||||
                        self.__msg
 | 
			
		||||
        if common : 
 | 
			
		||||
            #list with tuples (rank,handle person,rel_str_orig,rel_fam_orig,
 | 
			
		||||
            #       rel_str_other,rel_fam_str) and messages
 | 
			
		||||
            return common, self.__msg
 | 
			
		||||
        if not self.__all_dist :
 | 
			
		||||
            return  (-1,None,'',[],'',[]), self.__msg
 | 
			
		||||
        else :
 | 
			
		||||
            return [(-1,None,'',[],'',[])], self.__msg
 | 
			
		||||
    
 | 
			
		||||
    def __apply_filter_new(self, db, person, rel_str, rel_fam, pmap,
 | 
			
		||||
                            depth=1, stoprecursemap=None, store_all=True):
 | 
			
		||||
        '''We recursively add parents of person in pmap with correct rel_str, 
 | 
			
		||||
            if store_all. If store_all false, only store parents if in the
 | 
			
		||||
            stoprecursemap.
 | 
			
		||||
            Stop recursion if parent is in the stoprecursemap (no need to 
 | 
			
		||||
            look parents of otherpers if done so already for origpers)
 | 
			
		||||
            store pers
 | 
			
		||||
        '''
 | 
			
		||||
        if person == None or not person.handle :
 | 
			
		||||
            return
 | 
			
		||||
        if depth > self.__max_depth:
 | 
			
		||||
            self.__maxDepthReached = True
 | 
			
		||||
            print 'Max depth reached for ', person.get_primary_name(), depth,\
 | 
			
		||||
                        rel_str
 | 
			
		||||
            return
 | 
			
		||||
        depth += 1
 | 
			
		||||
        
 | 
			
		||||
        commonancestor = False
 | 
			
		||||
        if stoprecursemap and stoprecursemap.has_key(person.handle) :
 | 
			
		||||
            commonancestor = True
 | 
			
		||||
 | 
			
		||||
        #add person to the map, take into account that person can be obtained 
 | 
			
		||||
        #from different sides 
 | 
			
		||||
        if pmap.has_key(person.handle) :
 | 
			
		||||
            #person is already a grandparent in another branch, we already have
 | 
			
		||||
            # had lookup of all parents
 | 
			
		||||
            pmap[person.handle][0] += [rel_str]
 | 
			
		||||
            pmap[person.handle][1] += [rel_fam]
 | 
			
		||||
            #check if there is no loop father son of his son, ...
 | 
			
		||||
            # loop means person is twice reached, same rel_str in begin
 | 
			
		||||
            for rel1 in pmap[person.handle][0]: 
 | 
			
		||||
                for rel2 in pmap[person.handle][0] :
 | 
			
		||||
                    if len(rel1) < len(rel2) and \
 | 
			
		||||
                            rel1 == rel2[:len(rel1)]:
 | 
			
		||||
                        #loop, keep one message in storage!
 | 
			
		||||
                        self.__loopDetected = True
 | 
			
		||||
                        self.__msg += [_("Relationship loop detected:") + \
 | 
			
		||||
                            _("Person %s connects to himself via %s") % \
 | 
			
		||||
                                (person.get_primary_name().get_name(),
 | 
			
		||||
                                 rel2[len(rel1):])]
 | 
			
		||||
                        return
 | 
			
		||||
        elif store_all or commonancestor:
 | 
			
		||||
            pmap[person.handle] = [[rel_str],[rel_fam]]
 | 
			
		||||
            
 | 
			
		||||
        #having added person to the pmap, we only look up recursively to 
 | 
			
		||||
        # parents if this person is not common relative
 | 
			
		||||
        if commonancestor :
 | 
			
		||||
##            print 'common ancestor found'
 | 
			
		||||
            return 
 | 
			
		||||
 | 
			
		||||
        family_handles = []
 | 
			
		||||
        main = person.get_main_parents_family_handle()
 | 
			
		||||
##        print 'main',main
 | 
			
		||||
        if main :
 | 
			
		||||
            family_handles = [main]
 | 
			
		||||
        if self.__all_families :
 | 
			
		||||
            family_handles = person.get_parent_family_handle_list()    
 | 
			
		||||
##            print 'all_families', family_handles
 | 
			
		||||
            
 | 
			
		||||
        try:
 | 
			
		||||
            parentsdone = [] #avoid doing same parent twice in diff families
 | 
			
		||||
            fam = 0
 | 
			
		||||
##            print 'starting family loop over family_handles', family_handles
 | 
			
		||||
            for family_handle in family_handles :
 | 
			
		||||
                rel_fam_new = rel_fam +[fam]
 | 
			
		||||
                family = db.get_family_from_handle(family_handle)
 | 
			
		||||
                #obtain childref for this person
 | 
			
		||||
                childrel = [(ref.get_mother_relation(), 
 | 
			
		||||
                             ref.get_father_relation()) for ref in 
 | 
			
		||||
                                family.get_child_ref_list() 
 | 
			
		||||
                                if ref.ref == person.handle]
 | 
			
		||||
                fhandle = family.father_handle
 | 
			
		||||
##                print 'fhandle', fhandle, parentsdone
 | 
			
		||||
                if fhandle and not fhandle in parentsdone:
 | 
			
		||||
                    father = db.get_person_from_handle(fhandle)
 | 
			
		||||
                    if childrel[0][1] == gen.lib.ChildRefType.BIRTH :
 | 
			
		||||
                        addstr = self.REL_FATHER
 | 
			
		||||
                    elif not self.only_birth :
 | 
			
		||||
                        addstr = self.REL_FATHER_NOTBIRTH
 | 
			
		||||
                    else :
 | 
			
		||||
                        addstr = ''
 | 
			
		||||
##                    print 'for father, add string is =',addstr
 | 
			
		||||
                    if addstr :
 | 
			
		||||
                        parentsdone.append(fhandle)
 | 
			
		||||
                        self.__apply_filter_new(db, father,
 | 
			
		||||
                                rel_str + addstr, rel_fam_new,
 | 
			
		||||
                                pmap, depth, stoprecursemap, store_all)
 | 
			
		||||
                mhandle = family.mother_handle
 | 
			
		||||
                if mhandle and not mhandle in parentsdone:
 | 
			
		||||
                    mother = db.get_person_from_handle(mhandle)
 | 
			
		||||
                    if childrel[0][0] == gen.lib.ChildRefType.BIRTH :
 | 
			
		||||
                        addstr = self.REL_MOTHER
 | 
			
		||||
                    elif not self.only_birth :
 | 
			
		||||
                        addstr = self.REL_MOTHER_NOTBIRTH
 | 
			
		||||
                    else :
 | 
			
		||||
                        addstr = ''
 | 
			
		||||
##                    print 'for mother, add string is =',addstr
 | 
			
		||||
                    if addstr:
 | 
			
		||||
                        parentsdone.append(mhandle)
 | 
			
		||||
                        self.__apply_filter_new(db, mother,
 | 
			
		||||
                                rel_str + addstr, rel_fam_new,
 | 
			
		||||
                                pmap, depth, stoprecursemap, store_all)
 | 
			
		||||
                if not fhandle and not mhandle :
 | 
			
		||||
                    #family without parents, add brothers
 | 
			
		||||
                    child_list = [ref.ref for ref in family.get_child_ref_list()
 | 
			
		||||
                          if ref.ref != person.handle]
 | 
			
		||||
                    addstr = self.REL_SIBLING
 | 
			
		||||
                    if pmap.has_key(person.handle) :
 | 
			
		||||
                        pmap[person.handle][0] += [rel_str + addstr]
 | 
			
		||||
                        pmap[person.handle][1] += [rel_fam_new]
 | 
			
		||||
                        #person is already a grandparent in another branch
 | 
			
		||||
                    elif store_all or commonancestor:
 | 
			
		||||
                        pmap[person.handle] = [[rel_str+addstr],[rel_fam_new]]
 | 
			
		||||
                fam += 1
 | 
			
		||||
        except:
 | 
			
		||||
            import traceback
 | 
			
		||||
            print traceback.print_exc()
 | 
			
		||||
            return
 | 
			
		||||
           
 | 
			
		||||
    def get_relationship(self,db,orig_person,other_person):
 | 
			
		||||
        """
 | 
			
		||||
        returns a string representping the relationshp between the two people,
 | 
			
		||||
        returns a string representing the relationshp between the two people,
 | 
			
		||||
        along with a list of common ancestors (typically father,mother) 
 | 
			
		||||
        """
 | 
			
		||||
 | 
			
		||||
        if orig_person == None:
 | 
			
		||||
            return ("undefined",[])
 | 
			
		||||
            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,[])
 | 
			
		||||
 | 
			
		||||
        (firstRel,secondRel,common) = \
 | 
			
		||||
                     self.get_relationship_distance(db,orig_person,other_person)
 | 
			
		||||
                self.get_relationship_distance(db,orig_person,other_person)
 | 
			
		||||
        
 | 
			
		||||
        if type(common) == types.StringType or \
 | 
			
		||||
           type(common) == types.UnicodeType:
 | 
			
		||||
            return (common,[])
 | 
			
		||||
            if is_spouse:
 | 
			
		||||
                return (is_spouse,[])
 | 
			
		||||
            else:
 | 
			
		||||
                return (common,[])
 | 
			
		||||
        elif common:
 | 
			
		||||
            person_handle = common[0]
 | 
			
		||||
        else:
 | 
			
		||||
            return ("",[])
 | 
			
		||||
            if is_spouse:
 | 
			
		||||
                return (is_spouse,[])
 | 
			
		||||
            else:
 | 
			
		||||
                return ("",[])
 | 
			
		||||
 | 
			
		||||
        firstRel = len(firstRel)
 | 
			
		||||
        secondRel = len(secondRel)
 | 
			
		||||
 | 
			
		||||
        if firstRel == 0:
 | 
			
		||||
            if secondRel == 0:
 | 
			
		||||
                return ('',common)
 | 
			
		||||
            elif other_person.get_gender() == gen.lib.Person.MALE:
 | 
			
		||||
                return (self.get_father(secondRel),common)
 | 
			
		||||
            else:
 | 
			
		||||
                return (self.get_mother(secondRel),common)
 | 
			
		||||
        elif secondRel == 0:
 | 
			
		||||
            if other_person.get_gender() == gen.lib.Person.MALE:
 | 
			
		||||
                return (self.get_son(firstRel),common)
 | 
			
		||||
            else:
 | 
			
		||||
                return (self.get_daughter(firstRel),common)
 | 
			
		||||
        elif firstRel == 1:
 | 
			
		||||
            if other_person.get_gender() == gen.lib.Person.MALE:
 | 
			
		||||
                return (self.get_uncle(secondRel),common)
 | 
			
		||||
            else:
 | 
			
		||||
                return (self.get_aunt(secondRel),common)
 | 
			
		||||
        elif secondRel == 1:
 | 
			
		||||
            if other_person.get_gender() == gen.lib.Person.MALE:
 | 
			
		||||
                return (self.get_nephew(firstRel-1),common)
 | 
			
		||||
            else:
 | 
			
		||||
                return (self.get_niece(firstRel-1),common)
 | 
			
		||||
        #distance from common ancestor to the people
 | 
			
		||||
        dist_orig = len(firstRel)
 | 
			
		||||
        dist_other= len(secondRel)
 | 
			
		||||
        rel_str = self.get_single_relationship_string(dist_orig,
 | 
			
		||||
                                                      dist_other,
 | 
			
		||||
                                                      orig_person.get_gender(),
 | 
			
		||||
                                                      other_person.get_gender()
 | 
			
		||||
                                                     )
 | 
			
		||||
        if is_spouse:
 | 
			
		||||
            return (is_spouse + ' and ' + rel_str, common)
 | 
			
		||||
        else:
 | 
			
		||||
            if secondRel > firstRel:
 | 
			
		||||
                return (self.get_cousin(firstRel-1,secondRel-firstRel),common)
 | 
			
		||||
            else:
 | 
			
		||||
                return (self.get_cousin(secondRel-1,firstRel-secondRel),common)
 | 
			
		||||
            return (rel_str, common)
 | 
			
		||||
##        #original programmer did a sick joke here, switching first with other!
 | 
			
		||||
##        firstRel = dist_other
 | 
			
		||||
##        secondRel = dist_orig
 | 
			
		||||
##
 | 
			
		||||
##        if firstRel == 0:        #other is common ancestor, so a father/mother
 | 
			
		||||
##            if secondRel == 0:
 | 
			
		||||
##                return ('',common)
 | 
			
		||||
##            elif other_person.get_gender() == gen.lib.Person.MALE:
 | 
			
		||||
##                return (self.get_father(secondRel),common)
 | 
			
		||||
##            else:
 | 
			
		||||
##                return (self.get_mother(secondRel),common)
 | 
			
		||||
##        elif secondRel == 0:    #orig is common ancestor, so other is son/daugh
 | 
			
		||||
##            if other_person.get_gender() == gen.lib.Person.MALE:
 | 
			
		||||
##                return (self.get_son(firstRel),common)
 | 
			
		||||
##            else:
 | 
			
		||||
##                return (self.get_daughter(firstRel),common)
 | 
			
		||||
##        elif firstRel == 1:
 | 
			
		||||
##            if other_person.get_gender() == gen.lib.Person.MALE:
 | 
			
		||||
##                return (self.get_uncle(secondRel),common)
 | 
			
		||||
##            else:
 | 
			
		||||
##                return (self.get_aunt(secondRel),common)
 | 
			
		||||
##        elif secondRel == 1:
 | 
			
		||||
##            if other_person.get_gender() == gen.lib.Person.MALE:
 | 
			
		||||
##                return (self.get_nephew(firstRel-1),common)
 | 
			
		||||
##            else:
 | 
			
		||||
##                return (self.get_niece(firstRel-1),common)
 | 
			
		||||
##        else:
 | 
			
		||||
##            if secondRel > firstRel:
 | 
			
		||||
##                return (self.get_cousin(firstRel-1,secondRel-firstRel),common)
 | 
			
		||||
##            else:
 | 
			
		||||
##                return (self.get_cousin(secondRel-1,firstRel-secondRel),common)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def get_grandparents_string(self,db,orig_person,other_person):
 | 
			
		||||
@@ -488,7 +873,7 @@ class RelationshipCalculator:
 | 
			
		||||
        else:
 | 
			
		||||
            return None
 | 
			
		||||
        
 | 
			
		||||
    def get_plural_relationship_string(self,Ga,Gb):
 | 
			
		||||
    def get_plural_relationship_string(self, Ga, Gb):
 | 
			
		||||
        """
 | 
			
		||||
        Provides a string that describes the relationsip between a person, and
 | 
			
		||||
        a group of people with the same relationship. E.g. "grandparents" or
 | 
			
		||||
@@ -558,3 +943,106 @@ class RelationshipCalculator:
 | 
			
		||||
            else:
 | 
			
		||||
                rel_str =  "distant cousins"
 | 
			
		||||
        return rel_str
 | 
			
		||||
    
 | 
			
		||||
    def get_single_relationship_string(self, Ga, Gb, gender_a, gender_b,
 | 
			
		||||
                                       only_birth=True):
 | 
			
		||||
        """
 | 
			
		||||
        Provides a string that describes the relationsip between a person, and
 | 
			
		||||
        another person. E.g. "grandparent" or "child".
 | 
			
		||||
        To be used as: 'person a is the grandparent of b', this will 
 | 
			
		||||
            be in translation string :
 | 
			
		||||
                            'person a is the %(relation)s of b'
 | 
			
		||||
            Note that languages with gender should add 'the' inside the 
 | 
			
		||||
            translation, so eg in french:
 | 
			
		||||
                            'person a est %(relation)s de b'
 | 
			
		||||
            where relation will be here: le grandparent
 | 
			
		||||
        
 | 
			
		||||
        Ga and Gb can be used to mathematically calculate the relationship.
 | 
			
		||||
        See the Wikipedia entry for more information:
 | 
			
		||||
            http://en.wikipedia.org/wiki/Cousin#Mathematical_definitions
 | 
			
		||||
            
 | 
			
		||||
        @param Ga: The number of generations between the main person and the 
 | 
			
		||||
                   common ancestor.
 | 
			
		||||
        @type Ga: int
 | 
			
		||||
        @param Gb: The number of generations between the other person and the
 | 
			
		||||
                   common ancestor
 | 
			
		||||
        @type Gb: int
 | 
			
		||||
        @param gender_a : gender of person a
 | 
			
		||||
        @type gender_a: int gender
 | 
			
		||||
        @param gender_b : gender of person b
 | 
			
		||||
        @type gender_b: int gender
 | 
			
		||||
        @param only_birth : True if relation between a and b is by birth only
 | 
			
		||||
                            False otherwise
 | 
			
		||||
        @type only_birth: bool
 | 
			
		||||
        @returns: A string describing the relationship between the two people
 | 
			
		||||
        @rtype: str
 | 
			
		||||
        """
 | 
			
		||||
##        print 'Ga, Gb :', Ga, Gb
 | 
			
		||||
        rel_str = "distant relatives"
 | 
			
		||||
        if Ga == 0:
 | 
			
		||||
            # b is descendant of a
 | 
			
		||||
            if Gb == 0 :
 | 
			
		||||
                rel_str = 'same person'
 | 
			
		||||
            elif gender_b == gen.lib.Person.MALE and Gb < len(_son_level):
 | 
			
		||||
                rel_str = _son_level[Gb]
 | 
			
		||||
            elif gender_b == gen.lib.Person.FEMALE and Gb < len(_daughter_level):
 | 
			
		||||
                rel_str = _daughter_level[Gb]
 | 
			
		||||
            elif Gb < len(_level_name):
 | 
			
		||||
                rel_str = _level_name[Gb] + ' ' + 'descendant'
 | 
			
		||||
            else:
 | 
			
		||||
                rel_str = "distant descendant (%d generations)" % Gb
 | 
			
		||||
        elif Gb == 0:
 | 
			
		||||
            # b is parents/grand parent of a
 | 
			
		||||
            if gender_b == gen.lib.Person.MALE and Ga < len(_father_level):
 | 
			
		||||
                rel_str = _father_level[Ga]
 | 
			
		||||
            elif gender_b == gen.lib.Person.FEMALE and Gb < len(_mother_level):
 | 
			
		||||
                rel_str = _mother_level[Ga]
 | 
			
		||||
            elif Ga < len(_level_name):
 | 
			
		||||
                rel_str = _level_name[Ga] + ' ' + 'ancestor'
 | 
			
		||||
            else:
 | 
			
		||||
                rel_str = "distant ancestor (%d generations)" % Ga
 | 
			
		||||
        elif Gb == 1:
 | 
			
		||||
            # b is sibling/aunt/uncle of a
 | 
			
		||||
            if gender_b == gen.lib.Person.MALE and Ga < len(_brother_level):
 | 
			
		||||
                rel_str = _brother_level[Ga]
 | 
			
		||||
            elif gender_b == gen.lib.Person.FEMALE and Ga < len(_sister_level):
 | 
			
		||||
                rel_str = _sister_level[Ga]
 | 
			
		||||
            elif Ga < len(_sibling_level):
 | 
			
		||||
                rel_str = _sibling_level[Ga]
 | 
			
		||||
            else:
 | 
			
		||||
                rel_str = "distant uncle/aunt"
 | 
			
		||||
        elif Ga == 1:
 | 
			
		||||
            # b is niece/nephew of a
 | 
			
		||||
            if gender_b == gen.lib.Person.MALE and Gb < len(_nephew_level):
 | 
			
		||||
                rel_str = _nephew_level[Gb]
 | 
			
		||||
            elif gender_b == gen.lib.Person.FEMALE and Gb < len(_niece_level):
 | 
			
		||||
                rel_str = _niece_level[Gb]
 | 
			
		||||
            elif Gb < len(_niece_level) and Gb < len(_nephew_level):
 | 
			
		||||
                rel_str = "%s or %s" %(_nephew_level[Gb], _niece_level[Gb])
 | 
			
		||||
            else:
 | 
			
		||||
                rel_str = "distant nephews/nieces"
 | 
			
		||||
        elif Ga > 1 and Ga == Gb:
 | 
			
		||||
            # a and b cousins in the same generation
 | 
			
		||||
            if Ga <= len(_level_name):
 | 
			
		||||
                rel_str = "%s cousin" % _level_name[Ga-1]
 | 
			
		||||
            else:
 | 
			
		||||
                rel_str = "distant cousin"
 | 
			
		||||
        elif Ga > 1 and Ga > Gb:
 | 
			
		||||
            # These are cousins in different generations with the second person 
 | 
			
		||||
            # being in a higher generation from the common ancestor than the 
 | 
			
		||||
            # first person.
 | 
			
		||||
            if Gb <= len(_level_name) and (Ga-Gb) < len(_removed_level):
 | 
			
		||||
                rel_str = "%s cousin%s (up)" % ( _level_name[Gb-1], 
 | 
			
		||||
                                                  _removed_level[Ga-Gb] )
 | 
			
		||||
            else:
 | 
			
		||||
                rel_str =  "distant cousin"
 | 
			
		||||
        elif Gb > 1 and Gb > Ga:
 | 
			
		||||
            # These are cousins in different generations with the second person 
 | 
			
		||||
            # being in a lower generation from the common ancestor than the 
 | 
			
		||||
            # first person.
 | 
			
		||||
            if Ga <= len(_level_name) and (Gb-Ga) < len(_removed_level):
 | 
			
		||||
                rel_str = "%s cousin%s (down)" % ( _level_name[Ga-1], 
 | 
			
		||||
                                                    _removed_level[Gb-Ga] )
 | 
			
		||||
            else:
 | 
			
		||||
                rel_str =  "distant cousin"
 | 
			
		||||
        return rel_str
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										177
									
								
								src/plugins/all_relations.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										177
									
								
								src/plugins/all_relations.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,177 @@
 | 
			
		||||
#
 | 
			
		||||
# Gramps - a GTK+/GNOME based genealogy program
 | 
			
		||||
#
 | 
			
		||||
# Copyright (C) 2007  B. Malengier
 | 
			
		||||
#
 | 
			
		||||
# This program is free software; you can redistribute it and/or modify
 | 
			
		||||
# it under the terms of the GNU General Public License as published by
 | 
			
		||||
# the Free Software Foundation; either version 2 of the License, or
 | 
			
		||||
# (at your option) any later version.
 | 
			
		||||
#
 | 
			
		||||
# This program is distributed in the hope that it will be useful,
 | 
			
		||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
# GNU General Public License for more details.
 | 
			
		||||
#
 | 
			
		||||
# You should have received a copy of the GNU General Public License
 | 
			
		||||
# along with this program; if not, write to the Free Software
 | 
			
		||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
Display a person's relations to the home person
 | 
			
		||||
"""
 | 
			
		||||
#-------------------------------------------------------------------------
 | 
			
		||||
#
 | 
			
		||||
# GRAMPS modules
 | 
			
		||||
#
 | 
			
		||||
#-------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
from Simple import SimpleAccess, SimpleDoc
 | 
			
		||||
from gettext import gettext as _
 | 
			
		||||
from PluginUtils import register_quick_report
 | 
			
		||||
from ReportBase import CATEGORY_QR_PERSON
 | 
			
		||||
 | 
			
		||||
from PluginUtils import Tool, relationship_class, register_tool
 | 
			
		||||
import RelLib
 | 
			
		||||
 | 
			
		||||
# define the formatting string once as a constant. Since this is reused
 | 
			
		||||
 | 
			
		||||
__FMT     = "%-3d %s"
 | 
			
		||||
__FMT_DET1 ="%-3s %-15s"
 | 
			
		||||
__FMT_DET2 ="%-30s %-15s\t%-10s %-2s"
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
def run(database, document, person):
 | 
			
		||||
    """
 | 
			
		||||
    Obtains all relationships, displays the relations, and in details, the 
 | 
			
		||||
    relation path
 | 
			
		||||
    """
 | 
			
		||||
    
 | 
			
		||||
    sdb = SimpleAccess(database)
 | 
			
		||||
    sdoc = SimpleDoc(document)
 | 
			
		||||
    rel_class = relationship_class()
 | 
			
		||||
 | 
			
		||||
    #get home_person
 | 
			
		||||
    home_person = database.get_default_person()
 | 
			
		||||
    if not home_person :
 | 
			
		||||
        sdoc.paragraph(_("Home person not set."))
 | 
			
		||||
        return
 | 
			
		||||
 | 
			
		||||
    #print title
 | 
			
		||||
    sdoc.title(_("Relationships of %s to %s") % (sdb.name(person) ,
 | 
			
		||||
                    sdb.name(home_person)))
 | 
			
		||||
    sdoc.paragraph("")
 | 
			
		||||
    
 | 
			
		||||
    #obtain all relationships, assume home person has largest tree
 | 
			
		||||
    common, msg_list = rel_class.get_relationship_distance_new(
 | 
			
		||||
                database, person, home_person,
 | 
			
		||||
                all_families=True, 
 | 
			
		||||
                all_dist=True, 
 | 
			
		||||
                only_birth=False,
 | 
			
		||||
                max_depth=20)
 | 
			
		||||
                
 | 
			
		||||
    #check if not a family too:
 | 
			
		||||
    is_spouse = rel_class.is_spouse(database,person,home_person)
 | 
			
		||||
    if is_spouse:
 | 
			
		||||
        msg_list.insert(0,_('Additional relation:')+is_spouse)
 | 
			
		||||
    
 | 
			
		||||
    #all relations
 | 
			
		||||
    if not common or common[0][0]== -1 :
 | 
			
		||||
        rel_str = _("Not related.")
 | 
			
		||||
        remarks(msg_list,sdoc)
 | 
			
		||||
        return
 | 
			
		||||
    
 | 
			
		||||
    count = 1  
 | 
			
		||||
    for relation in common: 
 | 
			
		||||
        rel_str = rel_class.get_single_relationship_string(len(relation[4]),
 | 
			
		||||
                        len(relation[2]),person.get_gender())
 | 
			
		||||
        sdoc.paragraph(__FMT % (count, rel_str))
 | 
			
		||||
        count += 1
 | 
			
		||||
            
 | 
			
		||||
    remarks(msg_list, sdoc)
 | 
			
		||||
    
 | 
			
		||||
    sdoc.paragraph("")
 | 
			
		||||
    sdoc.header1(_("Detailed path to common ancestor"))
 | 
			
		||||
    sdoc.paragraph("")
 | 
			
		||||
    sdoc.header2(__FMT_DET1 % (_('   '), _('Name Common ancestor')))
 | 
			
		||||
    sdoc.header2(__FMT_DET2 % (' ', _('Parent'), _('Birth'), _('Family')))
 | 
			
		||||
    sdoc.paragraph("")
 | 
			
		||||
    count = 1
 | 
			
		||||
    for relation in common: 
 | 
			
		||||
        counter = str(count)
 | 
			
		||||
        name = sdb.name(database.get_person_from_handle(relation[1]))
 | 
			
		||||
        sdoc.paragraph(__FMT_DET1 % (counter, name))
 | 
			
		||||
        for rel,fam in zip(relation[2],relation[3]) :
 | 
			
		||||
            par_str = _('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')
 | 
			
		||||
            birth_str = _('Yes')
 | 
			
		||||
            if rel == rel_class.REL_MOTHER_NOTBIRTH \
 | 
			
		||||
                    or rel == rel_class.REL_FATHER_NOTBIRTH:
 | 
			
		||||
                birth_str = _('No')
 | 
			
		||||
            sdoc.paragraph(__FMT_DET2 % (' ', par_str, birth_str, str(fam+1)))
 | 
			
		||||
            counter=''
 | 
			
		||||
            name = ''
 | 
			
		||||
        count += 1
 | 
			
		||||
    
 | 
			
		||||
    sdoc.paragraph("")
 | 
			
		||||
    sdoc.header1(_("Detailed path for home person to common ancestor"))
 | 
			
		||||
    sdoc.paragraph("")
 | 
			
		||||
    sdoc.header2(__FMT_DET1 % (_('   '), _('Name Common ancestor')))
 | 
			
		||||
    sdoc.header2(__FMT_DET2 % (' ', _('Parent'), _('Birth'), _('Family')))
 | 
			
		||||
    sdoc.paragraph("")
 | 
			
		||||
    count = 1
 | 
			
		||||
    for relation in common: 
 | 
			
		||||
        counter = str(count)
 | 
			
		||||
        name = sdb.name(database.get_person_from_handle(relation[1]))
 | 
			
		||||
        sdoc.paragraph(__FMT_DET1 % (counter, name))
 | 
			
		||||
        for rel,fam in zip(relation[4],relation[5]) :
 | 
			
		||||
            par_str = _('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')
 | 
			
		||||
            birth_str = _('Yes')
 | 
			
		||||
            if rel == rel_class.REL_MOTHER_NOTBIRTH \
 | 
			
		||||
                    or rel == rel_class.REL_FATHER_NOTBIRTH:
 | 
			
		||||
                birth_str = _('No')
 | 
			
		||||
            sdoc.paragraph(__FMT_DET2 % (' ', par_str, birth_str, str(fam+1)))
 | 
			
		||||
            counter=''
 | 
			
		||||
            name = ''
 | 
			
		||||
        count += 1
 | 
			
		||||
    
 | 
			
		||||
            
 | 
			
		||||
def remarks(msg_list,sdoc):
 | 
			
		||||
    if msg_list :
 | 
			
		||||
        sdoc.paragraph("")
 | 
			
		||||
        sdoc.header1(_("Remarks"))
 | 
			
		||||
        sdoc.paragraph("")
 | 
			
		||||
        sdoc.paragraph(_("The following problems where encountered:"))
 | 
			
		||||
        for msg in msg_list :
 | 
			
		||||
            sdoc.paragraph(msg)
 | 
			
		||||
        sdoc.paragraph("")
 | 
			
		||||
        sdoc.paragraph("")
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
#------------------------------------------------------------------------
 | 
			
		||||
#
 | 
			
		||||
# 
 | 
			
		||||
#
 | 
			
		||||
#------------------------------------------------------------------------
 | 
			
		||||
register_quick_report(
 | 
			
		||||
    name = 'all_relations',
 | 
			
		||||
    category = CATEGORY_QR_PERSON,
 | 
			
		||||
    run_func = run,
 | 
			
		||||
    translated_name = _("Relation to Home Person"),
 | 
			
		||||
    status = _("Stable"),
 | 
			
		||||
    description= _("Display all relationships between person and home person."),
 | 
			
		||||
    author_name="B. Malengier",
 | 
			
		||||
    author_email="benny.malengier@gramps-project.org"
 | 
			
		||||
    )
 | 
			
		||||
		Reference in New Issue
	
	Block a user