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#
8# This program is free software; you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation; either version 2 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program; if not, write to the Free Software
20# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21#
22
23"""Tools/Database Processing/Fix Capitalization of Family Names"""
24
25#-------------------------------------------------------------------------
26#
27# gnome/gtk
28#
29#-------------------------------------------------------------------------
30from gi.repository import GObject
31from gi.repository import Gtk
32
33#-------------------------------------------------------------------------
34#
35# gramps modules
36#
37#-------------------------------------------------------------------------
38from gramps.gen.db import find_surname_name, DbTxn
39from gramps.gen.const import URL_MANUAL_PAGE
40from gramps.gui.utils import ProgressMeter
41from gramps.gui.display import display_help
42from gramps.gui.managedwindow import ManagedWindow
43
44from gramps.gui.dialog import OkDialog
45from gramps.gui.plug import tool
46from gramps.gen.const import GRAMPS_LOCALE as glocale
47_ = glocale.translation.sgettext
48from gramps.gui.glade import Glade
49
50#-------------------------------------------------------------------------
51#
52# constants
53#
54#-------------------------------------------------------------------------
55
56prefix_list = [
57    "de", "van", "von", "di", "le", "du", "dela", "della",
58    "des", "vande", "ten", "da", "af", "den", "das", "dello",
59    "del", "en", "ein", "el" "et", "les", "lo", "los", "un",
60    "um", "una", "uno",
61    ]
62
63WIKI_HELP_PAGE = '%s_-_Tools' % URL_MANUAL_PAGE
64WIKI_HELP_SEC = _('manual|Fix_Capitalization_of_Family_Names')
65
66#-------------------------------------------------------------------------
67#
68# ChangeNames
69#
70#-------------------------------------------------------------------------
71class ChangeNames(tool.BatchTool, ManagedWindow):
72
73    def __init__(self, dbstate, user, options_class, name, callback=None):
74        uistate = user.uistate
75        self.label = _('Capitalization changes')
76        self.cb = callback
77
78        ManagedWindow.__init__(self,uistate,[],self.__class__)
79        self.set_window(Gtk.Window(),Gtk.Label(),'')
80
81        tool.BatchTool.__init__(self, dbstate, user, options_class, name)
82        if self.fail:
83            return
84
85        self.progress = ProgressMeter(
86            _('Checking Family Names'), '', parent=uistate.window)
87        self.progress.set_pass(_('Searching family names'),
88                               len(self.db.get_surname_list()))
89        self.name_list = []
90
91        for name in self.db.get_surname_list():
92            name.strip()
93            namesplitSP= name.split()
94            lSP = len(namesplitSP)
95            namesplitHY= name.split('-')
96            lHY = len(namesplitHY)
97            if lSP == lHY == 1:
98                if name != name.capitalize():
99                    # Single surname without hyphen(s)
100                    self.name_list.append(name)
101            #if lSP == 1 and lHY > 1:
102                #print "LSP==1", name, name.capitalize()
103                #if name != name.capitalize():
104                    # Single surname with hyphen(s)
105                    #self.name_list.append(name)
106            if lSP>1 and lHY == 1:
107                # more than one string in surname but no hyphen
108                # check if first string is in prefix_list, if so test for cap in rest
109                s1 = 0
110                if namesplitSP[0].lower() in prefix_list:
111                    s1 = 1
112                for x in range(len(namesplitSP)-s1):
113                    # check if any subsurname is not cap
114                    notcap = False
115                    if namesplitSP[s1+x] != namesplitSP[s1+x].capitalize():
116                        notcap = True
117                        break
118                if notcap:
119                    # Multiple surnames possibly after prefix
120                    self.name_list.append(name)
121            if lHY > 1:
122                # more than one string in surname but hyphen(s) exists
123                # check if first string is in prefix_list, if so test for cap
124                if namesplitSP[0].lower() in prefix_list:
125                    namesplitHY[0] = namesplitHY[0].replace(namesplitSP[0],'').strip()
126                for x in range(len(namesplitHY)):
127                    # check if any subsurname is not cap
128                    notcap = False
129                    if namesplitHY[x] != namesplitHY[x].capitalize():
130                        notcap = True
131                        break
132                if notcap:
133                    # Multiple surnames possibly after frefix
134                    self.name_list.append(name)
135
136            if uistate:
137                self.progress.step()
138
139        if self.name_list:
140            self.display()
141        else:
142            self.progress.close()
143            self.close()
144            OkDialog(_('No modifications made'),
145                     _("No capitalization changes were detected."),
146                     parent=uistate.window)
147
148    def name_cap(self, name):
149        name.strip()
150        namesplitSP = name.split()
151        lSP = len(namesplitSP)
152        lHY = len(name.split('-'))
153        namesep = ' '
154        if lHY > 1:
155            namesep = '-'
156            namesplitSP = name.replace(namesep,' ').split()
157            lSP= len(namesplitSP)
158        if lSP == lHY == 1:
159            #if name != name.capitalize():
160            # Single surname without space(s) or hyphen(s), normal case
161            return name.capitalize()
162        else:
163            # more than one string in surname but no hyphen
164            # check if first string is in prefix_list, if so CAP the rest
165            # Names like (von) Kohl(-)Brandt
166            result = ""
167            s1 = 0
168            if namesplitSP[0].lower() in prefix_list:
169                s1 = 1
170                result = namesplitSP[0].lower()+ ' '
171            for x in range(lSP-s1):
172                # CAP all subsurnames
173                result = result + namesplitSP[s1+x].capitalize() + namesep
174            return result[:-1]
175
176    def display(self):
177
178        self.top = Glade()
179        window = self.top.toplevel
180        self.top.connect_signals({
181            "destroy_passed_object" : self.close,
182            "on_ok_clicked" : self.on_ok_clicked,
183            "on_help_clicked" : self.on_help_clicked,
184            "on_delete_event"   : self.close,
185            })
186
187        self.list = self.top.get_object("list")
188        self.set_window(window,self.top.get_object('title'),self.label)
189        self.setup_configs('interface.changenames', 500, 450)
190
191        self.model = Gtk.ListStore(GObject.TYPE_BOOLEAN, GObject.TYPE_STRING,
192                                   GObject.TYPE_STRING)
193
194        r = Gtk.CellRendererToggle()
195        r.connect('toggled',self.toggled)
196        c = Gtk.TreeViewColumn(_('Select'),r,active=0)
197        self.list.append_column(c)
198
199        c = Gtk.TreeViewColumn(_('Original Name'),
200                               Gtk.CellRendererText(),text=1)
201        self.list.append_column(c)
202
203        c = Gtk.TreeViewColumn(_('Capitalization Change'),
204                               Gtk.CellRendererText(),text=2)
205        self.list.append_column(c)
206
207        self.list.set_model(self.model)
208
209        self.iter_list = []
210        self.progress.set_pass(_('Building display'),len(self.name_list))
211        for name in self.name_list:
212            handle = self.model.append()
213            self.model.set_value(handle,0,True)
214            self.model.set_value(handle,1, name)
215            namecap = self.name_cap(name)
216            self.model.set_value(handle,2, namecap)
217            self.iter_list.append(handle)
218            self.progress.step()
219        self.progress.close()
220
221        self.show()
222
223    def toggled(self,cell,path_string):
224        path = tuple(map(int, path_string.split(':')))
225        row = self.model[path]
226        row[0] = not row[0]
227
228    def build_menu_names(self, obj):
229        return (self.label,None)
230
231    def on_help_clicked(self, obj):
232        """Display the relevant portion of Gramps manual"""
233        display_help(WIKI_HELP_PAGE , WIKI_HELP_SEC)
234
235    def on_ok_clicked(self, obj):
236        with DbTxn(_("Capitalization changes"), self.db, batch=True
237                   ) as self.trans:
238            self.db.disable_signals()
239            changelist = set(self.model.get_value(node,1)
240                            for node in self.iter_list
241                                if self.model.get_value(node,0))
242
243            #with self.db.get_person_cursor(update=True, commit=True) as cursor:
244            #  for handle, data in cursor:
245            for handle in self.db.get_person_handles(False):
246                person = self.db.get_person_from_handle(handle)
247                #person = Person(data)
248                change = False
249                for name in [person.get_primary_name()] + person.get_alternate_names():
250                    sname = find_surname_name(handle, name.serialize())
251                    if sname in changelist:
252                        change = True
253                        for surn in name.get_surname_list():
254                            sname = self.name_cap(surn.get_surname())
255                            surn.set_surname(sname)
256                if change:
257                    #cursor.update(handle, person.serialize())
258                    self.db.commit_person(person, self.trans)
259
260        self.db.enable_signals()
261        self.db.request_rebuild()
262        # FIXME: this probably needs to be removed, and bookmarks
263        # should always be rebuilt on a commit_person via signals
264        # self.parent.bookmarks.redraw()
265        self.close()
266        self.cb()
267
268#------------------------------------------------------------------------
269#
270#
271#
272#------------------------------------------------------------------------
273class ChangeNamesOptions(tool.ToolOptions):
274    """
275    Defines options and provides handling interface.
276    """
277
278    def __init__(self, name,person_id=None):
279        tool.ToolOptions.__init__(self, name,person_id)
280