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