# # Gramps - a GTK+/GNOME based genealogy program # # Copyright (C) 2000-2007 Donald N. Allingham # Copyright (C) 2010 Michiel D. Nauta # Copyright (C) 2010 Jakim Friant # # 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$ """ Provide merge capabilities for persons. """ #------------------------------------------------------------------------- # # GTK/Gnome modules # #------------------------------------------------------------------------- import pango #------------------------------------------------------------------------- # # Gramps modules # #------------------------------------------------------------------------- from gen.ggettext import sgettext as _ from gen.plug.report import utils as ReportUtils from gen.display.name import displayer as name_displayer import const from gui.display import display_help import gen.datehandler from Errors import MergeError from gui.dialog import ErrorDialog from gui.managedwindow import ManagedWindow from gen.merge import MergePersonQuery #------------------------------------------------------------------------- # # Gramps constants # #------------------------------------------------------------------------- WIKI_HELP_PAGE = "%s_-_Entering_and_Editing_Data:_Detailed_-_part_3" % \ const.URL_MANUAL_PAGE WIKI_HELP_SEC = _("manual|Merge_People") _GLADE_FILE = "mergeperson.glade" sex = ( _("female"), _("male"), _("unknown") ) def name_of(person): """Return string with name and ID of a person.""" if not person: return "" return "%s [%s]" % (name_displayer.display(person), person.get_gramps_id()) #------------------------------------------------------------------------- # # MergePerson # #------------------------------------------------------------------------- class MergePerson(ManagedWindow): """ Displays a dialog box that allows the persons to be combined into one. """ def __init__(self, dbstate, uistate, handle1, handle2, cb_update=None, expand_context_info=False): ManagedWindow.__init__(self, uistate, [], self.__class__) self.database = dbstate.db self.pr1 = self.database.get_person_from_handle(handle1) self.pr2 = self.database.get_person_from_handle(handle2) self.update = cb_update self.define_glade('mergeperson', _GLADE_FILE) self.set_window(self._gladeobj.toplevel, self.get_widget("person_title"), _("Merge People")) # Detailed selection widgets name1 = name_displayer.display_name(self.pr1.get_primary_name()) name2 = name_displayer.display_name(self.pr2.get_primary_name()) entry1 = self.get_widget("name1") entry2 = self.get_widget("name2") entry1.set_text(name1) entry2.set_text(name2) if entry1.get_text() == entry2.get_text(): for widget_name in ('name1', 'name2', 'name_btn1', 'name_btn2'): self.get_widget(widget_name).set_sensitive(False) entry1 = self.get_widget("gender1") entry2 = self.get_widget("gender2") entry1.set_text(sex[self.pr1.get_gender()]) entry2.set_text(sex[self.pr2.get_gender()]) if entry1.get_text() == entry2.get_text(): for widget_name in ('gender1', 'gender2', 'gender_btn1', 'gender_btn2'): self.get_widget(widget_name).set_sensitive(False) gramps1 = self.pr1.get_gramps_id() gramps2 = self.pr2.get_gramps_id() entry1 = self.get_widget("gramps1") entry2 = self.get_widget("gramps2") entry1.set_text(gramps1) entry2.set_text(gramps2) if entry1.get_text() == entry2.get_text(): for widget_name in ('gramps1', 'gramps2', 'gramps_btn1', 'gramps_btn2'): self.get_widget(widget_name).set_sensitive(False) # Main window widgets that determine which handle survives rbutton1 = self.get_widget("handle_btn1") rbutton_label1 = self.get_widget("label_handle_btn1") rbutton_label2 = self.get_widget("label_handle_btn2") rbutton_label1.set_label(name1 + " [" + gramps1 + "]") rbutton_label2.set_label(name2 + " [" + gramps2 + "]") rbutton1.connect("toggled", self.on_handle1_toggled) expander2 = self.get_widget("expander2") self.expander_handler = expander2.connect("notify::expanded", self.cb_expander2_activated) expander2.set_expanded(expand_context_info) self.connect_button("person_help", self.cb_help) self.connect_button("person_ok", self.cb_merge) self.connect_button("person_cancel", self.close) self.show() def on_handle1_toggled(self, obj): """Preferred person changes""" if obj.get_active(): self.get_widget("name_btn1").set_active(True) self.get_widget("gender_btn1").set_active(True) self.get_widget("gramps_btn1").set_active(True) else: self.get_widget("name_btn2").set_active(True) self.get_widget("gender_btn2").set_active(True) self.get_widget("gramps_btn2").set_active(True) def cb_expander2_activated(self, obj, param_spec): """Context Information expander is activated""" if obj.get_expanded(): text1 = self.get_widget('text1') text2 = self.get_widget('text2') self.display(text1.get_buffer(), self.pr1) self.display(text2.get_buffer(), self.pr2) obj.disconnect(self.expander_handler) def add(self, tobj, tag, text): """Add text text to text buffer tobj with formatting tag.""" text += "\n" tobj.insert_with_tags(tobj.get_end_iter(), text, tag) def display(self, tobj, person): """Fill text buffer tobj with detailed info on person person.""" normal = tobj.create_tag() normal.set_property('indent', 10) normal.set_property('pixels-above-lines', 1) normal.set_property('pixels-below-lines', 1) indent = tobj.create_tag() indent.set_property('indent', 30) indent.set_property('pixels-above-lines', 1) indent.set_property('pixels-below-lines', 1) title = tobj.create_tag() title.set_property('weight', pango.WEIGHT_BOLD) title.set_property('scale', pango.SCALE_LARGE) self.add(tobj, title, name_displayer.display(person)) self.add(tobj, normal, "%s:\t%s" % (_('ID'), person.get_gramps_id())) self.add(tobj, normal, "%s:\t%s" % (_('Gender'), sex[person.get_gender()])) bref = person.get_birth_ref() if bref: self.add(tobj, normal, "%s:\t%s" % (_('Birth'), self.get_event_info(bref.ref))) dref = person.get_death_ref() if dref: self.add(tobj, normal, "%s:\t%s" % (_('Death'), self.get_event_info(dref.ref))) nlist = person.get_alternate_names() if len(nlist) > 0: self.add(tobj, title, _("Alternate Names")) for name in nlist: self.add(tobj, normal, name_displayer.display_name(name)) elist = person.get_event_ref_list() if len(elist) > 0: self.add(tobj, title, _("Events")) for event_ref in person.get_event_ref_list(): event_handle = event_ref.ref role = event_ref.get_role() name = str( self.database.get_event_from_handle(event_handle).get_type()) if role.is_primary(): self.add(tobj, normal, "%s:\t%s" % (name, self.get_event_info(event_handle))) else: self.add(tobj, normal, "%s (%s):\t%s" % (name, role, self.get_event_info(event_handle))) plist = person.get_parent_family_handle_list() if len(plist) > 0: self.add(tobj, title, _("Parents")) for fid in person.get_parent_family_handle_list(): (fname, mname, gid) = self.get_parent_info(fid) self.add(tobj, normal, "%s:\t%s" % (_('Family ID'), gid)) if fname: self.add(tobj, indent, "%s:\t%s" % (_('Father'), fname)) if mname: self.add(tobj, indent, "%s:\t%s" % (_('Mother'), mname)) else: self.add(tobj, normal, _("No parents found")) self.add(tobj, title, _("Spouses")) slist = person.get_family_handle_list() if len(slist) > 0: for fid in slist: (fname, mname, pid) = self.get_parent_info(fid) family = self.database.get_family_from_handle(fid) self.add(tobj, normal, "%s:\t%s" % (_('Family ID'), pid)) spouse_id = ReportUtils.find_spouse(person, family) if spouse_id: spouse = self.database.get_person_from_handle(spouse_id) self.add(tobj, indent, "%s:\t%s" % (_('Spouse'), name_of(spouse))) relstr = str(family.get_relationship()) self.add(tobj, indent, "%s:\t%s" % (_('Type'), relstr)) event = ReportUtils.find_marriage(self.database, family) if event: self.add(tobj, indent, "%s:\t%s" % ( _('Marriage'), self.get_event_info(event.get_handle()))) for child_ref in family.get_child_ref_list(): child = self.database.get_person_from_handle(child_ref.ref) self.add(tobj, indent, "%s:\t%s" % (_('Child'), name_of(child))) else: self.add(tobj, normal, _("No spouses or children found")) alist = person.get_address_list() if len(alist) > 0: self.add(tobj, title, _("Addresses")) for addr in alist: location = ", ".join([addr.get_street(), addr.get_city(), addr.get_state(), addr.get_country(), addr.get_postal_code(), addr.get_phone()]) self.add(tobj, normal, location.strip()) def get_parent_info(self, fid): """Return tuple of father name, mother name and family ID""" family = self.database.get_family_from_handle(fid) father_id = family.get_father_handle() mother_id = family.get_mother_handle() if father_id: father = self.database.get_person_from_handle(father_id) fname = name_of(father) else: fname = u"" if mother_id: mother = self.database.get_person_from_handle(mother_id) mname = name_of(mother) else: mname = u"" return (fname, mname, family.get_gramps_id()) def get_event_info(self, handle): """Return date and place of an event as string.""" date = "" place = "" if handle: event = self.database.get_event_from_handle(handle) date = gen.datehandler.get_date(event) place = self.place_name(event) if date: return ("%s, %s" % (date, place)) if place else date else: return place or "" else: return "" def place_name(self, event): """Return place name of an event as string.""" place_id = event.get_place_handle() if place_id: place = self.database.get_place_from_handle(place_id) return place.get_title() else: return "" def cb_help(self, obj): """Display the relevant portion of Gramps manual""" display_help(webpage = WIKI_HELP_PAGE, section = WIKI_HELP_SEC) def cb_merge(self, obj): """ Perform the merge of the persons when the merge button is clicked. """ self.uistate.set_busy_cursor(True) use_handle1 = self.get_widget("handle_btn1").get_active() if use_handle1: phoenix = self.pr1 titanic = self.pr2 else: phoenix = self.pr2 titanic = self.pr1 # Add second handle to history so that when merge is complete, # phoenix is the selected row. self.uistate.viewmanager.active_page.get_history().push( phoenix.get_handle()) if self.get_widget("name_btn1").get_active() ^ use_handle1: swapname = phoenix.get_primary_name() phoenix.set_primary_name(titanic.get_primary_name()) titanic.set_primary_name(swapname) if self.get_widget("gender_btn1").get_active() ^ use_handle1: phoenix.set_gender(titanic.get_gender()) if self.get_widget("gramps_btn1").get_active() ^ use_handle1: swapid = phoenix.get_gramps_id() phoenix.set_gramps_id(titanic.get_gramps_id()) titanic.set_gramps_id(swapid) try: query = MergePersonQuery(self.database, phoenix, titanic) query.execute() except MergeError, err: ErrorDialog( _("Cannot merge people"), str(err)) self.uistate.set_busy_cursor(False) self.close() if self.update: self.update()