diff --git a/src/config.py b/src/config.py index a16b67690..a2abebd13 100644 --- a/src/config.py +++ b/src/config.py @@ -304,6 +304,7 @@ register('preferences.last-view', '') register('preferences.last-views', []) register('preferences.use-bsddb3', False) register('preferences.family-relation-type', 3) # UNKNOWN +register('preferences.age-display-precision', 1) register('researcher.researcher-addr', '') register('researcher.researcher-locality', '') diff --git a/src/gui/configure.py b/src/gui/configure.py index 3afea832d..c2920946e 100644 --- a/src/gui/configure.py +++ b/src/gui/configure.py @@ -902,6 +902,28 @@ class GrampsPreferences(ConfigureDialog): table.attach(obox, 1, 3, row, row+1, yoptions=0) row += 1 + # Age precision: + # precision=1 for "year", 2: "year, month" or 3: "year, month, days" + obox = gtk.combo_box_new_text() + age_precision = [_("Years"), + _("Years, Months"), + _("Years, Months, Days")] + map(obox.append_text, age_precision) + # Combo_box active index is from 0 to 2, we need values from 1 to 3 + active = config.get('preferences.age-display-precision') - 1 + if active >= 0 and active <= 2: + obox.set_active(active) + else: + obox.set_active(0) + obox.connect('changed', + lambda obj: config.set('preferences.age-display-precision', + obj.get_active() + 1)) + lwidget = BasicLabel("%s: " + % _('Age display precision (requires restart)')) + table.attach(lwidget, 0, 1, row, row+1, yoptions=0) + table.attach(obox, 1, 3, row, row+1, yoptions=0) + row += 1 + # Calendar format on report: obox = gtk.combo_box_new_text() map(obox.append_text, gen.lib.Date.ui_calendar_names) diff --git a/src/gui/editors/displaytabs/embeddedlist.py b/src/gui/editors/displaytabs/embeddedlist.py index 7df8d0bc0..a202153dd 100644 --- a/src/gui/editors/displaytabs/embeddedlist.py +++ b/src/gui/editors/displaytabs/embeddedlist.py @@ -448,7 +448,10 @@ class EmbeddedList(ButtonTab): column.set_resizable(True) column.set_clickable(True) column.set_expand(True) - column.set_min_width(self._column_names[pair[1]][2]) + column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) + #column.set_min_width(self._column_names[pair[1]][2]) + column.set_fixed_width(self._column_names[pair[1]][2]) + column.set_sort_column_id(self._column_names[pair[1]][1]) self.columns.append(column) self.tree.append_column(column) diff --git a/src/gui/editors/displaytabs/eventembedlist.py b/src/gui/editors/displaytabs/eventembedlist.py index 462cb0d03..5cddc7d45 100644 --- a/src/gui/editors/displaytabs/eventembedlist.py +++ b/src/gui/editors/displaytabs/eventembedlist.py @@ -74,25 +74,26 @@ class EventEmbedList(DbGUIElement, GroupEmbeddedList): (_('Description'), -1, 240, 0, EventRefModel.COL_FONTWEIGHT[0]), (_('Type'), EventRefModel.COL_TYPE[0], 100, 0, EventRefModel.COL_FONTWEIGHT[0]), - (_('ID'), EventRefModel.COL_GID[0], 60, 0, + (_('ID'), EventRefModel.COL_GID[0], 50, 0, EventRefModel.COL_FONTWEIGHT[0]), - (_('Date'), EventRefModel.COL_SORTDATE[0], 150, 1, -1), - (_('Place'), EventRefModel.COL_PLACE[0], 140, 0, -1), - (_('Role'), EventRefModel.COL_ROLE[0], 80, 0, -1), + (_('Date'), EventRefModel.COL_SORTDATE[0], 80, 1, -1), + (_('Place'), EventRefModel.COL_PLACE[0], 150, 0, -1), + (_('Role'), EventRefModel.COL_ROLE[0], 60, 0, -1), None, None, + None, + (_('Age'), EventRefModel.COL_SORTAGE[0], 60, 0, -1), None ] - def __init__(self, dbstate, uistate, track, obj, - build_model=EventRefModel): + def __init__(self, dbstate, uistate, track, obj, build_model=EventRefModel, **kwargs): self.obj = obj self._groups = [] self._data = [] DbGUIElement.__init__(self, dbstate.db) GroupEmbeddedList.__init__(self, dbstate, uistate, track, _('_Events'), build_model, share_button=True, - move_buttons=True) + move_buttons=True, **kwargs) def _connect_db_signals(self): """ @@ -186,7 +187,14 @@ class EventEmbedList(DbGUIElement, GroupEmbeddedList): The columns to show as a tuple containing tuples (show/noshow, model column) """ - return ((1, 0), (1, 1), (1, 2), (1, 3), (1, 4), (1, 5)) + return ((1, 0), # desc + (1, 1), # type + (1, 2), # gid + (1, 3), # date + (1, 9), # age + (1, 4), # place + (1, 5), # role + ) def default_types(self): return [ diff --git a/src/gui/editors/displaytabs/eventrefmodel.py b/src/gui/editors/displaytabs/eventrefmodel.py index 3ba80b690..ce104d33e 100644 --- a/src/gui/editors/displaytabs/eventrefmodel.py +++ b/src/gui/editors/displaytabs/eventrefmodel.py @@ -51,6 +51,7 @@ import config # #------------------------------------------------------------------------- invalid_date_format = config.get('preferences.invalid-date-format') +age_precision = config.get('preferences.age-display-precision') #------------------------------------------------------------------------- # @@ -71,11 +72,13 @@ class EventRefModel(gtk.TreeStore): COL_SORTDATE = (6, str) COL_EVENTREF = (7, object) COL_FONTWEIGHT = (8, int) + COL_AGE = (9, str) + COL_SORTAGE = (10, str) COLS = (COL_DESCR, COL_TYPE, COL_GID, COL_DATE, COL_PLACE, COL_ROLE, - COL_SORTDATE, COL_EVENTREF, COL_FONTWEIGHT) + COL_SORTDATE, COL_EVENTREF, COL_FONTWEIGHT, COL_AGE, COL_SORTAGE) - def __init__(self, event_list, db, groups): + def __init__(self, event_list, db, groups, **kwargs): """ @param event_list: A list of lists, every entry is a group, the entries in a group are the data that needs to be shown subordinate to the @@ -83,7 +86,9 @@ class EventRefModel(gtk.TreeStore): @param db: a database objects that can be used to obtain info @param groups: a list of (key, name) tuples. key is a key for the group that might be used. name is the name for the group. + @param kwargs: A dictionary of additional settings/values. """ + self.start_date = kwargs.get("start_date", None) typeobjs = (x[1] for x in self.COLS) gtk.TreeStore.__init__(self, *typeobjs) self.db = db @@ -96,7 +101,7 @@ class EventRefModel(gtk.TreeStore): def row_group(self, index, group): name = self.namegroup(index, len(group)) - return [name, '', '', '', '', '', '', (index, None), WEIGHT_BOLD] + return [name, '', '', '', '', '', '', (index, None), WEIGHT_BOLD, '', ''] def namegroup(self, groupindex, length): return self._GROUPSTRING % {'groupname': self.groups[groupindex][1], @@ -112,6 +117,8 @@ class EventRefModel(gtk.TreeStore): self.column_sort_date(eventref), (index, eventref), self.colweight(index), + self.column_age(event), + self.column_sort_age(event), ] def colweight(self, index): @@ -144,3 +151,25 @@ class EventRefModel(gtk.TreeStore): if place_handle: return self.db.get_place_from_handle(place_handle).get_title() return u"" + + def column_age(self, event): + """ + Returns a string representation of age in years. Change + precision=2 for "year, month", or precision=3 for "year, + month, days" + """ + date = event.get_date_object() + if date and self.start_date: + return (date - self.start_date).format(precision=age_precision) + else: + return "" + + def column_sort_age(self, event): + """ + Returns a string version of number of days of age. + """ + date = event.get_date_object() + if date and self.start_date: + return "%09d" % int(date - self.start_date) + else: + return "" diff --git a/src/gui/editors/displaytabs/groupembeddedlist.py b/src/gui/editors/displaytabs/groupembeddedlist.py index 0ce139ede..c213c422c 100644 --- a/src/gui/editors/displaytabs/groupembeddedlist.py +++ b/src/gui/editors/displaytabs/groupembeddedlist.py @@ -60,10 +60,11 @@ class GroupEmbeddedList(EmbeddedList): _WORKGROUP = 0 def __init__(self, dbstate, uistate, track, name, build_model, - share_button=False, move_buttons=False, jump_button=False): + share_button=False, move_buttons=False, jump_button=False, **kwargs): """ Create a new list, using the passed build_model to populate the list. """ + self.kwargs = kwargs EmbeddedList.__init__(self, dbstate, uistate, track, name, build_model, share_button, move_buttons, jump_button) #connect click on the first column @@ -79,7 +80,7 @@ class GroupEmbeddedList(EmbeddedList): groups """ return self.build_model(self.get_data(), self.dbstate.db, - self.groups()) + self.groups(), **self.kwargs) def groups(self): """ diff --git a/src/gui/editors/displaytabs/personeventembedlist.py b/src/gui/editors/displaytabs/personeventembedlist.py index 7bdf270e0..aec38bd75 100644 --- a/src/gui/editors/displaytabs/personeventembedlist.py +++ b/src/gui/editors/displaytabs/personeventembedlist.py @@ -60,9 +60,10 @@ class PersonEventEmbedList(EventEmbedList): 'down' : _('Move the selected event downwards or change family order'), } - def __init__(self, dbstate, uistate, track, obj): + def __init__(self, dbstate, uistate, track, obj, **kwargs): + self.dbstate = dbstate EventEmbedList.__init__(self, dbstate, uistate, track, obj, - build_model=EventRefModel ) + build_model=EventRefModel, **kwargs) def get_data(self): if not self._data or self.changed: diff --git a/src/gui/editors/editfamily.py b/src/gui/editors/editfamily.py index 66ee0d9ea..2550b8326 100644 --- a/src/gui/editors/editfamily.py +++ b/src/gui/editors/editfamily.py @@ -63,6 +63,7 @@ import gobject import Utils import config from gen.display.name import displayer as name_displayer +from gen.utils import get_marriage_or_fallback import gen.lib from gen.db import DbTxn import Errors @@ -605,6 +606,14 @@ class EditFamily(EditPrimary): self.phandles = filter(None, self.phandles) + def get_start_date(self): + """ + Get the start date for a family, usually a marriage date, or + something close to marriage. + """ + event = get_marriage_or_fallback(self.dbstate.db, self.obj) + return event.get_date_object() if event else None + def _create_tabbed_pages(self): notebook = gtk.Notebook() @@ -620,7 +629,9 @@ class EditFamily(EditPrimary): self.event_list = EventEmbedList(self.dbstate, self.uistate, self.track, - self.obj) + self.obj, + start_date=self.get_start_date()) + self._add_tab(notebook, self.event_list) self.track_ref_for_deletion("event_list") diff --git a/src/gui/editors/editperson.py b/src/gui/editors/editperson.py index 4d7a3fffa..cfb449baa 100644 --- a/src/gui/editors/editperson.py +++ b/src/gui/editors/editperson.py @@ -52,6 +52,7 @@ import pango import Utils import ThumbNails from gui.utils import add_menuitem, open_file_with_default_application +from gen.utils import get_birth_or_fallback import gen.lib from gen.db import DbTxn from gui import widgets @@ -420,6 +421,13 @@ class EditPerson(EditPrimary): self.preview_name = self.top.get_object("full_name") self.preview_name.modify_font(pango.FontDescription('sans bold 12')) + def get_start_date(self): + """ + Get the start date for a person, usually a birth date, or + something close to birth. + """ + event = get_birth_or_fallback(self.dbstate.db, self.obj) + return event.get_date_object() if event else None def _create_tabbed_pages(self): """ @@ -428,10 +436,13 @@ class EditPerson(EditPrimary): notebook = gtk.Notebook() notebook.set_scrollable(True) - self.event_list = PersonEventEmbedList(self.dbstate, - self.uistate, - self.track, - self.obj) + self.event_list = PersonEventEmbedList( + self.dbstate, + self.uistate, + self.track, + self.obj, + start_date=self.get_start_date()) + self._add_tab(notebook, self.event_list) self.track_ref_for_deletion("event_list") diff --git a/src/gui/views/listview.py b/src/gui/views/listview.py index a0d875119..d3cad6511 100644 --- a/src/gui/views/listview.py +++ b/src/gui/views/listview.py @@ -237,10 +237,13 @@ class ListView(NavigationView): column.add_attribute(self.renderer, 'text', pair[1]) column.connect('clicked', self.column_clicked, index) + column.set_resizable(True) + column.set_clickable(True) + column.set_expand(True) column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) column.set_fixed_width(pair[2]) - column.set_clickable(True) + self.columns.append(column) self.list.append_column(column) index += 1 @@ -486,7 +489,7 @@ class ListView(NavigationView): return colord def get_column_widths(self): - return [column.get_width() for column in self.columns] + return [column.get_width() for column in self.columns] def remove_selected_objects(self): """ diff --git a/src/plugins/gramplet/Events.py b/src/plugins/gramplet/Events.py index 878ac7a41..69d2a1e98 100644 --- a/src/plugins/gramplet/Events.py +++ b/src/plugins/gramplet/Events.py @@ -25,8 +25,12 @@ from gen.plug import Gramplet from gen.ggettext import gettext as _ from gen.display.name import displayer as name_displayer import gen.datehandler +from gen.utils import get_birth_or_fallback import Errors import gtk +import config + +age_precision = config.get('preferences.age-display-precision') class Events(Gramplet): """ @@ -48,8 +52,10 @@ class Events(Gramplet): titles = [('', NOSORT, 50,), (_('Type'), 1, 100), (_('Details'), 2, 200), - (_('Date'), 4, 100), - ('', 4, 100), + (_('Date'), 3, 100), + ('', NOSORT, 50), + (_('Age'), 4, 100), + ('', NOSORT, 50), (_('Place'), 5, 400), (_('Role'), 6, 100)] self.model = ListModel(top, titles, event_func=self.edit_event) @@ -62,6 +68,8 @@ class Events(Gramplet): event = self.dbstate.db.get_event_from_handle(event_ref.ref) event_date = gen.datehandler.get_date(event) event_sort = '%012d' % event.get_date_object().get_sort_value() + person_age = self.column_age(event) + person_age_sort = self.column_sort_age(event) place = '' handle = event.get_place_handle() if handle: @@ -75,9 +83,45 @@ class Events(Gramplet): details, event_date, event_sort, + person_age, + person_age_sort, place, str(event_ref.get_role()))) + def column_age(self, event): + """ + Returns a string representation of age in years. Change + precision=2 for "year, month", or precision=3 for "year, + month, days" + """ + date = event.get_date_object() + start_date = self.get_start_date() + if date and start_date: + return (date - start_date).format(precision=age_precision) + else: + return "" + + def column_sort_age(self, event): + """ + Returns a string version of number of days of age. + """ + date = event.get_date_object() + start_date = self.get_start_date() + if date and start_date: + return "%09d" % int(date - start_date) + else: + return "" + + def get_start_date(self): + """ + Get the start date for a person, usually a birth date, or + something close to birth. + """ + active_handle = self.get_active('Person') + active = self.dbstate.db.get_person_from_handle(active_handle) + event = get_birth_or_fallback(self.dbstate.db, active) + return event.get_date_object() if event else None + def edit_event(self, treeview): """ Edit the selected event.