From 248002b8196da1ec362977cd5f4fe9f81f431b1f Mon Sep 17 00:00:00 2001 From: Doug Blank Date: Sun, 1 Feb 2009 16:42:57 +0000 Subject: [PATCH] Split DefaultGramplets into their respective files svn: r11790 --- po/POTFILES.in | 17 +- src/plugins/gramplet/AgeOnDateGramplet.py | 94 + src/plugins/gramplet/CalendarGramplet.py | 68 + src/plugins/gramplet/DataEntryGramplet.py | 750 +++++++ src/plugins/gramplet/DeepConnections.py | 184 -- src/plugins/gramplet/DefaultGramplets.py | 2041 ------------------ src/plugins/gramplet/FaqGramplet.py | 49 + src/plugins/gramplet/HeadlineNewsGramplet.py | 198 ++ src/plugins/gramplet/Makefile.am | 17 +- src/plugins/gramplet/PedigreeGramplet.py | 279 +++ src/plugins/gramplet/PythonGramplet.py | 157 ++ src/plugins/gramplet/QuickViewGramplet.py | 131 ++ src/plugins/gramplet/RelativeGramplet.py | 150 ++ src/plugins/gramplet/SessionLogGramplet.py | 101 + src/plugins/gramplet/StatsGramplet.py | 198 ++ src/plugins/gramplet/SurnameCloudGramplet.py | 162 ++ src/plugins/gramplet/ToDoGramplet.py | 61 + src/plugins/gramplet/TopSurnamesGramplet.py | 116 + src/plugins/gramplet/WelcomeGramplet.py | 73 + 19 files changed, 2619 insertions(+), 2227 deletions(-) create mode 100644 src/plugins/gramplet/AgeOnDateGramplet.py create mode 100644 src/plugins/gramplet/CalendarGramplet.py create mode 100644 src/plugins/gramplet/DataEntryGramplet.py delete mode 100644 src/plugins/gramplet/DeepConnections.py delete mode 100644 src/plugins/gramplet/DefaultGramplets.py create mode 100644 src/plugins/gramplet/FaqGramplet.py create mode 100644 src/plugins/gramplet/HeadlineNewsGramplet.py create mode 100644 src/plugins/gramplet/PedigreeGramplet.py create mode 100644 src/plugins/gramplet/PythonGramplet.py create mode 100644 src/plugins/gramplet/QuickViewGramplet.py create mode 100644 src/plugins/gramplet/RelativeGramplet.py create mode 100644 src/plugins/gramplet/SessionLogGramplet.py create mode 100644 src/plugins/gramplet/StatsGramplet.py create mode 100644 src/plugins/gramplet/SurnameCloudGramplet.py create mode 100644 src/plugins/gramplet/ToDoGramplet.py create mode 100644 src/plugins/gramplet/TopSurnamesGramplet.py create mode 100644 src/plugins/gramplet/WelcomeGramplet.py diff --git a/po/POTFILES.in b/po/POTFILES.in index 15addbb1c..57b543816 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -262,12 +262,27 @@ src/plugins/export/ExportVCalendar.py src/plugins/export/ExportVCard.py # plugins/gramplet directory +src/plugins/gramplet/AgeOnDateGramplet.py src/plugins/gramplet/AgeStats.py src/plugins/gramplet/AttributesGramplet.py -src/plugins/gramplet/DefaultGramplets.py +src/plugins/gramplet/CalendarGramplet.py +src/plugins/gramplet/DataEntryGramplet.py src/plugins/gramplet/DescendGramplet.py +src/plugins/gramplet/FanChartGramplet.py +src/plugins/gramplet/FaqGramplet.py src/plugins/gramplet/GivenNameGramplet.py +src/plugins/gramplet/HeadlineNewsGramplet.py src/plugins/gramplet/NoteGramplet.py +src/plugins/gramplet/PedigreeGramplet.py +src/plugins/gramplet/PythonGramplet.py +src/plugins/gramplet/QuickViewGramplet.py +src/plugins/gramplet/RelativeGramplet.py +src/plugins/gramplet/SessionLogGramplet.py +src/plugins/gramplet/StatsGramplet.py +src/plugins/gramplet/SurnameCloudGramplet.py +src/plugins/gramplet/ToDoGramplet.py +src/plugins/gramplet/TopSurnamesGramplet.py +src/plugins/gramplet/WelcomeGramplet.py src/plugins/gramplet/WhatsNext.py # plugins/graph directory diff --git a/src/plugins/gramplet/AgeOnDateGramplet.py b/src/plugins/gramplet/AgeOnDateGramplet.py new file mode 100644 index 000000000..11cedc0a4 --- /dev/null +++ b/src/plugins/gramplet/AgeOnDateGramplet.py @@ -0,0 +1,94 @@ +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2007-2009 Douglas S. Blank +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# $Id$ + +#------------------------------------------------------------------------ +# +# Python modules +# +#------------------------------------------------------------------------ + +#------------------------------------------------------------------------ +# +# GRAMPS modules +# +#------------------------------------------------------------------------ +from DataViews import register, Gramplet +from TransUtils import sgettext as _ +import DateHandler +from QuickReports import run_quick_report_by_name + +#------------------------------------------------------------------------ +# +# Gramplet class +# +#------------------------------------------------------------------------ +class AgeOnDateGramplet(Gramplet): + def init(self): + import gtk + # GUI setup: + self.set_tooltip(_("Enter a date, click Run")) + vbox = gtk.VBox() + hbox = gtk.HBox() + # label, entry + description = gtk.TextView() + description.set_wrap_mode(gtk.WRAP_WORD) + description.set_editable(False) + buffer = description.get_buffer() + buffer.set_text(_("Enter a date in the entry below and click Run." + " This will compute the ages for everyone in your" + " Family Tree on that date. You can then sort by" + " the age column, and double-click the row to view" + " or edit.")) + label = gtk.Label() + label.set_text(_("Date") + ":") + self.entry = gtk.Entry() + button = gtk.Button(_("Run")) + button.connect("clicked", self.run) + ##self.filter = + hbox.pack_start(label, False) + hbox.pack_start(self.entry, True) + vbox.pack_start(description, True) + vbox.pack_start(hbox, False) + vbox.pack_start(button, False) + self.gui.get_container_widget().remove(self.gui.textview) + self.gui.get_container_widget().add_with_viewport(vbox) + vbox.show_all() + + def run(self, obj): + text = self.entry.get_text() + date = DateHandler.parser.parse(text) + run_quick_report_by_name(self.gui.dbstate, + self.gui.uistate, + 'ageondate', + date) + +#------------------------------------------------------------------------ +# +# Register Gramplet +# +#------------------------------------------------------------------------ +register(type="gramplet", + name="Age on Date Gramplet", + tname=_("Age on Date Gramplet"), + height=200, + content = AgeOnDateGramplet, + title=_("Age on Date"), + ) + diff --git a/src/plugins/gramplet/CalendarGramplet.py b/src/plugins/gramplet/CalendarGramplet.py new file mode 100644 index 000000000..f20ec2a6e --- /dev/null +++ b/src/plugins/gramplet/CalendarGramplet.py @@ -0,0 +1,68 @@ +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2007-2009 Douglas S. Blank +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# $Id$ + +#------------------------------------------------------------------------ +# +# GRAMPS modules +# +#------------------------------------------------------------------------ +from DataViews import register, Gramplet +from TransUtils import sgettext as _ +from QuickReports import run_quick_report_by_name +import gen.lib + +#------------------------------------------------------------------------ +# +# Gramplet class +# +#------------------------------------------------------------------------ +class CalendarGramplet(Gramplet): + def init(self): + import gtk + self.set_tooltip(_("Double-click a day for details")) + self.gui.calendar = gtk.Calendar() + self.gui.calendar.connect('day-selected-double-click', self.double_click) + self.gui.get_container_widget().remove(self.gui.textview) + self.gui.get_container_widget().add_with_viewport(self.gui.calendar) + self.gui.calendar.show() + + def double_click(self, obj): + # bring up events on this day + year, month, day = self.gui.calendar.get_date() + date = gen.lib.Date() + date.set_yr_mon_day(year, month + 1, day) + run_quick_report_by_name(self.gui.dbstate, + self.gui.uistate, + 'onthisday', + date) + +#------------------------------------------------------------------------ +# +# Register Gramplet +# +#------------------------------------------------------------------------ +register(type="gramplet", + name="Calendar Gramplet", + tname=_("Calendar Gramplet"), + height=200, + content = CalendarGramplet, + title=_("Calendar"), + ) + diff --git a/src/plugins/gramplet/DataEntryGramplet.py b/src/plugins/gramplet/DataEntryGramplet.py new file mode 100644 index 000000000..0919a05b7 --- /dev/null +++ b/src/plugins/gramplet/DataEntryGramplet.py @@ -0,0 +1,750 @@ +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2007-2009 Douglas S. Blank +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# $Id$ + +#------------------------------------------------------------------------ +# +# GRAMPS modules +# +#------------------------------------------------------------------------ +from DataViews import register, Gramplet +from BasicUtils import name_displayer +from ReportBase import ReportUtils +import DateHandler +import Errors +import gen.lib + +#------------------------------------------------------------------------ +# +# Gramplet class +# +#------------------------------------------------------------------------ +class DataEntryGramplet(Gramplet): + NO_REL = 0 + AS_PARENT = 1 + AS_SPOUSE = 2 + AS_SIBLING = 3 + AS_CHILD = 4 + def init(self): + self.de_column_width = 20 + import gtk + rows = gtk.VBox() + self.dirty = False + self.dirty_person = None + self.dirty_family = None + self.de_widgets = {} + for items in [("Active person", _("Active person"), None, True, + [("Edit person", "", self.edit_person), ("Edit family", _("Family:"), self.edit_family)], + False, 0), + ("APName", _("Surname, Given"), None, False, [], True, 0), + ("APGender", _("Gender"), [_("female"), _("male"), _("unknown")], False, [], True, 2), + ("APBirth", _("Birth"), None, False, [], True, 0), + ("APDeath", _("Death"), None, False, [], True, 0) + ]: + pos, text, choices, readonly, callback, dirty, default = items + row = self.make_row(pos, text, choices, readonly, callback, dirty, default) + rows.pack_start(row, False) + + # Save and Abandon + row = gtk.HBox() + button = gtk.Button(_("Save")) + button.connect("clicked", self.save_data_edit) + row.pack_start(button, True) + button = gtk.Button(_("Abandon")) + button.connect("clicked", self.abandon_data_edit) + row.pack_start(button, True) + rows.pack_start(row, False) + + for items in [("New person", _("New person"), None, True, 0), + ("NPRelation", _("Add relation"), + [_("No relation to active person"), + _("Add as a Parent"), + _("Add as a Spouse"), + _("Add as a Sibling"), + _("Add as a Child")], + False, 0), + ("NPName", _("Surname, Given"), None, False, 0), + ("NPGender", _("Gender"), [_("female"), _("male"), _("unknown")], False, 2), + ("NPBirth", _("Birth"), None, False, 0), + ("NPDeath", _("Death"), None, False, 0) + ]: + pos, text, choices, readonly, default = items + row = self.make_row(pos, text, choices, readonly, default=default) + rows.pack_start(row, False) + + # Save, Abandon, Clear + row = gtk.HBox() + button = gtk.Button(_("Add")) + button.connect("clicked", self.add_data_entry) + row.pack_start(button, True) + button = gtk.Button(_("Copy Active Data")) + button.connect("clicked", self.copy_data_entry) + row.pack_start(button, True) + button = gtk.Button(_("Clear")) + button.connect("clicked", self.clear_data_entry) + row.pack_start(button, True) + rows.pack_start(row, False) + + self.gui.get_container_widget().remove(self.gui.textview) + self.gui.get_container_widget().add_with_viewport(rows) + rows.show_all() + self.clear_data_entry(None) + + def main(self): # return false finishes + if self.dirty: + return + self.de_widgets["Active person:Edit family"].hide() + self.de_widgets["Active person:Edit family:Label"].hide() + active_person = self.dbstate.get_active_person() + self.dirty_person = active_person + self.dirty_family = None + if active_person: + self.de_widgets["Active person:Edit person"].show() + self.de_widgets["Active person:Edit family"].hide() + self.de_widgets["Active person:Edit family:Label"].hide() + # Fill in current person edits: + name = name_displayer.display(active_person) + self.de_widgets["Active person"].set_text("%s " % name) + self.de_widgets["Active person"].set_use_markup(True) + # Name: + name_obj = active_person.get_primary_name() + if name_obj: + self.de_widgets["APName"].set_text("%s, %s" % + (name_obj.get_surname(), name_obj.get_first_name())) + self.de_widgets["APGender"].set_active(active_person.get_gender()) # gender + # Birth: + birth = ReportUtils.get_birth_or_fallback(self.dbstate.db, active_person) + birth_text = "" + if birth: + sdate = DateHandler.get_date(birth) + birth_text += sdate + " " + place_handle = birth.get_place_handle() + if place_handle: + place = self.dbstate.db.get_place_from_handle(place_handle) + place_text = place.get_title() + if place_text: + birth_text += _("in") + " " + place_text + + self.de_widgets["APBirth"].set_text(birth_text) + # Death: + death = ReportUtils.get_death_or_fallback(self.dbstate.db, active_person) + death_text = "" + if death: + sdate = DateHandler.get_date(death) + death_text += sdate + " " + place_handle = death.get_place_handle() + if place_handle: + place = self.dbstate.db.get_place_from_handle(place_handle) + place_text = place.get_title() + if place_text: + death_text += _("in") + " " + place_text + self.de_widgets["APDeath"].set_text(death_text) + family_list = active_person.get_family_handle_list() + if len(family_list) > 0: + self.dirty_family = self.dbstate.db.get_family_from_handle(family_list[0]) + self.de_widgets["Active person:Edit family"].show() + self.de_widgets["Active person:Edit family:Label"].show() + else: + family_list = active_person.get_parent_family_handle_list() + if len(family_list) > 0: + self.dirty_family = self.dbstate.db.get_family_from_handle(family_list[0]) + self.de_widgets["Active person:Edit family"].show() + self.de_widgets["Active person:Edit family:Label"].show() + else: + self.clear_data_edit(None) + self.de_widgets["Active person:Edit person"].hide() + self.de_widgets["Active person:Edit family"].hide() + self.de_widgets["Active person:Edit family:Label"].hide() + self.dirty = False + + def make_row(self, pos, text, choices=None, readonly=False, callback_list=[], + mark_dirty=False, default=0): + import gtk + # Data Entry: Active Person + row = gtk.HBox() + label = gtk.Label() + if readonly: + label.set_text("%s" % text) + label.set_width_chars(self.de_column_width) + label.set_use_markup(True) + self.de_widgets[pos] = gtk.Label() + self.de_widgets[pos].set_alignment(0.0, 0.5) + self.de_widgets[pos].set_use_markup(True) + label.set_alignment(0.0, 0.5) + row.pack_start(label, False) + row.pack_start(self.de_widgets[pos], False) + else: + label.set_text("%s: " % text) + label.set_width_chars(self.de_column_width) + label.set_alignment(1.0, 0.5) + if choices == None: + self.de_widgets[pos] = gtk.Entry() + if mark_dirty: + self.de_widgets[pos].connect("changed", self.mark_dirty) + row.pack_start(label, False) + row.pack_start(self.de_widgets[pos], True) + else: + eventBox = gtk.EventBox() + self.de_widgets[pos] = gtk.combo_box_new_text() + eventBox.add(self.de_widgets[pos]) + for add_type in choices: + self.de_widgets[pos].append_text(add_type) + self.de_widgets[pos].set_active(default) + if mark_dirty: + self.de_widgets[pos].connect("changed", self.mark_dirty) + row.pack_start(label, False) + row.pack_start(eventBox, True, True) + for name, text, callback in callback_list: + label = gtk.Label() + label.set_text(text) + self.de_widgets[pos + ":" + name + ":Label"] = label + row.pack_start(label, False) + icon = gtk.STOCK_EDIT + size = gtk.ICON_SIZE_MENU + button = gtk.Button() + image = gtk.Image() + image.set_from_stock(icon, size) + button.add(image) + button.set_relief(gtk.RELIEF_NONE) + button.connect("clicked", callback) + self.de_widgets[pos + ":" + name] = button + row.pack_start(button, False) + row.show_all() + return row + + def mark_dirty(self, obj): + self.dirty = True + + def abandon_data_edit(self, obj): + self.dirty = False + self.update() + + def edit_callback(self, person): + self.dirty = False + self.update() + + def edit_person(self, obj): + from Editors import EditPerson + try: + EditPerson(self.gui.dbstate, + self.gui.uistate, [], + self.dirty_person, + callback=self.edit_callback) + except Errors.WindowActiveError: + pass + + def edit_family(self, obj): + from Editors import EditFamily + try: + EditFamily(self.gui.dbstate, + self.gui.uistate, [], + self.dirty_family) + except Errors.WindowActiveError: + pass + + def process_dateplace(self, text): + if text == "": return None, None + prep_in = _("in") # word or phrase that separates date from place + text = text.strip() + if (" %s " % prep_in) in text: + date, place = text.split((" %s " % prep_in), 1) + elif text.startswith("%s " % prep_in): + date, place = text.split(("%s " % prep_in), 1) + else: + date, place = text, "" + date = date.strip() + place = place.strip() + if date != "": + date = DateHandler.parser.parse(date) + else: + date = None + if place != "": + newq, place = self.get_or_create_place(place) + else: + place = None + return date, place + + def get_or_create_place(self, place_name): + if place_name == "": return (-1, None) + place_list = self.dbstate.db.get_place_handles() + for place_handle in place_list: + place = self.dbstate.db.get_place_from_handle(place_handle) + if place.get_title().strip() == place_name: + return (0, place) # (old, object) + place = gen.lib.Place() + place.set_title(place_name) + self.dbstate.db.add_place(place,self.trans) + return (1, place) # (new, object) + + def get_or_create_event(self, object, type, date, place): + """ Add or find a type event on object """ + if date == place == None: return (-1, None) + # first, see if it exists + ref_list = object.get_event_ref_list() + # look for a match, and possible correction + for ref in ref_list: + event = self.dbstate.db.get_event_from_handle(ref.ref) + if event is not None: + if int(event.get_type()) == type: + # Match! Let's update + if date: + event.set_date_object(date) + if place: + event.set_place_handle(place.get_handle()) + self.dbstate.db.commit_event(event, self.trans) + return (0, event) + # else create it: + event = gen.lib.Event() + if type: + event.set_type(gen.lib.EventType(type)) + if date: + event.set_date_object(date) + if place: + event.set_place_handle(place.get_handle()) + self.dbstate.db.add_event(event, self.trans) + return (1, event) + + def make_event(self, type, date, place): + if date == place == None: return None + event = gen.lib.Event() + event.set_type(gen.lib.EventType(type)) + if date: + event.set_date_object(date) + if place: + event.set_place_handle(place.get_handle()) + self.dbstate.db.add_event(event, self.trans) + return event + + def make_person(self, firstname, surname, gender): + person = gen.lib.Person() + name = gen.lib.Name() + name.set_type(gen.lib.NameType(gen.lib.NameType.BIRTH)) + name.set_first_name(firstname) + name.set_surname(surname) + person.set_primary_name(name) + person.set_gender(gender) + return person + + def save_data_edit(self, obj): + if self.dirty: + # Save the edits ---------------------------------- + person = self.dirty_person + # First, get the data: + gender = self.de_widgets["APGender"].get_active() + if "," in self.de_widgets["APName"].get_text(): + surname, firstname = self.de_widgets["APName"].get_text().split(",", 1) + else: + surname, firstname = self.de_widgets["APName"].get_text(), "" + surname = surname.strip() + firstname = firstname.strip() + name = person.get_primary_name() + # Now, edit it: + self.trans = self.dbstate.db.transaction_begin() + name.set_surname(surname) + name.set_first_name(firstname) + person.set_gender(gender) + birthdate, birthplace = self.process_dateplace(self.de_widgets["APBirth"].get_text().strip()) + new, birthevent = self.get_or_create_event(person, gen.lib.EventType.BIRTH, birthdate, birthplace) + # reference it, if need be: + birthref = person.get_birth_ref() + if birthevent: + if birthref is None: + # need new + birthref = gen.lib.EventRef() + birthref.set_reference_handle(birthevent.get_handle()) + person.set_birth_ref(birthref) + deathdate, deathplace = self.process_dateplace(self.de_widgets["APDeath"].get_text().strip()) + new, deathevent = self.get_or_create_event(person, gen.lib.EventType.DEATH, deathdate, deathplace) + # reference it, if need be: + deathref = person.get_death_ref() + if deathevent: + if deathref is None: + # need new + deathref = gen.lib.EventRef() + deathref.set_reference_handle(deathevent.get_handle()) + person.set_death_ref(deathref) + self.dbstate.db.commit_person(person,self.trans) + self.dbstate.db.transaction_commit(self.trans, + (_("Gramplet Data Edit: %s") % name_displayer.display(person))) + self.dirty = False + self.update() + + def add_data_entry(self, obj): + from QuestionDialog import ErrorDialog + # First, get the data: + if "," in self.de_widgets["NPName"].get_text(): + surname, firstname = self.de_widgets["NPName"].get_text().split(",", 1) + else: + surname, firstname = self.de_widgets["NPName"].get_text(), "" + surname = surname.strip() + firstname = firstname.strip() + gender = self.de_widgets["NPGender"].get_active() + if self.dirty: + current_person = self.dirty_person + else: + current_person = self.dbstate.get_active_person() + # Pre-check to make sure everything is ok: ------------------------------------------- + if surname == "" and firstname == "": + ErrorDialog(_("Please provide a name."), _("Can't add new person.")) + return + if self.de_widgets["NPRelation"].get_active() == self.NO_REL: + # "No relation to active person" + pass + elif self.de_widgets["NPRelation"].get_active() == self.AS_PARENT: + # "Add as a Parent" + if current_person == None: + ErrorDialog(_("Please set an active person."), _("Can't add new person as a parent.")) + return + elif gender == gen.lib.Person.UNKNOWN: # unknown + ErrorDialog(_("Please set the new person's gender."), _("Can't add new person as a parent.")) + return + elif self.de_widgets["NPRelation"].get_active() == self.AS_SPOUSE: + # "Add as a Spouse" + if current_person == None: + ErrorDialog(_("Please set an active person."), _("Can't add new person as a spouse.")) + return + elif (gender == gen.lib.Person.UNKNOWN and + current_person.get_gender() == gen.lib.Person.UNKNOWN): # both genders unknown + ErrorDialog(_("Please set the new person's gender."), _("Can't add new person as a spouse.")) + return + elif self.de_widgets["NPRelation"].get_active() == self.AS_SIBLING: + # "Add as a Sibling" + if current_person == None: + ErrorDialog(_("Please set an active person."), _("Can't add new person as a sibling.")) + return + elif self.de_widgets["NPRelation"].get_active() == self.AS_CHILD: + # "Add as a Child" + if current_person == None: + ErrorDialog(_("Please set an active person."), _("Can't add new person as a child.")) + return + # Start the transaction: ------------------------------------------------------------ + self.trans = self.dbstate.db.transaction_begin() + # New person -------------------------------------------------- + # Add birth + new_birth_date, new_birth_place = self.process_dateplace(self.de_widgets["NPBirth"].get_text().strip()) + birth_event = self.make_event(gen.lib.EventType.BIRTH, new_birth_date, new_birth_place) + # Add death + new_death_date, new_death_place = self.process_dateplace(self.de_widgets["NPDeath"].get_text()) + death_event = self.make_event(gen.lib.EventType.DEATH, new_death_date, new_death_place) + # Now, create the person and events: + person = self.make_person(firstname, surname, gender) + # New birth for person: + if birth_event: + birth_ref = gen.lib.EventRef() + birth_ref.set_reference_handle(birth_event.get_handle()) + person.set_birth_ref(birth_ref) + # New death for person: + if death_event: + death_ref = gen.lib.EventRef() + death_ref.set_reference_handle(death_event.get_handle()) + person.set_death_ref(death_ref) + self.dbstate.db.add_person(person, self.trans) + # All error checking done; just add relation: + if self.de_widgets["NPRelation"].get_active() == self.NO_REL: + # "No relation to active person" + pass + elif self.de_widgets["NPRelation"].get_active() == self.AS_PARENT: + # "Add as a Parent" + # Go through current_person parent families + added = False + for family_handle in current_person.get_parent_family_handle_list(): + family = self.dbstate.db.get_family_from_handle(family_handle) + if family: + # find one that person would fit as a parent + fam_husband_handle = family.get_father_handle() + fam_wife_handle = family.get_mother_handle() + # can we add person as wife? + if fam_wife_handle == None and person.get_gender() == gen.lib.Person.FEMALE: + # add the person + family.set_mother_handle(person.get_handle()) + family.set_relationship(gen.lib.FamilyRelType.MARRIED) + person.add_family_handle(family.get_handle()) + added = True + break + elif fam_husband_handle == None and person.get_gender() == gen.lib.Person.MALE: + # add the person + family.set_father_handle(person.get_handle()) + family.set_relationship(gen.lib.FamilyRelType.MARRIED) + person.add_family_handle(family.get_handle()) + added = True + break + if added: + self.dbstate.db.commit_family(family, self.trans) + else: + family = gen.lib.Family() + self.dbstate.db.add_family(family, self.trans) + if person.get_gender() == gen.lib.Person.MALE: + family.set_father_handle(person.get_handle()) + elif person.get_gender() == gen.lib.Person.FEMALE: + family.set_mother_handle(person.get_handle()) + family.set_relationship(gen.lib.FamilyRelType.MARRIED) + # add curent_person as child + childref = gen.lib.ChildRef() + childref.set_reference_handle(current_person.get_handle()) + family.add_child_ref( childref) + current_person.add_parent_family_handle(family.get_handle()) + # finalize + person.add_family_handle(family.get_handle()) + self.dbstate.db.commit_family(family, self.trans) + elif self.de_widgets["NPRelation"].get_active() == self.AS_SPOUSE: + # "Add as a Spouse" + added = False + family = None + for family_handle in current_person.get_family_handle_list(): + family = self.dbstate.db.get_family_from_handle(family_handle) + if family: + fam_husband_handle = family.get_father_handle() + fam_wife_handle = family.get_mother_handle() + if current_person.get_handle() == fam_husband_handle: + # can we add person as wife? + if fam_wife_handle == None: + if person.get_gender() == gen.lib.Person.FEMALE: + # add the person + family.set_mother_handle(person.get_handle()) + family.set_relationship(gen.lib.FamilyRelType.MARRIED) + person.add_family_handle(family.get_handle()) + added = True + break + elif person.get_gender() == gen.lib.Person.UNKNOWN: + family.set_mother_handle(person.get_handle()) + family.set_relationship(gen.lib.FamilyRelType.MARRIED) + person.set_gender(gen.lib.Person.FEMALE) + self.de_widgets["NPGender"].set_active(gen.lib.Person.FEMALE) + person.add_family_handle(family.get_handle()) + added = True + break + elif current_person.get_handle() == fam_wife_handle: + # can we add person as husband? + if fam_husband_handle == None: + if person.get_gender() == gen.lib.Person.MALE: + # add the person + family.set_father_handle(person.get_handle()) + family.set_relationship(gen.lib.FamilyRelType.MARRIED) + person.add_family_handle(family.get_handle()) + added = True + break + elif person.get_gender() == gen.lib.Person.UNKNOWN: + family.set_father_handle(person.get_handle()) + family.set_relationship(gen.lib.FamilyRelType.MARRIED) + person.add_family_handle(family.get_handle()) + person.set_gender(gen.lib.Person.MALE) + self.de_widgets["NPGender"].set_active(gen.lib.Person.MALE) + added = True + break + if added: + self.dbstate.db.commit_family(family, self.trans) + else: + if person.get_gender() == gen.lib.Person.UNKNOWN: + if current_person.get_gender() == gen.lib.Person.UNKNOWN: + ErrorDialog(_("Please set gender on Active or new person."), + _("Can't add new person as a spouse.")) + return + elif current_person.get_gender() == gen.lib.Person.MALE: + family = gen.lib.Family() + self.dbstate.db.add_family(family, self.trans) + family.set_father_handle(current_person.get_handle()) + family.set_mother_handle(person.get_handle()) + family.set_relationship(gen.lib.FamilyRelType.MARRIED) + person.set_gender(gen.lib.Person.FEMALE) + self.de_widgets["NPGender"].set_active(gen.lib.Person.FEMALE) + person.add_family_handle(family.get_handle()) + current_person.add_family_handle(family.get_handle()) + self.dbstate.db.commit_family(family, self.trans) + elif current_person.get_gender() == gen.lib.Person.FEMALE: + family = gen.lib.Family() + self.dbstate.db.add_family(family, self.trans) + family.set_father_handle(person.get_handle()) + family.set_mother_handle(current_person.get_handle()) + family.set_relationship(gen.lib.FamilyRelType.MARRIED) + person.set_gender(gen.lib.Person.MALE) + self.de_widgets["NPGender"].set_active(gen.lib.Person.MALE) + person.add_family_handle(family.get_handle()) + current_person.add_family_handle(family.get_handle()) + self.dbstate.db.commit_family(family, self.trans) + elif person.get_gender() == gen.lib.Person.MALE: + if current_person.get_gender() == gen.lib.Person.UNKNOWN: + family = gen.lib.Family() + self.dbstate.db.add_family(family, self.trans) + family.set_father_handle(person.get_handle()) + family.set_mother_handle(current_person.get_handle()) + family.set_relationship(gen.lib.FamilyRelType.MARRIED) + current_person.set_gender(gen.lib.Person.FEMALE) + person.add_family_handle(family.get_handle()) + current_person.add_family_handle(family.get_handle()) + self.dbstate.db.commit_family(family, self.trans) + elif current_person.get_gender() == gen.lib.Person.MALE: + ErrorDialog(_("Same genders on Active and new person."), + _("Can't add new person as a spouse.")) + return + elif current_person.get_gender() == gen.lib.Person.FEMALE: + family = gen.lib.Family() + self.dbstate.db.add_family(family, self.trans) + family.set_father_handle(person.get_handle()) + family.set_mother_handle(current_person.get_handle()) + family.set_relationship(gen.lib.FamilyRelType.MARRIED) + person.add_family_handle(family.get_handle()) + current_person.add_family_handle(family.get_handle()) + self.dbstate.db.commit_family(family, self.trans) + elif person.get_gender() == gen.lib.Person.FEMALE: + if current_person.get_gender() == gen.lib.Person.UNKNOWN: + family = gen.lib.Family() + self.dbstate.db.add_family(family, self.trans) + family.set_father_handle(current_person.get_handle()) + family.set_mother_handle(person.get_handle()) + family.set_relationship(gen.lib.FamilyRelType.MARRIED) + current_person.set_gender(gen.lib.Person.MALE) + person.add_family_handle(family.get_handle()) + current_person.add_family_handle(family.get_handle()) + self.dbstate.db.commit_family(family, self.trans) + elif current_person.get_gender() == gen.lib.Person.MALE: + family = gen.lib.Family() + self.dbstate.db.add_family(family, self.trans) + family.set_father_handle(current_person.get_handle()) + family.set_mother_handle(person.get_handle()) + family.set_relationship(gen.lib.FamilyRelType.MARRIED) + person.add_family_handle(family.get_handle()) + current_person.add_family_handle(family.get_handle()) + self.dbstate.db.commit_family(family, self.trans) + elif current_person.get_gender() == gen.lib.Person.FEMALE: + ErrorDialog(_("Same genders on Active and new person."), + _("Can't add new person as a spouse.")) + return + elif self.de_widgets["NPRelation"].get_active() == self.AS_SIBLING: + # "Add as a Sibling" + added = False + for family_handle in current_person.get_parent_family_handle_list(): + family = self.dbstate.db.get_family_from_handle(family_handle) + if family: + childref = gen.lib.ChildRef() + childref.set_reference_handle(person.get_handle()) + family.add_child_ref( childref) + person.add_parent_family_handle(family.get_handle()) + added = True + break + if added: + self.dbstate.db.commit_family(family, self.trans) + else: + family = gen.lib.Family() + self.dbstate.db.add_family(family, self.trans) + childref = gen.lib.ChildRef() + childref.set_reference_handle(person.get_handle()) + family.add_child_ref( childref) + childref = gen.lib.ChildRef() + childref.set_reference_handle(current_person.get_handle()) + family.add_child_ref( childref) + person.add_parent_family_handle(family.get_handle()) + current_person.add_parent_family_handle(family.get_handle()) + self.dbstate.db.commit_family(family, self.trans) + elif self.de_widgets["NPRelation"].get_active() == self.AS_CHILD: + # "Add as a Child" + added = False + family = None + for family_handle in current_person.get_family_handle_list(): + family = self.dbstate.db.get_family_from_handle(family_handle) + if family: + childref = gen.lib.ChildRef() + childref.set_reference_handle(person.get_handle()) + family.add_child_ref( childref) + person.add_parent_family_handle(family.get_handle()) + added = True + break + if added: + self.dbstate.db.commit_family(family, self.trans) + else: + if current_person.get_gender() == gen.lib.Person.UNKNOWN: + ErrorDialog(_("Please set gender on Active person."), + _("Can't add new person as a child.")) + return + else: + family = gen.lib.Family() + self.dbstate.db.add_family(family, self.trans) + childref = gen.lib.ChildRef() + childref.set_reference_handle(person.get_handle()) + family.add_child_ref( childref) + person.add_parent_family_handle(family.get_handle()) + current_person.add_family_handle(family.get_handle()) + if gen.lib.Person.FEMALE: + family.set_mother_handle(current_person.get_handle()) + else: + family.set_father_handle(current_person.get_handle()) + self.dbstate.db.commit_family(family, self.trans) + # Commit changes ------------------------------------------------- + if current_person: + self.dbstate.db.commit_person(current_person, self.trans) + if person: + self.dbstate.db.commit_person(person, self.trans) + self.dbstate.db.transaction_commit(self.trans, + (_("Gramplet Data Entry: %s") % name_displayer.display(person))) + + def copy_data_entry(self, obj): + self.de_widgets["NPName"].set_text(self.de_widgets["APName"].get_text()) + self.de_widgets["NPBirth"].set_text(self.de_widgets["APBirth"].get_text()) + self.de_widgets["NPDeath"].set_text(self.de_widgets["APDeath"].get_text()) + self.de_widgets["NPGender"].set_active(self.de_widgets["APGender"].get_active()) + # FIXME: put cursor in add surname + + def clear_data_edit(self, obj): + self.de_widgets["Active person"].set_text("") + self.de_widgets["APName"].set_text("") + self.de_widgets["APBirth"].set_text("") + self.de_widgets["APDeath"].set_text("") + self.de_widgets["APGender"].set_active(gen.lib.Person.UNKNOWN) + + def clear_data_entry(self, obj): + self.de_widgets["NPName"].set_text("") + self.de_widgets["NPBirth"].set_text("") + self.de_widgets["NPDeath"].set_text("") + self.de_widgets["NPRelation"].set_active(self.NO_REL) + self.de_widgets["NPGender"].set_active(gen.lib.Person.UNKNOWN) + + def db_changed(self): + """ + If person or family changes, the relatives of active person might have + changed + """ + self.dbstate.db.connect('person-add', self.update) + self.dbstate.db.connect('person-delete', self.update) + self.dbstate.db.connect('person-edit', self.update) + self.dbstate.db.connect('family-add', self.update) + self.dbstate.db.connect('family-delete', self.update) + self.dbstate.db.connect('person-rebuild', self.update) + self.dbstate.db.connect('family-rebuild', self.update) + self.dirty = False + self.dirty_person = None + self.clear_data_entry(None) + + def active_changed(self, handle): + self.update() + +#------------------------------------------------------------------------ +# +# Register Gramplet +# +#------------------------------------------------------------------------ +register(type="gramplet", + name="Data Entry Gramplet", + tname=_("Data Entry Gramplet"), + height=375, + expand=False, + content = DataEntryGramplet, + title=_("Data Entry"), + detached_width = 510, + detached_height = 480, + ) + diff --git a/src/plugins/gramplet/DeepConnections.py b/src/plugins/gramplet/DeepConnections.py deleted file mode 100644 index 65c438bf6..000000000 --- a/src/plugins/gramplet/DeepConnections.py +++ /dev/null @@ -1,184 +0,0 @@ -# encoding: utf-8 -# -# Gramps - a GTK+/GNOME based genealogy program - What Next Gramplet plugin -# -# Copyright (C) 2009 Doug Blank -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# - -# $Id$ - -#------------------------------------------------------------------------ -# -# Python modules -# -#------------------------------------------------------------------------ -import gtk - -#------------------------------------------------------------------------ -# -# GRAMPS modules -# -#------------------------------------------------------------------------ -from gen.lib import EventType, FamilyRelType -from BasicUtils import name_displayer -from DataViews import register, Gramplet -from TransUtils import sgettext as _ - -#------------------------------------------------------------------------ -# -# The Gramplet -# -#------------------------------------------------------------------------ -class DeepConnectionsGramplet(Gramplet): - """ - Finds deep connections people the home person and the active person. - """ - def init(self): - self.set_tooltip(_("Double-click name for details")) - self.set_text(_("No Family Tree loaded.")) - self.set_use_markup(True) - self.gui.get_container_widget().remove(self.gui.textview) - vbox = gtk.VBox() - hbox = gtk.HBox() - pause_button = gtk.Button(_("Pause")) - pause_button.connect("clicked", self.interrupt) - continue_button = gtk.Button(_("Continue")) - continue_button.connect("clicked", self.resume) - hbox.pack_start(pause_button, True) - hbox.pack_start(continue_button, True) - vbox.pack_start(self.gui.textview, True) - vbox.pack_start(hbox, False) - self.gui.get_container_widget().add_with_viewport(vbox) - vbox.show_all() - - def get_relatives(self, person_handle, path): - """ - Gets all of the direct relatives of person_handle. - """ - retval = [] - person = self.dbstate.db.get_person_from_handle(person_handle) - if person is None: return [] - family_list = person.get_family_handle_list() - for family_handle in family_list: - family = self.dbstate.db.get_family_from_handle(family_handle) - children = family.get_child_ref_list() - for child_ref in children: - retval += [(child_ref.ref, (path, (_("child"), person_handle)))] - husband = family.get_father_handle() - if husband: - retval += [(husband, (path, (_("husband"), person_handle)))] - wife = family.get_mother_handle() - if wife: - retval += [(wife, (path, (_("wife"), person_handle)))] - parent_family_list = person.get_parent_family_handle_list() - for family_handle in parent_family_list: - family = self.dbstate.db.get_family_from_handle(family_handle) - children = family.get_child_ref_list() - for child_ref in children: - retval += [(child_ref.ref, (path, (_("sibling"), person_handle)))] - husband = family.get_father_handle() - if husband: - retval += [(husband, (path, (_("father"), person_handle)))] - wife = family.get_mother_handle() - if wife: - retval += [(wife, (path, (_("mother"), person_handle)))] - return retval - - def active_changed(self, handle): - """ - Update the gramplet on active person change. - """ - self.update() - - def pretty_print(self, path): - """ - Print a path to a person, with links. - """ - more_path, relation = path - text, handle = relation - person = self.dbstate.db.get_person_from_handle(handle) - name = person.get_primary_name() - if text != "self": - self.append_text(_("\n who is a %s of ") % text) - self.link(name_displayer.display_name(name), "Person", handle) - if more_path is not None: - self.pretty_print(more_path) - - def main(self): - """ - Main method. - """ - self.total_relations_found = 0 - yield True - default_person = self.dbstate.db.get_default_person() - active_person = self.dbstate.get_active_person() - if default_person == None: - self.set_text(_("No Home Person set.")) - return - if active_person == None: - self.set_text(_("No Active Person set.")) - return - self.cache = {} - self.queue = [(default_person.handle, (None, (_("self"), default_person.handle)))] - default_name = default_person.get_primary_name() - active_name = active_person.get_primary_name() - self.set_text("") - self.render_text(_("Looking for relationship between\n" + - " %s (Home Person) and\n" + - " %s (Active Person)...\n") % - (name_displayer.display_name(default_name), - name_displayer.display_name(active_name))) - yield True - while self.queue: - current_handle, current_path = self.queue.pop(0) - if current_handle == active_person.handle: - self.total_relations_found += 1 - self.append_text(_("Found relation #%d: \n ") % self.total_relations_found) - - self.link(name_displayer.display_name(active_name), "Person", active_person.handle) - self.pretty_print(current_path) - self.append_text("\n") - if default_person.handle != active_person.handle: - self.append_text(_("Paused.\nPress Continue to search for additional relations.\n")) - self.pause() - yield False - else: - break - elif current_handle in self.cache: - continue - self.cache[current_handle] = 1 - relatives = self.get_relatives(current_handle, current_path) - for (person_handle, path) in relatives: - if person_handle is not None and person_handle not in self.cache: - self.queue.append( (person_handle, path)) - yield True - self.append_text(_("\nSearch completed. %d relations found.") % self.total_relations_found) - yield False - -#------------------------------------------------------------------------ -# -# Register the gramplet -# -#------------------------------------------------------------------------ -register( - type = "gramplet", - name = "Deep Connections Gramplet", - tname =_("Deep Connections Gramplet"), - height = 230, - expand = True, - content = DeepConnectionsGramplet, - title = _("Deep Connections")) diff --git a/src/plugins/gramplet/DefaultGramplets.py b/src/plugins/gramplet/DefaultGramplets.py deleted file mode 100644 index e0ae4b50b..000000000 --- a/src/plugins/gramplet/DefaultGramplets.py +++ /dev/null @@ -1,2041 +0,0 @@ -# Gramps - a GTK+/GNOME based genealogy program -# -# Copyright (C) 2007-2009 Douglas S. Blank -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -# $Id$ - -#------------------------------------------------------------------------ -# -# Python modules -# -#------------------------------------------------------------------------ -import sys -import re -import urllib -import posixpath -import cgi -import gobject - -#------------------------------------------------------------------------ -# -# GRAMPS modules -# -#------------------------------------------------------------------------ -from BasicUtils import name_displayer -from DataViews import register, Gramplet -from PluginUtils import * -from QuickReports import run_quick_report_by_name, get_quick_report_list -from ReportBase import ReportUtils -from gen.utils import set_birth_death_index -from TransUtils import sgettext as _ -from Utils import media_path_full -import Config -import DateHandler -import gen.lib -import Errors -from ReportBase import (CATEGORY_QR_PERSON, CATEGORY_QR_FAMILY, - CATEGORY_QR_EVENT, CATEGORY_QR_SOURCE, - CATEGORY_QR_MISC, CATEGORY_QR_PLACE, - CATEGORY_QR_REPOSITORY) -from const import URL_WIKISTRING, URL_MANUAL_PAGE - -#------------------------------------------------------------------------ -# -# Gramplets -# -#------------------------------------------------------------------------ -class CalendarGramplet(Gramplet): - def init(self): - import gtk - self.set_tooltip(_("Double-click a day for details")) - self.gui.calendar = gtk.Calendar() - self.gui.calendar.connect('day-selected-double-click', self.double_click) - self.gui.get_container_widget().remove(self.gui.textview) - self.gui.get_container_widget().add_with_viewport(self.gui.calendar) - self.gui.calendar.show() - self.birthdays = True - self.dates = {} - - def double_click(self, obj): - # bring up events on this day - year, month, day = self.gui.calendar.get_date() - month += 1 - date = gen.lib.Date() - date.set_yr_mon_day(year, month, day) - run_quick_report_by_name(self.gui.dbstate, - self.gui.uistate, - 'onthisday', - date) - -class LogGramplet(Gramplet): - def init(self): - self.set_tooltip(_("Click name to change active\nDouble-click name to edit")) - self.set_text(_("Log for this Session")) - self.gui.force_update = True # will always update, even if minimized - self.last_log = None - self.append_text("\n") - - def db_changed(self): - self.append_text("Opened data base -----------\n") - self.dbstate.db.connect('person-add', - lambda handles: self.log(_('Person'), _('Added'), handles)) - self.dbstate.db.connect('person-delete', - lambda handles: self.log(_('Person'), _('Deleted'), handles)) - self.dbstate.db.connect('person-update', - lambda handles: self.log(_('Person'), _('Edited'), handles)) - self.dbstate.db.connect('family-add', - lambda handles: self.log(_('Family'), _('Added'), handles)) - self.dbstate.db.connect('family-delete', - lambda handles: self.log(_('Family'), _('Deleted'), handles)) - self.dbstate.db.connect('family-update', - lambda handles: self.log(_('Family'), _('Added'), handles)) - - def active_changed(self, handle): - self.log(_('Person'), _('Selected'), [handle]) - - def log(self, ltype, action, handles): - for handle in set(handles): - if self.last_log == (ltype, action, handle): - continue - self.last_log = (ltype, action, handle) - self.append_text("%s: " % action) - if ltype == _("Person"): - person = self.dbstate.db.get_person_from_handle(handle) - name = name_displayer.display(person) - elif ltype == _("Family"): - family = self.dbstate.db.get_family_from_handle(handle) - father_name = _("unknown") - mother_name = _("unknown") - if family: - father_handle = family.get_father_handle() - if father_handle: - father = self.dbstate.db.get_person_from_handle(father_handle) - if father: - father_name = name_displayer.display(father) - mother_handle = family.get_mother_handle() - if mother_handle: - mother = self.dbstate.db.get_person_from_handle(mother_handle) - mother_name = name_displayer.display(mother) - name = _("%s and %s") % (mother_name, father_name) - self.link(name, ltype, handle) - self.append_text("\n") - -class TopSurnamesGramplet(Gramplet): - def init(self): - self.set_tooltip(_("Double-click surname for details")) - self.top_size = 10 # will be overwritten in load - self.set_text(_("No Family Tree loaded.")) - - def db_changed(self): - self.dbstate.db.connect('person-add', self.update) - self.dbstate.db.connect('person-delete', self.update) - self.dbstate.db.connect('person-update', self.update) - self.dbstate.db.connect('person-rebuild', self.update) - self.dbstate.db.connect('family-rebuild', self.update) - - def on_load(self): - if len(self.gui.data) > 0: - self.top_size = int(self.gui.data[0]) - - def on_save(self): - self.gui.data = [self.top_size] - - def main(self): - self.set_text(_("Processing...") + "\n") - people = self.dbstate.db.get_person_handles(sort_handles=False) - surnames = {} - representative_handle = {} - cnt = 0 - for person_handle in people: - person = self.dbstate.db.get_person_from_handle(person_handle) - if person: - allnames = [person.get_primary_name()] + person.get_alternate_names() - allnames = set([name.get_group_name().strip() for name in allnames]) - for surname in allnames: - surnames[surname] = surnames.get(surname, 0) + 1 - representative_handle[surname] = person_handle - if cnt % 350 == 0: - yield True - cnt += 1 - total_people = cnt - surname_sort = [] - total = 0 - cnt = 0 - for surname in surnames: - surname_sort.append( (surnames[surname], surname) ) - total += surnames[surname] - if cnt % 350 == 0: - yield True - cnt += 1 - total_surnames = cnt - surname_sort.sort(lambda a,b: -cmp(a,b)) - line = 0 - ### All done! - self.set_text("") - for (count, surname) in surname_sort: - if len(surname) == 0: - text = "%s, %d%% (%d)\n" % (Config.get(Config.NO_SURNAME_TEXT), - int((float(count)/total) * 100), - count) - else: - text = "%s, %d%% (%d)\n" % (surname, int((float(count)/total) * 100), - count) - self.append_text(" %d. " % (line + 1)) - self.link(text, 'Surname', representative_handle[surname]) - line += 1 - if line >= self.top_size: - break - self.append_text(("\n" + _("Total unique surnames") + ": %d\n") % - total_surnames) - self.append_text((_("Total people") + ": %d") % total_people, "begin") - -def make_tag_size(n, counts, mins=8, maxs=20): - # return font sizes mins to maxs - diff = maxs - mins - # based on counts (biggest to smallest) - if len(counts) > 1: - position = diff - (diff * (float(counts.index(n)) / (len(counts) - 1))) - else: - position = 0 - return int(position) + mins - -class SurnameCloudGramplet(Gramplet): - def init(self): - self.set_tooltip(_("Double-click surname for details")) - self.top_size = 100 # will be overwritten in load - self.set_text(_("No Family Tree loaded.")) - - def db_changed(self): - self.dbstate.db.connect('person-add', self.update) - self.dbstate.db.connect('person-delete', self.update) - self.dbstate.db.connect('person-update', self.update) - self.dbstate.db.connect('person-rebuild', self.update) - self.dbstate.db.connect('family-rebuild', self.update) - - def on_load(self): - if len(self.gui.data) > 0: - self.top_size = int(self.gui.data[0]) - - def on_save(self): - self.gui.data = [self.top_size] - - def main(self): - self.set_text(_("Processing...") + "\n") - yield True - people = self.dbstate.db.get_person_handles(sort_handles=False) - surnames = {} - representative_handle = {} - cnt = 0 - for person_handle in people: - person = self.dbstate.db.get_person_from_handle(person_handle) - if person: - allnames = [person.get_primary_name()] + person.get_alternate_names() - allnames = set([name.get_group_name().strip() for name in allnames]) - for surname in allnames: - surnames[surname] = surnames.get(surname, 0) + 1 - representative_handle[surname] = person_handle - if cnt % 350 == 0: - yield True - cnt += 1 - total_people = cnt - surname_sort = [] - total = 0 - cnt = 0 - for surname in surnames: - surname_sort.append( (surnames[surname], surname) ) - total += surnames[surname] - if cnt % 350 == 0: - yield True - cnt += 1 - total_surnames = cnt - surname_sort.sort(lambda a,b: -cmp(a,b)) - cloud_names = [] - cloud_values = [] - cnt = 0 - for (count, surname) in surname_sort: - cloud_names.append( (count, surname) ) - cloud_values.append( count ) - cnt += 1 - cloud_names.sort(lambda a,b: cmp(a[1], b[1])) - counts = list(set(cloud_values)) - counts.sort() - counts.reverse() - line = 0 - ### All done! - # Now, find out how many we can display without going over top_size: - totals = {} - for (count, givensubname) in cloud_names: # givensubname_sort: - totals[count] = totals.get(count, 0) + 1 - sums = totals.keys() - sums.sort() - sums.reverse() - total = 0 - include_greater_than = 0 - for s in sums: - if total + totals[s] <= self.top_size: - total += totals[s] - else: - include_greater_than = s - break - # Ok, now we can show those counts > include_greater_than: - showing = 0 - self.set_text("") - for (count, surname) in cloud_names: # surname_sort: - if count > include_greater_than: - if len(surname) == 0: - text = Config.get(Config.NO_SURNAME_TEXT) - else: - text = surname - size = make_tag_size(count, counts) - self.link(text, 'Surname', representative_handle[surname], size, - "%s, %d%% (%d)" % (text, - int((float(count)/total_people) * 100), - count)) - self.append_text(" ") - showing += 1 - self.append_text(("\n\n" + _("Total unique surnames") + ": %d\n") % - total_surnames) - self.append_text((_("Total surnames showing") + ": %d\n") % showing) - self.append_text((_("Total people") + ": %d") % total_people, "begin") - -class RelativesGramplet(Gramplet): - """ - This gramplet gives a list of clickable relatives of the active person. - Clicking them, changes the active person. - """ - def init(self): - self.set_text(_("No Family Tree loaded.")) - self.set_tooltip(_("Click name to make person active\n") + - _("Right-click name to edit person")) - - def db_changed(self): - """ - If person or family changes, the relatives of active person might have - changed - """ - self.dbstate.db.connect('person-add', self.update) - self.dbstate.db.connect('person-delete', self.update) - self.dbstate.db.connect('family-add', self.update) - self.dbstate.db.connect('family-delete', self.update) - self.dbstate.db.connect('person-rebuild', self.update) - self.dbstate.db.connect('family-rebuild', self.update) - - def active_changed(self, handle): - self.update() - - def main(self): # return false finishes - """ - Generator which will be run in the background. - """ - self.set_text("") - database = self.dbstate.db - active_person = self.dbstate.get_active_person() - if not active_person: - return - name = name_displayer.display(active_person) - self.append_text(_("Active person: %s") % name) - self.append_text("\n\n") - #obtain families - famc = 0 - for family_handle in active_person.get_family_handle_list(): - famc += 1 - family = database.get_family_from_handle(family_handle) - if not family: continue - if active_person.handle == family.get_father_handle(): - spouse_handle = family.get_mother_handle() - else: - spouse_handle = family.get_father_handle() - if spouse_handle: - spouse = database.get_person_from_handle(spouse_handle) - spousename = name_displayer.display(spouse) - text = "%s" % spousename - self.append_text(_("%d. Partner: ") % (famc)) - self.link(text, 'Person', spouse_handle) - self.append_text("\n") - else: - self.append_text(_("%d. Partner: Not known") % (famc)) - self.append_text("\n") - #obtain children - childc = 0 - for child_ref in family.get_child_ref_list(): - childc += 1 - child = database.get_person_from_handle(child_ref.ref) - childname = name_displayer.display(child) - text = "%s" % childname - self.append_text(" %d.%-3d: " % (famc, childc)) - self.link(text, 'Person', child_ref.ref) - self.append_text("\n") - yield True - #obtain parent families - self.append_text("\n") - self.append_text(_("Parents:")) - self.append_text("\n") - famc = 0 - for family_handle in active_person.get_parent_family_handle_list(): - famc += 1 - family = database.get_family_from_handle(family_handle) - mother_handle = family.get_mother_handle() - father_handle = family.get_father_handle() - if mother_handle: - mother = database.get_person_from_handle(mother_handle) - mothername = name_displayer.display(mother) - text = "%s" % mothername - self.append_text(_(" %d.a Mother: ") % (famc)) - self.link(text, 'Person', mother_handle) - self.append_text("\n") - else: - self.append_text(_(" %d.a Mother: ") % (famc)) - self.append_text(_("Unknown")) - self.append_text("\n") - if father_handle: - father = database.get_person_from_handle(father_handle) - fathername = name_displayer.display(father) - text = "%s" % fathername - self.append_text(_(" %d.b Father: ") % (famc)) - self.link(text, 'Person', father_handle) - self.append_text("\n") - else: - self.append_text(_(" %d.b Father: ") % (famc)) - self.append_text(_("Unknown")) - self.append_text("\n") - -class PedigreeGramplet(Gramplet): - def init(self): - self.set_text(_("No Family Tree loaded.")) - self.set_tooltip(_("Move mouse over links for options")) - self.set_use_markup(True) - self.max_generations = 100 - self.show_dates = 1 - self.box_mode = "UTF" - - def build_options(self): - from gen.plug.menu import NumberOption - self.add_option(NumberOption(_("Max generations"), - self.max_generations, 1, 100)) - - def save_options(self): - self.max_generations = int(self.get_option(_("Max generations")).get_value()) - - def on_load(self): - if len(self.gui.data) > 0: - self.max_generations = int(self.gui.data[0]) - if len(self.gui.data) > 1: - self.show_dates = int(self.gui.data[1]) - if len(self.gui.data) > 2: - self.box_mode = self.gui.data[2] # ASCII or UTF - - def on_save(self): - self.gui.data = [self.max_generations, self.show_dates, self.box_mode] - - def db_changed(self): - """ - If a person or family changes, the ancestors of active person might have - changed. - """ - self.dbstate.db.connect('person-add', self.update) - self.dbstate.db.connect('person-delete', self.update) - self.dbstate.db.connect('family-add', self.update) - self.dbstate.db.connect('family-delete', self.update) - self.dbstate.db.connect('person-rebuild', self.update) - self.dbstate.db.connect('family-rebuild', self.update) - - def active_changed(self, handle): - self.update() - - def get_boxes(self, generation, what): - retval = u"" - if self.box_mode == "UTF": - space = u" " - elif self.box_mode == "ASCII": - space = u" " - space_len = len(space) + 2 - for i in range(generation+1): - if self._boxes[i]: - retval += space + u"|" - else: - retval += space + u" " - if retval[-1] == u' ': - if what == 'sf': - retval = retval[:-space_len] + u"/" - elif what == 'sm': - retval = retval[:-space_len] + u"\\" - elif retval.endswith(u"|" + space + u"|"): - retval = retval[:-space_len] + u"+" - if self.box_mode == "UTF": - retval += u"-" - retval = retval.replace(u"\\", u"\u2514") - retval = retval.replace(u"-", u"\u2500") - retval = retval.replace(u"|", u"\u2502") - retval = retval.replace(u"/", u"\u250c") - elif self.box_mode == "ASCII": - retval += u"--" - return retval - - def set_box(self, pos, value): - self._boxes[pos] = value - - def process_person(self, handle, generation, what): - if generation > self.max_generations: - return - person = self.dbstate.db.get_person_from_handle(handle) - family_list = person.get_parent_family_handle_list() - if what == "f": - if len(family_list) > 0: - family = self.dbstate.db.get_family_from_handle(family_list[0]) - father = family.get_father_handle() - mother = family.get_mother_handle() - if father: - self.process_person(father, generation + 1, "f") - self.set_box(generation, 1) - self.process_person(father, generation + 1, "sf") - self.process_person(father, generation + 1, "m") - elif mother: - self.set_box(generation, 1) - elif what[0] == "s": - boxes = self.get_boxes(generation, what) - if what[-1] == 'f': - if self.box_mode == "UTF": - boxes = boxes.replace("+", u"\u250c") - else: - boxes = boxes.replace("+", u"/") - else: - if self.box_mode == "UTF": - boxes = boxes.replace("+", u"\u2514") - else: - boxes = boxes.replace("+", u"\\") - self.append_text(boxes) - self.link(name_displayer.display_name(person.get_primary_name()), - 'Person', person.handle, - tooltip=_("Click to make active\n") + \ - _("Right-click to edit")) - if self.show_dates: - self.append_text(" ") - self.render_text(self.info_string(person)) - self.append_text("\n") - if generation not in self._generations: - self._generations[generation] = [] - self._generations[generation].append(handle) - elif what == "a": - if self.box_mode == "UTF": - self.append_text(u"o" + (u"\u2500" * 3)) - elif self.box_mode == "ASCII": - self.append_text(u"o---") - self.append_text("%s " % name_displayer.display_name(person.get_primary_name())) - if self.show_dates: - self.render_text(self.info_string(person)) - self.append_text("\n") - if generation not in self._generations: - self._generations[generation] = [] - self._generations[generation].append(handle) - elif what == "m": - if len(family_list) > 0: - family = self.dbstate.db.get_family_from_handle(family_list[0]) - mother = family.get_mother_handle() - if mother: - self.process_person(mother, generation + 1, "f") - self.process_person(mother, generation + 1, "sm") - self.set_box(generation, 0) - self.process_person(mother, generation + 1, "m") - self.set_box(generation, 0) # regardless, turn off line if on - - def info_string(self, person): - birth = ReportUtils.get_birth_or_fallback(self.dbstate.db, person) - if birth and birth.get_type != gen.lib.EventType.BIRTH: - sdate = DateHandler.get_date(birth) - if sdate: - bdate = "%s" % cgi.escape(sdate) - else: - bdate = "" - elif birth: - bdate = cgi.escape(DateHandler.get_date(birth)) - else: - bdate = "" - - death = ReportUtils.get_death_or_fallback(self.dbstate.db, person) - if death and death.get_type != gen.lib.EventType.DEATH: - sdate = DateHandler.get_date(death) - if sdate: - ddate = "%s" % cgi.escape(sdate) - else: - ddate = "" - elif death: - ddate = cgi.escape(DateHandler.get_date(death)) - else: - ddate = "" - - if bdate and ddate: - value = _("(b. %(birthdate)s, d. %(deathdate)s)") % { - 'birthdate' : bdate, - 'deathdate' : ddate - } - elif bdate: - value = _("(b. %s)") % (bdate) - elif ddate: - value = _("(d. %s)") % (ddate) - else: - value = "" - return value - - def main(self): # return false finishes - """ - Generator which will be run in the background. - """ - self._boxes = [0] * (self.max_generations + 1) - self._generations = {} - self.gui.buffer.set_text("") - active_person = self.dbstate.get_active_person() - if not active_person: - return False - #no wrap in Gramplet - self.no_wrap() - self.process_person(active_person.handle, 1, "f") # father - self.process_person(active_person.handle, 0, "a") # active #FIXME: should be 1? - self.process_person(active_person.handle, 1, "m") # mother - gens = self._generations.keys() - gens.sort() - self.append_text(_("\nBreakdown by generation:\n")) - all = [active_person.handle] - for g in gens: - count = len(self._generations[g]) - handles = self._generations[g] - self.append_text(" ") - if g == 0: - self.link(_("Generation 1"), 'PersonList', handles, - tooltip=_("Double-click to see people in generation")) - self.append_text(_(" has 1 of 1 individual (100.00% complete)\n")) - else: - all.extend(handles) - self.link(_("Generation %d") % g, 'PersonList', handles, - tooltip=_("Double-click to see people in generation")) - self.append_text(_(" has %d of %d individuals (%.2f%% complete)\n") % - (count, 2**(g-1), float(count)/2**(g-1) * 100)) - self.link(_("All generations"), 'PersonList', all, - tooltip=_("Double-click to see all generations")) - self.append_text(_(" have %d individuals\n") % len(all)) - # Set to a fixed font - if self.box_mode == "UTF": - start, end = self.gui.buffer.get_bounds() - self.gui.buffer.apply_tag_by_name("fixed", start, end) - self.append_text("", scroll_to="begin") - -class StatsGramplet(Gramplet): - def init(self): - self.set_text(_("No Family Tree loaded.")) - self.set_tooltip(_("Double-click item to see matches")) - - def db_changed(self): - self.dbstate.db.connect('person-add', self.update) - self.dbstate.db.connect('person-edit', self.update) - self.dbstate.db.connect('person-delete', self.update) - self.dbstate.db.connect('family-add', self.update) - self.dbstate.db.connect('family-delete', self.update) - self.dbstate.db.connect('person-rebuild', self.update) - self.dbstate.db.connect('family-rebuild', self.update) - - def main(self): - self.set_text(_("Processing...")) - database = self.dbstate.db - personList = database.get_person_handles(sort_handles=False) - familyList = database.get_family_handles() - - with_photos = 0 - total_photos = 0 - incomp_names = 0 - disconnected = 0 - missing_bday = 0 - males = 0 - females = 0 - unknowns = 0 - bytes = 0 - namelist = [] - notfound = [] - - pobjects = len(database.get_media_object_handles()) - for photo_id in database.get_media_object_handles(): - photo = database.get_object_from_handle(photo_id) - fullname = media_path_full(database, photo.get_path()) - try: - bytes = bytes + posixpath.getsize(fullname) - except: - notfound.append(photo.get_path()) - - cnt = 0 - for person_handle in personList: - person = database.get_person_from_handle(person_handle) - if not person: - continue - length = len(person.get_media_list()) - if length > 0: - with_photos = with_photos + 1 - total_photos = total_photos + length - - person = database.get_person_from_handle(person_handle) - names = [person.get_primary_name()] + person.get_alternate_names() - for name in names: - if name.get_first_name() == "" or name.get_group_name() == "": - incomp_names = incomp_names + 1 - if name.get_group_name() not in namelist: - namelist.append(name.get_group_name()) - if ((not person.get_main_parents_family_handle()) and - (not len(person.get_family_handle_list()))): - disconnected = disconnected + 1 - birth_ref = person.get_birth_ref() - if birth_ref: - birth = database.get_event_from_handle(birth_ref.ref) - if not DateHandler.get_date(birth): - missing_bday = missing_bday + 1 - else: - missing_bday = missing_bday + 1 - if person.get_gender() == gen.lib.Person.FEMALE: - females = females + 1 - elif person.get_gender() == gen.lib.Person.MALE: - males = males + 1 - else: - unknowns += 1 - if cnt % 200 == 0: - yield True - cnt += 1 - - self.clear_text() - self.append_text(_("Individuals") + "\n") - self.append_text("----------------------------\n") - self.link(_("Number of individuals") + ":", - 'Filter', 'all people') - self.append_text(" %s" % len(personList)) - self.append_text("\n") - self.link("%s:" % _("Males"), 'Filter', 'males') - self.append_text(" %s" % males) - self.append_text("\n") - self.link("%s:" % _("Females"), 'Filter', 'females') - self.append_text(" %s" % females) - self.append_text("\n") - self.link("%s:" % _("Individuals with unknown gender"), - 'Filter', 'people with unknown gender') - self.append_text(" %s" % unknowns) - self.append_text("\n") - self.link("%s:" % _("Individuals with incomplete names"), - 'Filter', 'people with incomplete names') - self.append_text(" %s" % incomp_names) - self.append_text("\n") - self.link("%s:" % _("Individuals missing birth dates"), - 'Filter', 'people with missing birth dates') - self.append_text(" %s" % missing_bday) - self.append_text("\n") - self.link("%s:" % _("Disconnected individuals"), - 'Filter', 'disconnected people') - self.append_text(" %s" % disconnected) - self.append_text("\n") - self.append_text("\n%s\n" % _("Family Information")) - self.append_text("----------------------------\n") - self.link("%s:" % _("Number of families"), - 'Filter', 'all families') - self.append_text(" %s" % len(familyList)) - self.append_text("\n") - self.link("%s:" % _("Unique surnames"), - 'Filter', 'unique surnames') - self.append_text(" %s" % len(namelist)) - self.append_text("\n") - self.append_text("\n%s\n" % _("Media Objects")) - self.append_text("----------------------------\n") - self.link("%s:" % _("Individuals with media objects"), - 'Filter', 'people with media') - self.append_text(" %s" % with_photos) - self.append_text("\n") - self.link("%s:" % _("Total number of media object references"), - 'Filter', 'media references') - self.append_text(" %s" % total_photos) - self.append_text("\n") - self.link("%s:" % _("Number of unique media objects"), - 'Filter', 'unique media') - self.append_text(" %s" % pobjects) - self.append_text("\n") - - self.link("%s:" % _("Total size of media objects"), - 'Filter', 'media by size') - self.append_text(" %d %s" % (bytes, _("bytes"))) - self.append_text("\n") - self.link("%s:" % _("Missing Media Objects"), - 'Filter', 'missing media') - self.append_text(" %s\n" % len(notfound)) - self.append_text("", scroll_to="begin") - -class PythonGramplet(Gramplet): - def init(self): - import gc - gc.set_debug(gc.DEBUG_UNCOLLECTABLE|gc.DEBUG_OBJECTS|gc.DEBUG_SAVEALL) - self.prompt = ">" - self.set_tooltip(_("Enter Python expressions")) - self.gc = gc - self.env = {"dbstate": self.gui.dbstate, - "uistate": self.gui.uistate, - "gc": self.gc, - "self": self, - _("class name|Date"): gen.lib.Date, - } - # GUI setup: - self.gui.textview.set_editable(True) - self.set_text("Python %s\n%s " % (sys.version, self.prompt)) - self.gui.textview.connect('key-press-event', self.on_key_press) - - def format_exception(self, max_tb_level=10): - retval = '' - cla, exc, trbk = sys.exc_info() - retval += _("Error") + (" : %s %s" %(cla, exc)) - return retval - - def process_command(self, command): - # update states, in case of change: - self.env["dbstate"] = self.gui.dbstate - self.env["uistate"] = self.gui.uistate - _retval = None - if "_retval" in self.env: - del self.env["_retval"] - exp1 = """_retval = """ + command - exp2 = command.strip() - try: - _retval = eval(exp2, self.env) - except: - try: - exec exp1 in self.env - except: - try: - exec exp2 in self.env - except: - _retval = self.format_exception() - if "_retval" in self.env: - _retval = self.env["_retval"] - return _retval - - def on_key_press(self, widget, event): - import gtk - if (event.keyval == gtk.keysyms.Home or - ((event.keyval == gtk.keysyms.a and - event.get_state() & gtk.gdk.CONTROL_MASK))): - buffer = widget.get_buffer() - cursor_pos = buffer.get_property("cursor-position") - iter = buffer.get_iter_at_offset(cursor_pos) - line_cnt = iter.get_line() - start = buffer.get_iter_at_line(line_cnt) - start.forward_chars(2) - buffer.place_cursor(start) - return True - elif (event.keyval == gtk.keysyms.End or - (event.keyval == gtk.keysyms.e and - event.get_state() & gtk.gdk.CONTROL_MASK)): - buffer = widget.get_buffer() - end = buffer.get_end_iter() - buffer.place_cursor(end) - return True - elif event.keyval == gtk.keysyms.Return: - echo = False - buffer = widget.get_buffer() - cursor_pos = buffer.get_property("cursor-position") - iter = buffer.get_iter_at_offset(cursor_pos) - line_cnt = iter.get_line() - start = buffer.get_iter_at_line(line_cnt) - line_len = iter.get_chars_in_line() - buffer_cnt = buffer.get_line_count() - if (buffer_cnt - line_cnt) > 1: - line_len -= 1 - echo = True - end = buffer.get_iter_at_line_offset(line_cnt, line_len) - line = buffer.get_text(start, end) - self.append_text("\n") - if line.startswith(self.prompt): - line = line[1:].strip() - else: - self.append_text("%s " % self.prompt) - end = buffer.get_end_iter() - buffer.place_cursor(end) - return True - if echo: - self.append_text(("%s " % self.prompt) + line) - end = buffer.get_end_iter() - buffer.place_cursor(end) - return True - _retval = self.process_command(line) - if _retval is not None: - self.append_text("%s\n" % str(_retval)) - self.append_text("%s " % self.prompt) - end = buffer.get_end_iter() - buffer.place_cursor(end) - return True - return False - -class QueryGramplet(PythonGramplet): - def init(self): - self.prompt = "$" - self.set_tooltip(_("Enter SQL query")) - # GUI setup: - self.gui.textview.set_editable(True) - self.set_text("Structured Query Language\n%s " % self.prompt) - self.gui.textview.connect('key-press-event', self.on_key_press) - - def process_command(self, command): - retval = run_quick_report_by_name(self.gui.dbstate, - self.gui.uistate, - 'query', - command) - return retval - -class TODOGramplet(Gramplet): - def init(self): - # GUI setup: - self.set_tooltip(_("Enter text")) - self.gui.textview.set_editable(True) - self.append_text(_("Enter your TODO list here.")) - - def on_load(self): - self.load_data_to_text() - - def on_save(self): - self.gui.data = [] # clear out old data - self.save_text_to_data() - -class FAQGramplet(Gramplet): - def init(self): - self.set_use_markup(True) - self.clear_text() - self.render_text("Draft of a Frequently Asked Questions Gramplet\n\n") - self.render_text(" 1. Test 1\n") - self.render_text(" 2. Test 2\n") - -def make_welcome_content(gui): - text = _( - 'Welcome to GRAMPS!\n\n' - 'GRAMPS is a software package designed for genealogical research.' - ' Although similar to other genealogical programs, GRAMPS offers ' - 'some unique and powerful features.\n\n' - 'GRAMPS is an Open Source Software package, which means you are ' - 'free to make copies and distribute it to anyone you like. It\'s ' - 'developed and maintained by a worldwide team of volunteers whose' - ' goal is to make GRAMPS powerful, yet easy to use.\n\n' - 'Getting Started\n\n' - 'The first thing you must do is to create a new Family Tree. To ' - 'create a new Family Tree (sometimes called a database) select ' - '"Family Trees" from the menu, pick "Manage Family Trees", press ' - '"New" and name your database. For more details, please read the ' - 'User Manual, or the on-line manual at http://gramps-project.org.\n\n' - 'You are currently reading from the "Gramplets" page, where you can' - ' add your own gramplets.\n\n' - 'You can right-click on the background of this page to add additional' - ' gramplets and change the number of columns. You can also drag the ' - 'Properties button to reposition the gramplet on this page, and detach' - ' the gramplet to float above GRAMPS. If you close GRAMPS with a gramplet' - ' detached, it will re-open detached the next time you start ' - 'GRAMPS.' - ) - gui.set_text(text) - -class HeadlineNewsGramplet(Gramplet): - """ - Headlines News Gramplet reads the Headline News every hour. - """ - RAW = URL_WIKISTRING + "%s&action=raw" - URL = URL_WIKISTRING + "%s" - - def init(self): - """ - Initialize gramplet. Start up update timer. - """ - self.set_tooltip(_("Read headline news from the GRAMPS wiki")) - self.update_interval = 3600 * 1000 # in miliseconds (1 hour) - self.timer = gobject.timeout_add(self.update_interval, - self.update_by_timer) - - def update_by_timer(self): - """ - Update, and return True to continually update on interval. - """ - self.update() - return True # keep updating! - - def main(self): - continuation = self.process('HeadlineNews') - retval = True - while retval: - retval, text = continuation.next() - self.set_text(text) - yield True - self.cleanup(text) - yield False - - def cleanup(self, text): - # final text - text = text.replace("
", "\n") - while "\n\n\n" in text: - text = text.replace("\n\n\n", "\n\n") - text = text.strip() - ## Wiki text: - ### Internal wiki URL with title: - pattern = re.compile('\[\[(.*?)\|(.*?)\]\]') - matches = pattern.findall(text) - for (g1, g2) in matches: - text = text.replace("[[%s|%s]]" % (g1, g2), - ("""%s""" % - (self.wiki(g1), self.nice_title(g2)))) - ### Internal wiki URL: - pattern = re.compile('\[\[(.*?)\]\]') - matches = pattern.findall(text) - for match in matches: - text = text.replace("[[%s]]" % match, - ("""%s""" % - (self.wiki(match), self.nice_title(match)))) - ### URL with title: - pattern = re.compile('\[http\:\/\/(.*?) (.*?)\]') - matches = pattern.findall(text) - for (g1, g2) in matches: - text = text.replace("[http://%s %s]" % (g1, g2), - ("""%s""" % - (g1, g2))) - ### URL: - pattern = re.compile('\[http\:\/\/(.*?)\]') - matches = pattern.findall(text) - count = 1 - for g1 in matches: - text = text.replace("[http://%s]" % (g1), - ("""%s""" % - (g1, ("[%d]" % count)))) - count += 1 - ### Bold: - pattern = re.compile("'''(.*?)'''") - matches = pattern.findall(text) - for match in matches: - text = text.replace("'''%s'''" % match, "%s" % match) - text = """Live update from www.gramps-project.org:\n\n""" + text - self.clear_text() - self.set_use_markup(True) - try: - self.render_text(text) - except: - cla, exc, trbk = sys.exc_info() - self.append_text(_("Error") + (" : %s %s\n\n" %(cla, exc))) - self.append_text(text) - self.append_text("", scroll_to="begin") - - def wiki(self, title): - return (self.URL % title) - - def nice_title(self, title): - return title.replace("_", " ") - - def process(self, title): - #print "processing '%s'..." % title - title = self.nice_title(title) - yield True, (_("Reading") + " '%s'..." % title) - fp = urllib.urlopen(self.RAW % title) - text = fp.read() - #text = text.replace("\n", " ") - html = re.findall('<.*?>', text) - for exp in html: - text = text.replace(exp, "") - text = text.replace("\n", "
") - fp.close() - pattern = '{{.*?}}' - matches = re.findall(pattern, text) - #print " before:", text - for match in matches: - page = match[2:-2] - oldtext = match - if "|" in page: - template, heading, body = page.split("|", 2) - if template.lower() == "release": - newtext = "GRAMPS " + heading + " released.

" - else: - newtext = "%s

" % heading - newtext += body + "
" - text = text.replace(oldtext, newtext) - else: # a macro/redirect - continuation = self.process("Template:" + page) - retval = True - while retval: - retval, newtext = continuation.next() - yield True, newtext - text = text.replace(oldtext, newtext) - #print " after:", text - pattern = '#REDIRECT \[\[.*?\]\]' - matches = re.findall(pattern, text) - #print " before:", text - for match in matches: - page = match[12:-2] - oldtext = match - continuation = self.process(page) - retval = True - while retval: - retval, newtext = continuation.next() - yield True, newtext - text = text.replace(oldtext, newtext) - #print " after:", text - yield False, text - -class AgeOnDateGramplet(Gramplet): - def init(self): - import gtk - # GUI setup: - self.set_tooltip(_("Enter a date, click Run")) - vbox = gtk.VBox() - hbox = gtk.HBox() - # label, entry - description = gtk.TextView() - description.set_wrap_mode(gtk.WRAP_WORD) - description.set_editable(False) - buffer = description.get_buffer() - buffer.set_text(_("Enter a date in the entry below and click Run." - " This will compute the ages for everyone in your" - " Family Tree on that date. You can then sort by" - " the age column, and double-click the row to view" - " or edit.")) - label = gtk.Label() - label.set_text(_("Date") + ":") - self.entry = gtk.Entry() - button = gtk.Button(_("Run")) - button.connect("clicked", self.run) - ##self.filter = - hbox.pack_start(label, False) - hbox.pack_start(self.entry, True) - vbox.pack_start(description, True) - vbox.pack_start(hbox, False) - vbox.pack_start(button, False) - self.gui.get_container_widget().remove(self.gui.textview) - self.gui.get_container_widget().add_with_viewport(vbox) - vbox.show_all() - - def run(self, obj): - text = self.entry.get_text() - date = DateHandler.parser.parse(text) - run_quick_report_by_name(self.gui.dbstate, - self.gui.uistate, - 'ageondate', - date) - -class QuickViewGramplet(Gramplet): - def active_changed(self, handle): - self.update() - - def main(self): - qv_type = self.get_option(_("View Type")) - quick_type = qv_type.get_value() - qv_option = self.get_option(_("Quick Views")) - quick_view = qv_option.get_value() - if quick_type == CATEGORY_QR_PERSON: - active = self.dbstate.get_active_person() - if active: - run_quick_report_by_name(self.gui.dbstate, - self.gui.uistate, - quick_view, - active.handle, - container=self.gui.textview) - else: - active_list = [] - for item in self.gui.uistate.viewmanager.pages: - if (item.get_title() == _("Families") and - quick_type == CATEGORY_QR_FAMILY): - active_list = item.selected_handles() - elif (item.get_title() == _("Events") and - quick_type == CATEGORY_QR_EVENT): - active_list = item.selected_handles() - elif (item.get_title() == _("Sources") and - quick_type == CATEGORY_QR_SOURCE): - active_list = item.selected_handles() - elif (item.get_title() == _("Places") and - quick_type == CATEGORY_QR_PLACE): - active_list = item.selected_handles() - elif (item.get_title() == _("Repositories") and - quick_type == CATEGORY_QR_REPOSITORY): - active_list = item.selected_handles() - if len(active_list) > 0: - run_quick_report_by_name(self.gui.dbstate, - self.gui.uistate, - quick_view, - active_list[0], - container=self.gui.textview) - - def build_options(self): - from gen.plug.menu import EnumeratedListOption - # Add types: - type_list = EnumeratedListOption(_("View Type"), CATEGORY_QR_PERSON) - for item in [(CATEGORY_QR_PERSON, "Person"), - (CATEGORY_QR_FAMILY, "Family"), - (CATEGORY_QR_EVENT, "Event"), - (CATEGORY_QR_SOURCE, "Source"), - (CATEGORY_QR_PLACE, "Place"), - (CATEGORY_QR_REPOSITORY, "Repository")]: - type_list.add_item(item[0], item[1]) - # Add particular lists: - qv_list = get_quick_report_list(CATEGORY_QR_PERSON) - list_option = EnumeratedListOption(_("Quick Views"), qv_list[0][2]) - for item in qv_list: - #(title, category, name, status) - list_option.add_item(item[2], item[0]) - self.add_option(type_list) - self.add_option(list_option) - type_widget = self.get_option_widget(_("View Type")) - type_widget.value_changed = self.rebuild_option_list - - def rebuild_option_list(self): - qv_option = self.get_option(_("View Type")) - list_option = self.get_option(_("Quick Views")) - list_option.clear() - qv_list = get_quick_report_list(qv_option.get_value()) - for item in qv_list: - #(title, category, name, status) - list_option.add_item(item[2], item[0]) - -class DataEntryGramplet(Gramplet): - NO_REL = 0 - AS_PARENT = 1 - AS_SPOUSE = 2 - AS_SIBLING = 3 - AS_CHILD = 4 - def init(self): - self.de_column_width = 20 - import gtk - rows = gtk.VBox() - self.dirty = False - self.dirty_person = None - self.dirty_family = None - self.de_widgets = {} - for items in [("Active person", _("Active person"), None, True, - [("Edit person", "", self.edit_person), ("Edit family", _("Family:"), self.edit_family)], - False, 0), - ("APName", _("Surname, Given"), None, False, [], True, 0), - ("APGender", _("Gender"), [_("female"), _("male"), _("unknown")], False, [], True, 2), - ("APBirth", _("Birth"), None, False, [], True, 0), - ("APDeath", _("Death"), None, False, [], True, 0) - ]: - pos, text, choices, readonly, callback, dirty, default = items - row = self.make_row(pos, text, choices, readonly, callback, dirty, default) - rows.pack_start(row, False) - - # Save and Abandon - row = gtk.HBox() - button = gtk.Button(_("Save")) - button.connect("clicked", self.save_data_edit) - row.pack_start(button, True) - button = gtk.Button(_("Abandon")) - button.connect("clicked", self.abandon_data_edit) - row.pack_start(button, True) - rows.pack_start(row, False) - - for items in [("New person", _("New person"), None, True, 0), - ("NPRelation", _("Add relation"), - [_("No relation to active person"), - _("Add as a Parent"), - _("Add as a Spouse"), - _("Add as a Sibling"), - _("Add as a Child")], - False, 0), - ("NPName", _("Surname, Given"), None, False, 0), - ("NPGender", _("Gender"), [_("female"), _("male"), _("unknown")], False, 2), - ("NPBirth", _("Birth"), None, False, 0), - ("NPDeath", _("Death"), None, False, 0) - ]: - pos, text, choices, readonly, default = items - row = self.make_row(pos, text, choices, readonly, default=default) - rows.pack_start(row, False) - - # Save, Abandon, Clear - row = gtk.HBox() - button = gtk.Button(_("Add")) - button.connect("clicked", self.add_data_entry) - row.pack_start(button, True) - button = gtk.Button(_("Copy Active Data")) - button.connect("clicked", self.copy_data_entry) - row.pack_start(button, True) - button = gtk.Button(_("Clear")) - button.connect("clicked", self.clear_data_entry) - row.pack_start(button, True) - rows.pack_start(row, False) - - self.gui.get_container_widget().remove(self.gui.textview) - self.gui.get_container_widget().add_with_viewport(rows) - rows.show_all() - self.clear_data_entry(None) - - def main(self): # return false finishes - if self.dirty: - return - self.de_widgets["Active person:Edit family"].hide() - self.de_widgets["Active person:Edit family:Label"].hide() - active_person = self.dbstate.get_active_person() - self.dirty_person = active_person - self.dirty_family = None - if active_person: - self.de_widgets["Active person:Edit person"].show() - self.de_widgets["Active person:Edit family"].hide() - self.de_widgets["Active person:Edit family:Label"].hide() - # Fill in current person edits: - name = name_displayer.display(active_person) - self.de_widgets["Active person"].set_text("%s " % name) - self.de_widgets["Active person"].set_use_markup(True) - # Name: - name_obj = active_person.get_primary_name() - if name_obj: - self.de_widgets["APName"].set_text("%s, %s" % - (name_obj.get_surname(), name_obj.get_first_name())) - self.de_widgets["APGender"].set_active(active_person.get_gender()) # gender - # Birth: - birth = ReportUtils.get_birth_or_fallback(self.dbstate.db, active_person) - birth_text = "" - if birth: - sdate = DateHandler.get_date(birth) - birth_text += sdate + " " - place_handle = birth.get_place_handle() - if place_handle: - place = self.dbstate.db.get_place_from_handle(place_handle) - place_text = place.get_title() - if place_text: - birth_text += _("in") + " " + place_text - - self.de_widgets["APBirth"].set_text(birth_text) - # Death: - death = ReportUtils.get_death_or_fallback(self.dbstate.db, active_person) - death_text = "" - if death: - sdate = DateHandler.get_date(death) - death_text += sdate + " " - place_handle = death.get_place_handle() - if place_handle: - place = self.dbstate.db.get_place_from_handle(place_handle) - place_text = place.get_title() - if place_text: - death_text += _("in") + " " + place_text - self.de_widgets["APDeath"].set_text(death_text) - family_list = active_person.get_family_handle_list() - if len(family_list) > 0: - self.dirty_family = self.dbstate.db.get_family_from_handle(family_list[0]) - self.de_widgets["Active person:Edit family"].show() - self.de_widgets["Active person:Edit family:Label"].show() - else: - family_list = active_person.get_parent_family_handle_list() - if len(family_list) > 0: - self.dirty_family = self.dbstate.db.get_family_from_handle(family_list[0]) - self.de_widgets["Active person:Edit family"].show() - self.de_widgets["Active person:Edit family:Label"].show() - else: - self.clear_data_edit(None) - self.de_widgets["Active person:Edit person"].hide() - self.de_widgets["Active person:Edit family"].hide() - self.de_widgets["Active person:Edit family:Label"].hide() - self.dirty = False - - def make_row(self, pos, text, choices=None, readonly=False, callback_list=[], - mark_dirty=False, default=0): - import gtk - # Data Entry: Active Person - row = gtk.HBox() - label = gtk.Label() - if readonly: - label.set_text("%s" % text) - label.set_width_chars(self.de_column_width) - label.set_use_markup(True) - self.de_widgets[pos] = gtk.Label() - self.de_widgets[pos].set_alignment(0.0, 0.5) - self.de_widgets[pos].set_use_markup(True) - label.set_alignment(0.0, 0.5) - row.pack_start(label, False) - row.pack_start(self.de_widgets[pos], False) - else: - label.set_text("%s: " % text) - label.set_width_chars(self.de_column_width) - label.set_alignment(1.0, 0.5) - if choices == None: - self.de_widgets[pos] = gtk.Entry() - if mark_dirty: - self.de_widgets[pos].connect("changed", self.mark_dirty) - row.pack_start(label, False) - row.pack_start(self.de_widgets[pos], True) - else: - eventBox = gtk.EventBox() - self.de_widgets[pos] = gtk.combo_box_new_text() - eventBox.add(self.de_widgets[pos]) - for add_type in choices: - self.de_widgets[pos].append_text(add_type) - self.de_widgets[pos].set_active(default) - if mark_dirty: - self.de_widgets[pos].connect("changed", self.mark_dirty) - row.pack_start(label, False) - row.pack_start(eventBox, True, True) - for name, text, callback in callback_list: - label = gtk.Label() - label.set_text(text) - self.de_widgets[pos + ":" + name + ":Label"] = label - row.pack_start(label, False) - icon = gtk.STOCK_EDIT - size = gtk.ICON_SIZE_MENU - button = gtk.Button() - image = gtk.Image() - image.set_from_stock(icon, size) - button.add(image) - button.set_relief(gtk.RELIEF_NONE) - button.connect("clicked", callback) - self.de_widgets[pos + ":" + name] = button - row.pack_start(button, False) - row.show_all() - return row - - def mark_dirty(self, obj): - self.dirty = True - - def abandon_data_edit(self, obj): - self.dirty = False - self.update() - - def edit_callback(self, person): - self.dirty = False - self.update() - - def edit_person(self, obj): - from Editors import EditPerson - try: - EditPerson(self.gui.dbstate, - self.gui.uistate, [], - self.dirty_person, - callback=self.edit_callback) - except Errors.WindowActiveError: - pass - - def edit_family(self, obj): - from Editors import EditFamily - try: - EditFamily(self.gui.dbstate, - self.gui.uistate, [], - self.dirty_family) - except Errors.WindowActiveError: - pass - - def process_dateplace(self, text): - if text == "": return None, None - prep_in = _("in") # word or phrase that separates date from place - text = text.strip() - if (" %s " % prep_in) in text: - date, place = text.split((" %s " % prep_in), 1) - elif text.startswith("%s " % prep_in): - date, place = text.split(("%s " % prep_in), 1) - else: - date, place = text, "" - date = date.strip() - place = place.strip() - if date != "": - date = DateHandler.parser.parse(date) - else: - date = None - if place != "": - newq, place = self.get_or_create_place(place) - else: - place = None - return date, place - - def get_or_create_place(self, place_name): - if place_name == "": return (-1, None) - place_list = self.dbstate.db.get_place_handles() - for place_handle in place_list: - place = self.dbstate.db.get_place_from_handle(place_handle) - if place.get_title().strip() == place_name: - return (0, place) # (old, object) - place = gen.lib.Place() - place.set_title(place_name) - self.dbstate.db.add_place(place,self.trans) - return (1, place) # (new, object) - - def get_or_create_event(self, object, type, date, place): - """ Add or find a type event on object """ - if date == place == None: return (-1, None) - # first, see if it exists - ref_list = object.get_event_ref_list() - # look for a match, and possible correction - for ref in ref_list: - event = self.dbstate.db.get_event_from_handle(ref.ref) - if event is not None: - if int(event.get_type()) == type: - # Match! Let's update - if date: - event.set_date_object(date) - if place: - event.set_place_handle(place.get_handle()) - self.dbstate.db.commit_event(event, self.trans) - return (0, event) - # else create it: - event = gen.lib.Event() - if type: - event.set_type(gen.lib.EventType(type)) - if date: - event.set_date_object(date) - if place: - event.set_place_handle(place.get_handle()) - self.dbstate.db.add_event(event, self.trans) - return (1, event) - - def make_event(self, type, date, place): - if date == place == None: return None - event = gen.lib.Event() - event.set_type(gen.lib.EventType(type)) - if date: - event.set_date_object(date) - if place: - event.set_place_handle(place.get_handle()) - self.dbstate.db.add_event(event, self.trans) - return event - - def make_person(self, firstname, surname, gender): - person = gen.lib.Person() - name = gen.lib.Name() - name.set_type(gen.lib.NameType(gen.lib.NameType.BIRTH)) - name.set_first_name(firstname) - name.set_surname(surname) - person.set_primary_name(name) - person.set_gender(gender) - return person - - def save_data_edit(self, obj): - if self.dirty: - # Save the edits ---------------------------------- - person = self.dirty_person - # First, get the data: - gender = self.de_widgets["APGender"].get_active() - if "," in self.de_widgets["APName"].get_text(): - surname, firstname = self.de_widgets["APName"].get_text().split(",", 1) - else: - surname, firstname = self.de_widgets["APName"].get_text(), "" - surname = surname.strip() - firstname = firstname.strip() - name = person.get_primary_name() - # Now, edit it: - self.trans = self.dbstate.db.transaction_begin() - name.set_surname(surname) - name.set_first_name(firstname) - person.set_gender(gender) - birthdate, birthplace = self.process_dateplace(self.de_widgets["APBirth"].get_text().strip()) - new, birthevent = self.get_or_create_event(person, gen.lib.EventType.BIRTH, birthdate, birthplace) - # reference it, if need be: - birthref = person.get_birth_ref() - if birthevent: - if birthref is None: - # need new - birthref = gen.lib.EventRef() - birthref.set_reference_handle(birthevent.get_handle()) - person.set_birth_ref(birthref) - deathdate, deathplace = self.process_dateplace(self.de_widgets["APDeath"].get_text().strip()) - new, deathevent = self.get_or_create_event(person, gen.lib.EventType.DEATH, deathdate, deathplace) - # reference it, if need be: - deathref = person.get_death_ref() - if deathevent: - if deathref is None: - # need new - deathref = gen.lib.EventRef() - deathref.set_reference_handle(deathevent.get_handle()) - person.set_death_ref(deathref) - self.dbstate.db.commit_person(person,self.trans) - self.dbstate.db.transaction_commit(self.trans, - (_("Gramplet Data Edit: %s") % name_displayer.display(person))) - self.dirty = False - self.update() - - def add_data_entry(self, obj): - from QuestionDialog import ErrorDialog - # First, get the data: - if "," in self.de_widgets["NPName"].get_text(): - surname, firstname = self.de_widgets["NPName"].get_text().split(",", 1) - else: - surname, firstname = self.de_widgets["NPName"].get_text(), "" - surname = surname.strip() - firstname = firstname.strip() - gender = self.de_widgets["NPGender"].get_active() - if self.dirty: - current_person = self.dirty_person - else: - current_person = self.dbstate.get_active_person() - # Pre-check to make sure everything is ok: ------------------------------------------- - if surname == "" and firstname == "": - ErrorDialog(_("Please provide a name."), _("Can't add new person.")) - return - if self.de_widgets["NPRelation"].get_active() == self.NO_REL: - # "No relation to active person" - pass - elif self.de_widgets["NPRelation"].get_active() == self.AS_PARENT: - # "Add as a Parent" - if current_person == None: - ErrorDialog(_("Please set an active person."), _("Can't add new person as a parent.")) - return - elif gender == gen.lib.Person.UNKNOWN: # unknown - ErrorDialog(_("Please set the new person's gender."), _("Can't add new person as a parent.")) - return - elif self.de_widgets["NPRelation"].get_active() == self.AS_SPOUSE: - # "Add as a Spouse" - if current_person == None: - ErrorDialog(_("Please set an active person."), _("Can't add new person as a spouse.")) - return - elif (gender == gen.lib.Person.UNKNOWN and - current_person.get_gender() == gen.lib.Person.UNKNOWN): # both genders unknown - ErrorDialog(_("Please set the new person's gender."), _("Can't add new person as a spouse.")) - return - elif self.de_widgets["NPRelation"].get_active() == self.AS_SIBLING: - # "Add as a Sibling" - if current_person == None: - ErrorDialog(_("Please set an active person."), _("Can't add new person as a sibling.")) - return - elif self.de_widgets["NPRelation"].get_active() == self.AS_CHILD: - # "Add as a Child" - if current_person == None: - ErrorDialog(_("Please set an active person."), _("Can't add new person as a child.")) - return - # Start the transaction: ------------------------------------------------------------ - self.trans = self.dbstate.db.transaction_begin() - # New person -------------------------------------------------- - # Add birth - new_birth_date, new_birth_place = self.process_dateplace(self.de_widgets["NPBirth"].get_text().strip()) - birth_event = self.make_event(gen.lib.EventType.BIRTH, new_birth_date, new_birth_place) - # Add death - new_death_date, new_death_place = self.process_dateplace(self.de_widgets["NPDeath"].get_text()) - death_event = self.make_event(gen.lib.EventType.DEATH, new_death_date, new_death_place) - # Now, create the person and events: - person = self.make_person(firstname, surname, gender) - # New birth for person: - if birth_event: - birth_ref = gen.lib.EventRef() - birth_ref.set_reference_handle(birth_event.get_handle()) - person.set_birth_ref(birth_ref) - # New death for person: - if death_event: - death_ref = gen.lib.EventRef() - death_ref.set_reference_handle(death_event.get_handle()) - person.set_death_ref(death_ref) - self.dbstate.db.add_person(person, self.trans) - # All error checking done; just add relation: - if self.de_widgets["NPRelation"].get_active() == self.NO_REL: - # "No relation to active person" - pass - elif self.de_widgets["NPRelation"].get_active() == self.AS_PARENT: - # "Add as a Parent" - # Go through current_person parent families - added = False - for family_handle in current_person.get_parent_family_handle_list(): - family = self.dbstate.db.get_family_from_handle(family_handle) - if family: - # find one that person would fit as a parent - fam_husband_handle = family.get_father_handle() - fam_wife_handle = family.get_mother_handle() - # can we add person as wife? - if fam_wife_handle == None and person.get_gender() == gen.lib.Person.FEMALE: - # add the person - family.set_mother_handle(person.get_handle()) - family.set_relationship(gen.lib.FamilyRelType.MARRIED) - person.add_family_handle(family.get_handle()) - added = True - break - elif fam_husband_handle == None and person.get_gender() == gen.lib.Person.MALE: - # add the person - family.set_father_handle(person.get_handle()) - family.set_relationship(gen.lib.FamilyRelType.MARRIED) - person.add_family_handle(family.get_handle()) - added = True - break - if added: - self.dbstate.db.commit_family(family, self.trans) - else: - family = gen.lib.Family() - self.dbstate.db.add_family(family, self.trans) - if person.get_gender() == gen.lib.Person.MALE: - family.set_father_handle(person.get_handle()) - elif person.get_gender() == gen.lib.Person.FEMALE: - family.set_mother_handle(person.get_handle()) - family.set_relationship(gen.lib.FamilyRelType.MARRIED) - # add curent_person as child - childref = gen.lib.ChildRef() - childref.set_reference_handle(current_person.get_handle()) - family.add_child_ref( childref) - current_person.add_parent_family_handle(family.get_handle()) - # finalize - person.add_family_handle(family.get_handle()) - self.dbstate.db.commit_family(family, self.trans) - elif self.de_widgets["NPRelation"].get_active() == self.AS_SPOUSE: - # "Add as a Spouse" - added = False - family = None - for family_handle in current_person.get_family_handle_list(): - family = self.dbstate.db.get_family_from_handle(family_handle) - if family: - fam_husband_handle = family.get_father_handle() - fam_wife_handle = family.get_mother_handle() - if current_person.get_handle() == fam_husband_handle: - # can we add person as wife? - if fam_wife_handle == None: - if person.get_gender() == gen.lib.Person.FEMALE: - # add the person - family.set_mother_handle(person.get_handle()) - family.set_relationship(gen.lib.FamilyRelType.MARRIED) - person.add_family_handle(family.get_handle()) - added = True - break - elif person.get_gender() == gen.lib.Person.UNKNOWN: - family.set_mother_handle(person.get_handle()) - family.set_relationship(gen.lib.FamilyRelType.MARRIED) - person.set_gender(gen.lib.Person.FEMALE) - self.de_widgets["NPGender"].set_active(gen.lib.Person.FEMALE) - person.add_family_handle(family.get_handle()) - added = True - break - elif current_person.get_handle() == fam_wife_handle: - # can we add person as husband? - if fam_husband_handle == None: - if person.get_gender() == gen.lib.Person.MALE: - # add the person - family.set_father_handle(person.get_handle()) - family.set_relationship(gen.lib.FamilyRelType.MARRIED) - person.add_family_handle(family.get_handle()) - added = True - break - elif person.get_gender() == gen.lib.Person.UNKNOWN: - family.set_father_handle(person.get_handle()) - family.set_relationship(gen.lib.FamilyRelType.MARRIED) - person.add_family_handle(family.get_handle()) - person.set_gender(gen.lib.Person.MALE) - self.de_widgets["NPGender"].set_active(gen.lib.Person.MALE) - added = True - break - if added: - self.dbstate.db.commit_family(family, self.trans) - else: - if person.get_gender() == gen.lib.Person.UNKNOWN: - if current_person.get_gender() == gen.lib.Person.UNKNOWN: - ErrorDialog(_("Please set gender on Active or new person."), - _("Can't add new person as a spouse.")) - return - elif current_person.get_gender() == gen.lib.Person.MALE: - family = gen.lib.Family() - self.dbstate.db.add_family(family, self.trans) - family.set_father_handle(current_person.get_handle()) - family.set_mother_handle(person.get_handle()) - family.set_relationship(gen.lib.FamilyRelType.MARRIED) - person.set_gender(gen.lib.Person.FEMALE) - self.de_widgets["NPGender"].set_active(gen.lib.Person.FEMALE) - person.add_family_handle(family.get_handle()) - current_person.add_family_handle(family.get_handle()) - self.dbstate.db.commit_family(family, self.trans) - elif current_person.get_gender() == gen.lib.Person.FEMALE: - family = gen.lib.Family() - self.dbstate.db.add_family(family, self.trans) - family.set_father_handle(person.get_handle()) - family.set_mother_handle(current_person.get_handle()) - family.set_relationship(gen.lib.FamilyRelType.MARRIED) - person.set_gender(gen.lib.Person.MALE) - self.de_widgets["NPGender"].set_active(gen.lib.Person.MALE) - person.add_family_handle(family.get_handle()) - current_person.add_family_handle(family.get_handle()) - self.dbstate.db.commit_family(family, self.trans) - elif person.get_gender() == gen.lib.Person.MALE: - if current_person.get_gender() == gen.lib.Person.UNKNOWN: - family = gen.lib.Family() - self.dbstate.db.add_family(family, self.trans) - family.set_father_handle(person.get_handle()) - family.set_mother_handle(current_person.get_handle()) - family.set_relationship(gen.lib.FamilyRelType.MARRIED) - current_person.set_gender(gen.lib.Person.FEMALE) - person.add_family_handle(family.get_handle()) - current_person.add_family_handle(family.get_handle()) - self.dbstate.db.commit_family(family, self.trans) - elif current_person.get_gender() == gen.lib.Person.MALE: - ErrorDialog(_("Same genders on Active and new person."), - _("Can't add new person as a spouse.")) - return - elif current_person.get_gender() == gen.lib.Person.FEMALE: - family = gen.lib.Family() - self.dbstate.db.add_family(family, self.trans) - family.set_father_handle(person.get_handle()) - family.set_mother_handle(current_person.get_handle()) - family.set_relationship(gen.lib.FamilyRelType.MARRIED) - person.add_family_handle(family.get_handle()) - current_person.add_family_handle(family.get_handle()) - self.dbstate.db.commit_family(family, self.trans) - elif person.get_gender() == gen.lib.Person.FEMALE: - if current_person.get_gender() == gen.lib.Person.UNKNOWN: - family = gen.lib.Family() - self.dbstate.db.add_family(family, self.trans) - family.set_father_handle(current_person.get_handle()) - family.set_mother_handle(person.get_handle()) - family.set_relationship(gen.lib.FamilyRelType.MARRIED) - current_person.set_gender(gen.lib.Person.MALE) - person.add_family_handle(family.get_handle()) - current_person.add_family_handle(family.get_handle()) - self.dbstate.db.commit_family(family, self.trans) - elif current_person.get_gender() == gen.lib.Person.MALE: - family = gen.lib.Family() - self.dbstate.db.add_family(family, self.trans) - family.set_father_handle(current_person.get_handle()) - family.set_mother_handle(person.get_handle()) - family.set_relationship(gen.lib.FamilyRelType.MARRIED) - person.add_family_handle(family.get_handle()) - current_person.add_family_handle(family.get_handle()) - self.dbstate.db.commit_family(family, self.trans) - elif current_person.get_gender() == gen.lib.Person.FEMALE: - ErrorDialog(_("Same genders on Active and new person."), - _("Can't add new person as a spouse.")) - return - elif self.de_widgets["NPRelation"].get_active() == self.AS_SIBLING: - # "Add as a Sibling" - added = False - for family_handle in current_person.get_parent_family_handle_list(): - family = self.dbstate.db.get_family_from_handle(family_handle) - if family: - childref = gen.lib.ChildRef() - childref.set_reference_handle(person.get_handle()) - family.add_child_ref( childref) - person.add_parent_family_handle(family.get_handle()) - added = True - break - if added: - self.dbstate.db.commit_family(family, self.trans) - else: - family = gen.lib.Family() - self.dbstate.db.add_family(family, self.trans) - childref = gen.lib.ChildRef() - childref.set_reference_handle(person.get_handle()) - family.add_child_ref( childref) - childref = gen.lib.ChildRef() - childref.set_reference_handle(current_person.get_handle()) - family.add_child_ref( childref) - person.add_parent_family_handle(family.get_handle()) - current_person.add_parent_family_handle(family.get_handle()) - self.dbstate.db.commit_family(family, self.trans) - elif self.de_widgets["NPRelation"].get_active() == self.AS_CHILD: - # "Add as a Child" - added = False - family = None - for family_handle in current_person.get_family_handle_list(): - family = self.dbstate.db.get_family_from_handle(family_handle) - if family: - childref = gen.lib.ChildRef() - childref.set_reference_handle(person.get_handle()) - family.add_child_ref( childref) - person.add_parent_family_handle(family.get_handle()) - added = True - break - if added: - self.dbstate.db.commit_family(family, self.trans) - else: - if current_person.get_gender() == gen.lib.Person.UNKNOWN: - ErrorDialog(_("Please set gender on Active person."), - _("Can't add new person as a child.")) - return - else: - family = gen.lib.Family() - self.dbstate.db.add_family(family, self.trans) - childref = gen.lib.ChildRef() - childref.set_reference_handle(person.get_handle()) - family.add_child_ref( childref) - person.add_parent_family_handle(family.get_handle()) - current_person.add_family_handle(family.get_handle()) - if gen.lib.Person.FEMALE: - family.set_mother_handle(current_person.get_handle()) - else: - family.set_father_handle(current_person.get_handle()) - self.dbstate.db.commit_family(family, self.trans) - # Commit changes ------------------------------------------------- - if current_person: - self.dbstate.db.commit_person(current_person, self.trans) - if person: - self.dbstate.db.commit_person(person, self.trans) - self.dbstate.db.transaction_commit(self.trans, - (_("Gramplet Data Entry: %s") % name_displayer.display(person))) - - def copy_data_entry(self, obj): - self.de_widgets["NPName"].set_text(self.de_widgets["APName"].get_text()) - self.de_widgets["NPBirth"].set_text(self.de_widgets["APBirth"].get_text()) - self.de_widgets["NPDeath"].set_text(self.de_widgets["APDeath"].get_text()) - self.de_widgets["NPGender"].set_active(self.de_widgets["APGender"].get_active()) - # FIXME: put cursor in add surname - - def clear_data_edit(self, obj): - self.de_widgets["Active person"].set_text("") - self.de_widgets["APName"].set_text("") - self.de_widgets["APBirth"].set_text("") - self.de_widgets["APDeath"].set_text("") - self.de_widgets["APGender"].set_active(gen.lib.Person.UNKNOWN) - - def clear_data_entry(self, obj): - self.de_widgets["NPName"].set_text("") - self.de_widgets["NPBirth"].set_text("") - self.de_widgets["NPDeath"].set_text("") - self.de_widgets["NPRelation"].set_active(self.NO_REL) - self.de_widgets["NPGender"].set_active(gen.lib.Person.UNKNOWN) - - def db_changed(self): - """ - If person or family changes, the relatives of active person might have - changed - """ - self.dbstate.db.connect('person-add', self.update) - self.dbstate.db.connect('person-delete', self.update) - self.dbstate.db.connect('person-edit', self.update) - self.dbstate.db.connect('family-add', self.update) - self.dbstate.db.connect('family-delete', self.update) - self.dbstate.db.connect('person-rebuild', self.update) - self.dbstate.db.connect('family-rebuild', self.update) - self.dirty = False - self.dirty_person = None - self.clear_data_entry(None) - - def active_changed(self, handle): - self.update() - -register(type="gramplet", - name= "Top Surnames Gramplet", - tname=_("Top Surnames Gramplet"), - height=230, - content = TopSurnamesGramplet, - title=_("Top Surnames"), - ) - -register(type="gramplet", - name= "Surname Cloud Gramplet", - tname=_("Surname Cloud Gramplet"), - height=300, - expand=True, - content = SurnameCloudGramplet, - title=_("Surname Cloud"), - ) - -register(type="gramplet", - name="Statistics Gramplet", - tname=_("Statistics Gramplet"), - height=230, - expand=True, - content = StatsGramplet, - title=_("Statistics"), - ) - -register(type="gramplet", - name="Session Log Gramplet", - tname=_("Session Log Gramplet"), - height=230, - data=['no'], - content = LogGramplet, - title=_("Session Log"), - ) - -register(type="gramplet", - name="Python Gramplet", - tname=_("Python Gramplet"), - height=250, - content = PythonGramplet, - title=_("Python Shell"), - ) - -register(type="gramplet", - name="TODO Gramplet", - tname=_("TODO Gramplet"), - height=300, - expand=True, - content = TODOGramplet, - title=_("TODO List"), - ) - -register(type="gramplet", - name="Welcome Gramplet", - tname=_("Welcome Gramplet"), - height=300, - expand=True, - content = make_welcome_content, - title=_("Welcome to GRAMPS!"), - ) - -register(type="gramplet", - name="Calendar Gramplet", - tname=_("Calendar Gramplet"), - height=200, - content = CalendarGramplet, - title=_("Calendar"), - ) - -register(type="gramplet", - name="Headline News Gramplet", - tname=_("Headline News Gramplet"), - height=300, - expand=True, - content = HeadlineNewsGramplet, - title=_("Headline News"), - ) - -register(type="gramplet", - name="Age on Date Gramplet", - tname=_("Age on Date Gramplet"), - height=200, - content = AgeOnDateGramplet, - title=_("Age on Date"), - ) - -register(type="gramplet", - name="Relatives Gramplet", - tname=_("Relatives Gramplet"), - height=200, - content = RelativesGramplet, - title=_("Relatives"), - detached_width = 250, - detached_height = 300, - ) - -register(type="gramplet", - name="Pedigree Gramplet", - tname=_("Pedigree Gramplet"), - height=300, - content = PedigreeGramplet, - title=_("Pedigree"), - expand=True, - detached_width = 600, - detached_height = 400, - ) - -register(type="gramplet", - name="FAQ Gramplet", - tname=_("FAQ Gramplet"), - height=300, - content = FAQGramplet, - title=_("FAQ"), - ) - -register(type="gramplet", - name="Query Gramplet", - tname=_("Query Gramplet"), - height=300, - content = QueryGramplet, - title=_("Query"), - detached_width = 600, - detached_height = 400, - ) - -register(type="gramplet", - name="Quick View Gramplet", - tname=_("Quick View Gramplet"), - height=300, - expand=True, - content = QuickViewGramplet, - title=_("Quick View"), - detached_width = 600, - detached_height = 400, - ) - -register(type="gramplet", - name="Data Entry Gramplet", - tname=_("Data Entry Gramplet"), - height=375, - expand=False, - content = DataEntryGramplet, - title=_("Data Entry"), - detached_width = 510, - detached_height = 480, - ) - diff --git a/src/plugins/gramplet/FaqGramplet.py b/src/plugins/gramplet/FaqGramplet.py new file mode 100644 index 000000000..ab4db01fa --- /dev/null +++ b/src/plugins/gramplet/FaqGramplet.py @@ -0,0 +1,49 @@ +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2007-2009 Douglas S. Blank +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# $Id$ + +#------------------------------------------------------------------------ +# +# GRAMPS modules +# +#------------------------------------------------------------------------ +from DataViews import register, Gramplet +from TransUtils import sgettext as _ + +#------------------------------------------------------------------------ +# +# Register Gramplet +# +#------------------------------------------------------------------------ +class FAQGramplet(Gramplet): + def init(self): + self.set_use_markup(True) + self.clear_text() + self.render_text("Draft of a Frequently Asked Questions Gramplet\n\n") + self.render_text(" 1. Test 1\n") + self.render_text(" 2. Test 2\n") + +register(type="gramplet", + name="FAQ Gramplet", + tname=_("FAQ Gramplet"), + height=300, + content = FAQGramplet, + title=_("FAQ"), + ) + diff --git a/src/plugins/gramplet/HeadlineNewsGramplet.py b/src/plugins/gramplet/HeadlineNewsGramplet.py new file mode 100644 index 000000000..f21096214 --- /dev/null +++ b/src/plugins/gramplet/HeadlineNewsGramplet.py @@ -0,0 +1,198 @@ +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2007-2009 Douglas S. Blank +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# $Id$ + +#------------------------------------------------------------------------ +# +# Python modules +# +#------------------------------------------------------------------------ +import re +import gobject +import urllib +import sys + +#------------------------------------------------------------------------ +# +# GRAMPS modules +# +#------------------------------------------------------------------------ +from DataViews import register, Gramplet +from const import URL_WIKISTRING +from TransUtils import sgettext as _ + +#------------------------------------------------------------------------ +# +# Gramplet class +# +#------------------------------------------------------------------------ +class HeadlineNewsGramplet(Gramplet): + """ + Headlines News Gramplet reads the Headline News every hour. + """ + RAW = URL_WIKISTRING + "%s&action=raw" + URL = URL_WIKISTRING + "%s" + + def init(self): + """ + Initialize gramplet. Start up update timer. + """ + self.set_tooltip(_("Read headline news from the GRAMPS wiki")) + self.update_interval = 3600 * 1000 # in miliseconds (1 hour) + self.timer = gobject.timeout_add(self.update_interval, + self.update_by_timer) + + def update_by_timer(self): + """ + Update, and return True to continually update on interval. + """ + self.update() + return True # keep updating! + + def main(self): + continuation = self.process('HeadlineNews') + retval = True + while retval: + retval, text = continuation.next() + self.set_text(text) + yield True + self.cleanup(text) + yield False + + def cleanup(self, text): + # final text + text = text.replace("
", "\n") + while "\n\n\n" in text: + text = text.replace("\n\n\n", "\n\n") + text = text.strip() + ## Wiki text: + ### Internal wiki URL with title: + pattern = re.compile('\[\[(.*?)\|(.*?)\]\]') + matches = pattern.findall(text) + for (g1, g2) in matches: + text = text.replace("[[%s|%s]]" % (g1, g2), + ("""%s""" % + (self.wiki(g1), self.nice_title(g2)))) + ### Internal wiki URL: + pattern = re.compile('\[\[(.*?)\]\]') + matches = pattern.findall(text) + for match in matches: + text = text.replace("[[%s]]" % match, + ("""%s""" % + (self.wiki(match), self.nice_title(match)))) + ### URL with title: + pattern = re.compile('\[http\:\/\/(.*?) (.*?)\]') + matches = pattern.findall(text) + for (g1, g2) in matches: + text = text.replace("[http://%s %s]" % (g1, g2), + ("""%s""" % + (g1, g2))) + ### URL: + pattern = re.compile('\[http\:\/\/(.*?)\]') + matches = pattern.findall(text) + count = 1 + for g1 in matches: + text = text.replace("[http://%s]" % (g1), + ("""%s""" % + (g1, ("[%d]" % count)))) + count += 1 + ### Bold: + pattern = re.compile("'''(.*?)'''") + matches = pattern.findall(text) + for match in matches: + text = text.replace("'''%s'''" % match, "%s" % match) + text = """Live update from www.gramps-project.org:\n\n""" + text + self.clear_text() + self.set_use_markup(True) + try: + self.render_text(text) + except: + cla, exc, trbk = sys.exc_info() + self.append_text(_("Error") + (" : %s %s\n\n" %(cla, exc))) + self.append_text(text) + self.append_text("", scroll_to="begin") + + def wiki(self, title): + return (self.URL % title) + + def nice_title(self, title): + return title.replace("_", " ") + + def process(self, title): + #print "processing '%s'..." % title + title = self.nice_title(title) + yield True, (_("Reading") + " '%s'..." % title) + fp = urllib.urlopen(self.RAW % title) + text = fp.read() + #text = text.replace("\n", " ") + html = re.findall('<.*?>', text) + for exp in html: + text = text.replace(exp, "") + text = text.replace("\n", "
") + fp.close() + pattern = '{{.*?}}' + matches = re.findall(pattern, text) + #print " before:", text + for match in matches: + page = match[2:-2] + oldtext = match + if "|" in page: + template, heading, body = page.split("|", 2) + if template.lower() == "release": + newtext = "GRAMPS " + heading + " released.

" + else: + newtext = "%s

" % heading + newtext += body + "
" + text = text.replace(oldtext, newtext) + else: # a macro/redirect + continuation = self.process("Template:" + page) + retval = True + while retval: + retval, newtext = continuation.next() + yield True, newtext + text = text.replace(oldtext, newtext) + #print " after:", text + pattern = '#REDIRECT \[\[.*?\]\]' + matches = re.findall(pattern, text) + #print " before:", text + for match in matches: + page = match[12:-2] + oldtext = match + continuation = self.process(page) + retval = True + while retval: + retval, newtext = continuation.next() + yield True, newtext + text = text.replace(oldtext, newtext) + #print " after:", text + yield False, text + +#------------------------------------------------------------------------ +# +# Register Gramplet +# +#------------------------------------------------------------------------ +register(type="gramplet", + name="Headline News Gramplet", + tname=_("Headline News Gramplet"), + height=300, + expand=True, + content = HeadlineNewsGramplet, + title=_("Headline News"), + ) diff --git a/src/plugins/gramplet/Makefile.am b/src/plugins/gramplet/Makefile.am index e3ab15b66..a72580e20 100644 --- a/src/plugins/gramplet/Makefile.am +++ b/src/plugins/gramplet/Makefile.am @@ -6,12 +6,27 @@ pkgdatadir = $(datadir)/@PACKAGE@/plugins/gramplet pkgdata_PYTHON = \ + AgeOnDateGramplet.py \ AgeStats.py \ AttributesGramplet.py \ - DefaultGramplets.py \ + CalendarGramplet.py \ + DataEntryGramplet.py \ DescendGramplet.py \ + FanChartGramplet.py \ + FaqGramplet.py \ GivenNameGramplet.py \ + HeadlineNewsGramplet.py \ NoteGramplet.py \ + PedigreeGramplet.py \ + PythonGramplet.py \ + QuickViewGramplet.py \ + RelativeGramplet.py \ + SessionLogGramplet.py \ + StatsGramplet.py \ + SurnameCloudGramplet.py \ + ToDoGramplet.py \ + TopSurnamesGramplet.py \ + WelcomeGramplet.py \ WhatsNext.py pkgpyexecdir = @pkgpyexecdir@/plugins/gramplet diff --git a/src/plugins/gramplet/PedigreeGramplet.py b/src/plugins/gramplet/PedigreeGramplet.py new file mode 100644 index 000000000..7f3760bcb --- /dev/null +++ b/src/plugins/gramplet/PedigreeGramplet.py @@ -0,0 +1,279 @@ +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2007-2009 Douglas S. Blank +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# $Id$ + +#------------------------------------------------------------------------ +# +# Python modules +# +#------------------------------------------------------------------------ +import cgi + +#------------------------------------------------------------------------ +# +# GRAMPS modules +# +#------------------------------------------------------------------------ +from DataViews import register, Gramplet +from TransUtils import sgettext as _ +from BasicUtils import name_displayer +from ReportBase import ReportUtils +import DateHandler +import gen + +#------------------------------------------------------------------------ +# +# Gramplet class +# +#------------------------------------------------------------------------ +class PedigreeGramplet(Gramplet): + def init(self): + self.set_text(_("No Family Tree loaded.")) + self.set_tooltip(_("Move mouse over links for options")) + self.set_use_markup(True) + self.max_generations = 100 + self.show_dates = 1 + self.box_mode = "UTF" + + def build_options(self): + from gen.plug.menu import NumberOption + self.add_option(NumberOption(_("Max generations"), + self.max_generations, 1, 100)) + + def save_options(self): + self.max_generations = int(self.get_option(_("Max generations")).get_value()) + + def on_load(self): + if len(self.gui.data) > 0: + self.max_generations = int(self.gui.data[0]) + if len(self.gui.data) > 1: + self.show_dates = int(self.gui.data[1]) + if len(self.gui.data) > 2: + self.box_mode = self.gui.data[2] # ASCII or UTF + + def on_save(self): + self.gui.data = [self.max_generations, self.show_dates, self.box_mode] + + def db_changed(self): + """ + If a person or family changes, the ancestors of active person might have + changed. + """ + self.dbstate.db.connect('person-add', self.update) + self.dbstate.db.connect('person-delete', self.update) + self.dbstate.db.connect('family-add', self.update) + self.dbstate.db.connect('family-delete', self.update) + self.dbstate.db.connect('person-rebuild', self.update) + self.dbstate.db.connect('family-rebuild', self.update) + + def active_changed(self, handle): + self.update() + + def get_boxes(self, generation, what): + retval = u"" + if self.box_mode == "UTF": + space = u" " + elif self.box_mode == "ASCII": + space = u" " + space_len = len(space) + 2 + for i in range(generation+1): + if self._boxes[i]: + retval += space + u"|" + else: + retval += space + u" " + if retval[-1] == u' ': + if what == 'sf': + retval = retval[:-space_len] + u"/" + elif what == 'sm': + retval = retval[:-space_len] + u"\\" + elif retval.endswith(u"|" + space + u"|"): + retval = retval[:-space_len] + u"+" + if self.box_mode == "UTF": + retval += u"-" + retval = retval.replace(u"\\", u"\u2514") + retval = retval.replace(u"-", u"\u2500") + retval = retval.replace(u"|", u"\u2502") + retval = retval.replace(u"/", u"\u250c") + elif self.box_mode == "ASCII": + retval += u"--" + return retval + + def set_box(self, pos, value): + self._boxes[pos] = value + + def process_person(self, handle, generation, what): + if generation > self.max_generations: + return + person = self.dbstate.db.get_person_from_handle(handle) + family_list = person.get_parent_family_handle_list() + if what == "f": + if len(family_list) > 0: + family = self.dbstate.db.get_family_from_handle(family_list[0]) + father = family.get_father_handle() + mother = family.get_mother_handle() + if father: + self.process_person(father, generation + 1, "f") + self.set_box(generation, 1) + self.process_person(father, generation + 1, "sf") + self.process_person(father, generation + 1, "m") + elif mother: + self.set_box(generation, 1) + elif what[0] == "s": + boxes = self.get_boxes(generation, what) + if what[-1] == 'f': + if self.box_mode == "UTF": + boxes = boxes.replace("+", u"\u250c") + else: + boxes = boxes.replace("+", u"/") + else: + if self.box_mode == "UTF": + boxes = boxes.replace("+", u"\u2514") + else: + boxes = boxes.replace("+", u"\\") + self.append_text(boxes) + self.link(name_displayer.display_name(person.get_primary_name()), + 'Person', person.handle, + tooltip=_("Click to make active\n") + \ + _("Right-click to edit")) + if self.show_dates: + self.append_text(" ") + self.render_text(self.info_string(person)) + self.append_text("\n") + if generation not in self._generations: + self._generations[generation] = [] + self._generations[generation].append(handle) + elif what == "a": + if self.box_mode == "UTF": + self.append_text(u"o" + (u"\u2500" * 3)) + elif self.box_mode == "ASCII": + self.append_text(u"o---") + self.append_text("%s " % name_displayer.display_name(person.get_primary_name())) + if self.show_dates: + self.render_text(self.info_string(person)) + self.append_text("\n") + if generation not in self._generations: + self._generations[generation] = [] + self._generations[generation].append(handle) + elif what == "m": + if len(family_list) > 0: + family = self.dbstate.db.get_family_from_handle(family_list[0]) + mother = family.get_mother_handle() + if mother: + self.process_person(mother, generation + 1, "f") + self.process_person(mother, generation + 1, "sm") + self.set_box(generation, 0) + self.process_person(mother, generation + 1, "m") + self.set_box(generation, 0) # regardless, turn off line if on + + def info_string(self, person): + birth = ReportUtils.get_birth_or_fallback(self.dbstate.db, person) + if birth and birth.get_type != gen.lib.EventType.BIRTH: + sdate = DateHandler.get_date(birth) + if sdate: + bdate = "%s" % cgi.escape(sdate) + else: + bdate = "" + elif birth: + bdate = cgi.escape(DateHandler.get_date(birth)) + else: + bdate = "" + + death = ReportUtils.get_death_or_fallback(self.dbstate.db, person) + if death and death.get_type != gen.lib.EventType.DEATH: + sdate = DateHandler.get_date(death) + if sdate: + ddate = "%s" % cgi.escape(sdate) + else: + ddate = "" + elif death: + ddate = cgi.escape(DateHandler.get_date(death)) + else: + ddate = "" + + if bdate and ddate: + value = _("(b. %(birthdate)s, d. %(deathdate)s)") % { + 'birthdate' : bdate, + 'deathdate' : ddate + } + elif bdate: + value = _("(b. %s)") % (bdate) + elif ddate: + value = _("(d. %s)") % (ddate) + else: + value = "" + return value + + def main(self): # return false finishes + """ + Generator which will be run in the background. + """ + self._boxes = [0] * (self.max_generations + 1) + self._generations = {} + self.gui.buffer.set_text("") + active_person = self.dbstate.get_active_person() + if not active_person: + return False + #no wrap in Gramplet + self.no_wrap() + self.process_person(active_person.handle, 1, "f") # father + self.process_person(active_person.handle, 0, "a") # active #FIXME: should be 1? + self.process_person(active_person.handle, 1, "m") # mother + gens = self._generations.keys() + gens.sort() + self.append_text(_("\nBreakdown by generation:\n")) + all = [active_person.handle] + for g in gens: + count = len(self._generations[g]) + handles = self._generations[g] + self.append_text(" ") + if g == 0: + self.link(_("Generation 1"), 'PersonList', handles, + tooltip=_("Double-click to see people in generation")) + self.append_text(_(" has 1 of 1 individual (100.00% complete)\n")) + else: + all.extend(handles) + self.link(_("Generation %d") % g, 'PersonList', handles, + tooltip=_("Double-click to see people in generation")) + self.append_text(_(" has %d of %d individuals (%.2f%% complete)\n") % + (count, 2**(g-1), float(count)/2**(g-1) * 100)) + self.link(_("All generations"), 'PersonList', all, + tooltip=_("Double-click to see all generations")) + self.append_text(_(" have %d individuals\n") % len(all)) + # Set to a fixed font + if self.box_mode == "UTF": + start, end = self.gui.buffer.get_bounds() + self.gui.buffer.apply_tag_by_name("fixed", start, end) + self.append_text("", scroll_to="begin") + +#------------------------------------------------------------------------ +# +# Register Gramplet +# +#------------------------------------------------------------------------ +register(type="gramplet", + name="Pedigree Gramplet", + tname=_("Pedigree Gramplet"), + height=300, + content = PedigreeGramplet, + title=_("Pedigree"), + expand=True, + detached_width = 600, + detached_height = 400, + ) + diff --git a/src/plugins/gramplet/PythonGramplet.py b/src/plugins/gramplet/PythonGramplet.py new file mode 100644 index 000000000..a4eacd65e --- /dev/null +++ b/src/plugins/gramplet/PythonGramplet.py @@ -0,0 +1,157 @@ +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2007-2009 Douglas S. Blank +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# $Id$ + +#------------------------------------------------------------------------ +# +# Python modules +# +#------------------------------------------------------------------------ +import sys + +#------------------------------------------------------------------------ +# +# GRAMPS modules +# +#------------------------------------------------------------------------ +from DataViews import register, Gramplet +from TransUtils import sgettext as _ +import gen + +#------------------------------------------------------------------------ +# +# Gramplet class +# +#------------------------------------------------------------------------ +class PythonGramplet(Gramplet): + def init(self): + import gc + gc.set_debug(gc.DEBUG_UNCOLLECTABLE|gc.DEBUG_OBJECTS|gc.DEBUG_SAVEALL) + self.prompt = ">" + self.set_tooltip(_("Enter Python expressions")) + self.gc = gc + self.env = {"dbstate": self.gui.dbstate, + "uistate": self.gui.uistate, + "gc": self.gc, + "self": self, + _("class name|Date"): gen.lib.Date, + } + # GUI setup: + self.gui.textview.set_editable(True) + self.set_text("Python %s\n%s " % (sys.version, self.prompt)) + self.gui.textview.connect('key-press-event', self.on_key_press) + + def format_exception(self, max_tb_level=10): + retval = '' + cla, exc, trbk = sys.exc_info() + retval += _("Error") + (" : %s %s" %(cla, exc)) + return retval + + def process_command(self, command): + # update states, in case of change: + self.env["dbstate"] = self.gui.dbstate + self.env["uistate"] = self.gui.uistate + _retval = None + if "_retval" in self.env: + del self.env["_retval"] + exp1 = """_retval = """ + command + exp2 = command.strip() + try: + _retval = eval(exp2, self.env) + except: + try: + exec exp1 in self.env + except: + try: + exec exp2 in self.env + except: + _retval = self.format_exception() + if "_retval" in self.env: + _retval = self.env["_retval"] + return _retval + + def on_key_press(self, widget, event): + import gtk + if (event.keyval == gtk.keysyms.Home or + ((event.keyval == gtk.keysyms.a and + event.get_state() & gtk.gdk.CONTROL_MASK))): + buffer = widget.get_buffer() + cursor_pos = buffer.get_property("cursor-position") + iter = buffer.get_iter_at_offset(cursor_pos) + line_cnt = iter.get_line() + start = buffer.get_iter_at_line(line_cnt) + start.forward_chars(2) + buffer.place_cursor(start) + return True + elif (event.keyval == gtk.keysyms.End or + (event.keyval == gtk.keysyms.e and + event.get_state() & gtk.gdk.CONTROL_MASK)): + buffer = widget.get_buffer() + end = buffer.get_end_iter() + buffer.place_cursor(end) + return True + elif event.keyval == gtk.keysyms.Return: + echo = False + buffer = widget.get_buffer() + cursor_pos = buffer.get_property("cursor-position") + iter = buffer.get_iter_at_offset(cursor_pos) + line_cnt = iter.get_line() + start = buffer.get_iter_at_line(line_cnt) + line_len = iter.get_chars_in_line() + buffer_cnt = buffer.get_line_count() + if (buffer_cnt - line_cnt) > 1: + line_len -= 1 + echo = True + end = buffer.get_iter_at_line_offset(line_cnt, line_len) + line = buffer.get_text(start, end) + self.append_text("\n") + if line.startswith(self.prompt): + line = line[1:].strip() + else: + self.append_text("%s " % self.prompt) + end = buffer.get_end_iter() + buffer.place_cursor(end) + return True + if echo: + self.append_text(("%s " % self.prompt) + line) + end = buffer.get_end_iter() + buffer.place_cursor(end) + return True + _retval = self.process_command(line) + if _retval is not None: + self.append_text("%s\n" % str(_retval)) + self.append_text("%s " % self.prompt) + end = buffer.get_end_iter() + buffer.place_cursor(end) + return True + return False + +#------------------------------------------------------------------------ +# +# Register Gramplet +# +#------------------------------------------------------------------------ +register(type="gramplet", + name="Python Gramplet", + tname=_("Python Gramplet"), + height=250, + content = PythonGramplet, + title=_("Python Shell"), + ) + diff --git a/src/plugins/gramplet/QuickViewGramplet.py b/src/plugins/gramplet/QuickViewGramplet.py new file mode 100644 index 000000000..2a8d12cbd --- /dev/null +++ b/src/plugins/gramplet/QuickViewGramplet.py @@ -0,0 +1,131 @@ +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2007-2009 Douglas S. Blank +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# $Id$ + +#------------------------------------------------------------------------ +# +# Python modules +# +#------------------------------------------------------------------------ + + +#------------------------------------------------------------------------ +# +# GRAMPS modules +# +#------------------------------------------------------------------------ +from DataViews import register, Gramplet +from TransUtils import sgettext as _ +from QuickReports import run_quick_report_by_name, get_quick_report_list +from ReportBase import (CATEGORY_QR_PERSON, CATEGORY_QR_FAMILY, + CATEGORY_QR_EVENT, CATEGORY_QR_SOURCE, + CATEGORY_QR_MISC, CATEGORY_QR_PLACE, + CATEGORY_QR_REPOSITORY) + +#------------------------------------------------------------------------ +# +# Gramplet class +# +#------------------------------------------------------------------------ +class QuickViewGramplet(Gramplet): + def active_changed(self, handle): + self.update() + + def main(self): + qv_type = self.get_option(_("View Type")) + quick_type = qv_type.get_value() + qv_option = self.get_option(_("Quick Views")) + quick_view = qv_option.get_value() + if quick_type == CATEGORY_QR_PERSON: + active = self.dbstate.get_active_person() + if active: + run_quick_report_by_name(self.gui.dbstate, + self.gui.uistate, + quick_view, + active.handle, + container=self.gui.textview) + else: + active_list = [] + for item in self.gui.uistate.viewmanager.pages: + if (item.get_title() == _("Families") and + quick_type == CATEGORY_QR_FAMILY): + active_list = item.selected_handles() + elif (item.get_title() == _("Events") and + quick_type == CATEGORY_QR_EVENT): + active_list = item.selected_handles() + elif (item.get_title() == _("Sources") and + quick_type == CATEGORY_QR_SOURCE): + active_list = item.selected_handles() + elif (item.get_title() == _("Places") and + quick_type == CATEGORY_QR_PLACE): + active_list = item.selected_handles() + elif (item.get_title() == _("Repositories") and + quick_type == CATEGORY_QR_REPOSITORY): + active_list = item.selected_handles() + if len(active_list) > 0: + run_quick_report_by_name(self.gui.dbstate, + self.gui.uistate, + quick_view, + active_list[0], + container=self.gui.textview) + + def build_options(self): + from gen.plug.menu import EnumeratedListOption + # Add types: + type_list = EnumeratedListOption(_("View Type"), CATEGORY_QR_PERSON) + for item in [(CATEGORY_QR_PERSON, "Person"), + #TODO: add these once they have active change signals + #(CATEGORY_QR_FAMILY, "Family"), + #(CATEGORY_QR_EVENT, "Event"), + #(CATEGORY_QR_SOURCE, "Source"), + #(CATEGORY_QR_PLACE, "Place"), + #(CATEGORY_QR_REPOSITORY, "Repository"), + ]: + type_list.add_item(item[0], item[1]) + # Add particular lists: + qv_list = get_quick_report_list(CATEGORY_QR_PERSON) + list_option = EnumeratedListOption(_("Quick Views"), qv_list[0][2]) + for item in qv_list: + #(title, category, name, status) + list_option.add_item(item[2], item[0]) + self.add_option(type_list) + self.add_option(list_option) + type_widget = self.get_option_widget(_("View Type")) + type_widget.value_changed = self.rebuild_option_list + + def rebuild_option_list(self): + qv_option = self.get_option(_("View Type")) + list_option = self.get_option(_("Quick Views")) + list_option.clear() + qv_list = get_quick_report_list(qv_option.get_value()) + for item in qv_list: + #(title, category, name, status) + list_option.add_item(item[2], item[0]) + +register(type="gramplet", + name="Quick View Gramplet", + tname=_("Quick View Gramplet"), + height=300, + expand=True, + content = QuickViewGramplet, + title=_("Quick View"), + detached_width = 600, + detached_height = 400, + ) + diff --git a/src/plugins/gramplet/RelativeGramplet.py b/src/plugins/gramplet/RelativeGramplet.py new file mode 100644 index 000000000..b66e5dd19 --- /dev/null +++ b/src/plugins/gramplet/RelativeGramplet.py @@ -0,0 +1,150 @@ +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2007-2009 Douglas S. Blank +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# $Id$ + +#------------------------------------------------------------------------ +# +# GRAMPS modules +# +#------------------------------------------------------------------------ +from DataViews import register, Gramplet +from TransUtils import sgettext as _ +from BasicUtils import name_displayer + +#------------------------------------------------------------------------ +# +# Gramplet class +# +#------------------------------------------------------------------------ +class RelativesGramplet(Gramplet): + """ + This gramplet gives a list of clickable relatives of the active person. + Clicking them, changes the active person. + """ + def init(self): + self.set_text(_("No Family Tree loaded.")) + self.set_tooltip(_("Click name to make person active\n") + + _("Right-click name to edit person")) + + def db_changed(self): + """ + If person or family changes, the relatives of active person might have + changed + """ + self.dbstate.db.connect('person-add', self.update) + self.dbstate.db.connect('person-delete', self.update) + self.dbstate.db.connect('family-add', self.update) + self.dbstate.db.connect('family-delete', self.update) + self.dbstate.db.connect('person-rebuild', self.update) + self.dbstate.db.connect('family-rebuild', self.update) + + def active_changed(self, handle): + self.update() + + def main(self): # return false finishes + """ + Generator which will be run in the background. + """ + self.set_text("") + database = self.dbstate.db + active_person = self.dbstate.get_active_person() + if not active_person: + return + name = name_displayer.display(active_person) + self.append_text(_("Active person: %s") % name) + self.append_text("\n\n") + #obtain families + famc = 0 + for family_handle in active_person.get_family_handle_list(): + famc += 1 + family = database.get_family_from_handle(family_handle) + if not family: continue + if active_person.handle == family.get_father_handle(): + spouse_handle = family.get_mother_handle() + else: + spouse_handle = family.get_father_handle() + if spouse_handle: + spouse = database.get_person_from_handle(spouse_handle) + spousename = name_displayer.display(spouse) + text = "%s" % spousename + self.append_text(_("%d. Partner: ") % (famc)) + self.link(text, 'Person', spouse_handle) + self.append_text("\n") + else: + self.append_text(_("%d. Partner: Not known") % (famc)) + self.append_text("\n") + #obtain children + childc = 0 + for child_ref in family.get_child_ref_list(): + childc += 1 + child = database.get_person_from_handle(child_ref.ref) + childname = name_displayer.display(child) + text = "%s" % childname + self.append_text(" %d.%-3d: " % (famc, childc)) + self.link(text, 'Person', child_ref.ref) + self.append_text("\n") + yield True + #obtain parent families + self.append_text("\n") + self.append_text(_("Parents:")) + self.append_text("\n") + famc = 0 + for family_handle in active_person.get_parent_family_handle_list(): + famc += 1 + family = database.get_family_from_handle(family_handle) + mother_handle = family.get_mother_handle() + father_handle = family.get_father_handle() + if mother_handle: + mother = database.get_person_from_handle(mother_handle) + mothername = name_displayer.display(mother) + text = "%s" % mothername + self.append_text(_(" %d.a Mother: ") % (famc)) + self.link(text, 'Person', mother_handle) + self.append_text("\n") + else: + self.append_text(_(" %d.a Mother: ") % (famc)) + self.append_text(_("Unknown")) + self.append_text("\n") + if father_handle: + father = database.get_person_from_handle(father_handle) + fathername = name_displayer.display(father) + text = "%s" % fathername + self.append_text(_(" %d.b Father: ") % (famc)) + self.link(text, 'Person', father_handle) + self.append_text("\n") + else: + self.append_text(_(" %d.b Father: ") % (famc)) + self.append_text(_("Unknown")) + self.append_text("\n") + +#------------------------------------------------------------------------ +# +# Register Gramplet +# +#------------------------------------------------------------------------ +register(type="gramplet", + name="Relatives Gramplet", + tname=_("Relatives Gramplet"), + height=200, + content = RelativesGramplet, + title=_("Relatives"), + detached_width = 250, + detached_height = 300, + ) + diff --git a/src/plugins/gramplet/SessionLogGramplet.py b/src/plugins/gramplet/SessionLogGramplet.py new file mode 100644 index 000000000..9df9880f6 --- /dev/null +++ b/src/plugins/gramplet/SessionLogGramplet.py @@ -0,0 +1,101 @@ +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2007-2009 Douglas S. Blank +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# $Id$ + +#------------------------------------------------------------------------ +# +# GRAMPS modules +# +#------------------------------------------------------------------------ +from DataViews import register, Gramplet +from TransUtils import sgettext as _ +from BasicUtils import name_displayer + +#------------------------------------------------------------------------ +# +# Gramplet class +# +#------------------------------------------------------------------------ +class LogGramplet(Gramplet): + def init(self): + self.set_tooltip(_("Click name to change active\nDouble-click name to edit")) + self.set_text(_("Log for this Session")) + self.gui.force_update = True # will always update, even if minimized + self.last_log = None + self.append_text("\n") + + def db_changed(self): + self.append_text("Opened data base -----------\n") + self.dbstate.db.connect('person-add', + lambda handles: self.log(_('Person'), _('Added'), handles)) + self.dbstate.db.connect('person-delete', + lambda handles: self.log(_('Person'), _('Deleted'), handles)) + self.dbstate.db.connect('person-update', + lambda handles: self.log(_('Person'), _('Edited'), handles)) + self.dbstate.db.connect('family-add', + lambda handles: self.log(_('Family'), _('Added'), handles)) + self.dbstate.db.connect('family-delete', + lambda handles: self.log(_('Family'), _('Deleted'), handles)) + self.dbstate.db.connect('family-update', + lambda handles: self.log(_('Family'), _('Added'), handles)) + + def active_changed(self, handle): + self.log(_('Person'), _('Selected'), [handle]) + + def log(self, ltype, action, handles): + for handle in set(handles): + if self.last_log == (ltype, action, handle): + continue + self.last_log = (ltype, action, handle) + self.append_text("%s: " % action) + if ltype == _("Person"): + person = self.dbstate.db.get_person_from_handle(handle) + name = name_displayer.display(person) + elif ltype == _("Family"): + family = self.dbstate.db.get_family_from_handle(handle) + father_name = _("unknown") + mother_name = _("unknown") + if family: + father_handle = family.get_father_handle() + if father_handle: + father = self.dbstate.db.get_person_from_handle(father_handle) + if father: + father_name = name_displayer.display(father) + mother_handle = family.get_mother_handle() + if mother_handle: + mother = self.dbstate.db.get_person_from_handle(mother_handle) + mother_name = name_displayer.display(mother) + name = _("%s and %s") % (mother_name, father_name) + self.link(name, ltype, handle) + self.append_text("\n") + +#------------------------------------------------------------------------ +# +# Register Gramplet +# +#------------------------------------------------------------------------ +register(type="gramplet", + name="Session Log Gramplet", + tname=_("Session Log Gramplet"), + height=230, + data=['no'], + content = LogGramplet, + title=_("Session Log"), + ) + diff --git a/src/plugins/gramplet/StatsGramplet.py b/src/plugins/gramplet/StatsGramplet.py new file mode 100644 index 000000000..4a3f05dcb --- /dev/null +++ b/src/plugins/gramplet/StatsGramplet.py @@ -0,0 +1,198 @@ +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2007-2009 Douglas S. Blank +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# $Id$ + +#------------------------------------------------------------------------ +# +# Python modules +# +#------------------------------------------------------------------------ +import posixpath + +#------------------------------------------------------------------------ +# +# GRAMPS modules +# +#------------------------------------------------------------------------ +from DataViews import register, Gramplet +from TransUtils import sgettext as _ +from Utils import media_path_full +import DateHandler +import gen + +#------------------------------------------------------------------------ +# +# Gramplet class +# +#------------------------------------------------------------------------ +class StatsGramplet(Gramplet): + def init(self): + self.set_text(_("No Family Tree loaded.")) + self.set_tooltip(_("Double-click item to see matches")) + + def db_changed(self): + self.dbstate.db.connect('person-add', self.update) + self.dbstate.db.connect('person-edit', self.update) + self.dbstate.db.connect('person-delete', self.update) + self.dbstate.db.connect('family-add', self.update) + self.dbstate.db.connect('family-delete', self.update) + self.dbstate.db.connect('person-rebuild', self.update) + self.dbstate.db.connect('family-rebuild', self.update) + + def main(self): + self.set_text(_("Processing...")) + database = self.dbstate.db + personList = database.get_person_handles(sort_handles=False) + familyList = database.get_family_handles() + + with_photos = 0 + total_photos = 0 + incomp_names = 0 + disconnected = 0 + missing_bday = 0 + males = 0 + females = 0 + unknowns = 0 + bytes = 0 + namelist = [] + notfound = [] + + pobjects = len(database.get_media_object_handles()) + for photo_id in database.get_media_object_handles(): + photo = database.get_object_from_handle(photo_id) + fullname = media_path_full(database, photo.get_path()) + try: + bytes = bytes + posixpath.getsize(fullname) + except: + notfound.append(photo.get_path()) + + cnt = 0 + for person_handle in personList: + person = database.get_person_from_handle(person_handle) + if not person: + continue + length = len(person.get_media_list()) + if length > 0: + with_photos = with_photos + 1 + total_photos = total_photos + length + + person = database.get_person_from_handle(person_handle) + names = [person.get_primary_name()] + person.get_alternate_names() + for name in names: + if name.get_first_name() == "" or name.get_group_name() == "": + incomp_names = incomp_names + 1 + if name.get_group_name() not in namelist: + namelist.append(name.get_group_name()) + if ((not person.get_main_parents_family_handle()) and + (not len(person.get_family_handle_list()))): + disconnected = disconnected + 1 + birth_ref = person.get_birth_ref() + if birth_ref: + birth = database.get_event_from_handle(birth_ref.ref) + if not DateHandler.get_date(birth): + missing_bday = missing_bday + 1 + else: + missing_bday = missing_bday + 1 + if person.get_gender() == gen.lib.Person.FEMALE: + females = females + 1 + elif person.get_gender() == gen.lib.Person.MALE: + males = males + 1 + else: + unknowns += 1 + if cnt % 200 == 0: + yield True + cnt += 1 + + self.clear_text() + self.append_text(_("Individuals") + "\n") + self.append_text("----------------------------\n") + self.link(_("Number of individuals") + ":", + 'Filter', 'all people') + self.append_text(" %s" % len(personList)) + self.append_text("\n") + self.link("%s:" % _("Males"), 'Filter', 'males') + self.append_text(" %s" % males) + self.append_text("\n") + self.link("%s:" % _("Females"), 'Filter', 'females') + self.append_text(" %s" % females) + self.append_text("\n") + self.link("%s:" % _("Individuals with unknown gender"), + 'Filter', 'people with unknown gender') + self.append_text(" %s" % unknowns) + self.append_text("\n") + self.link("%s:" % _("Individuals with incomplete names"), + 'Filter', 'people with incomplete names') + self.append_text(" %s" % incomp_names) + self.append_text("\n") + self.link("%s:" % _("Individuals missing birth dates"), + 'Filter', 'people with missing birth dates') + self.append_text(" %s" % missing_bday) + self.append_text("\n") + self.link("%s:" % _("Disconnected individuals"), + 'Filter', 'disconnected people') + self.append_text(" %s" % disconnected) + self.append_text("\n") + self.append_text("\n%s\n" % _("Family Information")) + self.append_text("----------------------------\n") + self.link("%s:" % _("Number of families"), + 'Filter', 'all families') + self.append_text(" %s" % len(familyList)) + self.append_text("\n") + self.link("%s:" % _("Unique surnames"), + 'Filter', 'unique surnames') + self.append_text(" %s" % len(namelist)) + self.append_text("\n") + self.append_text("\n%s\n" % _("Media Objects")) + self.append_text("----------------------------\n") + self.link("%s:" % _("Individuals with media objects"), + 'Filter', 'people with media') + self.append_text(" %s" % with_photos) + self.append_text("\n") + self.link("%s:" % _("Total number of media object references"), + 'Filter', 'media references') + self.append_text(" %s" % total_photos) + self.append_text("\n") + self.link("%s:" % _("Number of unique media objects"), + 'Filter', 'unique media') + self.append_text(" %s" % pobjects) + self.append_text("\n") + + self.link("%s:" % _("Total size of media objects"), + 'Filter', 'media by size') + self.append_text(" %d %s" % (bytes, _("bytes"))) + self.append_text("\n") + self.link("%s:" % _("Missing Media Objects"), + 'Filter', 'missing media') + self.append_text(" %s\n" % len(notfound)) + self.append_text("", scroll_to="begin") + +#------------------------------------------------------------------------ +# +# Register Gramplet +# +#------------------------------------------------------------------------ +register(type="gramplet", + name="Statistics Gramplet", + tname=_("Statistics Gramplet"), + height=230, + expand=True, + content = StatsGramplet, + title=_("Statistics"), + ) + diff --git a/src/plugins/gramplet/SurnameCloudGramplet.py b/src/plugins/gramplet/SurnameCloudGramplet.py new file mode 100644 index 000000000..08d519a0c --- /dev/null +++ b/src/plugins/gramplet/SurnameCloudGramplet.py @@ -0,0 +1,162 @@ +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2007-2009 Douglas S. Blank +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# $Id$ + +#------------------------------------------------------------------------ +# +# GRAMPS modules +# +#------------------------------------------------------------------------ +from DataViews import register, Gramplet +from TransUtils import sgettext as _ +import Config + +#------------------------------------------------------------------------ +# +# Local functions +# +#------------------------------------------------------------------------ +def make_tag_size(n, counts, mins=8, maxs=20): + # return font sizes mins to maxs + diff = maxs - mins + # based on counts (biggest to smallest) + if len(counts) > 1: + position = diff - (diff * (float(counts.index(n)) / (len(counts) - 1))) + else: + position = 0 + return int(position) + mins + +#------------------------------------------------------------------------ +# +# Gramplet class +# +#------------------------------------------------------------------------ +class SurnameCloudGramplet(Gramplet): + def init(self): + self.set_tooltip(_("Double-click surname for details")) + self.top_size = 100 # will be overwritten in load + self.set_text(_("No Family Tree loaded.")) + + def db_changed(self): + self.dbstate.db.connect('person-add', self.update) + self.dbstate.db.connect('person-delete', self.update) + self.dbstate.db.connect('person-update', self.update) + self.dbstate.db.connect('person-rebuild', self.update) + self.dbstate.db.connect('family-rebuild', self.update) + + def on_load(self): + if len(self.gui.data) > 0: + self.top_size = int(self.gui.data[0]) + + def on_save(self): + self.gui.data = [self.top_size] + + def main(self): + self.set_text(_("Processing...") + "\n") + yield True + people = self.dbstate.db.get_person_handles(sort_handles=False) + surnames = {} + representative_handle = {} + cnt = 0 + for person_handle in people: + person = self.dbstate.db.get_person_from_handle(person_handle) + if person: + allnames = [person.get_primary_name()] + person.get_alternate_names() + allnames = set([name.get_group_name().strip() for name in allnames]) + for surname in allnames: + surnames[surname] = surnames.get(surname, 0) + 1 + representative_handle[surname] = person_handle + if cnt % 350 == 0: + yield True + cnt += 1 + total_people = cnt + surname_sort = [] + total = 0 + cnt = 0 + for surname in surnames: + surname_sort.append( (surnames[surname], surname) ) + total += surnames[surname] + if cnt % 350 == 0: + yield True + cnt += 1 + total_surnames = cnt + surname_sort.sort(lambda a,b: -cmp(a,b)) + cloud_names = [] + cloud_values = [] + cnt = 0 + for (count, surname) in surname_sort: + cloud_names.append( (count, surname) ) + cloud_values.append( count ) + cnt += 1 + cloud_names.sort(lambda a,b: cmp(a[1], b[1])) + counts = list(set(cloud_values)) + counts.sort() + counts.reverse() + line = 0 + ### All done! + # Now, find out how many we can display without going over top_size: + totals = {} + for (count, givensubname) in cloud_names: # givensubname_sort: + totals[count] = totals.get(count, 0) + 1 + sums = totals.keys() + sums.sort() + sums.reverse() + total = 0 + include_greater_than = 0 + for s in sums: + if total + totals[s] <= self.top_size: + total += totals[s] + else: + include_greater_than = s + break + # Ok, now we can show those counts > include_greater_than: + showing = 0 + self.set_text("") + for (count, surname) in cloud_names: # surname_sort: + if count > include_greater_than: + if len(surname) == 0: + text = Config.get(Config.NO_SURNAME_TEXT) + else: + text = surname + size = make_tag_size(count, counts) + self.link(text, 'Surname', representative_handle[surname], size, + "%s, %d%% (%d)" % (text, + int((float(count)/total_people) * 100), + count)) + self.append_text(" ") + showing += 1 + self.append_text(("\n\n" + _("Total unique surnames") + ": %d\n") % + total_surnames) + self.append_text((_("Total surnames showing") + ": %d\n") % showing) + self.append_text((_("Total people") + ": %d") % total_people, "begin") + +#------------------------------------------------------------------------ +# +# Register Gramplet +# +#------------------------------------------------------------------------ +register(type="gramplet", + name= "Surname Cloud Gramplet", + tname=_("Surname Cloud Gramplet"), + height=300, + expand=True, + content = SurnameCloudGramplet, + title=_("Surname Cloud"), + ) + diff --git a/src/plugins/gramplet/ToDoGramplet.py b/src/plugins/gramplet/ToDoGramplet.py new file mode 100644 index 000000000..8cd577bf0 --- /dev/null +++ b/src/plugins/gramplet/ToDoGramplet.py @@ -0,0 +1,61 @@ +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2007-2009 Douglas S. Blank +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# $Id$ + +#------------------------------------------------------------------------ +# +# GRAMPS modules +# +#------------------------------------------------------------------------ +from DataViews import register, Gramplet +from TransUtils import sgettext as _ + +#------------------------------------------------------------------------ +# +# Gramplet class +# +#------------------------------------------------------------------------ +class TODOGramplet(Gramplet): + def init(self): + # GUI setup: + self.set_tooltip(_("Enter text")) + self.gui.textview.set_editable(True) + self.append_text(_("Enter your TODO list here.")) + + def on_load(self): + self.load_data_to_text() + + def on_save(self): + self.gui.data = [] # clear out old data + self.save_text_to_data() + +#------------------------------------------------------------------------ +# +# Register Gramplet +# +#------------------------------------------------------------------------ +register(type="gramplet", + name="TODO Gramplet", + tname=_("TODO Gramplet"), + height=300, + expand=True, + content = TODOGramplet, + title=_("TODO List"), + ) + diff --git a/src/plugins/gramplet/TopSurnamesGramplet.py b/src/plugins/gramplet/TopSurnamesGramplet.py new file mode 100644 index 000000000..2714a7dac --- /dev/null +++ b/src/plugins/gramplet/TopSurnamesGramplet.py @@ -0,0 +1,116 @@ +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2007-2009 Douglas S. Blank +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# $Id$ + +#------------------------------------------------------------------------ +# +# GRAMPS modules +# +#------------------------------------------------------------------------ +from DataViews import register, Gramplet +from TransUtils import sgettext as _ +import Config + +#------------------------------------------------------------------------ +# +# Gramplet class +# +#------------------------------------------------------------------------ +class TopSurnamesGramplet(Gramplet): + def init(self): + self.set_tooltip(_("Double-click surname for details")) + self.top_size = 10 # will be overwritten in load + self.set_text(_("No Family Tree loaded.")) + + def db_changed(self): + self.dbstate.db.connect('person-add', self.update) + self.dbstate.db.connect('person-delete', self.update) + self.dbstate.db.connect('person-update', self.update) + self.dbstate.db.connect('person-rebuild', self.update) + self.dbstate.db.connect('family-rebuild', self.update) + + def on_load(self): + if len(self.gui.data) > 0: + self.top_size = int(self.gui.data[0]) + + def on_save(self): + self.gui.data = [self.top_size] + + def main(self): + self.set_text(_("Processing...") + "\n") + people = self.dbstate.db.get_person_handles(sort_handles=False) + surnames = {} + representative_handle = {} + cnt = 0 + for person_handle in people: + person = self.dbstate.db.get_person_from_handle(person_handle) + if person: + allnames = [person.get_primary_name()] + person.get_alternate_names() + allnames = set([name.get_group_name().strip() for name in allnames]) + for surname in allnames: + surnames[surname] = surnames.get(surname, 0) + 1 + representative_handle[surname] = person_handle + if cnt % 350 == 0: + yield True + cnt += 1 + total_people = cnt + surname_sort = [] + total = 0 + cnt = 0 + for surname in surnames: + surname_sort.append( (surnames[surname], surname) ) + total += surnames[surname] + if cnt % 350 == 0: + yield True + cnt += 1 + total_surnames = cnt + surname_sort.sort(lambda a,b: -cmp(a,b)) + line = 0 + ### All done! + self.set_text("") + for (count, surname) in surname_sort: + if len(surname) == 0: + text = "%s, %d%% (%d)\n" % (Config.get(Config.NO_SURNAME_TEXT), + int((float(count)/total) * 100), + count) + else: + text = "%s, %d%% (%d)\n" % (surname, int((float(count)/total) * 100), + count) + self.append_text(" %d. " % (line + 1)) + self.link(text, 'Surname', representative_handle[surname]) + line += 1 + if line >= self.top_size: + break + self.append_text(("\n" + _("Total unique surnames") + ": %d\n") % + total_surnames) + self.append_text((_("Total people") + ": %d") % total_people, "begin") + +#------------------------------------------------------------------------ +# +# Register Gramplet +# +#------------------------------------------------------------------------ +register(type="gramplet", + name= "Top Surnames Gramplet", + tname=_("Top Surnames Gramplet"), + height=230, + content = TopSurnamesGramplet, + title=_("Top Surnames"), + ) + diff --git a/src/plugins/gramplet/WelcomeGramplet.py b/src/plugins/gramplet/WelcomeGramplet.py new file mode 100644 index 000000000..052633b0d --- /dev/null +++ b/src/plugins/gramplet/WelcomeGramplet.py @@ -0,0 +1,73 @@ +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2007-2009 Douglas S. Blank +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# $Id$ + +#------------------------------------------------------------------------ +# +# GRAMPS modules +# +#------------------------------------------------------------------------ +from DataViews import register +from TransUtils import sgettext as _ + +#------------------------------------------------------------------------ +# +# Gramplet class +# +#------------------------------------------------------------------------ +def make_welcome_content(gui): + text = _( + 'Welcome to GRAMPS!\n\n' + 'GRAMPS is a software package designed for genealogical research.' + ' Although similar to other genealogical programs, GRAMPS offers ' + 'some unique and powerful features.\n\n' + 'GRAMPS is an Open Source Software package, which means you are ' + 'free to make copies and distribute it to anyone you like. It\'s ' + 'developed and maintained by a worldwide team of volunteers whose' + ' goal is to make GRAMPS powerful, yet easy to use.\n\n' + 'Getting Started\n\n' + 'The first thing you must do is to create a new Family Tree. To ' + 'create a new Family Tree (sometimes called a database) select ' + '"Family Trees" from the menu, pick "Manage Family Trees", press ' + '"New" and name your database. For more details, please read the ' + 'User Manual, or the on-line manual at http://gramps-project.org.\n\n' + 'You are currently reading from the "Gramplets" page, where you can' + ' add your own gramplets.\n\n' + 'You can right-click on the background of this page to add additional' + ' gramplets and change the number of columns. You can also drag the ' + 'Properties button to reposition the gramplet on this page, and detach' + ' the gramplet to float above GRAMPS. If you close GRAMPS with a gramplet' + ' detached, it will re-open detached the next time you start ' + 'GRAMPS.' + ) + gui.set_text(text) + +#------------------------------------------------------------------------ +# +# Register Gramplet +# +#------------------------------------------------------------------------ +register(type="gramplet", + name="Welcome Gramplet", + tname=_("Welcome Gramplet"), + height=300, + expand=True, + content = make_welcome_content, + title=_("Welcome to GRAMPS!"), + )