forked from gramps-project/addons-source
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathRelatedRelativesGramplet.py
255 lines (241 loc) · 13.4 KB
/
RelatedRelativesGramplet.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2011 Heinz Brinker
#
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
# $Id: RelativeRelations.py 15814 2010-08-25 04:25:08Z dsblank $
#------------------------------------------------------------------------
#
# Python modules
#
#------------------------------------------------------------------------
import posixpath
#------------------------------------------------------------------------
#
# GRAMPS modules
#
#------------------------------------------------------------------------
from gramps.gen.display.name import displayer as name_displayer
from gramps.gen.plug import Gramplet
from gramps.gen.const import GRAMPS_LOCALE as glocale
try:
_trans = glocale.get_addon_translator(__file__)
except ValueError:
_trans = glocale.translation
_ = _trans.gettext
from gramps.gen.utils.file import media_path_full
from gramps.gen.relationship import get_relationship_calculator
import gramps.gen.datehandler
#------------------------------------------------------------------------
#
# Gramplet class
#
#------------------------------------------------------------------------
class RelatedRelativesGramplet(Gramplet):
def init(self):
self.set_text(_("No Family Tree loaded."))
# self.set_tooltip(_("Double-click item to see matches"))
#
# Register database triggers for updates
#
def db_changed(self):
self.connect(self.dbstate.db, 'person-add', self.update)
self.connect(self.dbstate.db, 'person-delete', self.update)
self.connect(self.dbstate.db, 'family-add', self.update)
self.connect(self.dbstate.db, 'family-delete', self.update)
self.connect(self.dbstate.db, 'person-rebuild', self.update)
self.connect(self.dbstate.db, 'family-rebuild', self.update)
#
# Function that recursively adds all descendants of a person to the
# person_handle_list
#
def addDescendants(self, ancestorHandle):
# If this person is not yet in the list, add person (and its descendants
# to descendants list.
if ancestorHandle not in self.person_handle_list:
self.person_handle_list.append(ancestorHandle)
# Check if person is father or mother in a family
ancestor = self.dbstate.db.get_person_from_handle(ancestorHandle)
if ancestor:
for family_handle in ancestor.get_family_handle_list():
if family_handle:
family = self.dbstate.db.get_family_from_handle(family_handle)
if family:
# Add all children of the person to the list by
# recursively calling this function for each one.
childlist = family.get_child_ref_list()[:]
for child_ref in childlist:
self.addDescendants(child_ref.ref)
#
# Main function, called when the gramplet is opened or updated
#
def main(self):
# Write heading text to gramplet
self.set_text(_("Relations of related people in your database:"))
# Define basic variables
database = self.dbstate.db
rel_calc = get_relationship_calculator()
family_handle_list = [] # Will keep list of families with no ancestors
# Find all base families with no ancestors in the database.
flist = database.iter_family_handles()
for familyhandle in flist:
family = database.get_family_from_handle(familyhandle)
# Check if mother of this family is child of another family
# If this is the case, skip this family
ancestorHandle = family.get_mother_handle()
if ancestorHandle:
mother = database.get_person_from_handle(ancestorHandle)
parent_handle_list = mother.get_parent_family_handle_list()
if parent_handle_list:
continue
# Check if father of this family is child of another family
# If this is the case, skip this family
ancestorHandle = family.get_father_handle()
if ancestorHandle:
father = database.get_person_from_handle(ancestorHandle)
parent_handle_list = father.get_parent_family_handle_list()
if parent_handle_list:
continue
# Members of this family have no ancestors. Add family to base
# family handle list
family_handle_list.append(familyhandle)
yield True
# The base family handle list now contains all families that have
# no ancestors. Now iterate through found families. For each family
# first find all descendants and then check if one person in this
# family tree is partner of another person in the same tree.
#
# Related relatives may be found more than once from different base
# families. Therefore we hold a list of all found pairs to avoid
# listing them more than once
pair_p1_list = [] # List of all 1st related partners for all families
pair_p2_list = [] # List of all 2nd related partners for all families
for familyhandle in family_handle_list:
# Build list of all related persons (descendants) of this family.
self.person_handle_list = []
family = database.get_family_from_handle(familyhandle)
# Add all descendants of the father to person list of this family
father_handle = family.get_father_handle()
if father_handle:
father = database.get_person_from_handle(father_handle)
# Add all descendants of the father
self.addDescendants(father_handle)
mother_handle = family.get_mother_handle()
# Add all descendants of the mother to person list of this family
if mother_handle:
mother = database.get_person_from_handle(mother_handle)
# Add all descendants of the mother
self.addDescendants(mother_handle)
# The person list of all descendants for this family is complete.
# Now check for every person in the list if it has a partner that
# is also in this list
for checkHandle in self.person_handle_list:
person = database.get_person_from_handle(checkHandle)
if person:
pfamily_handle_list = person.get_family_handle_list()
if pfamily_handle_list:
for family_handle in pfamily_handle_list:
# Skip the family if it is listed in the base
# families list (which should be quite short).
if family_handle in family_handle_list:
continue
# If current person is father or mother in a family
# find the handle of the partner
family = database.get_family_from_handle(family_handle)
father_handle = family.get_father_handle()
mother_handle = family.get_mother_handle()
if checkHandle == father_handle:
handlepartner = mother_handle
else:
handlepartner = father_handle
# If the partner is in our list of persons of this
# family tree, both are related.
if handlepartner in self.person_handle_list:
newEntry = True;
# Check if this pair is already in the lists of
# related partners. A and B will also appear as
# B and A. So we have to cross check
for ii in range(len(pair_p1_list)):
if checkHandle == pair_p1_list[ii]:
if handlepartner == pair_p2_list[ii]:
newEntry = False
if checkHandle == pair_p2_list[ii]:
if handlepartner == pair_p1_list[ii]:
newEntry = False
# If this pair is not yet listed, add them to
# the list and show their relationship in the
# gramplet window.
if newEntry:
# Add pair to list of found related relatives
pair_p1_list.append(checkHandle)
pair_p2_list.append(handlepartner)
partner = self.dbstate.db. \
get_person_from_handle(handlepartner)
# Find relation between the partners by use
# of the relationship calculator. Print all
# relationships A to B and B to A.
rel_strings, common_an = \
rel_calc.get_all_relationships(database,
person,
partner)
rel_strings1, common_an1 = \
rel_calc.get_all_relationships(database,
partner,
person)
if len(rel_strings) > 1:
# Output names of both partners as links
p1name = name_displayer.display(person)
self.append_text("\n\n")
self.link(p1name, 'Person', checkHandle)
p2name = name_displayer.display(partner)
self.append_text(" " + _("and") + " ")
self.link(p2name, 'Person', handlepartner)
self.append_text(" " + \
_("are partners and") + \
":")
# Omit the first relationship from list
for x in range(1, len(rel_strings)):
self.append_text("\n%s" %
rel_strings[x])
try:
self.append_text(" & %s" %
rel_strings1[x])
except:
continue
# Print list of common ancestors for
# the found relation.
# Remove duplicate ancestors
anc_list = list(set(common_an[x]))
for anc in anc_list:
person = database. \
get_person_from_handle(anc)
if person:
# Print ancestor as link
pname = name_displayer. \
display(person)
self.append_text("\n\t" \
+ _("Common ancestor") \
+ " ")
self.link(pname, 'Person',
anc)
# After the check for each persons family allow other
# threads to do some work.
yield True
# If the list of related pairs is empty we did not find any related
# relatives in the database.
if len(pair_p1_list) == 0:
self.append_text("\n" + _("No relatives in a relation found") + ".\n")
self.append_text("\n\n" + _("END") + "\n")
return