1# Gramps - a GTK+/GNOME based genealogy program 2# 3# Copyright (C) 2011 Nick Hall 4# 5# This program is free software; you can redistribute it and/or modify 6# it under the terms of the GNU General Public License as published by 7# the Free Software Foundation; either version 2 of the License, or 8# (at your option) any later version. 9# 10# This program is distributed in the hope that it will be useful, 11# but WITHOUT ANY WARRANTY; without even the implied warranty of 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13# GNU General Public License for more details. 14# 15# You should have received a copy of the GNU General Public License 16# along with this program; if not, write to the Free Software 17# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18# 19 20#------------------------------------------------------------------------- 21# 22# Gtk modules 23# 24#------------------------------------------------------------------------- 25from gi.repository import Gtk 26 27#------------------------------------------------------------------------- 28# 29# Gramps modules 30# 31#------------------------------------------------------------------------- 32from gramps.gui.editors import EditEvent 33from gramps.gui.listmodel import ListModel, NOSORT 34from gramps.gen.plug import Gramplet 35from gramps.gen.lib import (EventType, Date) 36from gramps.gen.plug.report.utils import find_spouse 37from gramps.gui.dbguielement import DbGUIElement 38from gramps.gen.display.place import displayer as place_displayer 39from gramps.gen.datehandler import get_date 40from gramps.gen.utils.db import (get_participant_from_event, 41 get_birth_or_fallback, 42 get_marriage_or_fallback) 43from gramps.gen.errors import WindowActiveError 44from gramps.gen.config import config 45from gramps.gen.const import GRAMPS_LOCALE as glocale 46_ = glocale.translation.gettext 47 48age_precision = config.get('preferences.age-display-precision') 49 50class Events(Gramplet, DbGUIElement): 51 52 def __init__(self, gui, nav_group=0): 53 Gramplet.__init__(self, gui, nav_group) 54 DbGUIElement.__init__(self, self.dbstate.db) 55 56 """ 57 Displays the events for a person or family. 58 """ 59 def init(self): 60 self.gui.WIDGET = self.build_gui() 61 self.gui.get_container_widget().remove(self.gui.textview) 62 self.gui.get_container_widget().add(self.gui.WIDGET) 63 self.gui.WIDGET.show() 64 65 def _connect_db_signals(self): 66 """ 67 called on init of DbGUIElement, connect to db as required. 68 """ 69 self.callman.register_callbacks({'event-update': self.changed}) 70 self.callman.connect_all(keys=['event']) 71 72 def changed(self, handle): 73 """ 74 Called when a registered event is updated. 75 """ 76 self.update() 77 78 def build_gui(self): 79 """ 80 Build the GUI interface. 81 """ 82 tip = _('Double-click on a row to edit the selected event.') 83 self.set_tooltip(tip) 84 top = Gtk.TreeView() 85 titles = [('', NOSORT, 50,), 86 (_('Type'), 1, 100), 87 (_('Description'), 2, 150), 88 (_('Date'), 4, 100), 89 ('', NOSORT, 50), 90 (_('Age'), 6, 100), 91 ('', NOSORT, 50), 92 (_('Place'), 7, 400), 93 (_('Main Participants'), 8, 200), 94 (_('Role'), 9, 100)] 95 self.model = ListModel(top, titles, event_func=self.edit_event) 96 return top 97 98 def add_event_ref(self, event_ref, spouse=None): 99 """ 100 Add an event to the model. 101 """ 102 self.callman.register_handles({'event': [event_ref.ref]}) 103 event = self.dbstate.db.get_event_from_handle(event_ref.ref) 104 event_date = get_date(event) 105 event_sort = '%012d' % event.get_date_object().get_sort_value() 106 person_age = self.column_age(event) 107 person_age_sort = self.column_sort_age(event) 108 place = place_displayer.display_event(self.dbstate.db, event) 109 110 participants = get_participant_from_event(self.dbstate.db, 111 event_ref.ref) 112 113 self.model.add((event.get_handle(), 114 str(event.get_type()), 115 event.get_description(), 116 event_date, 117 event_sort, 118 person_age, 119 person_age_sort, 120 place, 121 participants, 122 str(event_ref.get_role()))) 123 124 def column_age(self, event): 125 """ 126 Returns a string representation of age in years. Change 127 precision=2 for "year, month", or precision=3 for "year, 128 month, days" 129 """ 130 date = event.get_date_object() 131 start_date = self.cached_start_date 132 if date and start_date: 133 if (date == start_date and date.modifier == Date.MOD_NONE 134 and not (event.get_type().is_death_fallback() or 135 event.get_type() == EventType.DEATH)): 136 return "" 137 else: 138 return (date - start_date).format(precision=age_precision) 139 else: 140 return "" 141 142 def column_sort_age(self, event): 143 """ 144 Returns a string version of number of days of age. 145 """ 146 date = event.get_date_object() 147 start_date = self.cached_start_date 148 if date and start_date: 149 return "%09d" % int(date - start_date) 150 else: 151 return "" 152 153 def edit_event(self, treeview): 154 """ 155 Edit the selected event. 156 """ 157 model, iter_ = treeview.get_selection().get_selected() 158 if iter_: 159 handle = model.get_value(iter_, 0) 160 try: 161 event = self.dbstate.db.get_event_from_handle(handle) 162 EditEvent(self.dbstate, self.uistate, [], event) 163 except WindowActiveError: 164 pass 165 166class PersonEvents(Events): 167 """ 168 Displays the events for a person. 169 """ 170 def db_changed(self): 171 self.connect(self.dbstate.db, 'person-update', self.update) 172 173 def active_changed(self, handle): 174 self.update() 175 176 def update_has_data(self): 177 active_handle = self.get_active('Person') 178 active = None 179 if active_handle: 180 active = self.dbstate.db.get_person_from_handle(active_handle) 181 self.set_has_data(self.get_has_data(active)) 182 183 def get_has_data(self, active_person): 184 """ 185 Return True if the gramplet has data, else return False. 186 """ 187 if active_person: 188 if active_person.get_event_ref_list(): 189 return True 190 for family_handle in active_person.get_family_handle_list(): 191 family = self.dbstate.db.get_family_from_handle(family_handle) 192 if family: 193 for event_ref in family.get_event_ref_list(): 194 return True 195 return False 196 197 def main(self): # return false finishes 198 active_handle = self.get_active('Person') 199 200 self.model.clear() 201 self.callman.unregister_all() 202 if active_handle: 203 self.display_person(active_handle) 204 else: 205 self.set_has_data(False) 206 207 def display_person(self, active_handle): 208 """ 209 Display the events for the active person. 210 """ 211 active_person = self.dbstate.db.get_person_from_handle(active_handle) 212 if active_person: 213 self.cached_start_date = self.get_start_date() 214 for event_ref in active_person.get_event_ref_list(): 215 self.add_event_ref(event_ref) 216 for family_handle in active_person.get_family_handle_list(): 217 family = self.dbstate.db.get_family_from_handle(family_handle) 218 self.display_family(family, active_person) 219 else: 220 self.cached_start_date = None 221 self.set_has_data(self.model.count > 0) 222 223 def display_family(self, family, active_person): 224 """ 225 Display the events for the given family. 226 """ 227 spouse_handle = find_spouse(active_person, family) 228 if spouse_handle: 229 spouse = self.dbstate.db.get_person_from_handle(spouse_handle) 230 else: 231 spouse = None 232 if family: 233 for event_ref in family.get_event_ref_list(): 234 self.add_event_ref(event_ref, spouse) 235 236 def get_start_date(self): 237 """ 238 Get the start date for a person, usually a birth date, or 239 something close to birth. 240 """ 241 active_handle = self.get_active('Person') 242 active = self.dbstate.db.get_person_from_handle(active_handle) 243 event = get_birth_or_fallback(self.dbstate.db, active) 244 return event.get_date_object() if event else None 245 246class FamilyEvents(Events): 247 """ 248 Displays the events for a family. 249 """ 250 def db_changed(self): 251 self.connect(self.dbstate.db, 'family-update', self.update) 252 self.connect_signal('Family', self.update) 253 254 def update_has_data(self): 255 active_handle = self.get_active('Family') 256 active = None 257 if active_handle: 258 active = self.dbstate.db.get_family_from_handle(active_handle) 259 self.set_has_data(self.get_has_data(active)) 260 261 def get_has_data(self, active_family): 262 """ 263 Return True if the gramplet has data, else return False. 264 """ 265 if active_family: 266 for event_ref in active_family.get_event_ref_list(): 267 return True 268 return False 269 270 def main(self): # return false finishes 271 active_handle = self.get_active('Family') 272 273 self.model.clear() 274 self.callman.unregister_all() 275 if active_handle: 276 self.display_family(active_handle) 277 else: 278 self.set_has_data(False) 279 280 def display_family(self, active_handle): 281 """ 282 Display the events for the active family. 283 """ 284 active_family = self.dbstate.db.get_family_from_handle(active_handle) 285 self.cached_start_date = self.get_start_date() 286 for event_ref in active_family.get_event_ref_list(): 287 self.add_event_ref(event_ref) 288 self.set_has_data(self.model.count > 0) 289 290 def get_start_date(self): 291 """ 292 Get the start date for a family, usually a marriage date, or 293 something close to marriage. 294 """ 295 active_handle = self.get_active('Family') 296 active = self.dbstate.db.get_family_from_handle(active_handle) 297 event = get_marriage_or_fallback(self.dbstate.db, active) 298 return event.get_date_object() if event else None 299 300