~ubuntu-branches/ubuntu/utopic/gramps/utopic

« back to all changes in this revision

Viewing changes to src/plugins/tool/MergeCitations.py

  • Committer: Package Import Robot
  • Author(s): James A. Treacy
  • Date: 2012-05-22 17:18:36 UTC
  • mfrom: (39.1.4 sid)
  • Revision ID: package-import@ubuntu.com-20120522171836-35fi62lp4w7jnrd7
Tags: 3.4.0-1
* New upstream version
* Updated desktop file. Closes: #667472

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#
 
2
# Gramps - a GTK+/GNOME based genealogy program
 
3
#
 
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
 
8
#
 
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.
 
13
#
 
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.
 
18
#
 
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
 
22
#
 
23
 
 
24
# $Id: MergeCitations.py 19007 2012-03-05 17:18:53Z romjerome $
 
25
 
 
26
"""Tools/Family Tree Processing/MergeCitations"""
 
27
 
 
28
#------------------------------------------------------------------------
 
29
#
 
30
# Python modules
 
31
#
 
32
#------------------------------------------------------------------------
 
33
import logging
 
34
LOG = logging.getLogger(".citation")
 
35
 
 
36
#-------------------------------------------------------------------------
 
37
#
 
38
# GNOME libraries
 
39
#
 
40
#-------------------------------------------------------------------------
 
41
import gtk
 
42
 
 
43
#-------------------------------------------------------------------------
 
44
#
 
45
# GRAMPS modules
 
46
#
 
47
#-------------------------------------------------------------------------
 
48
from Utils import confidence
 
49
import const
 
50
from gui.utils import ProgressMeter
 
51
from gui.plug import tool
 
52
from QuestionDialog import OkDialog
 
53
import GrampsDisplay
 
54
import DateHandler
 
55
import ManagedWindow
 
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, 
 
61
                     Repository)
 
62
from Errors import MergeError
 
63
 
 
64
#-------------------------------------------------------------------------
 
65
#
 
66
# Constants
 
67
#
 
68
#-------------------------------------------------------------------------
 
69
ALL_FIELDS = 0
 
70
IGNORE_DATE = 1
 
71
IGNORE_CONFIDENCE = 2
 
72
IGNORE_BOTH = 3
 
73
 
 
74
_val2label = {
 
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")
 
79
    }
 
80
 
 
81
WIKI_HELP_PAGE = '%s_-_Tools' % const.URL_MANUAL_PAGE
 
82
WIKI_HELP_SEC = _('manual|Merge citations...')
 
83
 
 
84
#-------------------------------------------------------------------------
 
85
#
 
86
# The Actual tool.
 
87
#
 
88
#-------------------------------------------------------------------------
 
89
class MergeCitations(tool.BatchTool,ManagedWindow.ManagedWindow):
 
90
    
 
91
    def __init__(self, dbstate, uistate, options_class, name, callback=None):
 
92
        
 
93
        ManagedWindow.ManagedWindow.__init__(self, uistate, [], self.__class__)
 
94
        self.dbstate = dbstate
 
95
        self.set_window(gtk.Window(), gtk.Label(), '')
 
96
 
 
97
        tool.BatchTool.__init__(self, dbstate, options_class, name)
 
98
 
 
99
        if not self.fail:
 
100
            uistate.set_busy_cursor(True)
 
101
            self.run()
 
102
            uistate.set_busy_cursor(False)
 
103
        
 
104
    def run(self):
 
105
 
 
106
        top = Glade(toplevel="mergecitations")
 
107
 
 
108
        # retrieve options
 
109
        fields = self.options.handler.options_dict['fields']
 
110
        dont_merge_notes = self.options.handler.options_dict['dont_merge_notes']
 
111
 
 
112
        my_menu = gtk.ListStore(str, object)
 
113
        for val in sorted(_val2label):
 
114
            my_menu.append([_val2label[val], val])
 
115
 
 
116
        self.notes_obj = top.get_object("notes")
 
117
        self.notes_obj.set_active(dont_merge_notes)
 
118
        self.notes_obj.show()
 
119
        
 
120
        self.menu = top.get_object("menu")
 
121
        self.menu.set_model(my_menu)
 
122
        self.menu.set_active(fields)
 
123
 
 
124
        window = top.toplevel
 
125
        window.show()
 
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."))
 
131
        
 
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,
 
138
            })
 
139
 
 
140
        self.show()
 
