2
# Gramps - a GTK+/GNOME based genealogy program
4
# Copyright (C) 2000-2007 Donald N. Allingham
5
# Copyright (C) 2008 Brian G. Matherly
6
# Copyright (C) 2010 Jakim Friant
7
# Copyright (C) 2011 Tim G L Lyons
9
# This program is free software; you can redistribute it and/or modify
10
# it under the terms of the GNU General Public License as published by
11
# the Free Software Foundation; either version 2 of the License, or
12
# (at your option) any later version.
14
# This program is distributed in the hope that it will be useful,
15
# but WITHOUT ANY WARRANTY; without even the implied warranty of
16
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
# GNU General Public License for more details.
19
# You should have received a copy of the GNU General Public License
20
# along with this program; if not, write to the Free Software
21
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24
# $Id: MergeCitations.py 19007 2012-03-05 17:18:53Z romjerome $
26
"""Tools/Family Tree Processing/MergeCitations"""
28
#------------------------------------------------------------------------
32
#------------------------------------------------------------------------
34
LOG = logging.getLogger(".citation")
36
#-------------------------------------------------------------------------
40
#-------------------------------------------------------------------------
43
#-------------------------------------------------------------------------
47
#-------------------------------------------------------------------------
48
from Utils import confidence
50
from gui.utils import ProgressMeter
51
from gui.plug import tool
52
from QuestionDialog import OkDialog
56
from gen.ggettext import sgettext as _
57
from gen.ggettext import ngettext
58
from glade import Glade
59
from gen.db import DbTxn
60
from gen.lib import (Person, Family, Event, Place, MediaObject, Citation,
62
from Errors import MergeError
64
#-------------------------------------------------------------------------
68
#-------------------------------------------------------------------------
75
ALL_FIELDS : _("Match on Page/Volume, Date and Confidence"),
76
IGNORE_DATE : _("Ignore Date"),
77
IGNORE_CONFIDENCE : _("Ignore Confidence"),
78
IGNORE_BOTH : _("Ignore Date and Confidence")
81
WIKI_HELP_PAGE = '%s_-_Tools' % const.URL_MANUAL_PAGE
82
WIKI_HELP_SEC = _('manual|Merge citations...')
84
#-------------------------------------------------------------------------
88
#-------------------------------------------------------------------------
89
class MergeCitations(tool.BatchTool,ManagedWindow.ManagedWindow):
91
def __init__(self, dbstate, uistate, options_class, name, callback=None):
93
ManagedWindow.ManagedWindow.__init__(self, uistate, [], self.__class__)
94
self.dbstate = dbstate
95
self.set_window(gtk.Window(), gtk.Label(), '')
97
tool.BatchTool.__init__(self, dbstate, options_class, name)
100
uistate.set_busy_cursor(True)
102
uistate.set_busy_cursor(False)
106
top = Glade(toplevel="mergecitations")
109
fields = self.options.handler.options_dict['fields']
110
dont_merge_notes = self.options.handler.options_dict['dont_merge_notes']
112
my_menu = gtk.ListStore(str, object)
113
for val in sorted(_val2label):
114
my_menu.append([_val2label[val], val])
116
self.notes_obj = top.get_object("notes")
117
self.notes_obj.set_active(dont_merge_notes)
118
self.notes_obj.show()
120
self.menu = top.get_object("menu")
121
self.menu.set_model(my_menu)
122
self.menu.set_active(fields)
124
window = top.toplevel
126
# self.set_window(window, top.get_object('title'),
127
# _('Merge citations'))
128
self.set_window(window, top.get_object('title2'),
129
_("Notes, media objects and data-items of matching "
130
"citations will be combined."))
132
top.connect_signals({
133
"on_merge_ok_clicked" : self.on_merge_ok_clicked,
134
"destroy_passed_object" : self.cancel,
135
"on_help_clicked" : self.on_help_clicked,
136
"on_delete_merge_event" : self.close,
137
"on_delete_event" : self.close,
142
def cancel(self, obj):
144
on cancel, update the saved values of the options.
146
fields = self.menu.get_model()[self.menu.get_active()][1]
147
dont_merge_notes = int(self.notes_obj.get_active())
148
LOG.debug("cancel fields %d dont_merge_notes %d" %
149
(fields, dont_merge_notes))
151
self.options.handler.options_dict['fields'] = fields
152
self.options.handler.options_dict['dont_merge_notes'] = dont_merge_notes
154
self.options.handler.save_options()
158
def build_menu_names(self, obj):
159
return (_("Tool settings"),_("Merge citations tool"))
161
def on_help_clicked(self, obj):
162
"""Display the relevant portion of GRAMPS manual"""
164
GrampsDisplay.help(WIKI_HELP_PAGE , WIKI_HELP_SEC)
166
def on_merge_ok_clicked(self, obj):
168
Performs the actual merge of citations
169
(Derived from ExtractCity)
171
fields = self.menu.get_model()[self.menu.get_active()][1]
172
dont_merge_notes = int(self.notes_obj.get_active())
173
LOG.debug("fields %d dont_merge_notes %d" % (fields, dont_merge_notes))
175
self.options.handler.options_dict['fields'] = fields
176
self.options.handler.options_dict['dont_merge_notes'] = dont_merge_notes
178
self.options.handler.save_options()
180
self.progress = ProgressMeter(_('Checking Sources'), '')
181
self.progress.set_pass(_('Looking for citation fields'),
182
self.db.get_number_of_citations())
188
with DbTxn(_("Merge Citation"), db) as trans:
189
for handle in db.iter_source_handles():
191
citation_handle_list = list(db.find_backlink_handles(handle))
192
for (class_name, citation_handle) in citation_handle_list:
193
if class_name <> Citation.__name__:
194
raise MergeError("Encountered an object of type %s "
195
"that has a citation reference." % class_name)
197
citation = db.get_citation_from_handle(citation_handle)
198
key = citation.get_page()
199
if fields <> IGNORE_DATE and fields <> IGNORE_BOTH:
200
key += "\n" + DateHandler.get_date(citation)
201
if fields <> IGNORE_CONFIDENCE and fields <> IGNORE_BOTH:
203
confidence[citation.get_confidence_level()]
205
(not dont_merge_notes or len(citation.note_list) == 0):
206
citation_match_handle = dict[key]
208
db.get_citation_from_handle(citation_match_handle)
210
self.Merge(db, citation_match, citation, trans)
211
except AssertionError:
212
print "Tool/Family Tree processing/MergeCitations", \
213
"citation1 gramps_id", citation_match.get_gramps_id(), \
214
"citation2 gramps_id", citation.get_gramps_id() , \
215
"citation backlink handles", \
216
list(db.find_backlink_handles(citation.get_handle()))
219
dict[key] = citation_handle
223
self.progress.close()
225
_("Number of merges done"),
226
ngettext("%(num)d citation merged",
227
"%(num)d citations merged", num_merges) % {'num': num_merges})
230
def Merge (self, db, citation1, citation2, trans):
232
Merges two citations into a single citation.
234
new_handle = citation1.get_handle()
235
old_handle = citation2.get_handle()
237
citation1.merge(citation2)
239
db.commit_citation(citation1, trans)
240
for (class_name, handle) in db.find_backlink_handles(
242
if class_name == Person.__name__:
243
person = db.get_person_from_handle(handle)
244
assert(person.has_citation_reference(old_handle))
245
person.replace_citation_references(old_handle, new_handle)
246
db.commit_person(person, trans)
247
elif class_name == Family.__name__:
248
family = db.get_family_from_handle(handle)
249
assert(family.has_citation_reference(old_handle))
250
family.replace_citation_references(old_handle, new_handle)
251
db.commit_family(family, trans)
252
elif class_name == Event.__name__:
253
event = db.get_event_from_handle(handle)
254
assert(event.has_citation_reference(old_handle))
255
event.replace_citation_references(old_handle, new_handle)
256
db.commit_event(event, trans)
257
elif class_name == Place.__name__:
258
place = db.get_place_from_handle(handle)
259
assert(place.has_citation_reference(old_handle))
260
place.replace_citation_references(old_handle, new_handle)
261
db.commit_place(place, trans)
262
elif class_name == MediaObject.__name__:
263
obj = db.get_object_from_handle(handle)
264
assert(obj.has_citation_reference(old_handle))
265
obj.replace_citation_references(old_handle, new_handle)
266
db.commit_media_object(obj, trans)
267
elif class_name == Repository.__name__:
268
repository = db.get_repository_from_handle(handle)
269
assert(repository.has_citation_reference(old_handle))
270
repository.replace_citation_references(old_handle, new_handle)
271
db.commit_repository(repository, trans)
273
raise MergeError("Encountered an object of type %s that has "
274
"a citation reference." % class_name)
275
db.remove_citation(old_handle, trans)
277
#------------------------------------------------------------------------
281
#------------------------------------------------------------------------
282
class MergeCitationsOptions(tool.ToolOptions):
284
Defines options and provides handling interface.
287
def __init__(self, name,person_id=None):
288
tool.ToolOptions.__init__(self, name,person_id)
290
# Options specific for this report
291
self.options_dict = {
293
'dont_merge_notes' : 0,
295
self.options_help = {
297
("=0/1","Whether to merge citations if they have notes",
298
["Merge citations with notes",
299
"Do not merge citations with notes"],
301
'fields' : ("=num","Threshold for matching",