Enhanced Calculate Estimated Dates tool

svn: r14014
This commit is contained in:
Doug Blank 2010-01-10 04:06:44 +00:00
parent 746e934937
commit 2d60b8763a

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# #
# Gramps - a GTK+/GNOME based genealogy program # Gramps - a GTK+/GNOME based genealogy program
# #
@ -38,12 +39,17 @@ import time
#------------------------------------------------------------------------ #------------------------------------------------------------------------
from PluginUtils import Tool, PluginWindows, MenuToolOptions from PluginUtils import Tool, PluginWindows, MenuToolOptions
from gen.plug.menu import BooleanOption, NumberOption, StringOption, \ from gen.plug.menu import BooleanOption, NumberOption, StringOption, \
FilterOption, PersonOption FilterOption, PersonOption, EnumeratedListOption
import gen.lib import gen.lib
import config import config
from BasicUtils import name_displayer from BasicUtils import name_displayer
import Errors import Errors
from ReportBase import ReportUtils 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 """ """ Calculate Estimated Date options """
def __init__(self, name, person_id=None, dbstate=None): def __init__(self, name, person_id=None, dbstate=None):
self.__db = dbstate.get_database() self.__db = dbstate.get_database()
self.__dbstate = dbstate
MenuToolOptions.__init__(self, name, person_id, dbstate) MenuToolOptions.__init__(self, name, person_id, dbstate)
def get_dbstate(self):
return self.__dbstate
def add_menu_options(self, menu): def add_menu_options(self, menu):
@ -78,24 +88,25 @@ class CalcEstDateOptions(MenuToolOptions):
source_text.set_help(_("Source to remove and/or add")) source_text.set_help(_("Source to remove and/or add"))
menu.add_option(category_name, "source_text", source_text) menu.add_option(category_name, "source_text", source_text)
remove = BooleanOption(_("Remove previously added dates"), True) remove = BooleanOption(_("Remove previously added events, notes, and source"), True)
remove.set_help(_("Remove")) remove.set_help(_("Remove calculated events, notes, and source; occurs immediately on Execute"))
menu.add_option(category_name, "remove", remove) menu.add_option(category_name, "remove", remove)
birth = BooleanOption(_("Add estimated birth dates"), True) birth = EnumeratedListOption(_("Birth"), 0)
birth.set_help(_("Add")) 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) menu.add_option(category_name, "add_birth", birth)
death = BooleanOption(_("Add estimated death dates"), True) death = EnumeratedListOption(_("Death"), 0)
death.set_help(_("Add estimated death dates")) 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) 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"), num = NumberOption(_("Maximum age"),
config.get('behavior.max-age-prob-alive'), config.get('behavior.max-age-prob-alive'),
0, 200) 0, 200)
@ -145,34 +156,91 @@ class CalcEstDateOptions(MenuToolOptions):
class CalcToolManagedWindow(PluginWindows.ToolManagedWindowBatch): 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): def get_title(self):
return _("Calculate Estimated Dates") return _("Calculate Estimated Dates")
def initial_frame(self): def initial_frame(self):
return _("Options") return _("Options")
def set_reselect(self):
self.reselect = True
def run(self): 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.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_option = self.options.menu.get_option_by_name('filter')
self.filter = self.filter_option.get_filter() # the actual filter self.filter = self.filter_option.get_filter() # the actual filter
people = self.filter.apply(self.db, people = self.filter.apply(self.db,
self.db.iter_person_handles()) self.db.iter_person_handles())
num_people = self.db.get_number_of_people() num_people = self.db.get_number_of_people()
source_text = self.options.handler.options_dict['source_text'] source_text = self.options.handler.options_dict['source_text']
source = None
add_birth = self.options.handler.options_dict['add_birth'] add_birth = self.options.handler.options_dict['add_birth']
add_death = self.options.handler.options_dict['add_death'] add_death = self.options.handler.options_dict['add_death']
remove_old = self.options.handler.options_dict['remove'] 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.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_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.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'] self.AVG_GENERATION_GAP = self.options.handler.options_dict['AVG_GENERATION_GAP']
if remove_old: 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), self.progress.set_pass((_("Removing '%s'...") % source_text),
num_people) num_people)
for person_handle in people: for person_handle in people:
@ -191,6 +259,12 @@ class CalcToolManagedWindow(PluginWindows.ToolManagedWindowBatch):
if source.get_title() == source_text: if source.get_title() == source_text:
person.set_birth_ref(None) person.set_birth_ref(None)
person.remove_handle_references('Event',[birth_ref.ref]) 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.remove_event(birth_ref.ref, self.trans)
self.db.commit_source(source, self.trans) self.db.commit_source(source, self.trans)
pupdate = 1 pupdate = 1
@ -207,64 +281,197 @@ class CalcToolManagedWindow(PluginWindows.ToolManagedWindowBatch):
if source.get_title() == source_text: if source.get_title() == source_text:
person.set_death_ref(None) person.set_death_ref(None)
person.remove_handle_references('Event',[death_ref.ref]) 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.remove_event(death_ref.ref, self.trans)
self.db.commit_source(source, self.trans) self.db.commit_source(source, self.trans)
pupdate = 1 pupdate = 1
break break
if pupdate == 1: if pupdate == 1:
self.db.commit_person(person, self.trans) 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: if add_birth or add_death:
self.results_write(_("Calculating...\n")) self.results_write(_("Selecting... \n\n"))
self.progress.set_pass(_('Calculating estimated dates...'), self.progress.set_pass(_('Selecting...'),
num_people) num_people)
source = self.get_or_create_source(source_text) row = 0
for person_handle in people: for person_handle in people:
self.progress.step() self.progress.step()
added_birth, added_death = 0, 0
person = self.db.get_person_from_handle(person_handle) person = self.db.get_person_from_handle(person_handle)
birth_ref = person.get_birth_ref() birth_ref = person.get_birth_ref()
death_ref = person.get_death_ref() death_ref = person.get_death_ref()
#print birth_ref, death_ref add_birth_event, add_death_event = False, False
date1, date2 = self.calc_estimates(person, birth_ref, death_ref) if not birth_ref or not death_ref:
#print date1, date2 date1, date2, explain, other = self.calc_estimates(person)
if not birth_ref and add_birth and date1: if birth_ref:
#print "added birth" ev = self.db.get_event_from_handle(birth_ref.ref)
birth = self.create_event(_("Estimated birth date"), date1 = ev.get_date_object()
gen.lib.EventType.BIRTH, elif not birth_ref and add_birth and date1:
date1, source) add_birth_event = True
event_ref = gen.lib.EventRef() date1.make_vague()
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?
else: else:
#print "added death" date1 = gen.lib.Date()
death = self.create_event(_("Estimated death date"), if death_ref:
gen.lib.EventType.DEATH, ev = self.db.get_event_from_handle(death_ref.ref)
date2, source) date2 = ev.get_date_object()
event_ref = gen.lib.EventRef() elif not death_ref and add_death and date2:
event_ref.set_reference_handle(death.get_handle()) current_date = gen.lib.Date()
person.set_death_ref(event_ref) current_date.set_yr_mon_day(*time.localtime(time.time())[0:3])
self.db.commit_person(person, self.trans) if date2.match( current_date, "<"):
added_death = 1 add_death_event = True
if (added_birth or added_death) and display_details: date2.make_vague()
self.results_write_link(name_displayer.display(person), else:
person, person_handle) date2 = gen.lib.Date()
if added_birth: else:
self.results_write(_(" added birth on %s") % date1) date2 = gen.lib.Date()
if added_death: # Describe
self.results_write(_(" added death on %s") % date2) if add_birth_event and add_death_event:
self.results_write("\n") action = _("Add birth and death events")
self.db.transaction_commit(self.trans, _("Calculate date estimates")) 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.enable_signals()
self.db.request_rebuild() 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): def get_or_create_source(self, source_text):
source_list = self.db.get_source_handles() source_list = self.db.get_source_handles()
@ -278,9 +485,16 @@ class CalcToolManagedWindow(PluginWindows.ToolManagedWindowBatch):
return source return source
def create_event(self, description=_("Estimated date"), 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 = gen.lib.Event()
event.set_description(description) 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: if type:
event.set_type(gen.lib.EventType(type)) event.set_type(gen.lib.EventType(type))
if date: if date:
@ -296,54 +510,65 @@ class CalcToolManagedWindow(PluginWindows.ToolManagedWindowBatch):
self.db.add_event(event, self.trans) self.db.add_event(event, self.trans)
return event 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 death_date = None
birth_date = None birth_date = None
explain = ""
# If the recorded death year is before current year then # If the recorded death year is before current year then
# things are simple. # 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) death = self.db.get_event_from_handle(death_ref.ref)
if death.get_date_object().get_start_date() != gen.lib.Date.EMPTY: if death.get_date_object().get_start_date() != gen.lib.Date.EMPTY:
death_date = death.get_date_object() death_date = death.get_date_object()
# Look for Cause Of Death, Burial or Cremation events. # Look for Cause Of Death, Burial or Cremation events.
# These are fairly good indications that someone's not alive. # These are fairly good indications that someone's not alive.
for ev_ref in person.get_primary_event_ref_list(): if not death_date:
ev = self.db.get_event_from_handle(ev_ref.ref) for ev_ref in person.get_primary_event_ref_list():
if ev and ev.type in [gen.lib.EventType.CAUSE_DEATH, ev = self.db.get_event_from_handle(ev_ref.ref)
gen.lib.EventType.BURIAL, if ev and ev.type.is_death_fallback():
gen.lib.EventType.CREMATION]:
if not death_date:
death_date = ev.get_date_object() 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). # assume they are alive (we already know they are not dead).
if birth_ref and birth_ref.get_role() == gen.lib.EventRoleType.PRIMARY: if not birth_date:
birth = self.db.get_event_from_handle(birth_ref.ref) if birth_ref and birth_ref.get_role().is_primary():
if birth.get_date_object().get_start_date() != gen.lib.Date.EMPTY: birth = self.db.get_event_from_handle(birth_ref.ref)
if not birth_date: if birth.get_date_object().get_start_date() != gen.lib.Date.EMPTY:
birth_date = birth.get_date_object() 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: if not birth_date and death_date:
# person died more than MAX after current year # person died more than MAX after current year
birth_date = death_date.copy_offset_ymd(year=-self.MAX_AGE_PROB_ALIVE) birth_date = death_date.copy_offset_ymd(year=-self.MAX_AGE_PROB_ALIVE)
explain = _("death date")
if not death_date and birth_date: if not death_date and birth_date:
# person died more than MAX after current year # person died more than MAX after current year
death_date = birth_date.copy_offset_ymd(year=self.MAX_AGE_PROB_ALIVE) death_date = birth_date.copy_offset_ymd(year=self.MAX_AGE_PROB_ALIVE)
explain = _("birth date")
if death_date and 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 # Neither birth nor death events are available. Try looking
# at siblings. If a sibling was born more than 120 years past, # at siblings. If a sibling was born more than X years past,
# or more than 20 future, then probably this person is # or more than Z future, then probably this person is
# not alive. If the sibling died more than 120 years # not alive. If the sibling died more than X years
# past, or more than 120 years future, then probably not alive. # past, or more than X years future, then probably not alive.
#print " searching family..."
family_list = person.get_parent_family_handle_list() family_list = person.get_parent_family_handle_list()
for family_handle in family_list: for family_handle in family_list:
@ -351,28 +576,70 @@ class CalcToolManagedWindow(PluginWindows.ToolManagedWindowBatch):
for child_ref in family.get_child_ref_list(): for child_ref in family.get_child_ref_list():
child_handle = child_ref.ref child_handle = child_ref.ref
child = self.db.get_person_from_handle(child_handle) child = self.db.get_person_from_handle(child_handle)
child_birth_ref = child.get_birth_ref() # Go through once looking for direct evidence:
if child_birth_ref: for ev_ref in child.get_primary_event_ref_list():
child_birth = self.db.get_event_from_handle(child_birth_ref.ref) ev = self.db.get_event_from_handle(ev_ref.ref)
dobj = child_birth.get_date_object() if ev and ev.type.is_birth():
if dobj.get_start_date() != gen.lib.Date.EMPTY: dobj = ev.get_date_object()
# if sibling birth date too far away, then not alive: if dobj.get_start_date() != gen.lib.Date.EMPTY:
year = dobj.get_year() # if sibling birth date too far away, then not alive:
if year != 0: year = dobj.get_year()
# sibling birth date if year != 0:
return (gen.lib.Date().copy_ymd(year - self.MAX_SIB_AGE_DIFF), # sibling birth date
gen.lib.Date().copy_ymd(year + self.MAX_SIB_AGE_DIFF + self.MAX_AGE_PROB_ALIVE)) return (gen.lib.Date().copy_ymd(year - self.MAX_SIB_AGE_DIFF),
child_death_ref = child.get_death_ref() gen.lib.Date().copy_ymd(year + self.MAX_SIB_AGE_DIFF + self.MAX_AGE_PROB_ALIVE),
if child_death_ref: _("sibling birth date"),
child_death = self.db.get_event_from_handle(child_death_ref.ref) child)
dobj = child_death.get_date_object() elif ev and ev.type.is_death():
if dobj.get_start_date() != gen.lib.Date.EMPTY: dobj = ev.get_date_object()
# if sibling death date too far away, then not alive: if dobj.get_start_date() != gen.lib.Date.EMPTY:
year = dobj.get_year() # if sibling death date too far away, then not alive:
if year != 0: year = dobj.get_year()
# sibling death date if year != 0:
return (gen.lib.Date().copy_ymd(year - self.MAX_SIB_AGE_DIFF - self.MAX_AGE_PROB_ALIVE), # sibling death date
gen.lib.Date().copy_ymd(year + self.MAX_SIB_AGE_DIFF)) 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 # Try looking for descendants that were born more than a lifespan
# ago. # ago.
@ -392,32 +659,58 @@ class CalcToolManagedWindow(PluginWindows.ToolManagedWindowBatch):
val = d.get_start_date() val = d.get_start_date()
val = d.get_year() - years val = d.get_year() - years
d.set_year(val) 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() child_death_ref = child.get_death_ref()
if child_death_ref: if child_death_ref:
child_death = self.db.get_event_from_handle(child_death_ref.ref) child_death = self.db.get_event_from_handle(child_death_ref.ref)
dobj = child_death.get_date_object() dobj = child_death.get_date_object()
if dobj.get_start_date() != gen.lib.Date.EMPTY: if dobj.get_start_date() != gen.lib.Date.EMPTY:
return (dobj.copy_offset_ymd(- self.MIN_GENERATION_YEARS), return (dobj.copy_offset_ymd(- self.MIN_GENERATION_YEARS),
dobj.copy_offset_ymd(- self.MIN_GENERATION_YEARS + self.MAX_AGE_PROB_ALIVE)) dobj.copy_offset_ymd(- self.MIN_GENERATION_YEARS + self.MAX_AGE_PROB_ALIVE),
date1, date2 = descendants_too_old (child, years + self.MIN_GENERATION_YEARS) _("descendent death date"),
child)
date1, date2, explain, other = descendants_too_old (child, years + self.MIN_GENERATION_YEARS)
if date1 and date2: if date1 and date2:
return date1, date2 return date1, date2, explain, other
return (None, None) # 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 # If there are descendants that are too old for the person to have
# been alive in the current year then they must be dead. # been alive in the current year then they must be dead.
date1, date2 = None, None date1, date2, explain, other = None, None, "", None
try: 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: except RuntimeError:
raise Errors.DatabaseError( raise Errors.DatabaseError(
_("Database error: %s is defined as his or her own ancestor") % _("Database error: %s is defined as his or her own ancestor") %
name_displayer.display(person)) name_displayer.display(person))
if date1 and date2: if date1 and date2:
return (date1, date2) return (date1, date2, explain, other)
def ancestors_too_old(person, year): def ancestors_too_old(person, year):
family_handle = person.get_main_parents_family_handle() family_handle = person.get_main_parents_family_handle()
@ -427,53 +720,104 @@ class CalcToolManagedWindow(PluginWindows.ToolManagedWindowBatch):
if father_handle: if father_handle:
father = self.db.get_person_from_handle(father_handle) father = self.db.get_person_from_handle(father_handle)
father_birth_ref = father.get_birth_ref() 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 = self.db.get_event_from_handle(
father_birth_ref.ref) father_birth_ref.ref)
dobj = father_birth.get_date_object() dobj = father_birth.get_date_object()
if dobj.get_start_date() != gen.lib.Date.EMPTY: if dobj.get_start_date() != gen.lib.Date.EMPTY:
return (dobj.copy_offset_ymd(- year), 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() 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 = self.db.get_event_from_handle(
father_death_ref.ref) father_death_ref.ref)
dobj = father_death.get_date_object() dobj = father_death.get_date_object()
if dobj.get_start_date() != gen.lib.Date.EMPTY: if dobj.get_start_date() != gen.lib.Date.EMPTY:
return (dobj.copy_offset_ymd(- year - self.MAX_AGE_PROB_ALIVE), 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)) 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) _("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: if date1 and date2:
return date1, date2 return date1, date2, explain, other
mother_handle = family.get_mother_handle() mother_handle = family.get_mother_handle()
if mother_handle: if mother_handle:
mother = self.db.get_person_from_handle(mother_handle) mother = self.db.get_person_from_handle(mother_handle)
mother_birth_ref = mother.get_birth_ref() 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) mother_birth = self.db.get_event_from_handle(mother_birth_ref.ref)
dobj = mother_birth.get_date_object() dobj = mother_birth.get_date_object()
if dobj.get_start_date() != gen.lib.Date.EMPTY: if dobj.get_start_date() != gen.lib.Date.EMPTY:
return (dobj.copy_offset_ymd(- year), 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() 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 = self.db.get_event_from_handle(
mother_death_ref.ref) mother_death_ref.ref)
dobj = mother_death.get_date_object() dobj = mother_death.get_date_object()
if dobj.get_start_date() != gen.lib.Date.EMPTY: if dobj.get_start_date() != gen.lib.Date.EMPTY:
return (dobj.copy_offset_ymd(- year - self.MAX_AGE_PROB_ALIVE), 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)) 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) _("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: if date1 and date2:
return (date1, date2) return (date1, date2, explain, other)
return (None, None)
return (None, None, "", None)
# If there are ancestors that would be too old in the current year # If there are ancestors that would be too old in the current year
# then assume our person must be dead too. # 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: if date1 and date2:
return (date1, date2) return (date1, date2, explain, other)
#print " FAIL"
# If we can't find any reason to believe that they are dead we # If we can't find any reason to believe that they are dead we
# must assume they are alive. # must assume they are alive.
return (None, None)
return (None, None, "", None)