141
 
 
142
    def cancel(self, obj):
 
143
        """
 
144
        on cancel, update the saved values of the options.
 
145
        """
 
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))
 
150
 
 
151
        self.options.handler.options_dict['fields'] = fields
 
152
        self.options.handler.options_dict['dont_merge_notes'] = dont_merge_notes
 
153
        # Save options
 
154
        self.options.handler.save_options()
 
155
        
 
156
        self.close(obj)
 
157
        
 
158
    def build_menu_names(self, obj):
 
159
        return (_("Tool settings"),_("Merge citations tool"))
 
160
 
 
161
    def on_help_clicked(self, obj):
 
162
        """Display the relevant portion of GRAMPS manual"""
 
163
        
 
164
        GrampsDisplay.help(WIKI_HELP_PAGE , WIKI_HELP_SEC)
 
165
 
 
166
    def on_merge_ok_clicked(self, obj):
 
167
        """
 
168
        Performs the actual merge of citations
 
169
        (Derived from ExtractCity)
 
170
        """
 
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))
 
174
 
 
175
        self.options.handler.options_dict['fields'] = fields
 
176
        self.options.handler.options_dict['dont_merge_notes'] = dont_merge_notes
 
177
        # Save options
 
178
        self.options.handler.save_options()
 
179
 
 
180
        self.progress = ProgressMeter(_('Checking Sources'), '')
 
181
        self.progress.set_pass(_('Looking for citation fields'), 
 
182
                               self.db.get_number_of_citations())
 
183
 
 
184
        db = self.dbstate.db
 
185
        
 
186
        db.disable_signals()
 
187
        num_merges = 0
 
188
        with DbTxn(_("Merge Citation"), db) as trans:
 
189
            for handle in db.iter_source_handles():
 
190
                dict = {}
 
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)
 
196
 
 
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:
 
202
                        key += "\n" + \
 
203
                            confidence[citation.get_confidence_level()]
 
204
                    if key in dict and \
 
205
                        (not dont_merge_notes or len(citation.note_list) == 0):
 
206
                        citation_match_handle = dict[key]
 
207
                        citation_match = \
 
208
                            db.get_citation_from_handle(citation_match_handle)
 
209
                        try:
 
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()))
 
217
                        num_merges += 1
 
218
                    else:
 
219
                        dict[key] = citation_handle
 
220
                    self.progress.step()
 
221
        db.enable_signals()
 
222
        db.request_rebuild()
 
223
        self.progress.close()
 
224
        OkDialog(
 
225
            _("Number of merges done"),
 
226
            ngettext("%(num)d citation merged",
 
227
            "%(num)d citations merged", num_merges) % {'num': num_merges})
 
228
        self.close(obj)
 
229
            
 
230
    def Merge (self, db, citation1, citation2, trans):
 
231
        """
 
232
        Merges two citations into a single citation.
 
233
        """
 
234
        new_handle = citation1.get_handle()
 
235
        old_handle = citation2.get_handle()
 
236
 
 
237
        citation1.merge(citation2)
 
238
 
 
239
        db.commit_citation(citation1, trans)
 
240
        for (class_name, handle) in db.find_backlink_handles(
 
241
                old_handle):
 
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)
 
272
            else:
 
273
                raise MergeError("Encountered an object of type %s that has "
 
274
                        "a citation reference." % class_name)
 
275
        db.remove_citation(old_handle, trans)
 
276
            
 
277
#------------------------------------------------------------------------
 
278
#
 
279
 
280
#
 
281
#------------------------------------------------------------------------
 
282
class MergeCitationsOptions(tool.ToolOptions):
 
283
    """
 
284
    Defines options and provides handling interface.
 
285
    """
 
286
 
 
287
    def __init__(self, name,person_id=None):
 
288
        tool.ToolOptions.__init__(self, name,person_id)
 
289
 
 
290
        # Options specific for this report
 
291
        self.options_dict = {
 
292
            'fields'   : 1,
 
293
            'dont_merge_notes' : 0,
 
294
        }
 
295
        self.options_help = {
 
296
            'dont_merge_notes'   : 
 
297
                ("=0/1","Whether to merge citations if they have notes", 
 
298
                 ["Merge citations with notes", 
 
299
                  "Do not merge citations with notes"],
 
300
                 False),
 
301
            'fields' : ("=num","Threshold for matching",
 
302
                           "Integer number")
 
303
            }