Skip to content

Commit dc5ba84

Browse files
todef96sam-m888
authored andcommitted
[HouseTimelineGramplet]ADD: houses organised by feature (#159)[gramps50]
ADD: houses organised by number/locality, residents with multiple records listed as date range
1 parent 7d06c2e commit dc5ba84

File tree

1 file changed

+56
-40
lines changed

1 file changed

+56
-40
lines changed

HouseTimelineGramplet/housetimeline.py

100644100755
Lines changed: 56 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,12 @@ class HouseTimelineGramplet(Gramplet):
2323
def init(self):
2424
self.house_width = 40
2525
self.set_tooltip(_("Double-click name for details"))
26+
# self.set_text(_("No Family Tree loaded."))
2627

2728
def on_load(self):
2829
self.no_wrap()
2930
tag = self.gui.buffer.create_tag("fixed")
3031
tag.set_property("font", "Courier 8")
31-
# set default house icon style.
3232
if len(self.gui.data) != 1:
3333
self.gui.data[:] = ["001", None]
3434

@@ -38,14 +38,13 @@ def db_changed(self):
3838
self.connect(self.dbstate.db,'person-delete', self.update)
3939

4040
def save_update_options(self, widget=None):
41-
# saves a specific house icon style.
4241
style = self.get_option(_("House Icon Style"))
4342
self.gui.data[:] = [style.get_value()]
4443
self.update()
4544

4645
def build_options(self):
47-
# builds a menu dropdown list of options.
4846
from gramps.gen.plug.menu import EnumeratedListOption
47+
# Add types:
4948
style_list = EnumeratedListOption(_("House Icon Style"), self.gui.data[0])
5049
for item in [("001", _("Standard")),
5150
("002", _("Small")),
@@ -58,11 +57,10 @@ def build_options(self):
5857
def main(self):
5958
self.set_text(_("Processing...") + "\n")
6059
yield True
61-
self.count_dict = defaultdict(int)
62-
self.residents = {}
6360
self.sorted_residents = {}
6461
self.clear_text()
6562
address_count = 0
63+
self.residents_range = []
6664
# get details of people dbhandle, name, address
6765
for p in self.dbstate.db.iter_people():
6866
person_handle = p.handle
@@ -74,9 +72,9 @@ def main(self):
7472
for item in person_addr:
7573
# address format from db is:
7674
# [0] street, [1] locality, [2] city, [3] pcode, [4] state/county, [5] country, [6] phone
77-
location = item.get_text_data_list()
75+
address = item.get_text_data_list()
7876
date = item.get_date_object()
79-
self.build_parent_address_dict(location,date,person_handle,person_name)
77+
self.build_parent_address_dict(address,date,person_handle,person_name)
8078

8179
if address_count == 0:
8280
self.set_text(_("There are no individuals with Address data. Please add Address data to people."))
@@ -88,17 +86,20 @@ def main(self):
8886

8987
def build_parent_address_dict(self, address, date, person_handle, person_name):
9088
"""
91-
Builds self.residents, The address + person_handle object.
92-
The collection is Address keyed (distinct)
89+
Builds self.sorted_residents, The address + person_handle object.
90+
The collection is grouped by locality/city (group_key) and sub key (address_key)
9391
"""
94-
# TODO: group addresses by locality or city
92+
# group key represents a group of similar locality/city.
93+
group_key = address[1] + address[2]
94+
# address key is the actual property address.
9595
address_key = self.format_address_key(address)
96-
# set resident to index key
97-
if address_key not in self.residents:
98-
self.residents[address_key] = {self.count_dict[address_key]: {'address':address,'date':date.get_ymd(),'handle':person_handle,'pname': person_name}}
99-
elif address_key in self.residents:
100-
self.residents[address_key][self.count_dict[address_key]] = {'address':address,'date':date.get_ymd(),'handle':person_handle,'pname': person_name}
101-
self.count_dict[address_key] += 1
96+
if group_key not in self.sorted_residents:
97+
self.sorted_residents[group_key] = {address_key: [[date.get_ymd(),person_handle,person_name]]}
98+
elif group_key in self.sorted_residents:
99+
if address_key not in self.sorted_residents[group_key]:
100+
self.sorted_residents[group_key][address_key] = [[date.get_ymd(),person_handle,person_name]]
101+
elif address_key in self.sorted_residents[group_key]:
102+
self.sorted_residents[group_key][address_key] += [[date.get_ymd(),person_handle,person_name]]
102103

103104
def format_address_key(self, address):
104105
"""
@@ -112,7 +113,7 @@ def format_address_key(self, address):
112113

113114
def build_house(self):
114115
"""
115-
Outputs sorted details from self.residents.
116+
Outputs sorted details from self.sorted_residents.
116117
"""
117118
gl_location = _("Location")
118119
gl_time = _("Time In Family")
@@ -121,29 +122,44 @@ def build_house(self):
121122
gl_timeline = _("Timeline")
122123
gl_unknown = _("Unknown")
123124
gl_total_residents = _("Total Known Residents")
124-
for resident in self.residents.items():
125-
# sort residents by date.
126-
sorted_dates = sorted(resident[1].items(),key=lambda k: k[1]['date'])
127-
first_year = 0
128-
last_year = int(sorted_dates[-1][1]['date'][0])
129-
for years in sorted_dates:
130-
date = years[1]['date'][0]
131-
first_year = date if date != 0 and first_year == 0 else first_year
132-
time_in_family = last_year - first_year if first_year != 0 else gl_unknown
133-
self.append_text("=========================\n")
134-
self.render_house(self.gui.data[0])
135-
self.append_text("{0}: {1}\n".format(gl_location,resident[0]) +
136-
("{0}: {1} years\n".format(gl_time,time_in_family)) +
137-
("{0}: {1} - {2}\n".format(gl_first_resident,sorted_dates[0][1]['date'][0],sorted_dates[0][1]['pname'])) +
138-
("{0}: {1} - {2}\n".format(gl_last_resident,sorted_dates[-1][1]['date'][0],sorted_dates[-1][1]['pname'])) +
139-
("{0}: {1}\n".format(gl_total_residents,len(sorted_dates))) +
140-
" \n")
141-
self.append_text("{0}:\n".format(gl_timeline))
142-
# TODO: if duplicate person handles exist, denote as time period of person.
143-
for item in sorted_dates:
144-
self.append_text("{0} - ".format(item[1]['date'][0]))
145-
self.link(item[1]['pname'],"Person",item[1]['handle'])
146-
self.append_text("\n")
125+
126+
for resident in self.sorted_residents.items():
127+
# sort by house number
128+
for item in sorted(resident[1].items()):
129+
# sort residents of an address by date.
130+
sorted_dates = sorted(item[1],key=lambda k: k[0][0])
131+
residents_reversed = sorted(sorted_dates, reverse=True)
132+
# we need a list of distinct handles to get the correct resident count per address.
133+
distinct_handles = []
134+
for h in sorted_dates:
135+
if h[1] not in distinct_handles:
136+
distinct_handles.append(h[1])
137+
first_year = int(sorted_dates[0][0][0])
138+
last_year = int(sorted_dates[-1][0][0])
139+
time_in_family = last_year - first_year if first_year != 0 else gl_unknown
140+
self.append_text("=========================\n")
141+
self.render_house(self.gui.data[0])
142+
self.append_text("{0}: {1}\n".format(gl_location,item[0]) +
143+
("{0}: {1} years\n".format(gl_time,time_in_family)) +
144+
("{0}: {1} - {2}\n".format(gl_first_resident,sorted_dates[0][0][0],sorted_dates[0][2])) +
145+
("{0}: {1} - {2}\n".format(gl_last_resident,sorted_dates[-1][0][0],sorted_dates[-1][2])) +
146+
("{0}: {1}\n".format(gl_total_residents,len(distinct_handles))) +
147+
" \n")
148+
self.append_text("{0}:\n".format(gl_timeline))
149+
# for each person that is a resident, display the date and name with link.
150+
for detail in sorted_dates:
151+
# if a person has two address details, display the person living there as a range between two dates.
152+
first_handle = detail
153+
last_handle = next(handle for handle in residents_reversed if handle[1] == first_handle[1])
154+
if (detail[0][0] != last_handle[0][0] and detail[1] not in self.residents_range):
155+
self.append_text("{0} -> {1} - ".format(first_handle[0][0],last_handle[0][0]))
156+
self.link(detail[2],"Person",detail[1])
157+
self.append_text("\n")
158+
self.residents_range.append(first_handle[1])
159+
elif detail[1] not in self.residents_range:
160+
self.append_text("{0} - ".format(detail[0][0]))
161+
self.link(detail[2],"Person",detail[1])
162+
self.append_text("\n")
147163

148164
def render_house(self,house_type):
149165
"""

0 commit comments

Comments
 (0)