Enhanced Calculate Estimated Dates tool
svn: r14014
This commit is contained in:
		| @@ -1,3 +1,4 @@ | ||||
| # -*- coding: utf-8 -*- | ||||
| # | ||||
| # Gramps - a GTK+/GNOME based genealogy program | ||||
| # | ||||
| @@ -38,12 +39,17 @@ import time | ||||
| #------------------------------------------------------------------------ | ||||
| from PluginUtils import Tool, PluginWindows, MenuToolOptions | ||||
| from gen.plug.menu import BooleanOption, NumberOption, StringOption, \ | ||||
|                          FilterOption, PersonOption | ||||
|                          FilterOption, PersonOption, EnumeratedListOption | ||||
| import gen.lib | ||||
| import config | ||||
| from BasicUtils import name_displayer | ||||
| import Errors | ||||
| from ReportBase import ReportUtils | ||||
| from docgen import TextBufDoc | ||||
| from Simple import make_basic_stylesheet, SimpleAccess, SimpleDoc, SimpleTable | ||||
| from QuestionDialog import QuestionDialog | ||||
| from Utils import create_id | ||||
| import DateHandler | ||||
|  | ||||
| #------------------------------------------------------------------------ | ||||
| # | ||||
| @@ -54,7 +60,11 @@ class CalcEstDateOptions(MenuToolOptions): | ||||
|     """ Calculate Estimated Date options  """ | ||||
|     def __init__(self, name, person_id=None, dbstate=None): | ||||
|         self.__db = dbstate.get_database() | ||||
|         self.__dbstate = dbstate | ||||
|         MenuToolOptions.__init__(self, name, person_id, dbstate) | ||||
|  | ||||
|     def get_dbstate(self): | ||||
|         return self.__dbstate | ||||
|      | ||||
|     def add_menu_options(self, menu): | ||||
|          | ||||
| @@ -78,24 +88,25 @@ class CalcEstDateOptions(MenuToolOptions): | ||||
|         source_text.set_help(_("Source to remove and/or add")) | ||||
|         menu.add_option(category_name, "source_text", source_text) | ||||
|  | ||||
|         remove = BooleanOption(_("Remove previously added dates"), True) | ||||
|         remove.set_help(_("Remove")) | ||||
|         remove = BooleanOption(_("Remove previously added events, notes, and source"), True) | ||||
|         remove.set_help(_("Remove calculated events, notes, and source; occurs immediately on Execute")) | ||||
|         menu.add_option(category_name, "remove", remove) | ||||
|  | ||||
|         birth = BooleanOption(_("Add estimated birth dates"), True) | ||||
|         birth.set_help(_("Add")) | ||||
|         birth = EnumeratedListOption(_("Birth"), 0) | ||||
|         birth.add_item(0, _("Do not add birth events")) | ||||
|         birth.add_item(1, _("Add birth events without dates")) | ||||
|         birth.add_item(2, _("Add birth events with dates")) | ||||
|         birth.set_help( _("Add a birth events with or without estimated dates")) | ||||
|         menu.add_option(category_name, "add_birth", birth) | ||||
|  | ||||
|         death = BooleanOption(_("Add estimated death dates"), True) | ||||
|         death.set_help(_("Add estimated death dates")) | ||||
|         death = EnumeratedListOption(_("Death"), 0) | ||||
|         death.add_item(0, _("Do not add death events")) | ||||
|         death.add_item(1, _("Add death events without dates")) | ||||
|         death.add_item(2, _("Add death events with dates")) | ||||
|         death.set_help( _("Add death events with or without estimated dates")) | ||||
|         menu.add_option(category_name, "add_death", death) | ||||
|  | ||||
|         display_details = BooleanOption(_("Display detailed results"), False) | ||||
|         display_details.set_help(_("Show details for every date entered")) | ||||
|         menu.add_option(category_name, "display_details", display_details) | ||||
|  | ||||
|         # ----------------------------------------------------- | ||||
|         category_name = _("Config") | ||||
|         num = NumberOption(_("Maximum age"),  | ||||
|                            config.get('behavior.max-age-prob-alive'), | ||||
|                            0, 200) | ||||
| @@ -145,34 +156,91 @@ class CalcEstDateOptions(MenuToolOptions): | ||||
|  | ||||
| class CalcToolManagedWindow(PluginWindows.ToolManagedWindowBatch): | ||||
|  | ||||
|     def __init__(self, *args, **kwargs): | ||||
|         PluginWindows.ToolManagedWindowBatch.__init__(self, *args, **kwargs) | ||||
|         self.help_page = self.add_page("Help") | ||||
|         self.write_to_page(self.help_page,  | ||||
|                            "The Calculate Estimated Dates Tool is used to add and remove " | ||||
|                            "birth and death events for people that are missing these " | ||||
|                            "events.\n\n" | ||||
|                            "To use:\n" | ||||
|                            "1. Go to the Options tab\n" | ||||
|                            "2. Check the [ ] Remove option to remove previous estimates\n" | ||||
|                            "3. Select the Add date options to date events with or without dates\n" | ||||
|                            "4. Click on Execute\n" | ||||
|                            "5. Select the people with which to add events\n" | ||||
|                            "6. Click on 'Add Selected Events' button to create\n\n" | ||||
|                            "NOTES: if you decide to make an event permanent, remove it from " | ||||
|                            "the Source. Otherwise, it will get removed the next time you " | ||||
|                            "automatically remove these events.\n\n" | ||||
|                            "You may have to run the tool repeatedly (without removing previous " | ||||
|                            "events) to add all of the events possible.") | ||||
|  | ||||
|     def get_title(self): | ||||
|         return _("Calculate Estimated Dates") | ||||
|  | ||||
|     def initial_frame(self): | ||||
|         return _("Options") | ||||
|  | ||||
|     def set_reselect(self): | ||||
|         self.reselect = True | ||||
|  | ||||
|     def run(self): | ||||
|         self.add_results_frame(_("Results")) | ||||
|         BUTTONS = ((_("Select All"), self.select_all), | ||||
|                    (_("Select None"), self.select_none), | ||||
|                    (_("Toggle Selection"), self.toggle_select), | ||||
|                    (_("Add Selected Events"), self.apply_selection), | ||||
|                    ) | ||||
|  | ||||
|         if hasattr(self, "table") and self.table: | ||||
|             self.reselect = False | ||||
|             if self.options.handler.options_dict['remove']: | ||||
|                 QuestionDialog(_("Remove Events, Notes, and Source and Reselect Data"), | ||||
|                                _("Are you sure you want to remove previous events, notes, and source and reselect data?"), | ||||
|                                _("Remove and Run Select Again"), | ||||
|                                self.set_reselect, | ||||
|                                self.window) | ||||
|             else: | ||||
|                 QuestionDialog(_("Reselect Data"), | ||||
|                                _("Are you sure you want to reselect data?"), | ||||
|                                _("Run Select Again"), | ||||
|                                self.set_reselect, | ||||
|                                self.window) | ||||
|             if not self.reselect: | ||||
|                 return | ||||
|         self.action = {} | ||||
|         widget = self.add_results_frame(_("Select")) | ||||
|         document = TextBufDoc(make_basic_stylesheet(), None) | ||||
|         document.dbstate = self.dbstate | ||||
|         document.uistate = self.uistate | ||||
|         document.open("", container=widget) | ||||
|         self.sdb = SimpleAccess(self.db) | ||||
|         sdoc = SimpleDoc(document) | ||||
|         stab = SimpleTable(self.sdb) | ||||
|         self.table = stab | ||||
|         stab.columns(_("Select"), _("Person"), _("Action"),  | ||||
|                      _("Birth Date"), _("Death Date"),  | ||||
|                      _("Evidence"), _("Relative")) | ||||
|         self.results_write(_("Processing...\n")) | ||||
|         self.trans = self.db.transaction_begin("",batch=True) | ||||
|         self.db.disable_signals() | ||||
|         self.filter_option =  self.options.menu.get_option_by_name('filter') | ||||
|         self.filter = self.filter_option.get_filter() # the actual filter | ||||
|         people = self.filter.apply(self.db, | ||||
|                                    self.db.iter_person_handles()) | ||||
|         num_people = self.db.get_number_of_people() | ||||
|         source_text = self.options.handler.options_dict['source_text'] | ||||
|         source = None | ||||
|         add_birth = self.options.handler.options_dict['add_birth'] | ||||
|         add_death = self.options.handler.options_dict['add_death'] | ||||
|         remove_old = self.options.handler.options_dict['remove'] | ||||
|         display_details = self.options.handler.options_dict['display_details'] | ||||
|  | ||||
|         self.MIN_GENERATION_YEARS = self.options.handler.options_dict['MIN_GENERATION_YEARS'] | ||||
|         self.MAX_SIB_AGE_DIFF = self.options.handler.options_dict['MAX_SIB_AGE_DIFF'] | ||||
|         self.MAX_AGE_PROB_ALIVE = self.options.handler.options_dict['MAX_AGE_PROB_ALIVE'] | ||||
|         self.AVG_GENERATION_GAP = self.options.handler.options_dict['AVG_GENERATION_GAP'] | ||||
|         if remove_old: | ||||
|             self.results_write(_("Replacing...\n")) | ||||
|             self.trans = self.db.transaction_begin("",batch=True) | ||||
|             self.db.disable_signals() | ||||
|             self.results_write(_("Removing old estimations... ")) | ||||
|             self.progress.set_pass((_("Removing '%s'...") % source_text),  | ||||
|                                    num_people) | ||||
|             for person_handle in people: | ||||
| @@ -191,6 +259,12 @@ class CalcToolManagedWindow(PluginWindows.ToolManagedWindowBatch): | ||||
|                             if source.get_title() == source_text: | ||||
|                                 person.set_birth_ref(None) | ||||
|                                 person.remove_handle_references('Event',[birth_ref.ref]) | ||||
|                                 # remove note | ||||
|                                 note_list = birth.get_referenced_note_handles() | ||||
|                                 birth.remove_handle_references('Note',  | ||||
|                                   [note_handle for (obj_type, note_handle) in note_list]) | ||||
|                                 for (obj_type, note_handle) in note_list: | ||||
|                                     self.db.remove_note(note_handle, self.trans) | ||||
|                                 self.db.remove_event(birth_ref.ref, self.trans) | ||||
|                                 self.db.commit_source(source, self.trans) | ||||
|                                 pupdate = 1 | ||||
| @@ -207,64 +281,197 @@ class CalcToolManagedWindow(PluginWindows.ToolManagedWindowBatch): | ||||
|                             if source.get_title() == source_text: | ||||
|                                 person.set_death_ref(None) | ||||
|                                 person.remove_handle_references('Event',[death_ref.ref]) | ||||
|                                 # remove note | ||||
|                                 note_list = death.get_referenced_note_handles() | ||||
|                                 birth.remove_handle_references('Note',  | ||||
|                                   [note_handle for (obj_type, note_handle) in note_list]) | ||||
|                                 for (obj_type, note_handle) in note_list: | ||||
|                                     self.db.remove_note(note_handle, self.trans) | ||||
|                                 self.db.remove_event(death_ref.ref, self.trans) | ||||
|                                 self.db.commit_source(source, self.trans) | ||||
|                                 pupdate = 1 | ||||
|                                 break | ||||
|                 if pupdate == 1: | ||||
|                     self.db.commit_person(person, self.trans) | ||||
|             if source: | ||||
|                 self.db.remove_source(source.handle, self.trans) | ||||
|             self.results_write(_("done!\n")) | ||||
|             self.db.transaction_commit(self.trans, _("Removed date estimates")) | ||||
|             self.db.enable_signals() | ||||
|             self.db.request_rebuild() | ||||
|         if add_birth or add_death: | ||||
|             self.results_write(_("Calculating...\n")) | ||||
|             self.progress.set_pass(_('Calculating estimated dates...'),  | ||||
|             self.results_write(_("Selecting... \n\n")) | ||||
|             self.progress.set_pass(_('Selecting...'),  | ||||
|                                    num_people) | ||||
|             source = self.get_or_create_source(source_text) | ||||
|             row = 0 | ||||
|             for person_handle in people: | ||||
|                 self.progress.step() | ||||
|                 added_birth, added_death = 0, 0 | ||||
|                 person = self.db.get_person_from_handle(person_handle) | ||||
|                 birth_ref = person.get_birth_ref() | ||||
|                 death_ref = person.get_death_ref() | ||||
|                 #print birth_ref, death_ref | ||||
|                 date1, date2 = self.calc_estimates(person, birth_ref, death_ref) | ||||
|                 #print date1, date2 | ||||
|                 if not birth_ref and add_birth and date1: | ||||
|                     #print "added birth" | ||||
|                     birth = self.create_event(_("Estimated birth date"),  | ||||
|                                               gen.lib.EventType.BIRTH,  | ||||
|                                               date1, source) | ||||
|                     event_ref = gen.lib.EventRef() | ||||
|                     event_ref.set_reference_handle(birth.get_handle()) | ||||
|                     person.set_birth_ref(event_ref) | ||||
|                     self.db.commit_person(person, self.trans) | ||||
|                     added_birth = 1 | ||||
|                 if not death_ref and add_death and date2: | ||||
|                     current_date = gen.lib.Date() | ||||
|                     current_date.set_yr_mon_day(*time.localtime(time.time())[0:3]) | ||||
|                     if current_date.match( date2, "<<"): | ||||
|                         # don't add events in the future! | ||||
|                         pass # FIXME: sometimes adds one in future? | ||||
|                 add_birth_event, add_death_event = False, False | ||||
|                 if not birth_ref or not death_ref: | ||||
|                     date1, date2, explain, other = self.calc_estimates(person) | ||||
|                     if birth_ref: | ||||
|                         ev = self.db.get_event_from_handle(birth_ref.ref) | ||||
|                         date1 = ev.get_date_object() | ||||
|                     elif not birth_ref and add_birth and date1: | ||||
|                         add_birth_event = True | ||||
|                         date1.make_vague() | ||||
|                     else: | ||||
|                         #print "added death" | ||||
|                         death = self.create_event(_("Estimated death date"),  | ||||
|                                                   gen.lib.EventType.DEATH,  | ||||
|                                                   date2, source) | ||||
|                         event_ref = gen.lib.EventRef() | ||||
|                         event_ref.set_reference_handle(death.get_handle()) | ||||
|                         person.set_death_ref(event_ref) | ||||
|                         self.db.commit_person(person, self.trans) | ||||
|                         added_death = 1 | ||||
|                 if (added_birth or added_death) and display_details: | ||||
|                     self.results_write_link(name_displayer.display(person), | ||||
|                                             person, person_handle) | ||||
|                     if added_birth: | ||||
|                         self.results_write(_(" added birth on %s") % date1) | ||||
|                     if added_death: | ||||
|                         self.results_write(_(" added death on %s") % date2) | ||||
|                     self.results_write("\n") | ||||
|         self.db.transaction_commit(self.trans, _("Calculate date estimates")) | ||||
|                         date1 = gen.lib.Date() | ||||
|                     if death_ref: | ||||
|                         ev = self.db.get_event_from_handle(death_ref.ref) | ||||
|                         date2 = ev.get_date_object() | ||||
|                     elif not death_ref and add_death and date2: | ||||
|                         current_date = gen.lib.Date() | ||||
|                         current_date.set_yr_mon_day(*time.localtime(time.time())[0:3]) | ||||
|                         if date2.match( current_date, "<"): | ||||
|                             add_death_event = True | ||||
|                             date2.make_vague() | ||||
|                         else: | ||||
|                             date2 = gen.lib.Date() | ||||
|                     else: | ||||
|                         date2 = gen.lib.Date() | ||||
|                     # Describe | ||||
|                     if add_birth_event and add_death_event:  | ||||
|                         action = _("Add birth and death events") | ||||
|                     elif add_birth_event: | ||||
|                         action = _("Add birth event") | ||||
|                     elif add_death_event:  | ||||
|                         action = _("Add death event") | ||||
|                     else: | ||||
|                         continue | ||||
|                     #stab.columns(_("Select"), _("Person"), _("Action"),  | ||||
|                     # _("Birth Date"), _("Death Date"), _("Evidence"), _("Relative")) | ||||
|                     if add_birth == 1 and not birth_ref: # no date | ||||
|                         date1 = gen.lib.Date() | ||||
|                     if add_death == 1 and not death_ref: # no date | ||||
|                         date2 = gen.lib.Date() | ||||
|                     stab.row("checkbox",  | ||||
|                              person,  | ||||
|                              action,  | ||||
|                              date1, | ||||
|                              date2, | ||||
|                              explain or "",  | ||||
|                              other or "") | ||||
|                     if add_birth_event: | ||||
|                         stab.set_cell_markup(3, row, "<b>%s</b>" % DateHandler.displayer.display(date1)) | ||||
|                     if add_death_event: | ||||
|                         stab.set_cell_markup(4, row, "<b>%s</b>" % DateHandler.displayer.display(date2)) | ||||
|                     self.action[person.handle] = (add_birth_event, add_death_event) | ||||
|                     row += 1 | ||||
|             if row > 0: | ||||
|                 self.results_write("  ") | ||||
|                 for text, function in BUTTONS: | ||||
|                     self.make_button(text, function, widget) | ||||
|                 self.results_write("\n") | ||||
|                 stab.write(sdoc) | ||||
|                 self.results_write("  ") | ||||
|                 for text, function in BUTTONS: | ||||
|                     self.make_button(text, function, widget) | ||||
|                 self.results_write("\n") | ||||
|             else: | ||||
|                 self.results_write(_("No events to be added.")) | ||||
|                 self.results_write("\n") | ||||
|         self.results_write("\n") | ||||
|         self.progress.close() | ||||
|  | ||||
|     def make_button(self, text, function, widget): | ||||
|         import gtk | ||||
|         button = gtk.Button(text) | ||||
|         buffer = widget.get_buffer() | ||||
|         iter = buffer.get_end_iter() | ||||
|         anchor = buffer.create_child_anchor(iter) | ||||
|         widget.add_child_at_anchor(button, anchor) | ||||
|         button.connect("clicked", function) | ||||
|         button.show() | ||||
|         self.results_write("  ") | ||||
|  | ||||
|     def select_all(self, obj): | ||||
|         select_col = self.table.model_index_of_column[_("Select")] | ||||
|         for row in self.table.treeview.get_model(): | ||||
|             row[select_col] = True  | ||||
|  | ||||
|     def select_none(self, obj): | ||||
|         select_col = self.table.model_index_of_column[_("Select")] | ||||
|         for row in self.table.treeview.get_model(): | ||||
|             row[select_col] = False | ||||
|  | ||||
|     def toggle_select(self, obj): | ||||
|         select_col = self.table.model_index_of_column[_("Select")] | ||||
|         for row in self.table.treeview.get_model(): | ||||
|             row[select_col] = not row[select_col] | ||||
|  | ||||
|     def apply_selection(self, *args, **kwargs): | ||||
|         # Do not add birth or death event if one exists, no matter what | ||||
|         if self.table.treeview.get_model() is None: | ||||
|             return | ||||
|         self.pre_run() | ||||
|         source_text = self.options.handler.options_dict['source_text'] | ||||
|         select_col = self.table.model_index_of_column[_("Select")] | ||||
|         source = self.get_or_create_source(source_text) | ||||
|         self.trans = self.db.transaction_begin("",batch=True) | ||||
|         self.db.disable_signals() | ||||
|         self.results_write(_("Selecting... ")) | ||||
|         self.progress.set_pass((_("Adding events '%s'...") % source_text),  | ||||
|                                len(self.table.treeview.get_model())) | ||||
|         self.trans = self.db.transaction_begin("",batch=True) | ||||
|         count = 0 | ||||
|         for row in self.table.treeview.get_model(): | ||||
|             self.progress.step() | ||||
|             select = row[select_col] # live select value | ||||
|             if not select: | ||||
|                 continue | ||||
|             pupdate = False | ||||
|             index = row[0] # order put in | ||||
|             row_data = self.table.get_raw_data(index) | ||||
|             person = row_data[1] # check, person, action, date1, date2 | ||||
|             date1 = row_data[3] # date | ||||
|             date2 = row_data[4] # date | ||||
|             evidence = row_data[5] # evidence | ||||
|             other = row_data[6] # other person | ||||
|             add_birth_event, add_death_event = self.action[person.handle] | ||||
|             birth_ref = person.get_birth_ref() | ||||
|             death_ref = person.get_death_ref() | ||||
|             if not birth_ref and add_birth_event: | ||||
|                 other_name = self.sdb.name(other) | ||||
|                 if other_name: | ||||
|                     explanation = _("Added birth event based on %s, from %s") % (evidence, other_name) | ||||
|                 else: | ||||
|                     explanation = _("Added birth event based on %s") % evidence | ||||
|                 birth = self.create_event(_("Estimated birth date"),  | ||||
|                                           gen.lib.EventType.BIRTH,  | ||||
|                                           date1, source, explanation) | ||||
|                 event_ref = gen.lib.EventRef() | ||||
|                 event_ref.set_reference_handle(birth.get_handle()) | ||||
|                 person.set_birth_ref(event_ref) | ||||
|                 pupdate = True | ||||
|                 count += 1 | ||||
|             if not death_ref and add_death_event: | ||||
|                 other_name = self.sdb.name(other) | ||||
|                 if other_name: | ||||
|                     explanation = _("Added death event based on %s, from %s") % (evidence, other_name) | ||||
|                 else: | ||||
|                     explanation = _("Added death event based on %s") % evidence | ||||
|                 death = self.create_event(_("Estimated death date"),  | ||||
|                                           gen.lib.EventType.DEATH,  | ||||
|                                           date2, source, explanation) | ||||
|                 event_ref = gen.lib.EventRef() | ||||
|                 event_ref.set_reference_handle(death.get_handle()) | ||||
|                 person.set_death_ref(event_ref) | ||||
|                 pupdate = True | ||||
|                 count += 1 | ||||
|             if pupdate: | ||||
|                 self.db.commit_person(person, self.trans) | ||||
|         self.results_write(_(" Done! Committing...")) | ||||
|         self.results_write("\n") | ||||
|         self.db.transaction_commit(self.trans, _("Add date estimates")) | ||||
|         self.db.enable_signals() | ||||
|         self.db.request_rebuild() | ||||
|         self.results_write(_("Done!\n")) | ||||
|         self.results_write(_("Added %d events.") % count) | ||||
|         self.results_write("\n\n") | ||||
|         self.progress.close() | ||||
|  | ||||
|     def get_or_create_source(self, source_text): | ||||
|         source_list = self.db.get_source_handles() | ||||
| @@ -278,9 +485,16 @@ class CalcToolManagedWindow(PluginWindows.ToolManagedWindowBatch): | ||||
|         return source | ||||
|  | ||||
|     def create_event(self, description=_("Estimated date"),  | ||||
|                      type=None, date=None, source=None): | ||||
|                      type=None, date=None, source=None,  | ||||
|                      note_text=""): | ||||
|         event = gen.lib.Event() | ||||
|         event.set_description(description) | ||||
|         note = gen.lib.Note() | ||||
|         note.handle = create_id() | ||||
|         note.type.set(gen.lib.NoteType.EVENT) | ||||
|         note.set(note_text) | ||||
|         self.db.add_note(note, self.trans) | ||||
|         event.add_note(note.handle) | ||||
|         if type: | ||||
|             event.set_type(gen.lib.EventType(type)) | ||||
|         if date: | ||||
| @@ -296,54 +510,65 @@ class CalcToolManagedWindow(PluginWindows.ToolManagedWindowBatch): | ||||
|         self.db.add_event(event, self.trans) | ||||
|         return event | ||||
|  | ||||
|     def calc_estimates(self, person, birth_ref, death_ref): | ||||
|     def calc_estimates(self, person, is_spouse=False): | ||||
|         if person is None: | ||||
|             return (None, None, "", None) | ||||
|         birth_ref = person.get_birth_ref() | ||||
|         death_ref = person.get_death_ref() | ||||
|         death_date = None | ||||
|         birth_date = None | ||||
|         explain = "" | ||||
|         # If the recorded death year is before current year then | ||||
|         # things are simple. | ||||
|         if death_ref and death_ref.get_role() == gen.lib.EventRoleType.PRIMARY: | ||||
|         if death_ref and death_ref.get_role().is_primary(): | ||||
|             death = self.db.get_event_from_handle(death_ref.ref) | ||||
|             if death.get_date_object().get_start_date() != gen.lib.Date.EMPTY: | ||||
|                 death_date = death.get_date_object() | ||||
|  | ||||
|         # Look for Cause Of Death, Burial or Cremation events. | ||||
|         # These are fairly good indications that someone's not alive. | ||||
|         for ev_ref in person.get_primary_event_ref_list(): | ||||
|             ev = self.db.get_event_from_handle(ev_ref.ref) | ||||
|             if ev and ev.type in [gen.lib.EventType.CAUSE_DEATH,  | ||||
|                                   gen.lib.EventType.BURIAL,  | ||||
|                                   gen.lib.EventType.CREMATION]: | ||||
|                 if not death_date: | ||||
|         if not death_date: | ||||
|             for ev_ref in person.get_primary_event_ref_list(): | ||||
|                 ev = self.db.get_event_from_handle(ev_ref.ref) | ||||
|                 if ev and ev.type.is_death_fallback(): | ||||
|                     death_date = ev.get_date_object() | ||||
|                     explain = _("death-related evidence") | ||||
|  | ||||
|         # If they were born within 100 years before current year then | ||||
|         # If they were born within X years before current year then | ||||
|         # assume they are alive (we already know they are not dead). | ||||
|         if birth_ref and birth_ref.get_role() == gen.lib.EventRoleType.PRIMARY: | ||||
|             birth = self.db.get_event_from_handle(birth_ref.ref) | ||||
|             if birth.get_date_object().get_start_date() != gen.lib.Date.EMPTY: | ||||
|                 if not birth_date: | ||||
|         if not birth_date: | ||||
|             if birth_ref and birth_ref.get_role().is_primary(): | ||||
|                 birth = self.db.get_event_from_handle(birth_ref.ref) | ||||
|                 if birth.get_date_object().get_start_date() != gen.lib.Date.EMPTY: | ||||
|                     birth_date = birth.get_date_object() | ||||
|  | ||||
|         #print "   calculating...", birth_date, death_date | ||||
|         # Look for Baptism, etc events. | ||||
|         # These are fairly good indications that someone's birth. | ||||
|         if not birth_date: | ||||
|             for ev_ref in person.get_primary_event_ref_list(): | ||||
|                 ev = self.db.get_event_from_handle(ev_ref.ref) | ||||
|                 if ev and ev.type.is_birth_fallback(): | ||||
|                     birth_date = ev.get_date_object() | ||||
|                     explain = _("birth-related evidence") | ||||
|  | ||||
|         if not birth_date and death_date: | ||||
|             # person died more than MAX after current year | ||||
|             birth_date = death_date.copy_offset_ymd(year=-self.MAX_AGE_PROB_ALIVE) | ||||
|  | ||||
|             explain = _("death date") | ||||
|          | ||||
|         if not death_date and birth_date: | ||||
|             # person died more than MAX after current year | ||||
|             death_date = birth_date.copy_offset_ymd(year=self.MAX_AGE_PROB_ALIVE) | ||||
|  | ||||
|             explain = _("birth date") | ||||
|          | ||||
|         if death_date and birth_date: | ||||
|             return (birth_date, death_date) | ||||
|             return (birth_date, death_date, explain, "") # direct self evidence | ||||
|          | ||||
|         # Neither birth nor death events are available. Try looking | ||||
|         # at siblings. If a sibling was born more than 120 years past,  | ||||
|         # or more than 20 future, then probably this person is | ||||
|         # not alive. If the sibling died more than 120 years | ||||
|         # past, or more than 120 years future, then probably not alive. | ||||
|  | ||||
|         #print "    searching family..." | ||||
|         # at siblings. If a sibling was born more than X years past,  | ||||
|         # or more than Z future, then probably this person is | ||||
|         # not alive. If the sibling died more than X years | ||||
|         # past, or more than X years future, then probably not alive. | ||||
|  | ||||
|         family_list = person.get_parent_family_handle_list() | ||||
|         for family_handle in family_list: | ||||
| @@ -351,28 +576,70 @@ class CalcToolManagedWindow(PluginWindows.ToolManagedWindowBatch): | ||||
|             for child_ref in family.get_child_ref_list(): | ||||
|                 child_handle = child_ref.ref | ||||
|                 child = self.db.get_person_from_handle(child_handle) | ||||
|                 child_birth_ref = child.get_birth_ref() | ||||
|                 if child_birth_ref: | ||||
|                     child_birth = self.db.get_event_from_handle(child_birth_ref.ref) | ||||
|                     dobj = child_birth.get_date_object() | ||||
|                     if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                         # if sibling birth date too far away, then not alive: | ||||
|                         year = dobj.get_year() | ||||
|                         if year != 0: | ||||
|                             # sibling birth date | ||||
|                             return (gen.lib.Date().copy_ymd(year - self.MAX_SIB_AGE_DIFF), | ||||
|                                     gen.lib.Date().copy_ymd(year + self.MAX_SIB_AGE_DIFF + self.MAX_AGE_PROB_ALIVE)) | ||||
|                 child_death_ref = child.get_death_ref() | ||||
|                 if child_death_ref: | ||||
|                     child_death = self.db.get_event_from_handle(child_death_ref.ref) | ||||
|                     dobj = child_death.get_date_object() | ||||
|                     if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                         # if sibling death date too far away, then not alive: | ||||
|                         year = dobj.get_year() | ||||
|                         if year != 0: | ||||
|                             # sibling death date | ||||
|                             return (gen.lib.Date().copy_ymd(year - self.MAX_SIB_AGE_DIFF - self.MAX_AGE_PROB_ALIVE), | ||||
|                                     gen.lib.Date().copy_ymd(year + self.MAX_SIB_AGE_DIFF)) | ||||
|                 # Go through once looking for direct evidence: | ||||
|                 for ev_ref in child.get_primary_event_ref_list(): | ||||
|                     ev = self.db.get_event_from_handle(ev_ref.ref) | ||||
|                     if ev and ev.type.is_birth(): | ||||
|                         dobj = ev.get_date_object()  | ||||
|                         if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                             # if sibling birth date too far away, then not alive: | ||||
|                             year = dobj.get_year() | ||||
|                             if year != 0: | ||||
|                                 # sibling birth date | ||||
|                                 return (gen.lib.Date().copy_ymd(year - self.MAX_SIB_AGE_DIFF), | ||||
|                                         gen.lib.Date().copy_ymd(year + self.MAX_SIB_AGE_DIFF + self.MAX_AGE_PROB_ALIVE), | ||||
|                                         _("sibling birth date"), | ||||
|                                         child) | ||||
|                     elif ev and ev.type.is_death(): | ||||
|                         dobj = ev.get_date_object()  | ||||
|                         if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                             # if sibling death date too far away, then not alive: | ||||
|                             year = dobj.get_year() | ||||
|                             if year != 0: | ||||
|                                 # sibling death date | ||||
|                                 return (gen.lib.Date().copy_ymd(year - self.MAX_SIB_AGE_DIFF - self.MAX_AGE_PROB_ALIVE), | ||||
|                                         gen.lib.Date().copy_ymd(year + self.MAX_SIB_AGE_DIFF), | ||||
|                                         _("sibling death date"), | ||||
|                                         child) | ||||
|                 # Go through again looking for fallback: | ||||
|                 for ev_ref in child.get_primary_event_ref_list(): | ||||
|                     ev = self.db.get_event_from_handle(ev_ref.ref) | ||||
|                     if ev and ev.type.is_birth_fallback(): | ||||
|                         dobj = ev.get_date_object()  | ||||
|                         if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                             # if sibling birth date too far away, then not alive: | ||||
|                             year = dobj.get_year() | ||||
|                             if year != 0: | ||||
|                                 # sibling birth date | ||||
|                                 return (gen.lib.Date().copy_ymd(year - self.MAX_SIB_AGE_DIFF), | ||||
|                                         gen.lib.Date().copy_ymd(year + self.MAX_SIB_AGE_DIFF + self.MAX_AGE_PROB_ALIVE), | ||||
|                                         _("sibling birth-related date"), | ||||
|                                         child) | ||||
|                     elif ev and ev.type.is_death_fallback(): | ||||
|                         dobj = ev.get_date_object()  | ||||
|                         if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                             # if sibling death date too far away, then not alive: | ||||
|                             year = dobj.get_year() | ||||
|                             if year != 0: | ||||
|                                 # sibling death date | ||||
|                                 return (gen.lib.Date().copy_ymd(year - self.MAX_SIB_AGE_DIFF - self.MAX_AGE_PROB_ALIVE), | ||||
|                                         gen.lib.Date().copy_ymd(year + self.MAX_SIB_AGE_DIFF), | ||||
|                                         _("sibling death-related date"), | ||||
|                                         child) | ||||
|  | ||||
|             if not is_spouse: # if you are not doing a spouse lookup, then let's do: | ||||
|                 mother_handle = family.get_mother_handle() | ||||
|                 father_handle = family.get_father_handle() | ||||
|                 if mother_handle == person.handle and father_handle: | ||||
|                     father = self.db.get_person_from_handle(father_handle) | ||||
|                     date1, date2, explain, other = self.calc_estimates(father, is_spouse=True) | ||||
|                     if date1 and date2: | ||||
|                         return date1, date2, _("a spouse, ") + explain, other | ||||
|                 elif father_handle == person.handle and mother_handle: | ||||
|                     mother = self.db.get_person_from_handle(mother_handle) | ||||
|                     date1, date2, explain, other = self.calc_estimates(father, is_spouse=True) | ||||
|                     if date1 and date2: | ||||
|                         return date1, date2, _("a spouse, ") + explain, other | ||||
|  | ||||
|         # Try looking for descendants that were born more than a lifespan | ||||
|         # ago. | ||||
| @@ -392,32 +659,58 @@ class CalcToolManagedWindow(PluginWindows.ToolManagedWindowBatch): | ||||
|                             val = d.get_start_date() | ||||
|                             val = d.get_year() - years | ||||
|                             d.set_year(val) | ||||
|                             return (d, d.copy_offset_ymd(self.MAX_AGE_PROB_ALIVE)) | ||||
|                             return (d, d.copy_offset_ymd(self.MAX_AGE_PROB_ALIVE), | ||||
|                                     _("descendent birth date"), | ||||
|                                     child) | ||||
|                     child_death_ref = child.get_death_ref() | ||||
|                     if child_death_ref: | ||||
|                         child_death = self.db.get_event_from_handle(child_death_ref.ref) | ||||
|                         dobj = child_death.get_date_object() | ||||
|                         if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                             return (dobj.copy_offset_ymd(- self.MIN_GENERATION_YEARS),  | ||||
|                                     dobj.copy_offset_ymd(- self.MIN_GENERATION_YEARS + self.MAX_AGE_PROB_ALIVE)) | ||||
|                     date1, date2 = descendants_too_old (child, years + self.MIN_GENERATION_YEARS) | ||||
|                                     dobj.copy_offset_ymd(- self.MIN_GENERATION_YEARS + self.MAX_AGE_PROB_ALIVE), | ||||
|                                     _("descendent death date"), | ||||
|                                     child) | ||||
|                     date1, date2, explain, other = descendants_too_old (child, years + self.MIN_GENERATION_YEARS) | ||||
|                     if date1 and date2: | ||||
|                         return date1, date2 | ||||
|             return (None, None) | ||||
|                         return date1, date2, explain, other | ||||
|                     # Check fallback data: | ||||
|                     for ev_ref in child.get_primary_event_ref_list(): | ||||
|                         ev = self.db.get_event_from_handle(ev_ref.ref) | ||||
|                         if ev and ev.type.is_birth_fallback(): | ||||
|                             dobj = ev.get_date_object()  | ||||
|                             if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                                 d = gen.lib.Date(dobj) | ||||
|                                 val = d.get_start_date() | ||||
|                                 val = d.get_year() - years | ||||
|                                 d.set_year(val) | ||||
|                                 return (d, d.copy_offset_ymd(self.MAX_AGE_PROB_ALIVE), | ||||
|                                         _("descendent birth-related date"), | ||||
|                                         child) | ||||
|  | ||||
|                         elif ev and ev.type.is_death_fallback(): | ||||
|                             dobj = ev.get_date_object()  | ||||
|                             if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                                 return (dobj.copy_offset_ymd(- self.MIN_GENERATION_YEARS),  | ||||
|                                         dobj.copy_offset_ymd(- self.MIN_GENERATION_YEARS + self.MAX_AGE_PROB_ALIVE), | ||||
|                                         _("descendent death-related date"), | ||||
|                                         child) | ||||
|  | ||||
|             return (None, None, "", None) | ||||
|  | ||||
|         # If there are descendants that are too old for the person to have | ||||
|         # been alive in the current year then they must be dead. | ||||
|  | ||||
|         date1, date2 = None, None | ||||
|         date1, date2, explain, other = None, None, "", None | ||||
|         try: | ||||
|             date1, date2 = descendants_too_old(person, self.MIN_GENERATION_YEARS) | ||||
|             date1, date2, explain, other = descendants_too_old(person, self.MIN_GENERATION_YEARS) | ||||
|         except RuntimeError: | ||||
|             raise Errors.DatabaseError( | ||||
|                 _("Database error: %s is defined as his or her own ancestor") % | ||||
|                 name_displayer.display(person)) | ||||
|  | ||||
|         if date1 and date2: | ||||
|             return (date1, date2) | ||||
|             return (date1, date2, explain, other) | ||||
|  | ||||
|         def ancestors_too_old(person, year): | ||||
|             family_handle = person.get_main_parents_family_handle() | ||||
| @@ -427,53 +720,104 @@ class CalcToolManagedWindow(PluginWindows.ToolManagedWindowBatch): | ||||
|                 if father_handle: | ||||
|                     father = self.db.get_person_from_handle(father_handle) | ||||
|                     father_birth_ref = father.get_birth_ref() | ||||
|                     if father_birth_ref and father_birth_ref.get_role() == gen.lib.EventRoleType.PRIMARY: | ||||
|                     if father_birth_ref and father_birth_ref.get_role().is_primary(): | ||||
|                         father_birth = self.db.get_event_from_handle( | ||||
|                             father_birth_ref.ref) | ||||
|                         dobj = father_birth.get_date_object() | ||||
|                         if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                             return (dobj.copy_offset_ymd(- year),  | ||||
|                                     dobj.copy_offset_ymd(- year + self.MAX_AGE_PROB_ALIVE)) | ||||
|                                     dobj.copy_offset_ymd(- year + self.MAX_AGE_PROB_ALIVE), | ||||
|                                     _("ancestor birth date"), | ||||
|                                     father) | ||||
|                     father_death_ref = father.get_death_ref() | ||||
|                     if father_death_ref and father_death_ref.get_role() == gen.lib.EventRoleType.PRIMARY: | ||||
|                     if father_death_ref and father_death_ref.get_role().is_primary(): | ||||
|                         father_death = self.db.get_event_from_handle( | ||||
|                             father_death_ref.ref) | ||||
|                         dobj = father_death.get_date_object() | ||||
|                         if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                             return (dobj.copy_offset_ymd(- year - self.MAX_AGE_PROB_ALIVE),  | ||||
|                                     dobj.copy_offset_ymd(- year - self.MAX_AGE_PROB_ALIVE + self.MAX_AGE_PROB_ALIVE)) | ||||
|                     date1, date2 = ancestors_too_old (father, year - self.AVG_GENERATION_GAP) | ||||
|                                     dobj.copy_offset_ymd(- year - self.MAX_AGE_PROB_ALIVE + self.MAX_AGE_PROB_ALIVE), | ||||
|                                     _("ancestor death date"), | ||||
|                                     father) | ||||
|  | ||||
|                     # Check fallback data: | ||||
|                     for ev_ref in father.get_primary_event_ref_list(): | ||||
|                         ev = self.db.get_event_from_handle(ev_ref.ref) | ||||
|                         if ev and ev.type.is_birth_fallback(): | ||||
|                             dobj = ev.get_date_object()  | ||||
|                             if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                                 return (dobj.copy_offset_ymd(- year),  | ||||
|                                         dobj.copy_offset_ymd(- year + self.MAX_AGE_PROB_ALIVE), | ||||
|                                         _("ancestor birth-related date"), | ||||
|                                         father) | ||||
|  | ||||
|                         elif ev and ev.type.is_death_fallback(): | ||||
|                             dobj = ev.get_date_object()  | ||||
|                             if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                                 return (dobj.copy_offset_ymd(- year - self.MAX_AGE_PROB_ALIVE),  | ||||
|                                         dobj.copy_offset_ymd(- year - self.MAX_AGE_PROB_ALIVE + self.MAX_AGE_PROB_ALIVE), | ||||
|                                         _("ancestor death-related date"), | ||||
|                                         father) | ||||
|  | ||||
|                     date1, date2, explain, other = ancestors_too_old (father, year - self.AVG_GENERATION_GAP) | ||||
|                     if date1 and date2: | ||||
|                         return date1, date2 | ||||
|                         return date1, date2, explain, other | ||||
|  | ||||
|                 mother_handle = family.get_mother_handle() | ||||
|                 if mother_handle: | ||||
|                     mother = self.db.get_person_from_handle(mother_handle) | ||||
|                     mother_birth_ref = mother.get_birth_ref() | ||||
|                     if mother_birth_ref and mother_birth_ref.get_role() == gen.lib.EventRoleType.PRIMARY: | ||||
|                     if mother_birth_ref and mother_birth_ref.get_role().is_primary(): | ||||
|                         mother_birth = self.db.get_event_from_handle(mother_birth_ref.ref) | ||||
|                         dobj = mother_birth.get_date_object() | ||||
|                         if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                             return (dobj.copy_offset_ymd(- year),  | ||||
|                                     dobj.copy_offset_ymd(- year + self.MAX_AGE_PROB_ALIVE)) | ||||
|                                     dobj.copy_offset_ymd(- year + self.MAX_AGE_PROB_ALIVE), | ||||
|                                     _("ancestor birth date"), | ||||
|                                     mother) | ||||
|                     mother_death_ref = mother.get_death_ref() | ||||
|                     if mother_death_ref and mother_death_ref.get_role() == gen.lib.EventRoleType.PRIMARY: | ||||
|                     if mother_death_ref and mother_death_ref.get_role().is_primary(): | ||||
|                         mother_death = self.db.get_event_from_handle( | ||||
|                             mother_death_ref.ref) | ||||
|                         dobj = mother_death.get_date_object() | ||||
|                         if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                             return (dobj.copy_offset_ymd(- year - self.MAX_AGE_PROB_ALIVE),  | ||||
|                                     dobj.copy_offset_ymd(- year - self.MAX_AGE_PROB_ALIVE + self.MAX_AGE_PROB_ALIVE)) | ||||
|                     date1, date2 = ancestors_too_old (mother, year - self.AVG_GENERATION_GAP) | ||||
|                                     dobj.copy_offset_ymd(- year - self.MAX_AGE_PROB_ALIVE + self.MAX_AGE_PROB_ALIVE), | ||||
|                                     _("ancestor death date"), | ||||
|                                     mother) | ||||
|  | ||||
|                     # Check fallback data: | ||||
|                     for ev_ref in mother.get_primary_event_ref_list(): | ||||
|                         ev = self.db.get_event_from_handle(ev_ref.ref) | ||||
|                         if ev and ev.type.is_birth_fallback(): | ||||
|                             dobj = ev.get_date_object()  | ||||
|                             if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                                 return (dobj.copy_offset_ymd(- year),  | ||||
|                                         dobj.copy_offset_ymd(- year + self.MAX_AGE_PROB_ALIVE), | ||||
|                                         _("ancestor birth-related date"), | ||||
|                                         mother) | ||||
|  | ||||
|                         elif ev and ev.type.is_death_fallback(): | ||||
|                             dobj = ev.get_date_object()  | ||||
|                             if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                                 return (dobj.copy_offset_ymd(- year - self.MAX_AGE_PROB_ALIVE),  | ||||
|                                         dobj.copy_offset_ymd(- year - self.MAX_AGE_PROB_ALIVE + self.MAX_AGE_PROB_ALIVE), | ||||
|                                         _("ancestor death-related date"), | ||||
|                                         mother) | ||||
|  | ||||
|                     date1, date2, explain, other = ancestors_too_old (mother, year - self.AVG_GENERATION_GAP) | ||||
|                     if date1 and date2: | ||||
|                         return (date1, date2) | ||||
|             return (None, None) | ||||
|                         return (date1, date2, explain, other) | ||||
|  | ||||
|             return (None, None, "", None) | ||||
|  | ||||
|         # If there are ancestors that would be too old in the current year | ||||
|         # then assume our person must be dead too. | ||||
|         date1, date2 = ancestors_too_old (person, - self.MIN_GENERATION_YEARS) | ||||
|         date1, date2, explain, other = ancestors_too_old (person, - self.MIN_GENERATION_YEARS) | ||||
|         if date1 and date2: | ||||
|             return (date1, date2) | ||||
|         #print "   FAIL" | ||||
|             return (date1, date2, explain, other) | ||||
|  | ||||
|         # If we can't find any reason to believe that they are dead we | ||||
|         # must assume they are alive. | ||||
|         return (None, None) | ||||
|  | ||||
|         return (None, None, "", None) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user