diff --git a/configure.in b/configure.in index ecaae5e11..dcd277923 100644 --- a/configure.in +++ b/configure.in @@ -110,6 +110,7 @@ src/gen/filters/rules/repository/Makefile src/gen/filters/rules/note/Makefile src/gen/filters/rules/citation/Makefile src/gen/lib/Makefile +src/gen/merge/Makefile src/gen/mime/Makefile src/gen/plug/Makefile src/gen/plug/docbackend/Makefile @@ -124,6 +125,7 @@ src/gui/editors/displaytabs/Makefile src/gui/filters/Makefile src/gui/filters/sidebar/Makefile src/gui/glade/Makefile +src/gui/merge/Makefile src/gui/plug/Makefile src/gui/plug/report/Makefile src/gui/selectors/Makefile @@ -131,7 +133,6 @@ src/gui/views/Makefile src/gui/views/treemodels/Makefile src/gui/widgets/Makefile src/GrampsLogger/Makefile -src/Merge/Makefile src/docgen/Makefile src/Simple/Makefile src/GrampsLocale/Makefile diff --git a/po/POTFILES.in b/po/POTFILES.in index 179698a1b..8b6f0e2d3 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -294,6 +294,17 @@ src/gen/lib/srcmediatype.py src/gen/lib/surnamebase.py src/gen/lib/urltype.py +# gen.merge package +src/gen/merge/mergecitationquery.py +src/gen/merge/mergeeventquery.py +src/gen/merge/mergefamilyquery.py +src/gen/merge/mergemediaquery.py +src/gen/merge/mergenotequery.py +src/gen/merge/mergepersonquery.py +src/gen/merge/mergeplacequery.py +src/gen/merge/mergerepositoryquery.py +src/gen/merge/mergesourcequery.py + # gen mime API src/gen/mime/_gnomemime.py src/gen/mime/_pythonmime.py @@ -396,6 +407,17 @@ src/gui/filters/sidebar/_mediasidebarfilter.py src/gui/filters/sidebar/_reposidebarfilter.py src/gui/filters/sidebar/_notesidebarfilter.py +# gui.merge package +src/gui/merge/mergecitation.py +src/gui/merge/mergeevent.py +src/gui/merge/mergefamily.py +src/gui/merge/mergemedia.py +src/gui/merge/mergenote.py +src/gui/merge/mergeperson.py +src/gui/merge/mergeplace.py +src/gui/merge/mergerepository.py +src/gui/merge/mergesource.py + # gui plugin API (was PluginUtils and ReportBase) src/gui/plug/_dialogs.py src/gui/plug/_guioptions.py @@ -451,20 +473,6 @@ src/Simple/_SimpleTable.py # Config package src/config.py -# Merge package -src/Merge/mergecitation.py -src/Merge/mergeevent.py -src/Merge/mergefamily.py -src/Merge/mergemedia.py -src/Merge/mergenote.py -src/Merge/mergeperson.py -src/Merge/mergeplace.py -src/Merge/mergerepository.py -src/Merge/mergesource.py -#src/Merge/_MergePerson.py -#src/Merge/_MergePlace.py -#src/Merge/_MergeSource.py - # docgen directory src/docgen/ODSTab.py src/docgen/TextBufDoc.py diff --git a/po/POTFILES.skip b/po/POTFILES.skip index bc113bf6c..9363739e0 100644 --- a/po/POTFILES.skip +++ b/po/POTFILES.skip @@ -162,6 +162,10 @@ src/gen/lib/url.py src/gen/lib/urlbase.py src/gen/lib/witness.py +# gen.merge package +src/gen/merge/__init__.py +src/gen/merge/test/merge_ref_test.py + # gen mime API src/gen/mime/__init__.py src/gen/mime/_winmime.py @@ -264,6 +268,9 @@ src/gui/filters/_filtercombobox.py src/gui/filters/_filtermenu.py src/gui/filters/__init__.py +# gui.merge package +src/gui/merge/__init__.py + # gui/selectors - the GUI selectors package src/gui/selectors/__init__.py src/gui/selectors/baseselector.py @@ -294,10 +301,6 @@ src/guiQML/views/centralview.py src/guiQML/views/personview.py src/guiQML/views/dbman.py -# Merge package -src/Merge/__init__.py -src/Merge/test/merge_ref_test.py - # plugins gpr directory src/plugins/sidebar/sidebar.gpr.py diff --git a/src/Makefile.am b/src/Makefile.am index 3004380ea..3cdaaf580 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -10,7 +10,6 @@ SUBDIRS = \ GrampsLogger \ gui \ images \ - Merge \ plugins \ Simple diff --git a/src/gen/Makefile.am b/src/gen/Makefile.am index e98a3a5dd..e7d5a6a91 100644 --- a/src/gen/Makefile.am +++ b/src/gen/Makefile.am @@ -10,6 +10,7 @@ SUBDIRS = \ display \ filters \ lib \ + merge \ mime \ plug \ proxy \ diff --git a/src/gen/__init__.py b/src/gen/__init__.py index 664733cf1..8d2991c12 100644 --- a/src/gen/__init__.py +++ b/src/gen/__init__.py @@ -26,5 +26,5 @@ The gen module provides packages that are common to all gramps interfaces (gui, cli and web). """ -__all__ = [ "datehandler", "db", "display", "filters", "lib", "mime", "plug", - "proxy", "utils" ] +__all__ = [ "datehandler", "db", "display", "filters", "lib", "merge", "mime", + "plug", "proxy", "utils" ] diff --git a/src/gen/merge/Makefile.am b/src/gen/merge/Makefile.am new file mode 100644 index 000000000..7d71f25e8 --- /dev/null +++ b/src/gen/merge/Makefile.am @@ -0,0 +1,30 @@ +# This is the src/RelLib level Makefile for Gramps +# $Id: Makefile.am 18851 2012-02-10 20:25:15Z josipsf $ +# We could use GNU make's ':=' syntax for nice wildcard use, +# but that is not necessarily portable. +# If not using GNU make, then list all .py files individually + +pkgpythondir = $(datadir)/@PACKAGE@/gen/merge + +pkgpython_PYTHON = \ + __init__.py \ + mergepersonquery.py \ + mergefamilyquery.py \ + mergeeventquery.py \ + mergeplacequery.py \ + mergesourcequery.py \ + mergecitationquery.py \ + mergerepositoryquery.py \ + mergemediaquery.py \ + mergenotequery.py + +pkgpyexecdir = @pkgpyexecdir@/gen/merge + +# Clean up all the byte-compiled files +MOSTLYCLEANFILES = *pyc *pyo + +GRAMPS_PY_MODPATH = "../../" + +pycheck: + (export PYTHONPATH=$(GRAMPS_PY_MODPATH); \ + pychecker $(pkgpython_PYTHON)); diff --git a/src/gen/merge/__init__.py b/src/gen/merge/__init__.py new file mode 100644 index 000000000..62d96a205 --- /dev/null +++ b/src/gen/merge/__init__.py @@ -0,0 +1,35 @@ +# +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2004-2006 Donald N. Allingham +# Copyright (C) 2011 Tim G L Lyons +# +# 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$ + +""" +""" + +from mergepersonquery import * +from mergefamilyquery import * +from mergeeventquery import * +from mergeplacequery import * +from mergesourcequery import * +from mergecitationquery import * +from mergerepositoryquery import * +from mergemediaquery import * +from mergenotequery import * diff --git a/src/gen/merge/mergecitationquery.py b/src/gen/merge/mergecitationquery.py new file mode 100644 index 000000000..7509099ad --- /dev/null +++ b/src/gen/merge/mergecitationquery.py @@ -0,0 +1,99 @@ +# +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2000-2005 Donald N. Allingham +# Copyright (C) 2011 Tim G L Lyons +# +# 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 citations. +""" + +#------------------------------------------------------------------------- +# +# Gramps modules +# +#------------------------------------------------------------------------- +from gen.lib import (Person, Family, Event, Place, MediaObject, Repository) +from gen.db import DbTxn +from gen.ggettext import sgettext as _ +from Errors import MergeError + +#------------------------------------------------------------------------- +# +# MergeCitationQuery +# +#------------------------------------------------------------------------- +class MergeCitationQuery(object): + """ + Create database query to merge two citations. + """ + def __init__(self, dbstate, phoenix, titanic): + self.database = dbstate.db + self.phoenix = phoenix + self.titanic = titanic + + def execute(self): + """ + Merges to citations into a single citation. + """ + new_handle = self.phoenix.get_handle() + old_handle = self.titanic.get_handle() + + self.phoenix.merge(self.titanic) + + with DbTxn(_("Merge Citation"), self.database) as trans: + self.database.commit_citation(self.phoenix, trans) + for (class_name, handle) in self.database.find_backlink_handles( + old_handle): + if class_name == Person.__name__: + person = self.database.get_person_from_handle(handle) + assert(person.has_citation_reference(old_handle)) + person.replace_citation_references(old_handle, new_handle) + self.database.commit_person(person, trans) + elif class_name == Family.__name__: + family = self.database.get_family_from_handle(handle) + assert(family.has_citation_reference(old_handle)) + family.replace_citation_references(old_handle, new_handle) + self.database.commit_family(family, trans) + elif class_name == Event.__name__: + event = self.database.get_event_from_handle(handle) + assert(event.has_citation_reference(old_handle)) + event.replace_citation_references(old_handle, new_handle) + self.database.commit_event(event, trans) + elif class_name == Place.__name__: + place = self.database.get_place_from_handle(handle) + assert(place.has_citation_reference(old_handle)) + place.replace_citation_references(old_handle, new_handle) + self.database.commit_place(place, trans) + elif class_name == MediaObject.__name__: + obj = self.database.get_object_from_handle(handle) + assert(obj.has_citation_reference(old_handle)) + obj.replace_citation_references(old_handle, new_handle) + self.database.commit_media_object(obj, trans) + elif class_name == Repository.__name__: + repository = self.database.get_repository_from_handle(handle) + assert(repository.has_citation_reference(old_handle)) + repository.replace_citation_references(old_handle, + new_handle) + self.database.commit_repository(repository, trans) + else: + raise MergeError("Encounter an object of type %s that has " + "a citation reference." % class_name) + self.database.remove_citation(old_handle, trans) diff --git a/src/gen/merge/mergeeventquery.py b/src/gen/merge/mergeeventquery.py new file mode 100644 index 000000000..23a05b1e3 --- /dev/null +++ b/src/gen/merge/mergeeventquery.py @@ -0,0 +1,95 @@ +# +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2010 Michiel D. Nauta +# +# 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 events. +""" + +#------------------------------------------------------------------------- +# +# Gramps modules +# +#------------------------------------------------------------------------- +from gen.lib import Person, Family +from gen.db import DbTxn +from gen.ggettext import sgettext as _ +from Errors import MergeError + +#------------------------------------------------------------------------- +# +# MergeEventQuery +# +#------------------------------------------------------------------------- +class MergeEventQuery(object): + """ + Create database query to merge two events. + """ + def __init__(self, dbstate, phoenix, titanic): + self.database = dbstate.db + self.phoenix = phoenix + self.titanic = titanic + + def execute(self): + """ + Merges two events into a single event. + """ + new_handle = self.phoenix.get_handle() + old_handle = self.titanic.get_handle() + + self.phoenix.merge(self.titanic) + + with DbTxn(_("Merge Event Objects"), self.database) as trans: + self.database.commit_event(self.phoenix, trans) + for (class_name, handle) in self.database.find_backlink_handles( + old_handle): + if class_name == Person.__name__: + person = self.database.get_person_from_handle(handle) + assert(person.has_handle_reference("Event", old_handle)) + bri = person.birth_ref_index + dri = person.death_ref_index + person.replace_handle_reference("Event", old_handle, + new_handle) + if person.birth_ref_index != bri and \ + person.birth_ref_index == -1: + for index, ref in enumerate(person.get_event_ref_list()): + event = self.database.get_event_from_handle(ref.ref) + if event.type.is_birth() and ref.role.is_primary(): + person.birth_ref_index = index + break + if person.death_ref_index != dri and \ + person.death_ref_index == -1: + for index, ref in enumerate(person.get_event_ref_list()): + event = self.database.get_event_from_handle(ref.ref) + if event.type.is_death() and ref.role.is_primary(): + person.death_ref_index = index + break + self.database.commit_person(person, trans) + elif class_name == Family.__name__: + family = self.database.get_family_from_handle(handle) + assert(family.has_handle_reference("Event", old_handle)) + family.replace_handle_reference("Event", old_handle, + new_handle) + self.database.commit_family(family, trans) + else: + raise MergeError("Encounter an object of type %s that has " + "an event reference." % class_name) + self.database.remove_event(old_handle, trans) diff --git a/src/gen/merge/mergefamilyquery.py b/src/gen/merge/mergefamilyquery.py new file mode 100644 index 000000000..275dd5450 --- /dev/null +++ b/src/gen/merge/mergefamilyquery.py @@ -0,0 +1,175 @@ +# +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2010 Michiel D. Nauta +# +# 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 families. +""" + +#------------------------------------------------------------------------- +# +# Gramps modules +# +#------------------------------------------------------------------------- +from gen.db import DbTxn +from gen.ggettext import sgettext as _ +from Errors import MergeError +from gen.merge import MergePersonQuery + +#------------------------------------------------------------------------- +# +# MergeFamilyQuery +# +#------------------------------------------------------------------------- +class MergeFamilyQuery(object): + """ + Create database query to merge two families. + """ + def __init__(self, database, phoenix, titanic, phoenix_fh=None, + phoenix_mh=None): + self.database = database + self.phoenix = phoenix + self.titanic = titanic + if phoenix_fh is None: + self.phoenix_fh = self.phoenix.get_father_handle() + else: + self.phoenix_fh = phoenix_fh + if phoenix_mh is None: + self.phoenix_mh = self.phoenix.get_mother_handle() + else: + self.phoenix_mh = phoenix_mh + + if self.phoenix.get_father_handle() == self.phoenix_fh: + self.titanic_fh = self.titanic.get_father_handle() + self.father_swapped = False + else: + assert self.phoenix_fh == self.titanic.get_father_handle() + self.titanic_fh = self.phoenix.get_father_handle() + self.father_swapped = True + if self.phoenix.get_mother_handle() == self.phoenix_mh: + self.titanic_mh = self.titanic.get_mother_handle() + self.mother_swapped = False + else: + assert self.phoenix_mh == self.titanic.get_mother_handle() + self.titanic_mh = self.phoenix.get_mother_handle() + self.mother_swapped = True + + def merge_person(self, phoenix_person, titanic_person, parent, trans): + """ + Merge two persons even if they are None; no families are merged! + """ + new_handle = self.phoenix.get_handle() + old_handle = self.titanic.get_handle() + + if parent == 'father': + swapped = self.father_swapped + family_add_person_handle = ( + (self.phoenix if swapped else self.titanic).set_father_handle) + elif parent == 'mother': + swapped = self.mother_swapped + family_add_person_handle = ( + (self.phoenix if swapped else self.titanic).set_mother_handle) + else: + raise ValueError(_("A parent should be a father or mother.")) + + if phoenix_person is None: + if titanic_person is not None: + raise MergeError("""When merging people where one person """ + """doesn't exist, that "person" must be the person that """ + """will be deleted from the database.""") + return + elif titanic_person is None: + if swapped: + if any(childref.get_reference_handle() == phoenix_person.get_handle() + for childref in self.phoenix.get_child_ref_list()): + + raise MergeError(_("A parent and child cannot be merged. " + "To merge these people, you must first break the " + "relationship between them.")) + + phoenix_person.add_family_handle(new_handle) + family_add_person_handle(phoenix_person.get_handle()) + self.database.commit_family(self.phoenix, trans) + else: + if any(childref.get_reference_handle() == phoenix_person.get_handle() + for childref in self.titanic.get_child_ref_list()): + + raise MergeError(_("A parent and child cannot be merged. " + "To merge these people, you must first break the " + "relationship between them.")) + + phoenix_person.add_family_handle(old_handle) + family_add_person_handle(phoenix_person.get_handle()) + self.database.commit_family(self.titanic, trans) + + self.database.commit_person(phoenix_person, trans) + else: + query = MergePersonQuery(self.database, phoenix_person, + titanic_person) + query.execute(family_merger=False, trans=trans) + + def execute(self): + """ + Merges two families into a single family. + """ + new_handle = self.phoenix.get_handle() + old_handle = self.titanic.get_handle() + + with DbTxn(_('Merge Family'), self.database) as trans: + + phoenix_father = self.database.get_person_from_handle(self.phoenix_fh) + titanic_father = self.database.get_person_from_handle(self.titanic_fh) + self.merge_person(phoenix_father, titanic_father, 'father', trans) + + phoenix_mother = self.database.get_person_from_handle(self.phoenix_mh) + titanic_mother = self.database.get_person_from_handle(self.titanic_mh) + self.phoenix = self.database.get_family_from_handle(new_handle) + self.titanic = self.database.get_family_from_handle(old_handle) + self.merge_person(phoenix_mother, titanic_mother, 'mother', trans) + + phoenix_father = self.database.get_person_from_handle(self.phoenix_fh) + phoenix_mother = self.database.get_person_from_handle(self.phoenix_mh) + self.phoenix = self.database.get_family_from_handle(new_handle) + self.titanic = self.database.get_family_from_handle(old_handle) + self.phoenix.merge(self.titanic) + self.database.commit_family(self.phoenix, trans) + for childref in self.titanic.get_child_ref_list(): + child = self.database.get_person_from_handle( + childref.get_reference_handle()) + if new_handle in child.parent_family_list: + child.remove_handle_references('Family', [old_handle]) + else: + child.replace_handle_reference('Family', old_handle, + new_handle) + self.database.commit_person(child, trans) + if phoenix_father: + phoenix_father.remove_family_handle(old_handle) + self.database.commit_person(phoenix_father, trans) + if phoenix_mother: + phoenix_mother.remove_family_handle(old_handle) + self.database.commit_person(phoenix_mother, trans) + # replace the family in lds ordinances + for (dummy, person_handle) in self.database.find_backlink_handles( + old_handle, ['Person']): + person = self.database.get_person_from_handle(person_handle) + person.replace_handle_reference('Family', old_handle,new_handle) + self.database.commit_person(person, trans) + self.database.remove_family(old_handle, trans) diff --git a/src/gen/merge/mergemediaquery.py b/src/gen/merge/mergemediaquery.py new file mode 100644 index 000000000..2648ee250 --- /dev/null +++ b/src/gen/merge/mergemediaquery.py @@ -0,0 +1,97 @@ +# +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2010 Michiel D. Nauta +# +# 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 media objects. +""" + +#------------------------------------------------------------------------- +# +# Gramps modules +# +#------------------------------------------------------------------------- +from gen.lib import Person, Family, Event, Source, Citation, Place +from gen.db import DbTxn +from gen.ggettext import sgettext as _ +from Errors import MergeError + +#------------------------------------------------------------------------- +# +# MergeMediaQuery +# +#------------------------------------------------------------------------- +class MergeMediaQuery(object): + """ + Create datqabase query to merge two media objects. + """ + def __init__(self, dbstate, phoenix, titanic): + self.database = dbstate.db + self.phoenix = phoenix + self.titanic = titanic + + def execute(self): + """ + Merges two media objects into a single object. + """ + new_handle = self.phoenix.get_handle() + old_handle = self.titanic.get_handle() + + self.phoenix.merge(self.titanic) + + with DbTxn(_("Merge Media Objects"), self.database) as trans: + self.database.commit_media_object(self.phoenix, trans) + for (class_name, handle) in self.database.find_backlink_handles( + old_handle): + if class_name == Person.__name__: + person = self.database.get_person_from_handle(handle) + assert(person.has_media_reference(old_handle)) + person.replace_media_references(old_handle, new_handle) + self.database.commit_person(person, trans) + elif class_name == Family.__name__: + family = self.database.get_family_from_handle(handle) + assert(family.has_media_reference(old_handle)) + family.replace_media_references(old_handle, new_handle) + self.database.commit_family(family, trans) + elif class_name == Event.__name__: + event = self.database.get_event_from_handle(handle) + assert(event.has_media_reference(old_handle)) + event.replace_media_references(old_handle, new_handle) + self.database.commit_event(event, trans) + elif class_name == Source.__name__: + source = self.database.get_source_from_handle(handle) + assert(source.has_media_reference(old_handle)) + source.replace_media_references(old_handle, new_handle) + self.database.commit_source(source, trans) + elif class_name == Citation.__name__: + citation = self.database.get_citation_from_handle(handle) + assert(citation.has_media_reference(old_handle)) + citation.replace_media_references(old_handle, new_handle) + self.database.commit_citation(citation, trans) + elif class_name == Place.__name__: + place = self.database.get_place_from_handle(handle) + assert(place.has_media_reference(old_handle)) + place.replace_media_references(old_handle, new_handle) + self.database.commit_place(place, trans) + else: + raise MergeError("Encounter an object of type % s that has " + "a media object reference." % class_name) + self.database.remove_object(old_handle, trans) diff --git a/src/gen/merge/mergenotequery.py b/src/gen/merge/mergenotequery.py new file mode 100644 index 000000000..59b8a8496 --- /dev/null +++ b/src/gen/merge/mergenotequery.py @@ -0,0 +1,106 @@ +# +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2010 Michiel D. Nauta +# +# 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 notes. +""" + +#------------------------------------------------------------------------- +# +# Gramps modules +# +#------------------------------------------------------------------------- +from gen.lib import (Person, Family, Event, Place, Source, Citation, Repository, + MediaObject) +from gen.db import DbTxn +from gen.ggettext import sgettext as _ +from Errors import MergeError + +#------------------------------------------------------------------------- +# +# MergeNoteQuery +# +#------------------------------------------------------------------------- +class MergeNoteQuery(object): + """ + Create database query to merge two notes. + """ + def __init__(self, dbstate, phoenix, titanic): + self.database = dbstate.db + self.phoenix = phoenix + self.titanic = titanic + + def execute(self): + """ + Merges two notes into a single note. + """ + new_handle = self.phoenix.get_handle() + old_handle = self.titanic.get_handle() + self.phoenix.merge(self.titanic) + with DbTxn(_("Merge Notes"), self.database) as trans: + self.database.commit_note(self.phoenix, trans) + for (class_name, handle) in self.database.find_backlink_handles( + old_handle): + if class_name == Person.__name__: + person = self.database.get_person_from_handle(handle) + assert(person.has_note_reference(old_handle)) + person.replace_note_references(old_handle, new_handle) + self.database.commit_person(person, trans) + elif class_name == Family.__name__: + family = self.database.get_family_from_handle(handle) + assert(family.has_note_reference(old_handle)) + family.replace_note_references(old_handle, new_handle) + self.database.commit_family(family, trans) + elif class_name == Event.__name__: + event = self.database.get_event_from_handle(handle) + assert(event.has_note_reference(old_handle)) + event.replace_note_references(old_handle, new_handle) + self.database.commit_event(event, trans) + elif class_name == Source.__name__: + source = self.database.get_source_from_handle(handle) + assert(source.has_note_reference(old_handle)) + source.replace_note_references(old_handle, new_handle) + self.database.commit_source(source, trans) + elif class_name == Citation.__name__: + citation = self.database.get_citation_from_handle(handle) + assert(citation.has_note_reference(old_handle)) + citation.replace_note_references(old_handle, new_handle) + self.database.commit_citation(citation, trans) + elif class_name == Place.__name__: + place = self.database.get_place_from_handle(handle) + assert(place.has_note_reference(old_handle)) + place.replace_note_references(old_handle, new_handle) + self.database.commit_place(place, trans) + elif class_name == MediaObject.__name__: + obj = self.database.get_object_from_handle(handle) + assert(obj.has_note_reference(old_handle)) + obj.replace_note_references(old_handle, new_handle) + self.database.commit_media_object(obj, trans) + elif class_name == Repository.__name__: + repo = self.database.get_repository_from_handle(handle) + assert(repo.has_note_reference(old_handle)) + repo.replace_note_references(old_handle, new_handle) + self.database.commit_repository(repo, trans) + else: + raise MergeError("Encounter object of type %s that has " + "a note reference." % class_name) + self.database.remove_note(old_handle, trans) diff --git a/src/gen/merge/mergepersonquery.py b/src/gen/merge/mergepersonquery.py new file mode 100644 index 000000000..95882b7d8 --- /dev/null +++ b/src/gen/merge/mergepersonquery.py @@ -0,0 +1,178 @@ +# +# 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. +""" + +#------------------------------------------------------------------------- +# +# Gramps modules +# +#------------------------------------------------------------------------- +from gen.db import DbTxn +from gen.ggettext import sgettext as _ +from Errors import MergeError + +#------------------------------------------------------------------------- +# +# MergePersonQuery +# +#------------------------------------------------------------------------- +class MergePersonQuery(object): + """ + Create database query to merge two persons. + """ + def __init__(self, database, phoenix, titanic): + self.database = database + self.phoenix = phoenix + self.titanic = titanic + if self.check_for_spouse(self.phoenix, self.titanic): + raise MergeError(_("Spouses cannot be merged. To merge these " + "people, you must first break the relationship between them.")) + if self.check_for_child(self.phoenix, self.titanic): + raise MergeError(_("A parent and child cannot be merged. To merge " + "these people, you must first break the relationship between " + "them.")) + + def check_for_spouse(self, person1, person2): + """Return if person1 and person2 are spouses of eachother.""" + fs1 = set(person1.get_family_handle_list()) + fs2 = set(person2.get_family_handle_list()) + return len(fs1.intersection(fs2)) != 0 + + def check_for_child(self, person1, person2): + """Return if person1 and person2 have a child-parent relationship.""" + fs1 = set(person1.get_family_handle_list()) + fp1 = set(person1.get_parent_family_handle_list()) + fs2 = set(person2.get_family_handle_list()) + fp2 = set(person2.get_parent_family_handle_list()) + return len(fs1.intersection(fp2)) != 0 or len(fs2.intersection(fp1)) + + def merge_families(self, main_family_handle, family, trans): + """ + Merge content of family into the family with handle main_family_handle. + """ + new_handle = self.phoenix.get_handle() if self.phoenix else None + old_handle = self.titanic.get_handle() if self.titanic else None + family_handle = family.get_handle() + main_family = self.database.get_family_from_handle(main_family_handle) + main_family.merge(family) + for childref in family.get_child_ref_list(): + child = self.database.get_person_from_handle( + childref.get_reference_handle()) + if main_family_handle in child.parent_family_list: + child.remove_handle_references('Family', [family_handle]) + else: + child.replace_handle_reference('Family', family_handle, + main_family_handle) + self.database.commit_person(child, trans) + if self.phoenix: + self.phoenix.remove_family_handle(family_handle) + self.database.commit_person(self.phoenix, trans) + family_father_handle = family.get_father_handle() + spouse_handle = family.get_mother_handle() if \ + new_handle == family_father_handle else family_father_handle + spouse = self.database.get_person_from_handle(spouse_handle) + if spouse: + spouse.remove_family_handle(family_handle) + self.database.commit_person(spouse, trans) + # replace the family in lds ordinances + for (dummy, person_handle) in self.database.find_backlink_handles( + family_handle, ['Person']): + if person_handle == old_handle: + continue + person = self.database.get_person_from_handle(person_handle) + person.replace_handle_reference('Family', family_handle, + main_family_handle) + self.database.commit_person(person, trans) + self.database.remove_family(family_handle, trans) + self.database.commit_family(main_family, trans) + + def execute(self, family_merger=True, trans=None): + """ + Merges two persons into a single person. + """ + if trans is None: + with DbTxn(_('Merge Person'), self.database) as trans: + self.__execute(family_merger, trans) + else: + self.__execute(family_merger, trans) + + def __execute(self, family_merger, trans): + """ + Merges two persons into a single person; trans is compulsory. + """ + new_handle = self.phoenix.get_handle() + old_handle = self.titanic.get_handle() + + self.phoenix.merge(self.titanic) + self.database.commit_person(self.phoenix, trans) + + for (dummy, person_handle) in self.database.find_backlink_handles( + old_handle, ['Person']): + person = self.database.get_person_from_handle(person_handle) + assert person.has_handle_reference('Person', old_handle) + person.replace_handle_reference('Person', old_handle, new_handle) + if person_handle != old_handle: + self.database.commit_person(person, trans) + + for family_handle in self.phoenix.get_parent_family_handle_list(): + family = self.database.get_family_from_handle(family_handle) + if family.has_handle_reference('Person', old_handle): + family.replace_handle_reference('Person', old_handle,new_handle) + self.database.commit_family(family, trans) + + family_merge_guard = False + parent_list = [] + parent_list_orig = [] + family_handle_list = self.phoenix.get_family_handle_list()[:] + for family_handle in family_handle_list: + family = self.database.get_family_from_handle(family_handle) + parents = (family.get_father_handle(), family.get_mother_handle()) + parent_list_orig.append(parents) + if family.has_handle_reference('Person', old_handle): + if family_merger and parent_list_orig.count(parents) > 1: + raise MergeError(_("A person with multiple relations with " + "the same spouse is about to be merged. This is beyond " + "the capabilities of the merge routine. The merge is " + "aborted.")) + family.replace_handle_reference('Person', old_handle,new_handle) + parents = (family.get_father_handle(), + family.get_mother_handle()) + # prune means merging families in this case. + if family_merger and parents in parent_list: + # also merge when father_handle or mother_handle == None! + if family_merge_guard: + raise MergeError(_("Multiple families get merged. " + "This is unusual, the merge is aborted.")) + idx = parent_list.index(parents) + main_family_handle = family_handle_list[idx] + self.merge_families(main_family_handle, family, trans) + family_merge_guard = True + continue + self.database.commit_family(family, trans) + parent_list.append(parents) + + self.database.remove_person(old_handle, trans) diff --git a/src/gen/merge/mergeplacequery.py b/src/gen/merge/mergeplacequery.py new file mode 100644 index 000000000..58dab3301 --- /dev/null +++ b/src/gen/merge/mergeplacequery.py @@ -0,0 +1,86 @@ +# +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2000-2007 Donald N. Allingham +# Copyright (C) 2010 Michiel D. Nauta +# +# 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 places. +""" + +#------------------------------------------------------------------------- +# +# Gramps modules +# +#------------------------------------------------------------------------- +from gen.lib import Person, Family, Event +from gen.db import DbTxn +from gen.ggettext import sgettext as _ +from Errors import MergeError + +#------------------------------------------------------------------------- +# +# MergePlaceQuery +# +#------------------------------------------------------------------------- +class MergePlaceQuery(object): + """ + Create database query to merge two places. + """ + def __init__(self, dbstate, phoenix, titanic): + self.database = dbstate.db + self.phoenix = phoenix + self.titanic = titanic + + def execute(self): + """ + Merges to places into a single place. + """ + new_handle = self.phoenix.get_handle() + old_handle = self.titanic.get_handle() + + self.phoenix.merge(self.titanic) + + with DbTxn(_("Merge Places"), self.database) as trans: + self.database.commit_place(self.phoenix, trans) + for (class_name, handle) in self.database.find_backlink_handles( + old_handle): + if class_name == Person.__name__: + person = self.database.get_person_from_handle(handle) + assert(person.has_handle_reference('Place', old_handle)) + person.replace_handle_reference('Place', old_handle, + new_handle) + self.database.commit_person(person, trans) + elif class_name == Family.__name__: + family = self.database.get_family_from_handle(handle) + assert(family.has_handle_reference('Place', old_handle)) + family.replace_handle_reference('Place', old_handle, + new_handle) + self.database.commit_family(family, trans) + elif class_name == Event.__name__: + event = self.database.get_event_from_handle(handle) + assert(event.has_handle_reference('Place', old_handle)) + event.replace_handle_reference('Place', old_handle, + new_handle) + self.database.commit_event(event, trans) + else: + raise MergeError("Encounter an object of type %s that has " + "a place reference." % class_name) + self.database.remove_place(old_handle, trans) diff --git a/src/gen/merge/mergerepositoryquery.py b/src/gen/merge/mergerepositoryquery.py new file mode 100644 index 000000000..527c84161 --- /dev/null +++ b/src/gen/merge/mergerepositoryquery.py @@ -0,0 +1,72 @@ +# +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2010 Michiel D. Nauta +# +# 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 repositories. +""" + +#------------------------------------------------------------------------- +# +# Gramps modules +# +#------------------------------------------------------------------------- +from gen.lib import Source +from gen.db import DbTxn +from gen.ggettext import sgettext as _ +from Errors import MergeError + +#------------------------------------------------------------------------- +# +# MergeRepoQuery +# +#------------------------------------------------------------------------- +class MergeRepositoryQuery(object): + """ + Create database query to merge two repositories. + """ + def __init__(self, dbstate, phoenix, titanic): + self.database = dbstate.db + self.phoenix = phoenix + self.titanic = titanic + + def execute(self): + """ + Merges two repositories into a single repository. + """ + new_handle = self.phoenix.get_handle() + old_handle = self.titanic.get_handle() + + self.phoenix.merge(self.titanic) + + with DbTxn(_("Merge Repositories"), self.database) as trans: + self.database.commit_repository(self.phoenix, trans) + for (class_name, handle) in self.database.find_backlink_handles( + old_handle): + if class_name == Source.__name__: + source = self.database.get_source_from_handle(handle) + assert source.has_handle_reference('Repository', old_handle) + source.replace_repo_references(old_handle, new_handle) + self.database.commit_source(source, trans) + else: + raise MergeError("Encounter an object of type %s that has " + "a repository reference." % class_name) + self.database.remove_repository(old_handle, trans) diff --git a/src/gen/merge/mergesourcequery.py b/src/gen/merge/mergesourcequery.py new file mode 100644 index 000000000..8537e3344 --- /dev/null +++ b/src/gen/merge/mergesourcequery.py @@ -0,0 +1,75 @@ +# +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2000-2005 Donald N. Allingham +# Copyright (C) 2010 Michiel D. Nauta +# Copyright (C) 2011 Tim G L Lyons +# +# 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 sources. +""" + +#------------------------------------------------------------------------- +# +# Gramps modules +# +#------------------------------------------------------------------------- +from gen.lib import (Person, Family, Event, Place, Source, Repository, + MediaObject, Citation) +from gen.db import DbTxn +from gen.ggettext import sgettext as _ +from Errors import MergeError + +#------------------------------------------------------------------------- +# +# MergeSourceQuery +# +#------------------------------------------------------------------------- +class MergeSourceQuery(object): + """ + Create database query to merge two sources. + """ + def __init__(self, dbstate, phoenix, titanic): + self.database = dbstate.db + self.phoenix = phoenix + self.titanic = titanic + + def execute(self): + """ + Merges to sources into a single source. + """ + new_handle = self.phoenix.get_handle() + old_handle = self.titanic.get_handle() + + self.phoenix.merge(self.titanic) + + with DbTxn(_("Merge Source"), self.database) as trans: + self.database.commit_source(self.phoenix, trans) + for (class_name, handle) in self.database.find_backlink_handles( + old_handle): + if class_name == Citation.__name__: + citation = self.database.get_citation_from_handle(handle) + assert(citation.get_reference_handle() == old_handle) + citation.set_reference_handle(new_handle) + self.database.commit_citation(citation, trans) + else: + raise MergeError("Encounter an object of type %s that has " + "a source reference." % class_name) + self.database.remove_source(old_handle, trans) diff --git a/src/Merge/test/merge_ref_test.py b/src/gen/merge/test/merge_ref_test.py similarity index 100% rename from src/Merge/test/merge_ref_test.py rename to src/gen/merge/test/merge_ref_test.py diff --git a/src/gui/Makefile.am b/src/gui/Makefile.am index 1f08dc2f0..8c04e81e7 100644 --- a/src/gui/Makefile.am +++ b/src/gui/Makefile.am @@ -8,6 +8,7 @@ SUBDIRS = \ editors \ filters \ glade \ + merge \ plug \ selectors \ views \ diff --git a/src/gui/__init__.py b/src/gui/__init__.py index 7efae72da..5dc420914 100644 --- a/src/gui/__init__.py +++ b/src/gui/__init__.py @@ -26,4 +26,4 @@ Package init for the gui package. # DO NOT IMPORT METHODS/CLASSES FROM src/gui HERE ! Only __all__ -__all__ = [ "editors", "filters", "selectors", "views", "widgets" ] +__all__ = [ "editors", "filters", "merge", "selectors", "views", "widgets" ] diff --git a/src/Merge/Makefile.am b/src/gui/merge/Makefile.am similarity index 83% rename from src/Merge/Makefile.am rename to src/gui/merge/Makefile.am index 4c24efad4..a8996f579 100644 --- a/src/Merge/Makefile.am +++ b/src/gui/merge/Makefile.am @@ -4,7 +4,7 @@ # but that is not necessarily portable. # If not using GNU make, then list all .py files individually -pkgpythondir = $(datadir)/@PACKAGE@/Merge +pkgpythondir = $(datadir)/@PACKAGE@/gui/merge pkgpython_PYTHON = \ __init__.py \ @@ -18,12 +18,12 @@ pkgpython_PYTHON = \ mergemedia.py \ mergenote.py -pkgpyexecdir = @pkgpyexecdir@/Merge +pkgpyexecdir = @pkgpyexecdir@/gui/merge # Clean up all the byte-compiled files MOSTLYCLEANFILES = *pyc *pyo -GRAMPS_PY_MODPATH = "../" +GRAMPS_PY_MODPATH = "../../" pycheck: (export PYTHONPATH=$(GRAMPS_PY_MODPATH); \ diff --git a/src/Merge/__init__.py b/src/gui/merge/__init__.py similarity index 100% rename from src/Merge/__init__.py rename to src/gui/merge/__init__.py diff --git a/src/Merge/mergecitation.py b/src/gui/merge/mergecitation.py similarity index 68% rename from src/Merge/mergecitation.py rename to src/gui/merge/mergecitation.py index 494c14787..13bbc04df 100644 --- a/src/Merge/mergecitation.py +++ b/src/gui/merge/mergecitation.py @@ -30,15 +30,13 @@ Provide merge capabilities for citations. # Gramps modules # #------------------------------------------------------------------------- -from gen.lib import (Person, Family, Event, Place, MediaObject, Repository) -from gen.db import DbTxn from gen.ggettext import sgettext as _ import const import GrampsDisplay import ManagedWindow import gen.datehandler -from Errors import MergeError from Utils import confidence +from gen.merge import MergeCitationQuery #------------------------------------------------------------------------- # @@ -52,10 +50,10 @@ _GLADE_FILE = 'mergecitation.glade' #------------------------------------------------------------------------- # -# Merge Citations +# MergeCitation # #------------------------------------------------------------------------- -class MergeCitations(ManagedWindow.ManagedWindow): +class MergeCitation(ManagedWindow.ManagedWindow): """ Displays a dialog box that allows the citations to be combined into one. """ @@ -171,61 +169,3 @@ class MergeCitations(ManagedWindow.ManagedWindow): query.execute() self.uistate.set_busy_cursor(False) self.close() - -class MergeCitationQuery(object): - """ - Create database query to merge two citations. - """ - def __init__(self, dbstate, phoenix, titanic): - self.database = dbstate.db - self.phoenix = phoenix - self.titanic = titanic - - def execute(self): - """ - Merges to citations into a single citation. - """ - new_handle = self.phoenix.get_handle() - old_handle = self.titanic.get_handle() - - self.phoenix.merge(self.titanic) - - with DbTxn(_("Merge Citation"), self.database) as trans: - self.database.commit_citation(self.phoenix, trans) - for (class_name, handle) in self.database.find_backlink_handles( - old_handle): - if class_name == Person.__name__: - person = self.database.get_person_from_handle(handle) - assert(person.has_citation_reference(old_handle)) - person.replace_citation_references(old_handle, new_handle) - self.database.commit_person(person, trans) - elif class_name == Family.__name__: - family = self.database.get_family_from_handle(handle) - assert(family.has_citation_reference(old_handle)) - family.replace_citation_references(old_handle, new_handle) - self.database.commit_family(family, trans) - elif class_name == Event.__name__: - event = self.database.get_event_from_handle(handle) - assert(event.has_citation_reference(old_handle)) - event.replace_citation_references(old_handle, new_handle) - self.database.commit_event(event, trans) - elif class_name == Place.__name__: - place = self.database.get_place_from_handle(handle) - assert(place.has_citation_reference(old_handle)) - place.replace_citation_references(old_handle, new_handle) - self.database.commit_place(place, trans) - elif class_name == MediaObject.__name__: - obj = self.database.get_object_from_handle(handle) - assert(obj.has_citation_reference(old_handle)) - obj.replace_citation_references(old_handle, new_handle) - self.database.commit_media_object(obj, trans) - elif class_name == Repository.__name__: - repository = self.database.get_repository_from_handle(handle) - assert(repository.has_citation_reference(old_handle)) - repository.replace_citation_references(old_handle, - new_handle) - self.database.commit_repository(repository, trans) - else: - raise MergeError("Encounter an object of type %s that has " - "a citation reference." % class_name) - self.database.remove_citation(old_handle, trans) diff --git a/src/Merge/mergeevent.py b/src/gui/merge/mergeevent.py similarity index 71% rename from src/Merge/mergeevent.py rename to src/gui/merge/mergeevent.py index 05d96879d..18353bcec 100644 --- a/src/Merge/mergeevent.py +++ b/src/gui/merge/mergeevent.py @@ -29,15 +29,13 @@ Provide merge capabilities for events. # Gramps modules # #------------------------------------------------------------------------- -from gen.lib import Person, Family -from gen.db import DbTxn from gen.ggettext import sgettext as _ import const import GrampsDisplay import ManagedWindow import gen.datehandler import Utils -from Errors import MergeError +from gen.merge import MergeEventQuery #------------------------------------------------------------------------- # @@ -51,10 +49,10 @@ _GLADE_FILE = 'mergeevent.glade' #------------------------------------------------------------------------- # -# Merge Events +# MergeEvent # #------------------------------------------------------------------------- -class MergeEvents(ManagedWindow.ManagedWindow): +class MergeEvent(ManagedWindow.ManagedWindow): """ Displays a dialog box that allows the events to be combined into one. """ @@ -189,63 +187,3 @@ class MergeEvents(ManagedWindow.ManagedWindow): query.execute() self.uistate.set_busy_cursor(False) self.close() - -#------------------------------------------------------------------------- -# -# Merge Event Query -# -#------------------------------------------------------------------------- -class MergeEventQuery(object): - """ - Create database query to merge two events. - """ - def __init__(self, dbstate, phoenix, titanic): - self.database = dbstate.db - self.phoenix = phoenix - self.titanic = titanic - - def execute(self): - """ - Merges two events into a single event. - """ - new_handle = self.phoenix.get_handle() - old_handle = self.titanic.get_handle() - - self.phoenix.merge(self.titanic) - - with DbTxn(_("Merge Event Objects"), self.database) as trans: - self.database.commit_event(self.phoenix, trans) - for (class_name, handle) in self.database.find_backlink_handles( - old_handle): - if class_name == Person.__name__: - person = self.database.get_person_from_handle(handle) - assert(person.has_handle_reference("Event", old_handle)) - bri = person.birth_ref_index - dri = person.death_ref_index - person.replace_handle_reference("Event", old_handle, - new_handle) - if person.birth_ref_index != bri and \ - person.birth_ref_index == -1: - for index, ref in enumerate(person.get_event_ref_list()): - event = self.database.get_event_from_handle(ref.ref) - if event.type.is_birth() and ref.role.is_primary(): - person.birth_ref_index = index - break - if person.death_ref_index != dri and \ - person.death_ref_index == -1: - for index, ref in enumerate(person.get_event_ref_list()): - event = self.database.get_event_from_handle(ref.ref) - if event.type.is_death() and ref.role.is_primary(): - person.death_ref_index = index - break - self.database.commit_person(person, trans) - elif class_name == Family.__name__: - family = self.database.get_family_from_handle(handle) - assert(family.has_handle_reference("Event", old_handle)) - family.replace_handle_reference("Event", old_handle, - new_handle) - self.database.commit_family(family, trans) - else: - raise MergeError("Encounter an object of type %s that has " - "an event reference." % class_name) - self.database.remove_event(old_handle, trans) diff --git a/src/Merge/mergefamily.py b/src/gui/merge/mergefamily.py similarity index 59% rename from src/Merge/mergefamily.py rename to src/gui/merge/mergefamily.py index bf07afeb3..83f496449 100644 --- a/src/Merge/mergefamily.py +++ b/src/gui/merge/mergefamily.py @@ -29,15 +29,14 @@ Provide merge capabilities for families. # Gramps modules # #------------------------------------------------------------------------- -from gen.db import DbTxn from gen.ggettext import sgettext as _ from gen.display.name import displayer as name_displayer import const import GrampsDisplay -from QuestionDialog import ErrorDialog from Errors import MergeError +from QuestionDialog import ErrorDialog import ManagedWindow -from Merge.mergeperson import MergePersonQuery +from gen.merge import MergePersonQuery, MergeFamilyQuery #------------------------------------------------------------------------- # @@ -51,10 +50,10 @@ _GLADE_FILE = 'mergefamily.glade' #------------------------------------------------------------------------- # -# Merge Families +# MergeFamily # #------------------------------------------------------------------------- -class MergeFamilies(ManagedWindow.ManagedWindow): +class MergeFamily(ManagedWindow.ManagedWindow): """ Merges two families into a single family. Displays a dialog box that allows the families to be combined into one. @@ -225,138 +224,3 @@ class MergeFamilies(ManagedWindow.ManagedWindow): ErrorDialog( _("Cannot merge people"), str(err)) self.uistate.set_busy_cursor(False) self.close() - -class MergeFamilyQuery(object): - """ - Create database query to merge two families. - """ - def __init__(self, database, phoenix, titanic, phoenix_fh=None, - phoenix_mh=None): - self.database = database - self.phoenix = phoenix - self.titanic = titanic - if phoenix_fh is None: - self.phoenix_fh = self.phoenix.get_father_handle() - else: - self.phoenix_fh = phoenix_fh - if phoenix_mh is None: - self.phoenix_mh = self.phoenix.get_mother_handle() - else: - self.phoenix_mh = phoenix_mh - - if self.phoenix.get_father_handle() == self.phoenix_fh: - self.titanic_fh = self.titanic.get_father_handle() - self.father_swapped = False - else: - assert self.phoenix_fh == self.titanic.get_father_handle() - self.titanic_fh = self.phoenix.get_father_handle() - self.father_swapped = True - if self.phoenix.get_mother_handle() == self.phoenix_mh: - self.titanic_mh = self.titanic.get_mother_handle() - self.mother_swapped = False - else: - assert self.phoenix_mh == self.titanic.get_mother_handle() - self.titanic_mh = self.phoenix.get_mother_handle() - self.mother_swapped = True - - def merge_person(self, phoenix_person, titanic_person, parent, trans): - """ - Merge two persons even if they are None; no families are merged! - """ - new_handle = self.phoenix.get_handle() - old_handle = self.titanic.get_handle() - - if parent == 'father': - swapped = self.father_swapped - family_add_person_handle = ( - (self.phoenix if swapped else self.titanic).set_father_handle) - elif parent == 'mother': - swapped = self.mother_swapped - family_add_person_handle = ( - (self.phoenix if swapped else self.titanic).set_mother_handle) - else: - raise ValueError(_("A parent should be a father or mother.")) - - if phoenix_person is None: - if titanic_person is not None: - raise MergeError("""When merging people where one person """ - """doesn't exist, that "person" must be the person that """ - """will be deleted from the database.""") - return - elif titanic_person is None: - if swapped: - if any(childref.get_reference_handle() == phoenix_person.get_handle() - for childref in self.phoenix.get_child_ref_list()): - - raise MergeError(_("A parent and child cannot be merged. " - "To merge these people, you must first break the " - "relationship between them.")) - - phoenix_person.add_family_handle(new_handle) - family_add_person_handle(phoenix_person.get_handle()) - self.database.commit_family(self.phoenix, trans) - else: - if any(childref.get_reference_handle() == phoenix_person.get_handle() - for childref in self.titanic.get_child_ref_list()): - - raise MergeError(_("A parent and child cannot be merged. " - "To merge these people, you must first break the " - "relationship between them.")) - - phoenix_person.add_family_handle(old_handle) - family_add_person_handle(phoenix_person.get_handle()) - self.database.commit_family(self.titanic, trans) - - self.database.commit_person(phoenix_person, trans) - else: - query = MergePersonQuery(self.database, phoenix_person, - titanic_person) - query.execute(family_merger=False, trans=trans) - - def execute(self): - """ - Merges two families into a single family. - """ - new_handle = self.phoenix.get_handle() - old_handle = self.titanic.get_handle() - - with DbTxn(_('Merge Family'), self.database) as trans: - - phoenix_father = self.database.get_person_from_handle(self.phoenix_fh) - titanic_father = self.database.get_person_from_handle(self.titanic_fh) - self.merge_person(phoenix_father, titanic_father, 'father', trans) - - phoenix_mother = self.database.get_person_from_handle(self.phoenix_mh) - titanic_mother = self.database.get_person_from_handle(self.titanic_mh) - self.phoenix = self.database.get_family_from_handle(new_handle) - self.titanic = self.database.get_family_from_handle(old_handle) - self.merge_person(phoenix_mother, titanic_mother, 'mother', trans) - - phoenix_father = self.database.get_person_from_handle(self.phoenix_fh) - phoenix_mother = self.database.get_person_from_handle(self.phoenix_mh) - self.phoenix = self.database.get_family_from_handle(new_handle) - self.titanic = self.database.get_family_from_handle(old_handle) - self.phoenix.merge(self.titanic) - self.database.commit_family(self.phoenix, trans) - for childref in self.titanic.get_child_ref_list(): - child = self.database.get_person_from_handle( - childref.get_reference_handle()) - if new_handle in child.parent_family_list: - child.remove_handle_references('Family', [old_handle]) - else: - child.replace_handle_reference('Family', old_handle, - new_handle) - self.database.commit_person(child, trans) - if phoenix_father: - phoenix_father.remove_family_handle(old_handle) - self.database.commit_person(phoenix_father, trans) - if phoenix_mother: - phoenix_mother.remove_family_handle(old_handle) - self.database.commit_person(phoenix_mother, trans) - # replace the family in lds ordinances - for (dummy, person_handle) in self.database.find_backlink_handles( - old_handle, ['Person']): - person = self.database.get_person_from_handle(person_handle) - person.replace_handle_reference('Family', old_handle,new_handle) - self.database.commit_person(person, trans) - self.database.remove_family(old_handle, trans) diff --git a/src/Merge/mergemedia.py b/src/gui/merge/mergemedia.py similarity index 67% rename from src/Merge/mergemedia.py rename to src/gui/merge/mergemedia.py index fdfdc1853..86a30ce9b 100644 --- a/src/Merge/mergemedia.py +++ b/src/gui/merge/mergemedia.py @@ -29,14 +29,12 @@ Provide merge capabilities for media objects. # Gramps modules # #------------------------------------------------------------------------- -from gen.lib import Person, Family, Event, Source, Citation, Place -from gen.db import DbTxn from gen.ggettext import sgettext as _ import const import GrampsDisplay import ManagedWindow import gen.datehandler -from Errors import MergeError +from gen.merge import MergeMediaQuery #------------------------------------------------------------------------- # @@ -50,10 +48,10 @@ _GLADE_FILE = 'mergemedia.glade' #------------------------------------------------------------------------- # -# Merge Media Objects +# MergeMedia # #------------------------------------------------------------------------- -class MergeMediaObjects(ManagedWindow.ManagedWindow): +class MergeMedia(ManagedWindow.ManagedWindow): """ Displays a dialog box that allows the media objects to be combined into one. """ @@ -168,60 +166,3 @@ class MergeMediaObjects(ManagedWindow.ManagedWindow): query = MergeMediaQuery(self.dbstate, phoenix, titanic) query.execute() self.close() - -class MergeMediaQuery(object): - """ - Create datqabase query to merge two media objects. - """ - def __init__(self, dbstate, phoenix, titanic): - self.database = dbstate.db - self.phoenix = phoenix - self.titanic = titanic - - def execute(self): - """ - Merges two media objects into a single object. - """ - new_handle = self.phoenix.get_handle() - old_handle = self.titanic.get_handle() - - self.phoenix.merge(self.titanic) - - with DbTxn(_("Merge Media Objects"), self.database) as trans: - self.database.commit_media_object(self.phoenix, trans) - for (class_name, handle) in self.database.find_backlink_handles( - old_handle): - if class_name == Person.__name__: - person = self.database.get_person_from_handle(handle) - assert(person.has_media_reference(old_handle)) - person.replace_media_references(old_handle, new_handle) - self.database.commit_person(person, trans) - elif class_name == Family.__name__: - family = self.database.get_family_from_handle(handle) - assert(family.has_media_reference(old_handle)) - family.replace_media_references(old_handle, new_handle) - self.database.commit_family(family, trans) - elif class_name == Event.__name__: - event = self.database.get_event_from_handle(handle) - assert(event.has_media_reference(old_handle)) - event.replace_media_references(old_handle, new_handle) - self.database.commit_event(event, trans) - elif class_name == Source.__name__: - source = self.database.get_source_from_handle(handle) - assert(source.has_media_reference(old_handle)) - source.replace_media_references(old_handle, new_handle) - self.database.commit_source(source, trans) - elif class_name == Citation.__name__: - citation = self.database.get_citation_from_handle(handle) - assert(citation.has_media_reference(old_handle)) - citation.replace_media_references(old_handle, new_handle) - self.database.commit_citation(citation, trans) - elif class_name == Place.__name__: - place = self.database.get_place_from_handle(handle) - assert(place.has_media_reference(old_handle)) - place.replace_media_references(old_handle, new_handle) - self.database.commit_place(place, trans) - else: - raise MergeError("Encounter an object of type % s that has " - "a media object reference." % class_name) - self.database.remove_object(old_handle, trans) diff --git a/src/Merge/mergenote.py b/src/gui/merge/mergenote.py similarity index 63% rename from src/Merge/mergenote.py rename to src/gui/merge/mergenote.py index 1d2226e40..0ea2443a2 100644 --- a/src/Merge/mergenote.py +++ b/src/gui/merge/mergenote.py @@ -29,15 +29,12 @@ Provide merge capabilities for notes. # Gramps modules # #------------------------------------------------------------------------- -from gen.lib import (Person, Family, Event, Place, Source, Citation, Repository, - MediaObject) -from gen.db import DbTxn from gen.ggettext import sgettext as _ import const import GrampsDisplay import ManagedWindow from gui.widgets.styledtextbuffer import StyledTextBuffer -from Errors import MergeError +from gen.merge import MergeNoteQuery #------------------------------------------------------------------------- # @@ -51,10 +48,10 @@ _GLADE_FILE = 'mergenote.glade' #------------------------------------------------------------------------- # -# Merge Notes +# MergeNote # #------------------------------------------------------------------------- -class MergeNotes(ManagedWindow.ManagedWindow): +class MergeNote(ManagedWindow.ManagedWindow): """ Displays a dialog box that allows two notes to be combined into one. """ @@ -178,73 +175,3 @@ class MergeNotes(ManagedWindow.ManagedWindow): query = MergeNoteQuery(self.dbstate, phoenix, titanic) query.execute() self.close() - -#------------------------------------------------------------------------- -# -# Merge Note Query -# -#------------------------------------------------------------------------- -class MergeNoteQuery(object): - """ - Create database query to merge two notes. - """ - def __init__(self, dbstate, phoenix, titanic): - self.database = dbstate.db - self.phoenix = phoenix - self.titanic = titanic - - def execute(self): - """ - Merges two notes into a single note. - """ - new_handle = self.phoenix.get_handle() - old_handle = self.titanic.get_handle() - self.phoenix.merge(self.titanic) - with DbTxn(_("Merge Notes"), self.database) as trans: - self.database.commit_note(self.phoenix, trans) - for (class_name, handle) in self.database.find_backlink_handles( - old_handle): - if class_name == Person.__name__: - person = self.database.get_person_from_handle(handle) - assert(person.has_note_reference(old_handle)) - person.replace_note_references(old_handle, new_handle) - self.database.commit_person(person, trans) - elif class_name == Family.__name__: - family = self.database.get_family_from_handle(handle) - assert(family.has_note_reference(old_handle)) - family.replace_note_references(old_handle, new_handle) - self.database.commit_family(family, trans) - elif class_name == Event.__name__: - event = self.database.get_event_from_handle(handle) - assert(event.has_note_reference(old_handle)) - event.replace_note_references(old_handle, new_handle) - self.database.commit_event(event, trans) - elif class_name == Source.__name__: - source = self.database.get_source_from_handle(handle) - assert(source.has_note_reference(old_handle)) - source.replace_note_references(old_handle, new_handle) - self.database.commit_source(source, trans) - elif class_name == Citation.__name__: - citation = self.database.get_citation_from_handle(handle) - assert(citation.has_note_reference(old_handle)) - citation.replace_note_references(old_handle, new_handle) - self.database.commit_citation(citation, trans) - elif class_name == Place.__name__: - place = self.database.get_place_from_handle(handle) - assert(place.has_note_reference(old_handle)) - place.replace_note_references(old_handle, new_handle) - self.database.commit_place(place, trans) - elif class_name == MediaObject.__name__: - obj = self.database.get_object_from_handle(handle) - assert(obj.has_note_reference(old_handle)) - obj.replace_note_references(old_handle, new_handle) - self.database.commit_media_object(obj, trans) - elif class_name == Repository.__name__: - repo = self.database.get_repository_from_handle(handle) - assert(repo.has_note_reference(old_handle)) - repo.replace_note_references(old_handle, new_handle) - self.database.commit_repository(repo, trans) - else: - raise MergeError("Encounter object of type %s that has " - "a note reference." % class_name) - self.database.remove_note(old_handle, trans) diff --git a/src/Merge/mergeperson.py b/src/gui/merge/mergeperson.py similarity index 66% rename from src/Merge/mergeperson.py rename to src/gui/merge/mergeperson.py index 6c5c22c88..402aff608 100644 --- a/src/Merge/mergeperson.py +++ b/src/gui/merge/mergeperson.py @@ -38,16 +38,16 @@ import pango # Gramps modules # #------------------------------------------------------------------------- -from gen.db import DbTxn 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 import GrampsDisplay import gen.datehandler -from QuestionDialog import ErrorDialog from Errors import MergeError +from QuestionDialog import ErrorDialog import ManagedWindow +from gen.merge import MergePersonQuery #------------------------------------------------------------------------- # @@ -67,7 +67,12 @@ def name_of(person): return "" return "%s [%s]" % (name_displayer.display(person), person.get_gramps_id()) -class MergePeople(ManagedWindow.ManagedWindow): +#------------------------------------------------------------------------- +# +# MergePerson +# +#------------------------------------------------------------------------- +class MergePerson(ManagedWindow.ManagedWindow): """ Displays a dialog box that allows the persons to be combined into one. """ @@ -336,140 +341,3 @@ class MergePeople(ManagedWindow.ManagedWindow): self.close() if self.update: self.update() - -class MergePersonQuery(object): - """ - Create database query to merge two persons. - """ - def __init__(self, database, phoenix, titanic): - self.database = database - self.phoenix = phoenix - self.titanic = titanic - if self.check_for_spouse(self.phoenix, self.titanic): - raise MergeError(_("Spouses cannot be merged. To merge these " - "people, you must first break the relationship between them.")) - if self.check_for_child(self.phoenix, self.titanic): - raise MergeError(_("A parent and child cannot be merged. To merge " - "these people, you must first break the relationship between " - "them.")) - - def check_for_spouse(self, person1, person2): - """Return if person1 and person2 are spouses of eachother.""" - fs1 = set(person1.get_family_handle_list()) - fs2 = set(person2.get_family_handle_list()) - return len(fs1.intersection(fs2)) != 0 - - def check_for_child(self, person1, person2): - """Return if person1 and person2 have a child-parent relationship.""" - fs1 = set(person1.get_family_handle_list()) - fp1 = set(person1.get_parent_family_handle_list()) - fs2 = set(person2.get_family_handle_list()) - fp2 = set(person2.get_parent_family_handle_list()) - return len(fs1.intersection(fp2)) != 0 or len(fs2.intersection(fp1)) - - def merge_families(self, main_family_handle, family, trans): - """ - Merge content of family into the family with handle main_family_handle. - """ - new_handle = self.phoenix.get_handle() if self.phoenix else None - old_handle = self.titanic.get_handle() if self.titanic else None - family_handle = family.get_handle() - main_family = self.database.get_family_from_handle(main_family_handle) - main_family.merge(family) - for childref in family.get_child_ref_list(): - child = self.database.get_person_from_handle( - childref.get_reference_handle()) - if main_family_handle in child.parent_family_list: - child.remove_handle_references('Family', [family_handle]) - else: - child.replace_handle_reference('Family', family_handle, - main_family_handle) - self.database.commit_person(child, trans) - if self.phoenix: - self.phoenix.remove_family_handle(family_handle) - self.database.commit_person(self.phoenix, trans) - family_father_handle = family.get_father_handle() - spouse_handle = family.get_mother_handle() if \ - new_handle == family_father_handle else family_father_handle - spouse = self.database.get_person_from_handle(spouse_handle) - if spouse: - spouse.remove_family_handle(family_handle) - self.database.commit_person(spouse, trans) - # replace the family in lds ordinances - for (dummy, person_handle) in self.database.find_backlink_handles( - family_handle, ['Person']): - if person_handle == old_handle: - continue - person = self.database.get_person_from_handle(person_handle) - person.replace_handle_reference('Family', family_handle, - main_family_handle) - self.database.commit_person(person, trans) - self.database.remove_family(family_handle, trans) - self.database.commit_family(main_family, trans) - - def execute(self, family_merger=True, trans=None): - """ - Merges two persons into a single person. - """ - if trans is None: - with DbTxn(_('Merge Person'), self.database) as trans: - self.__execute(family_merger, trans) - else: - self.__execute(family_merger, trans) - - def __execute(self, family_merger, trans): - """ - Merges two persons into a single person; trans is compulsory. - """ - new_handle = self.phoenix.get_handle() - old_handle = self.titanic.get_handle() - - self.phoenix.merge(self.titanic) - self.database.commit_person(self.phoenix, trans) - - for (dummy, person_handle) in self.database.find_backlink_handles( - old_handle, ['Person']): - person = self.database.get_person_from_handle(person_handle) - assert person.has_handle_reference('Person', old_handle) - person.replace_handle_reference('Person', old_handle, new_handle) - if person_handle != old_handle: - self.database.commit_person(person, trans) - - for family_handle in self.phoenix.get_parent_family_handle_list(): - family = self.database.get_family_from_handle(family_handle) - if family.has_handle_reference('Person', old_handle): - family.replace_handle_reference('Person', old_handle,new_handle) - self.database.commit_family(family, trans) - - family_merge_guard = False - parent_list = [] - parent_list_orig = [] - family_handle_list = self.phoenix.get_family_handle_list()[:] - for family_handle in family_handle_list: - family = self.database.get_family_from_handle(family_handle) - parents = (family.get_father_handle(), family.get_mother_handle()) - parent_list_orig.append(parents) - if family.has_handle_reference('Person', old_handle): - if family_merger and parent_list_orig.count(parents) > 1: - raise MergeError(_("A person with multiple relations with " - "the same spouse is about to be merged. This is beyond " - "the capabilities of the merge routine. The merge is " - "aborted.")) - family.replace_handle_reference('Person', old_handle,new_handle) - parents = (family.get_father_handle(), - family.get_mother_handle()) - # prune means merging families in this case. - if family_merger and parents in parent_list: - # also merge when father_handle or mother_handle == None! - if family_merge_guard: - raise MergeError(_("Multiple families get merged. " - "This is unusual, the merge is aborted.")) - idx = parent_list.index(parents) - main_family_handle = family_handle_list[idx] - self.merge_families(main_family_handle, family, trans) - family_merge_guard = True - continue - self.database.commit_family(family, trans) - parent_list.append(parents) - - self.database.remove_person(old_handle, trans) diff --git a/src/Merge/mergeplace.py b/src/gui/merge/mergeplace.py similarity index 77% rename from src/Merge/mergeplace.py rename to src/gui/merge/mergeplace.py index 08f614f2b..803e55a61 100644 --- a/src/Merge/mergeplace.py +++ b/src/gui/merge/mergeplace.py @@ -37,13 +37,11 @@ import gtk # Gramps modules # #------------------------------------------------------------------------- -from gen.lib import Person, Family, Event -from gen.db import DbTxn from gen.ggettext import sgettext as _ import const import GrampsDisplay import ManagedWindow -from Errors import MergeError +from gen.merge import MergePlaceQuery #------------------------------------------------------------------------- # @@ -57,10 +55,10 @@ _GLADE_FILE = 'mergeplace.glade' #------------------------------------------------------------------------- # -# Merge Places +# MergePlace # #------------------------------------------------------------------------- -class MergePlaces(ManagedWindow.ManagedWindow): +class MergePlace(ManagedWindow.ManagedWindow): """ Displays a dialog box that allows the places to be combined into one. """ @@ -195,48 +193,3 @@ class MergePlaces(ManagedWindow.ManagedWindow): query.execute() self.uistate.set_busy_cursor(False) self.close() - -class MergePlaceQuery(object): - """ - Create database query to merge two places. - """ - def __init__(self, dbstate, phoenix, titanic): - self.database = dbstate.db - self.phoenix = phoenix - self.titanic = titanic - - def execute(self): - """ - Merges to places into a single place. - """ - new_handle = self.phoenix.get_handle() - old_handle = self.titanic.get_handle() - - self.phoenix.merge(self.titanic) - - with DbTxn(_("Merge Places"), self.database) as trans: - self.database.commit_place(self.phoenix, trans) - for (class_name, handle) in self.database.find_backlink_handles( - old_handle): - if class_name == Person.__name__: - person = self.database.get_person_from_handle(handle) - assert(person.has_handle_reference('Place', old_handle)) - person.replace_handle_reference('Place', old_handle, - new_handle) - self.database.commit_person(person, trans) - elif class_name == Family.__name__: - family = self.database.get_family_from_handle(handle) - assert(family.has_handle_reference('Place', old_handle)) - family.replace_handle_reference('Place', old_handle, - new_handle) - self.database.commit_family(family, trans) - elif class_name == Event.__name__: - event = self.database.get_event_from_handle(handle) - assert(event.has_handle_reference('Place', old_handle)) - event.replace_handle_reference('Place', old_handle, - new_handle) - self.database.commit_event(event, trans) - else: - raise MergeError("Encounter an object of type %s that has " - "a place reference." % class_name) - self.database.remove_place(old_handle, trans) diff --git a/src/Merge/mergerepository.py b/src/gui/merge/mergerepository.py similarity index 79% rename from src/Merge/mergerepository.py rename to src/gui/merge/mergerepository.py index 48ddcbc85..4c1ba2ee9 100644 --- a/src/Merge/mergerepository.py +++ b/src/gui/merge/mergerepository.py @@ -29,13 +29,11 @@ Provide merge capabilities for repositories. # Gramps modules # #------------------------------------------------------------------------- -from gen.lib import Source -from gen.db import DbTxn from gen.ggettext import sgettext as _ import const import GrampsDisplay -from Errors import MergeError import ManagedWindow +from gen.merge import MergeRepositoryQuery #------------------------------------------------------------------------- # @@ -49,10 +47,10 @@ _GLADE_FILE = 'mergerepository.glade' #------------------------------------------------------------------------- # -# Merge Repositories +# MergeRepository # #------------------------------------------------------------------------- -class MergeRepositories(ManagedWindow.ManagedWindow): +class MergeRepository(ManagedWindow.ManagedWindow): """ Displays a dialog box that allows two repositories to be combined into one. """ @@ -151,39 +149,7 @@ class MergeRepositories(ManagedWindow.ManagedWindow): if self.get_widget("gramps_btn1").get_active() ^ use_handle1: phoenix.set_gramps_id(titanic.get_gramps_id()) - query = MergeRepoQuery(self.dbstate, phoenix, titanic) + query = MergeRepositoryQuery(self.dbstate, phoenix, titanic) query.execute() self.uistate.set_busy_cursor(False) self.close() - -class MergeRepoQuery(object): - """ - Create database query to merge two repositories. - """ - def __init__(self, dbstate, phoenix, titanic): - self.database = dbstate.db - self.phoenix = phoenix - self.titanic = titanic - - def execute(self): - """ - Merges two repositories into a single repository. - """ - new_handle = self.phoenix.get_handle() - old_handle = self.titanic.get_handle() - - self.phoenix.merge(self.titanic) - - with DbTxn(_("Merge Repositories"), self.database) as trans: - self.database.commit_repository(self.phoenix, trans) - for (class_name, handle) in self.database.find_backlink_handles( - old_handle): - if class_name == Source.__name__: - source = self.database.get_source_from_handle(handle) - assert source.has_handle_reference('Repository', old_handle) - source.replace_repo_references(old_handle, new_handle) - self.database.commit_source(source, trans) - else: - raise MergeError("Encounter an object of type %s that has " - "a repository reference." % class_name) - self.database.remove_repository(old_handle, trans) diff --git a/src/Merge/mergesource.py b/src/gui/merge/mergesource.py similarity index 83% rename from src/Merge/mergesource.py rename to src/gui/merge/mergesource.py index d06b69ccc..fb9bf905d 100644 --- a/src/Merge/mergesource.py +++ b/src/gui/merge/mergesource.py @@ -31,14 +31,11 @@ Provide merge capabilities for sources. # Gramps modules # #------------------------------------------------------------------------- -from gen.lib import (Person, Family, Event, Place, Source, Repository, - MediaObject, Citation) -from gen.db import DbTxn from gen.ggettext import sgettext as _ import const import GrampsDisplay import ManagedWindow -from Errors import MergeError +from gen.merge import MergeSourceQuery #------------------------------------------------------------------------- # @@ -52,10 +49,10 @@ _GLADE_FILE = 'mergesource.glade' #------------------------------------------------------------------------- # -# Merge Sources +# MergeSource # #------------------------------------------------------------------------- -class MergeSources(ManagedWindow.ManagedWindow): +class MergeSource(ManagedWindow.ManagedWindow): """ Displays a dialog box that allows the sources to be combined into one. """ @@ -183,35 +180,3 @@ class MergeSources(ManagedWindow.ManagedWindow): query.execute() self.uistate.set_busy_cursor(False) self.close() - -class MergeSourceQuery(object): - """ - Create database query to merge two sources. - """ - def __init__(self, dbstate, phoenix, titanic): - self.database = dbstate.db - self.phoenix = phoenix - self.titanic = titanic - - def execute(self): - """ - Merges to sources into a single source. - """ - new_handle = self.phoenix.get_handle() - old_handle = self.titanic.get_handle() - - self.phoenix.merge(self.titanic) - - with DbTxn(_("Merge Source"), self.database) as trans: - self.database.commit_source(self.phoenix, trans) - for (class_name, handle) in self.database.find_backlink_handles( - old_handle): - if class_name == Citation.__name__: - citation = self.database.get_citation_from_handle(handle) - assert(citation.get_reference_handle() == old_handle) - citation.set_reference_handle(new_handle) - self.database.commit_citation(citation, trans) - else: - raise MergeError("Encounter an object of type %s that has " - "a source reference." % class_name) - self.database.remove_source(old_handle, trans) diff --git a/src/plugins/lib/libpersonview.py b/src/plugins/lib/libpersonview.py index 0df2b5dbe..4e128f788 100644 --- a/src/plugins/lib/libpersonview.py +++ b/src/plugins/lib/libpersonview.py @@ -59,6 +59,7 @@ import config from DdTargets import DdTargets from gui.editors import EditPerson from gui.filters.sidebar import PersonSidebarFilter +from gui.merge import MergePerson from gen.plug import CATEGORY_QR_PERSON #------------------------------------------------------------------------- @@ -419,8 +420,7 @@ class BasePersonView(ListView): "A second person can be selected by holding down the " "control key while clicking on the desired person.")) else: - import Merge - Merge.MergePeople(self.dbstate, self.uistate, mlist[0], mlist[1]) + MergePerson(self.dbstate, self.uistate, mlist[0], mlist[1]) def tag_updated(self, handle_list): """ diff --git a/src/plugins/lib/libplaceview.py b/src/plugins/lib/libplaceview.py index c2cf7d644..936d811be 100644 --- a/src/plugins/lib/libplaceview.py +++ b/src/plugins/lib/libplaceview.py @@ -56,6 +56,7 @@ from gui.pluginmanager import GuiPluginManager from DdTargets import DdTargets from gui.editors import EditPlace, DeletePlaceQuery from gui.filters.sidebar import PlaceSidebarFilter +from gui.merge import MergePlace from gen.plug import CATEGORY_QR_PLACE #------------------------------------------------------------------------- @@ -412,8 +413,7 @@ class PlaceBaseView(ListView): "control key while clicking on the desired place.") ErrorDialog(msg, msg2) else: - import Merge - Merge.MergePlaces(self.dbstate, self.uistate, mlist[0], mlist[1]) + MergePlace(self.dbstate, self.uistate, mlist[0], mlist[1]) def get_handle_from_gramps_id(self, gid): obj = self.dbstate.db.get_place_from_gramps_id(gid) diff --git a/src/plugins/tool/FindDupes.py b/src/plugins/tool/FindDupes.py index 27160fb31..d1c311d76 100644 --- a/src/plugins/tool/FindDupes.py +++ b/src/plugins/tool/FindDupes.py @@ -45,7 +45,7 @@ from gen.display.name import displayer as name_displayer from QuestionDialog import OkDialog import ListModel import Errors -from Merge import MergePeople +from gui.merge import MergePerson import GrampsDisplay import ManagedWindow from QuestionDialog import RunDatabaseRepair @@ -600,7 +600,7 @@ class ShowMatches(ManagedWindow.ManagedWindow): return (self.p1,self.p2) = self.list.get_object(iter) - MergePeople(self.dbstate, self.uistate, self.p1, self.p2, + MergePerson(self.dbstate, self.uistate, self.p1, self.p2, self.on_update, True) def on_update(self): diff --git a/src/plugins/view/citationlistview.py b/src/plugins/view/citationlistview.py index adaef12bd..16acf44ab 100644 --- a/src/plugins/view/citationlistview.py +++ b/src/plugins/view/citationlistview.py @@ -56,6 +56,7 @@ from DdTargets import DdTargets from QuestionDialog import ErrorDialog from gui.editors import EditCitation, DeleteCitationQuery from gui.filters.sidebar import CitationSidebarFilter +from gui.merge import MergeCitation #------------------------------------------------------------------------- # @@ -336,9 +337,7 @@ class CitationListView(ListView): "sources first.") ErrorDialog(msg, msg2) else: - import Merge - Merge.MergeCitations(self.dbstate, self.uistate, - mlist[0], mlist[1]) + MergeCitation(self.dbstate, self.uistate, mlist[0], mlist[1]) def get_handle_from_gramps_id(self, gid): obj = self.dbstate.db.get_citation_from_gramps_id(gid) diff --git a/src/plugins/view/citationtreeview.py b/src/plugins/view/citationtreeview.py index 46ed29d5d..b8eee9db4 100644 --- a/src/plugins/view/citationtreeview.py +++ b/src/plugins/view/citationtreeview.py @@ -58,6 +58,7 @@ from QuestionDialog import ErrorDialog from gui.editors import EditCitation, DeleteCitationQuery, EditSource, \ DeleteSrcQuery from gui.filters.sidebar import SourceSidebarFilter +from gui.merge import MergeCitation, MergeSource #------------------------------------------------------------------------- # @@ -551,13 +552,10 @@ class CitationTreeView(ListView): "sources first.") ErrorDialog(msg, msg2) else: - import Merge - Merge.MergeCitations(self.dbstate, self.uistate, - mlist[0], mlist[1]) + MergeCitation(self.dbstate, self.uistate, mlist[0], + mlist[1]) elif source1 and source2: - import Merge - Merge.MergeSources(self.dbstate, self.uistate, - mlist[0], mlist[1]) + MergeSource(self.dbstate, self.uistate, mlist[0], mlist[1]) else: msg = _("Cannot perform merge.") msg2 = _("Both objects must be of the same type, either " diff --git a/src/plugins/view/eventview.py b/src/plugins/view/eventview.py index d3b4fb5a2..61b1476ca 100644 --- a/src/plugins/view/eventview.py +++ b/src/plugins/view/eventview.py @@ -57,6 +57,7 @@ from DdTargets import DdTargets from QuestionDialog import ErrorDialog from gui.editors import EditEvent, DeleteEventQuery from gui.filters.sidebar import EventSidebarFilter +from gui.merge import MergeEvent from gen.plug import CATEGORY_QR_EVENT #------------------------------------------------------------------------- @@ -276,8 +277,7 @@ class EventView(ListView): "control key while clicking on the desired event.") ErrorDialog(msg, msg2) else: - import Merge - Merge.MergeEvents(self.dbstate, self.uistate, mlist[0], mlist[1]) + MergeEvent(self.dbstate, self.uistate, mlist[0], mlist[1]) def dummy_report(self, obj): """ For the xml UI definition of popup to work, the submenu diff --git a/src/plugins/view/familyview.py b/src/plugins/view/familyview.py index 6d2c2bf24..bb0f31b3c 100644 --- a/src/plugins/view/familyview.py +++ b/src/plugins/view/familyview.py @@ -54,6 +54,7 @@ import Errors import config from QuestionDialog import ErrorDialog from gui.filters.sidebar import FamilySidebarFilter +from gui.merge import MergeFamily from gen.plug import CATEGORY_QR_FAMILY from DdTargets import DdTargets @@ -285,8 +286,7 @@ class FamilyView(ListView): "control key while clicking on the desired family.") ErrorDialog(msg, msg2) else: - import Merge - Merge.MergeFamilies(self.dbstate, self.uistate, mlist[0], mlist[1]) + MergeFamily(self.dbstate, self.uistate, mlist[0], mlist[1]) def _make_father_active(self, obj): """ diff --git a/src/plugins/view/mediaview.py b/src/plugins/view/mediaview.py index 5babd17f1..6334fc64e 100644 --- a/src/plugins/view/mediaview.py +++ b/src/plugins/view/mediaview.py @@ -64,6 +64,7 @@ from gen.db import DbTxn from gui.editors import EditMedia, DeleteMediaQuery import Errors from gui.filters.sidebar import MediaSidebarFilter +from gui.merge import MergeMedia from DdTargets import DdTargets from QuestionDialog import ErrorDialog from gen.plug import CATEGORY_QR_MEDIA @@ -386,9 +387,7 @@ class MediaView(ListView): "control key while clicking on the desired object.") ErrorDialog(msg, msg2) else: - import Merge - Merge.MergeMediaObjects(self.dbstate, self.uistate, mlist[0], - mlist[1]) + MergeMedia(self.dbstate, self.uistate, mlist[0], mlist[1]) def get_handle_from_gramps_id(self, gid): """ diff --git a/src/plugins/view/noteview.py b/src/plugins/view/noteview.py index 206ab0128..995c9a60b 100644 --- a/src/plugins/view/noteview.py +++ b/src/plugins/view/noteview.py @@ -56,6 +56,7 @@ from DdTargets import DdTargets from QuestionDialog import ErrorDialog from gui.filters.sidebar import NoteSidebarFilter from gui.editors import EditNote, DeleteNoteQuery +from gui.merge import MergeNote from gen.plug import CATEGORY_QR_NOTE #------------------------------------------------------------------------- @@ -272,8 +273,7 @@ class NoteView(ListView): "control key while clicking on the desired note.") ErrorDialog(msg, msg2) else: - import Merge - Merge.MergeNotes(self.dbstate, self.uistate, mlist[0], mlist[1]) + MergeNote(self.dbstate, self.uistate, mlist[0], mlist[1]) def tag_updated(self, handle_list): """ diff --git a/src/plugins/view/repoview.py b/src/plugins/view/repoview.py index dc9fdbe30..c7fbae9a1 100644 --- a/src/plugins/view/repoview.py +++ b/src/plugins/view/repoview.py @@ -46,6 +46,7 @@ from gui.editors import EditRepository, DeleteRepositoryQuery from DdTargets import DdTargets from QuestionDialog import ErrorDialog from gui.filters.sidebar import RepoSidebarFilter +from gui.merge import MergeRepository from gen.plug import CATEGORY_QR_REPOSITORY #------------------------------------------------------------------------- @@ -252,9 +253,7 @@ class RepositoryView(ListView): "repository.") ErrorDialog(msg, msg2) else: - import Merge - Merge.MergeRepositories(self.dbstate, self.uistate, mlist[0], - mlist[1]) + MergeRepository(self.dbstate, self.uistate, mlist[0], mlist[1]) def get_handle_from_gramps_id(self, gid): obj = self.dbstate.db.get_repository_from_gramps_id(gid) diff --git a/src/plugins/view/sourceview.py b/src/plugins/view/sourceview.py index b9268df82..0f4bfcb5d 100644 --- a/src/plugins/view/sourceview.py +++ b/src/plugins/view/sourceview.py @@ -50,6 +50,7 @@ from DdTargets import DdTargets from QuestionDialog import ErrorDialog from gui.editors import EditSource, DeleteSrcQuery from gui.filters.sidebar import SourceSidebarFilter +from gui.merge import MergeSource from gen.plug import CATEGORY_QR_SOURCE #------------------------------------------------------------------------- @@ -243,8 +244,7 @@ class SourceView(ListView): "control key while clicking on the desired source.") ErrorDialog(msg, msg2) else: - import Merge - Merge.MergeSources(self.dbstate, self.uistate, mlist[0], mlist[1]) + MergeSource(self.dbstate, self.uistate, mlist[0], mlist[1]) def get_handle_from_gramps_id(self, gid): obj = self.dbstate.db.get_source_from_gramps_id(gid)