def __build_window(self): """Build the window from Glade. """ from gramps.gui.glade import Glade glade_xml = Glade() self._window = glade_xml.toplevel self._window.set_transient_for(self._parent) # remember active widgets for future use self._swin = glade_xml.get_object('swin') self._drawing_area = glade_xml.get_object('drawingarea') self._first_button = glade_xml.get_object('first') self._prev_button = glade_xml.get_object('prev') self._next_button = glade_xml.get_object('next') self._last_button = glade_xml.get_object('last') self._pages_entry = glade_xml.get_object('entry') self._pages_label = glade_xml.get_object('label') self._zoom_fit_width_button = glade_xml.get_object('zoom_fit_width') self._zoom_fit_width_button.set_stock_id('gramps-zoom-fit-width') self._zoom_best_fit_button = glade_xml.get_object('zoom_best_fit') self._zoom_best_fit_button.set_stock_id('gramps-zoom-best-fit') self._zoom_in_button = glade_xml.get_object('zoom_in') self._zoom_in_button.set_stock_id('gramps-zoom-in') self._zoom_out_button = glade_xml.get_object('zoom_out') self._zoom_out_button.set_stock_id('gramps-zoom-out') # connect the signals glade_xml.connect_signals(self) self._drawing_area.connect("draw", self.on_drawingarea_draw_event)
def create_gui(self): self.filternames = [] category = self.uistate.viewmanager.active_page.get_category() if category == "People": category = "Person" if category.endswith("ies"): category = category[0:-3] + "y" if category.endswith("s"): category = category[0:-1] self.current_category = category glade = Glade(toplevel='dialog1') self.dialog = glade.toplevel combo_categories = glade.get_child_object("combo_categories") self.combo_filters = glade.get_child_object("combo_filters") self.add_button = glade.get_child_object("add_button") self.edit_button = glade.get_child_object("edit_button") self.delete_button = glade.get_child_object("delete_button") self.execute_button = glade.get_child_object("execute_button") self.update_button = glade.get_child_object("update_button") self.close_button = glade.get_child_object("close_button") self.box = glade.get_child_object("box") if 0: glade.connect_signals( { 'on_filter_changed': self.on_filter_changed, 'add_new_filter': self.add_new_filter, 'edit_filter': self.edit_filter, 'delete_filter': self.delete_filter, 'execute_clicked': self.execute_clicked, 'update_clicked': self.update_clicked, 'close_clicked': self.close_clicked, 'on_category_changed': self.on_category_changed, } ) if 1: self.combo_filters.connect("changed", self.on_filter_changed) self.add_button.connect("clicked", self.add_new_filter) self.edit_button.connect("clicked", self.edit_filter) self.delete_button.connect("clicked", self.delete_filter) self.execute_button.connect("clicked", self.execute_clicked) self.update_button.connect("clicked", self.update_clicked) self.close_button.connect("clicked", self.close_clicked) for cat in self.categories_translated: combo_categories.append_text(cat) combo_categories.connect("changed", self.on_category_changed) if self.current_category not in self.categories: self.current_category = "Person" i = self.categories.index(self.current_category) combo_categories.set_active(i) self.dialog.connect("delete-event", lambda x, y: self.close_clicked(self.dialog)) self.dialog.show_all() return self.dialog
def display(self): # get the main window from glade topDialog = Glade() # set gramps style title for the window window = topDialog.toplevel self.set_window(window, topDialog.get_object("title"), _("Database Owner Editor")) self.setup_configs('interface.ownereditor', 500, 400) # move help button to the left side action_area = topDialog.get_object("action_area") help_button = topDialog.get_object("help_button") action_area.set_child_secondary(help_button, True) # connect signals topDialog.connect_signals({ "on_ok_button_clicked": self.on_ok_button_clicked, "on_cancel_button_clicked": self.close, "on_help_button_clicked": self.on_help_button_clicked, "on_eventbox_button_press_event": self.on_button_press_event, "on_menu_activate": self.on_menu_activate}) # fetch the popup menu self.menu = topDialog.get_object("popup_menu") self.track_ref_for_deletion("menu") #topDialog.connect_signals({"on_menu_activate": self.on_menu_activate}) # get current db owner and attach it to the entries of the window self.owner = self.db.get_researcher() self.entries = [] entry = [ ("name", self.owner.set_name, self.owner.get_name), ("address", self.owner.set_address, self.owner.get_address), ("locality", self.owner.set_locality, self.owner.get_locality), ("city", self.owner.set_city, self.owner.get_city), ("state", self.owner.set_state, self.owner.get_state), ("country", self.owner.set_country, self.owner.get_country), ("zip", self.owner.set_postal_code, self.owner.get_postal_code), ("phone", self.owner.set_phone, self.owner.get_phone), ("email", self.owner.set_email, self.owner.get_email), ] for (name,set_fn,get_fn) in entry: self.entries.append(MonitoredEntry(topDialog.get_object(name), set_fn, get_fn, self.db.readonly)) # ok, let's see what we've done self.show()
def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate tool.Tool.__init__(self, dbstate, options_class, name) ManagedWindow.__init__(self, uistate, [], self.__class__) self.dbstate = dbstate self.uistate = uistate self.map = {} self.list = [] self.index = 0 self.merger = None self.mergee = None self.removed = {} self.update = callback self.use_soundex = 1 top = Glade(toplevel="finddupes", also_load=["liststore1"]) # retrieve options threshold = self.options.handler.options_dict['threshold'] use_soundex = self.options.handler.options_dict['soundex'] my_menu = Gtk.ListStore(str, object) for val in sorted(_val2label): my_menu.append([_val2label[val], val]) self.soundex_obj = top.get_object("soundex") self.soundex_obj.set_active(use_soundex) self.soundex_obj.show() self.menu = top.get_object("menu") self.menu.set_model(my_menu) self.menu.set_active(0) window = top.toplevel self.set_window(window, top.get_object('title'), _('Find Possible Duplicate People')) self.setup_configs('interface.duplicatepeopletool', 350, 220) top.connect_signals({ "on_do_merge_clicked" : self.__dummy, "on_help_show_clicked" : self.__dummy, "on_delete_show_event" : self.__dummy, "on_merge_ok_clicked" : self.on_merge_ok_clicked, "destroy_passed_object" : self.close, "on_help_clicked" : self.on_help_clicked, "on_delete_merge_event" : self.close, "on_delete_event" : self.close, }) self.show()
def display(self): # get the main window from glade topDialog = Glade() # set gramps style title for the window window = topDialog.toplevel self.set_window(window, topDialog.get_object("title"), _("Database Owner Editor")) self.setup_configs('interface.ownereditor', 500, 400) # move help button to the left side action_area = topDialog.get_object("action_area") help_button = topDialog.get_object("help_button") action_area.set_child_secondary(help_button, True) # connect signals topDialog.connect_signals({ "on_ok_button_clicked": self.on_ok_button_clicked, "on_cancel_button_clicked": self.close, "on_help_button_clicked": self.on_help_button_clicked, "on_eventbox_button_press_event": self.on_button_press_event, "on_menu_activate": self.on_menu_activate }) # fetch the popup menu self.menu = topDialog.get_object("popup_menu") self.track_ref_for_deletion("menu") #topDialog.connect_signals({"on_menu_activate": self.on_menu_activate}) # get current db owner and attach it to the entries of the window self.owner = self.db.get_researcher() self.entries = [] entry = [ ("name", self.owner.set_name, self.owner.get_name), ("address", self.owner.set_address, self.owner.get_address), ("locality", self.owner.set_locality, self.owner.get_locality), ("city", self.owner.set_city, self.owner.get_city), ("state", self.owner.set_state, self.owner.get_state), ("country", self.owner.set_country, self.owner.get_country), ("zip", self.owner.set_postal_code, self.owner.get_postal_code), ("phone", self.owner.set_phone, self.owner.get_phone), ("email", self.owner.set_email, self.owner.get_email), ] for (name, set_fn, get_fn) in entry: self.entries.append( MonitoredEntry(topDialog.get_object(name), set_fn, get_fn, self.db.readonly)) # ok, let's see what we've done self.show()
def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate tool.Tool.__init__(self, dbstate, options_class, name) ManagedWindow.__init__(self, uistate, [], self.__class__) self.dbstate = dbstate self.uistate = uistate self.map = {} self.list = [] self.index = 0 self.merger = None self.mergee = None self.removed = {} self.update = callback self.use_soundex = 1 top = Glade() # retrieve options threshold = self.options.handler.options_dict['threshold'] use_soundex = self.options.handler.options_dict['soundex'] my_menu = Gtk.ListStore(str, object) for val in sorted(_val2label): my_menu.append([_val2label[val], val]) self.soundex_obj = top.get_object("soundex") self.soundex_obj.set_active(use_soundex) self.soundex_obj.show() self.menu = top.get_object("menu") self.menu.set_model(my_menu) self.menu.set_active(0) window = top.toplevel self.set_window(window, top.get_object('title'), _('Find Possible Duplicate People')) self.setup_configs('interface.duplicatepeopletool', 350, 220) top.connect_signals({ "on_do_merge_clicked" : self.__dummy, "on_help_show_clicked" : self.__dummy, "on_delete_show_event" : self.__dummy, "on_merge_ok_clicked" : self.on_merge_ok_clicked, "destroy_passed_object" : self.close, "on_help_clicked" : self.on_help_clicked, "on_delete_merge_event" : self.close, "on_delete_event" : self.close, }) self.show()
def display(self): top_dialog = Glade() top_dialog.connect_signals({ "destroy_passed_object" : self.close, "on_ok_clicked" : self.on_ok_clicked, "on_help_clicked" : self.on_help_clicked, "on_delete_event" : self.close, }) window = top_dialog.toplevel self.set_window(window, top_dialog.get_object('title'), self.label) self.setup_configs('interface.changenames', 500, 450) self.clear_button = top_dialog.get_object('checkbutton1') self.copy_button = top_dialog.get_object('checkbutton2') self.tag_button = top_dialog.get_object('checkbutton3') self.treeview = top_dialog.get_object("list") self.r = Gtk.CellRendererToggle() self.r.set_property('activatable', True) self.r.set_property('radio', True) self.r.connect('toggled', self.toggled) c = Gtk.TreeViewColumn(_('Select'), self.r, active=1) self.treeview.append_column(c) c = Gtk.TreeViewColumn(_('Database'), Gtk.CellRendererText(),text=2) self.treeview.append_column(c) c = Gtk.TreeViewColumn(_('Display'), Gtk.CellRendererText(),text=3) self.treeview.append_column(c) self.selection = self.treeview.get_selection() self.model = Gtk.ListStore(str, bool, str, str) self.treeview.set_model(self.model) self.progress.set_pass(_('Building display'), len(self.name_list)) for handle, title, descr in self.name_list: self.model.append([handle, title == descr, title, descr]) self.progress.step() self.progress.close() self.show()
def __init__(self, dbstate, uistate, track, the_list, the_map, callback): ManagedWindow.__init__(self,uistate,track,self.__class__) self.dellist = set() self.list = the_list self.map = the_map self.length = len(self.list) self.update = callback self.db = dbstate.db self.dbstate = dbstate self.uistate = uistate top = Glade(toplevel="mergelist") window = top.toplevel self.set_window(window, top.get_object('title'), _('Potential Merges')) self.setup_configs('interface.duplicatepeopletoolmatches', 500, 350) self.mlist = top.get_object("mlist") top.connect_signals({ "destroy_passed_object" : self.close, "on_do_merge_clicked" : self.on_do_merge_clicked, "on_help_show_clicked" : self.on_help_clicked, "on_delete_show_event" : self.close, "on_merge_ok_clicked" : self.__dummy, "on_help_clicked" : self.__dummy, "on_delete_merge_event" : self.__dummy, "on_delete_event" : self.__dummy, }) self.db.connect("person-delete", self.person_delete) mtitles = [ (_('Rating'),3,75), (_('First Person'),1,200), (_('Second Person'),2,200), ('',-1,0) ] self.list = ListModel(self.mlist,mtitles, event_func=self.on_do_merge_clicked) self.redraw() self.show()
def run(self): top = Glade(toplevel="mergecitations", also_load=["liststore1"]) # retrieve options fields = self.options.handler.options_dict['fields'] dont_merge_notes = self.options.handler.options_dict[ 'dont_merge_notes'] my_menu = Gtk.ListStore(str, object) for val in sorted(_val2label): my_menu.append([_val2label[val], val]) self.notes_obj = top.get_object("notes") self.notes_obj.set_active(dont_merge_notes) self.notes_obj.show() self.menu = top.get_object("menu") self.menu.set_model(my_menu) self.menu.set_active(fields) window = top.toplevel window.set_transient_for(self.user.uistate.window) window.show() # self.set_window(window, top.get_object('title'), # _('Merge citations')) self.set_window( window, top.get_object('title2'), _("Notes, media objects and data-items of matching " "citations will be combined.")) self.setup_configs('interface.mergecitations', 700, 230) top.connect_signals({ "on_merge_ok_clicked": self.on_merge_ok_clicked, "destroy_passed_object": self.cancel, "on_help_clicked": self.on_help_clicked, "on_delete_merge_event": self.close, "on_delete_event": self.close, }) self.show()
def __init__(self, dbstate, uistate, track, the_list, the_map, callback): ManagedWindow.__init__(self,uistate,track,self.__class__) self.dellist = {} self.list = the_list self.map = the_map self.length = len(self.list) self.update = callback self.db = dbstate.db self.dbstate = dbstate self.uistate = uistate top = Glade(toplevel="mergelist") window = top.toplevel self.set_window(window, top.get_object('title'), _('Potential Merges')) self.setup_configs('interface.duplicatepeopletoolmatches', 500, 350) self.mlist = top.get_object("mlist") top.connect_signals({ "destroy_passed_object" : self.close, "on_do_merge_clicked" : self.on_do_merge_clicked, "on_help_show_clicked" : self.on_help_clicked, "on_delete_show_event" : self.close, "on_merge_ok_clicked" : self.__dummy, "on_help_clicked" : self.__dummy, "on_delete_merge_event" : self.__dummy, "on_delete_event" : self.__dummy, }) mtitles = [ (_('Rating'),3,75), (_('First Person'),1,200), (_('Second Person'),2,200), ('',-1,0) ] self.list = ListModel(self.mlist,mtitles, event_func=self.on_do_merge_clicked) self.redraw() self.show()
def run(self): top = Glade(toplevel="mergecitations") # retrieve options fields = self.options.handler.options_dict['fields'] dont_merge_notes = self.options.handler.options_dict['dont_merge_notes'] my_menu = Gtk.ListStore(str, object) for val in sorted(_val2label): my_menu.append([_val2label[val], val]) self.notes_obj = top.get_object("notes") self.notes_obj.set_active(dont_merge_notes) self.notes_obj.show() self.menu = top.get_object("menu") self.menu.set_model(my_menu) self.menu.set_active(fields) window = top.toplevel window.set_transient_for(self.user.uistate.window) window.show() # self.set_window(window, top.get_object('title'), # _('Merge citations')) self.set_window(window, top.get_object('title2'), _("Notes, media objects and data-items of matching " "citations will be combined.")) self.setup_configs('interface.mergecitations', 700, 230) top.connect_signals({ "on_merge_ok_clicked" : self.on_merge_ok_clicked, "destroy_passed_object" : self.cancel, "on_help_clicked" : self.on_help_clicked, "on_delete_merge_event" : self.close, "on_delete_event" : self.close, }) self.show()
def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate dummy_opt = options_class dummy_nme = name dummy_cb = callback self.title = _('Clean input data') ManagedWindow.__init__(self, uistate, [], self.__class__) self.dbstate = dbstate self.uistate = uistate self.db = dbstate.db self.tooltip = "" self.f_lat = False self.f_lon = False top_dialog = Glade() top_dialog.connect_signals({ "destroy_passed_object": self.close, "on_help_clicked": self.on_help_clicked, "on_delete_event": self.close, }) window = top_dialog.toplevel title = top_dialog.get_object("title") self.set_window(window, title, self.title) tip = _('Search leading and/or trailing spaces for persons' ' and places. Search comma or bad sign in coordinates' ' fields.\n' 'Double click on a row to edit its content.') title.set_tooltip_text(tip) # start the progress indicator self.progress = ProgressMeter(self.title, _('Starting'), parent=uistate.window) steps = self.db.get_number_of_people() + self.db.get_number_of_places() self.progress.set_pass( _('Looking for possible fields with leading or' ' trailing spaces'), steps) self.model_1 = Gtk.ListStore( GObject.TYPE_STRING, # 0==handle GObject.TYPE_STRING, # 1==firstname GObject.TYPE_STRING, # 2==surname GObject.TYPE_STRING, # 3==alternate name GObject.TYPE_STRING, # 4==group_as ) self.model_1.set_sort_column_id( Gtk.TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, 1) self.label_1 = top_dialog.get_object("label_1") self.label_1.set_text(_('Person')) self.treeview_1 = top_dialog.get_object("treeview_1") self.treeview_1.set_model(self.model_1) col1 = Gtk.TreeViewColumn(_('handle'), Gtk.CellRendererText(), text=0) renderer1 = Gtk.CellRendererText() renderer1.set_property('underline-set', True) renderer1.set_property('underline', 2) # 2=double underline col2 = Gtk.TreeViewColumn(_('firstname'), renderer1, text=1) renderer2 = Gtk.CellRendererText() renderer2.set_property('underline-set', True) renderer2.set_property('underline', 2) # 2=double underline col3 = Gtk.TreeViewColumn(_('surname'), renderer2, text=2) renderer3 = Gtk.CellRendererText() renderer3.set_property('underline-set', True) renderer3.set_property('underline', 2) # 2=double underline col4 = Gtk.TreeViewColumn(_('alternate name'), renderer3, text=3) renderer4 = Gtk.CellRendererText() renderer4.set_property('underline-set', True) renderer4.set_property('underline', 2) # 2=double underline col5 = Gtk.TreeViewColumn(_('group as'), renderer4, text=4) col1.set_resizable(True) col1.set_visible(False) col2.set_resizable(True) col3.set_resizable(True) col4.set_resizable(True) col5.set_resizable(True) col1.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) col2.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) col3.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) col4.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) col5.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) self.treeview_1.append_column(col1) self.treeview_1.append_column(col2) self.treeview_1.append_column(col3) self.treeview_1.append_column(col4) self.treeview_1.append_column(col5) self.treeselection = self.treeview_1.get_selection() self.treeview_1.connect('row-activated', self.rowactivated_cb1) self.model_2 = Gtk.ListStore( GObject.TYPE_STRING, # 0==handle GObject.TYPE_STRING, # 1==name GObject.TYPE_STRING, # 2==latitude GObject.TYPE_STRING, # 3==longitude GObject.TYPE_STRING) # 4==tooltip self.model_2.set_sort_column_id( Gtk.TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, 1) self.label_2 = top_dialog.get_object("label_2") self.label_2.set_text(_('Place')) self.treeview_2 = top_dialog.get_object("treeview_2") self.treeview_2.set_model(self.model_2) col1 = Gtk.TreeViewColumn(_('handle'), Gtk.CellRendererText(), text=0) renderer5 = Gtk.CellRendererText() renderer5.set_property('underline-set', True) renderer5.set_property('underline', 2) # 2=double underline col2 = Gtk.TreeViewColumn(_('name'), renderer5, text=1) renderer6 = Gtk.CellRendererText() renderer6.set_property('underline-set', True) renderer6.set_property('underline', 2) # 2=double underline col3 = Gtk.TreeViewColumn(_('latitude'), renderer6, text=2) renderer7 = Gtk.CellRendererText() renderer7.set_property('underline-set', True) renderer7.set_property('underline', 2) # 2=double underline col4 = Gtk.TreeViewColumn(_('longitude'), renderer7, text=3) col5 = Gtk.TreeViewColumn(_('tooltip'), Gtk.CellRendererText(), text=4) col1.set_resizable(True) col1.set_visible(False) col2.set_resizable(True) col3.set_resizable(True) col4.set_resizable(True) col5.set_visible(False) col1.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) col2.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) col3.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) col4.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) col5.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) self.treeview_2.append_column(col1) self.treeview_2.append_column(col2) self.treeview_2.append_column(col3) self.treeview_2.append_column(col4) self.treeview_2.append_column(col5) self.treeview_2.set_tooltip_column(4) self.treeselection = self.treeview_2.get_selection() self.treeview_2.connect('row-activated', self.rowactivated_cb2) self.places() self.people() # close the progress bar self.progress.close() self.show()
class PatchNames(tool.BatchTool, ManagedWindow): titleid = 1 nickid = 2 pref1id = 3 compid = 4 def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate self.label = _('Name and title extraction tool') ManagedWindow.__init__(self, uistate, [], self.__class__) self.set_window(Gtk.Window(), Gtk.Label(), '') tool.BatchTool.__init__(self, dbstate, user, options_class, name) if self.fail: return winprefix = Gtk.Dialog( _("Default prefix and connector settings"), self.uistate.window, Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT, (_('_OK'), Gtk.ResponseType.ACCEPT)) winprefix.vbox.set_spacing(5) hboxpref = Gtk.Box() label = Gtk.Label(label=_('Prefixes to search for:')) hboxpref.pack_start(label, False, False, 5) self.prefixbox = Gtk.Entry() self.prefixbox.set_text(', '.join(PREFIX_LIST)) hboxpref.pack_start(self.prefixbox, True, True, 0) winprefix.vbox.pack_start(hboxpref, True, True, 0) hboxcon = Gtk.Box() label = Gtk.Label(label=_('Connectors splitting surnames:')) hboxcon.pack_start(label, False, False, 5) self.conbox = Gtk.Entry() self.conbox.set_text(', '.join(CONNECTOR_LIST)) hboxcon.pack_start(self.conbox, True, True, 0) winprefix.vbox.pack_start(hboxcon, True, True, 0) hboxconns = Gtk.Box() label = Gtk.Label(label=_('Connectors not splitting surnames:')) hboxconns.pack_start(label, False, False, 5) self.connsbox = Gtk.Entry() self.connsbox.set_text(', '.join(CONNECTOR_LIST_NONSPLIT)) hboxconns.pack_start(self.connsbox, True, True, 0) winprefix.vbox.pack_start(hboxconns, True, True, 0) winprefix.show_all() winprefix.resize(700, 100) response = winprefix.run() self.prefix_list = self.prefixbox.get_text().split(',') self.prefix_list = list(map(strip, self.prefix_list)) self.prefixbox = None self.connector_list = self.conbox.get_text().split(',') self.connector_list = list(map(strip, self.connector_list)) self.conbox = None self.connector_list_nonsplit = self.connsbox.get_text().split(',') self.connector_list_nonsplit = list( map(strip, self.connector_list_nonsplit)) self.connsbox = None # Find a prefix in the first_name self._fn_prefix_re = re.compile( "(\S+)\s+(%s)\s*$" % '|'.join(self.prefix_list), re.IGNORECASE) # Find a prefix in the surname self._sn_prefix_re = re.compile( "^\s*(%s)\s+(.+)" % '|'.join(self.prefix_list), re.IGNORECASE) # Find a connector in the surname self._sn_con_re = re.compile( "^\s*(.+)\s+(%s)\s+(.+)" % '|'.join(self.connector_list), re.IGNORECASE) winprefix.destroy() self.cb = callback self.handle_to_action = {} self.progress = ProgressMeter( # parent-OK _('Extracting Information from Names'), '', parent=self.uistate.window) self.progress.set_pass(_('Analyzing names'), self.db.get_number_of_people()) for person in self.db.iter_people(): key = person.handle name = person.get_primary_name() first = name.get_first_name() sname = name.get_surname() old_prefix = [] old_surn = [] old_con = [] old_prim = [] old_orig = [] for surn in name.get_surname_list(): old_prefix.append(surn.get_prefix()) old_surn.append(surn.get_surname()) old_con.append(surn.get_connector()) old_prim.append(surn.get_primary()) old_orig.append(surn.get_origintype()) if name.get_title(): old_title = [name.get_title()] else: old_title = [] new_title = [] match = _title_re.match(first) while match: groups = match.groups() first = groups[1] new_title.append(groups[0]) match = _title_re.match(first) matchnick = _nick_re.match(first) if new_title: titleval = (" ".join(old_title + new_title), first) if key in self.handle_to_action: self.handle_to_action[key][self.titleid] = titleval else: self.handle_to_action[key] = {self.titleid: titleval} elif matchnick: # we check for nick, which changes given name like title groups = matchnick.groups() nickval = (groups[0], groups[1]) if key in self.handle_to_action: self.handle_to_action[key][self.nickid] = nickval else: self.handle_to_action[key] = {self.nickid: nickval} else: # Try to find the name prefix in the given name, also this # changes given name match = self._fn_prefix_re.match(first) if match: groups = match.groups() if old_prefix[0]: # Put the found prefix before the old prefix new_prefix = " ".join([groups[1], old_prefix[0]]) else: new_prefix = groups[1] pref1val = (groups[0], new_prefix, groups[1]) if key in self.handle_to_action: self.handle_to_action[key][self.pref1id] = pref1val else: self.handle_to_action[key] = {self.pref1id: pref1val} #check for Gedcom import of compound surnames if len(old_surn) == 1 and old_con[0] == '': prefixes = old_prefix[0].split(',') surnames = old_surn[0].split(',') if len(prefixes) > 1 and len(prefixes) == len(surnames): #assume a list of prefix and a list of surnames prefixes = list(map(strip, prefixes)) surnames = list(map(strip, surnames)) primaries = [False] * len(prefixes) primaries[0] = True origs = [] for ind in range(len(prefixes)): origs.append(NameOriginType()) origs[0] = old_orig[0] compoundval = (surnames, prefixes, [''] * len(prefixes), primaries, origs) if key in self.handle_to_action: self.handle_to_action[key][self.compid] = compoundval else: self.handle_to_action[key] = {self.compid: compoundval} #we cannot check compound surnames, so continue the loop continue # Next, try to split surname in compounds: prefix surname connector found = False new_prefix_list = [] new_surname_list = [] new_connector_list = [] new_prim_list = [] new_orig_list = [] ind = 0 cont = True for pref, surn, con, prim, orig in zip(old_prefix, old_surn, old_con, old_prim, old_orig): surnval = surn.split() if surnval == []: new_prefix_list.append(pref) new_surname_list.append('') new_connector_list.append(con) new_prim_list.append(prim) new_orig_list.append(orig) cont = False continue val = surnval.pop(0) while cont: new_prefix_list.append(pref) new_surname_list.append('') new_connector_list.append(con) new_prim_list.append(prim) new_orig_list.append(orig) while cont and (val.lower() in self.prefix_list): found = True if new_prefix_list[-1]: new_prefix_list[-1] += ' ' + val else: new_prefix_list[-1] = val try: val = surnval.pop(0) except IndexError: val = '' cont = False #after prefix we have a surname if cont: new_surname_list[-1] = val try: val = surnval.pop(0) except IndexError: val = '' cont = False #if value after surname indicates continue, then continue while cont and (val.lower() in self.connector_list_nonsplit): #add this val to the current surname new_surname_list[-1] += ' ' + val try: val = surnval.pop(0) except IndexError: val = '' cont = False # if previous is non-splitting connector, then add new val to # current surname if cont and (new_surname_list[-1].split()[-1].lower() in self.connector_list_nonsplit): new_surname_list[-1] += ' ' + val try: val = surnval.pop(0) except IndexError: val = '' cont = False #if next is a connector, add it to the surname if cont and val.lower() in self.connector_list: found = True if new_connector_list[-1]: new_connector_list[-1] = ' ' + val else: new_connector_list[-1] = val try: val = surnval.pop(0) except IndexError: val = '' cont = False #initialize for a next surname in case there are still #val if cont: found = True # we split surname pref = '' con = '' prim = False orig = NameOriginType() ind += 1 if found: compoundval = (new_surname_list, new_prefix_list, new_connector_list, new_prim_list, new_orig_list) if key in self.handle_to_action: self.handle_to_action[key][self.compid] = compoundval else: self.handle_to_action[key] = {self.compid: compoundval} self.progress.step() if self.handle_to_action: self.display() else: self.progress.close() self.close() OkDialog( _('No modifications made'), # parent-OK _("No titles, nicknames or prefixes were found"), parent=self.uistate.window) def build_menu_names(self, obj): return (self.label, None) def toggled(self, cell, path_string): path = tuple(map(int, path_string.split(':'))) row = self.model[path] row[0] = not row[0] self.model.row_changed(path, row.iter) def display(self): self.top = Glade() window = self.top.toplevel self.top.connect_signals({ "destroy_passed_object": self.close, "on_ok_clicked": self.on_ok_clicked, "on_help_clicked": self.on_help_clicked, "on_delete_event": self.close, }) self.list = self.top.get_object("list") self.set_window(window, self.top.get_object('title'), self.label) self.model = Gtk.ListStore(GObject.TYPE_BOOLEAN, GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_STRING) r = Gtk.CellRendererToggle() r.connect('toggled', self.toggled) c = Gtk.TreeViewColumn(_('Select'), r, active=0) self.list.append_column(c) c = Gtk.TreeViewColumn(_('ID'), Gtk.CellRendererText(), text=1) self.list.append_column(c) c = Gtk.TreeViewColumn(_('Type'), Gtk.CellRendererText(), text=2) self.list.append_column(c) c = Gtk.TreeViewColumn(_('Value'), Gtk.CellRendererText(), text=3) self.list.append_column(c) c = Gtk.TreeViewColumn(_('Current Name'), Gtk.CellRendererText(), text=4) self.list.append_column(c) self.list.set_model(self.model) self.nick_hash = {} self.title_hash = {} self.prefix1_hash = {} self.compound_hash = {} self.progress.set_pass(_('Building display'), len(list(self.handle_to_action.keys()))) for key, data in self.handle_to_action.items(): p = self.db.get_person_from_handle(key) gid = p.get_gramps_id() if self.nickid in data: given, nick = data[self.nickid] handle = self.model.append() self.model.set_value(handle, 0, 1) self.model.set_value(handle, 1, gid) self.model.set_value(handle, 2, _('Nickname')) self.model.set_value(handle, 3, nick) self.model.set_value(handle, 4, p.get_primary_name().get_name()) self.nick_hash[key] = handle if self.titleid in data: title, given = data[self.titleid] handle = self.model.append() self.model.set_value(handle, 0, 1) self.model.set_value(handle, 1, gid) self.model.set_value(handle, 2, _('Person|Title')) self.model.set_value(handle, 3, title) self.model.set_value(handle, 4, p.get_primary_name().get_name()) self.title_hash[key] = handle if self.pref1id in data: given, prefixtotal, new_prefix = data[self.pref1id] handle = self.model.append() self.model.set_value(handle, 0, 1) self.model.set_value(handle, 1, gid) self.model.set_value(handle, 2, _('Prefix in given name')) self.model.set_value(handle, 3, prefixtotal) self.model.set_value(handle, 4, p.get_primary_name().get_name()) self.prefix1_hash[key] = handle if self.compid in data: surn_list, pref_list, con_list, prims, origs = data[ self.compid] handle = self.model.append() self.model.set_value(handle, 0, 1) self.model.set_value(handle, 1, gid) self.model.set_value(handle, 2, _('Compound surname')) newval = '' for sur, pre, con in zip(surn_list, pref_list, con_list): if newval: newval += '-[' else: newval = '[' newval += pre + ',' + sur if con: newval += ',' + con + ']' else: newval += ']' self.model.set_value(handle, 3, newval) self.model.set_value(handle, 4, p.get_primary_name().get_name()) self.compound_hash[key] = handle self.progress.step() self.progress.close() self.show() def on_help_clicked(self, obj): """Display the relevant portion of GRAMPS manual""" display_help(webpage=WIKI_HELP_PAGE, section=WIKI_HELP_SEC) def on_ok_clicked(self, obj): with DbTxn(_("Extract information from names"), self.db, batch=True) as trans: self.db.disable_signals() for key, data in self.handle_to_action.items(): p = self.db.get_person_from_handle(key) if self.nickid in data: modelhandle = self.nick_hash[key] val = self.model.get_value(modelhandle, 0) if val: given, nick = data[self.nickid] name = p.get_primary_name() name.set_first_name(given.strip()) name.set_nick_name(nick.strip()) if self.titleid in data: modelhandle = self.title_hash[key] val = self.model.get_value(modelhandle, 0) if val: title, given = data[self.titleid] name = p.get_primary_name() name.set_first_name(given.strip()) name.set_title(title.strip()) if self.pref1id in data: modelhandle = self.prefix1_hash[key] val = self.model.get_value(modelhandle, 0) if val: given, prefixtotal, prefix = data[self.pref1id] name = p.get_primary_name() name.set_first_name(given.strip()) oldpref = name.get_surname_list()[0].get_prefix( ).strip() if oldpref == '' or oldpref == prefix.strip(): name.get_surname_list()[0].set_prefix(prefix) else: name.get_surname_list()[0].set_prefix( '%s %s' % (prefix, oldpref)) if self.compid in data: modelhandle = self.compound_hash[key] val = self.model.get_value(modelhandle, 0) if val: surns, prefs, cons, prims, origs = data[self.compid] name = p.get_primary_name() new_surn_list = [] for surn, pref, con, prim, orig in zip( surns, prefs, cons, prims, origs): new_surn_list.append(Surname()) new_surn_list[-1].set_surname(surn.strip()) new_surn_list[-1].set_prefix(pref.strip()) new_surn_list[-1].set_connector(con.strip()) new_surn_list[-1].set_primary(prim) new_surn_list[-1].set_origintype(orig) name.set_surname_list(new_surn_list) self.db.commit_person(p, trans) self.db.enable_signals() self.db.request_rebuild() self.close() self.cb()
class ReorderIds(tool.BatchTool, ManagedWindow, UpdateCallback): """ Class for Reodering Gramps ID Tool """ xobjects = (('person', 'people'), ('family', 'families'), ('event', 'events'), ('place', 'places'), ('source', 'sources'), ('citation', 'citations'), ('repository', 'repositories'), ('media', 'media'), ('note', 'notes')) def build_menu_names_(self, widget=None): """ The menu name """ return (_('Main window'), _("Reorder Gramps IDs")) def __init__(self, dbstate, user, options_class, name, callback=None): self.uistate = user.uistate self.dbstate = dbstate.db if self.uistate: tool.BatchTool.__init__(self, dbstate, user, options_class, name) if self.fail: return # user denied to modify Gramps IDs ManagedWindow.__init__(self, self.uistate, [], self.__class__) if not self.uistate: UpdateCallback.__init__(self, user.callback) self.object_status = True self.change_status = False self.start_zero = True self.step_cnt, self.step_list = 0, ['1', '2', '5', '10'] self.keep_status = True self.obj_values = {} # enable access to all internal values self.active_entries, self.format_entries = {}, {} self.change_entries = {} self.start_entries, self.step_entries = {}, {} self.keep_entries = {} self.prim_methods, self.obj_methods = {}, {} for prim_obj, prim_objs in self.xobjects: class_type = prim_obj.title() iter_handles = "self.dbstate.iter_%s_handles" % prim_obj get_number_obj = "self.dbstate.get_number_of_%s" % prim_objs prefix_fmt = "self.dbstate.%s_prefix" % prim_obj get_from_id = "self.dbstate.get_%s_from_gramps_id" % prim_obj get_from_handle = "self.dbstate.get_%s_from_handle" % prim_obj next_from_id = "self.dbstate.find_next_%s_gramps_id" % prim_obj commit = "self.dbstate.commit_%s" % prim_obj self.prim_methods[prim_obj] = (eval(prefix_fmt), eval(get_number_obj)(), eval(next_from_id)()) self.obj_methods[prim_obj] = (eval(class_type), eval(iter_handles), eval(commit), eval(get_from_id), eval(get_from_handle), eval(next_from_id)) object_fmt, quant_id, next_id = self.prim_methods[prim_obj] obj_value = ReorderEntry(object_fmt, quant_id, next_id) self.obj_values[prim_obj] = obj_value if self.uistate: self._display() else: self._execute() def __on_object_button_clicked(self, widget=None): """ compute all primary objects and toggle the 'Active' attribute """ self.object_status = not self.object_status for prim_obj, tmp in self.xobjects: obj = self.top.get_object('%s_active' % prim_obj) obj.set_active(self.object_status) def __on_object_button_toggled(self, widget): """ compute the primary object and toggle the 'Sensitive' attribute """ obj_state = widget.get_active() obj_name = Gtk.Buildable.get_name(widget).split('_', 1)[0] self.active_entries[obj_name].set_val(obj_state) for obj_entry in ['actual', 'quant', 'format', 'change']: obj = self.top.get_object('%s_%s' % (obj_name, obj_entry)) obj.set_sensitive(obj_state) for obj_entry in ['start', 'step', 'keep']: obj = self.top.get_object('%s_change' % obj_name) if obj.get_active(): obj = self.top.get_object('%s_%s' % (obj_name, obj_entry)) obj.set_sensitive(obj_state) def __on_format_button_clicked(self, widget=None): """ compute all sensitive primary objects and sets the 'Format' scheme of identifiers """ for prim_obj, tmp in self.xobjects: obj_format = self.top.get_object('%s_format' % prim_obj) if not obj_format.get_sensitive(): continue obj_fmt = self.obj_values[prim_obj].res_fmt() self.format_entries[prim_obj].force_value(obj_fmt) if self.start_zero: obj_id = self.obj_values[prim_obj].zero_id() else: obj_id = self.obj_values[prim_obj].last_id() self.start_entries[prim_obj].force_value(obj_id) def __on_change_button_clicked(self, widget=None): """ compute all primary objects and toggle the 'Change' attribute """ self.change_status = not self.change_status for prim_obj, tmp in self.xobjects: obj_change = self.top.get_object('%s_change' % prim_obj) if not obj_change.get_sensitive(): continue self.change_entries[prim_obj].set_val(self.change_status) obj_change.set_active(self.change_status) def __on_change_button_toggled(self, widget): """ compute the primary object and toggle the 'Sensitive' attribute """ obj_state = widget.get_active() obj_name = Gtk.Buildable.get_name(widget).split('_', 1)[0] for obj_entry in ['start', 'step', 'keep']: obj = self.top.get_object('%s_%s' % (obj_name, obj_entry)) if obj_entry == 'keep': if self.obj_values[obj_name].stored_prefix != \ self.obj_values[obj_name].object_prefix: self.keep_entries[obj_name].set_val(False) else: obj.set_active(obj_state) self.keep_entries[obj_name].set_val(obj_state) obj.set_sensitive(obj_state) def __on_start_button_clicked(self, widget=None): """ compute all sensitive primary objects and sets the 'Start' values of identifiers """ self.start_zero = not self.start_zero for prim_obj, tmp in self.xobjects: obj = self.top.get_object('%s_start' % prim_obj) if not obj.get_sensitive(): continue if self.start_zero: obj_id = self.obj_values[prim_obj].zero_id() else: obj_id = self.obj_values[prim_obj].next_id() self.start_entries[prim_obj].force_value(obj_id) def __on_step_button_clicked(self, widget=None): """ compute all sensitive primary objects and sets the 'Step' width of identifiers """ self.step_cnt = self.step_cnt + 1 if self.step_cnt < 3 else 0 for prim_obj, tmp in self.xobjects: obj = self.top.get_object('%s_step' % prim_obj) if not obj.get_sensitive(): continue step_val = self.step_list[self.step_cnt] self.step_entries[prim_obj].force_value(step_val) def __on_keep_button_clicked(self, widget=None): """ compute the primary object and toggle the 'Active' attribute """ self.keep_status = not self.keep_status for prim_obj, tmp in self.xobjects: obj = self.top.get_object('%s_change' % prim_obj) if not obj.get_active(): continue obj = self.top.get_object('%s_keep' % prim_obj) obj.set_active(self.keep_status) self.keep_entries[prim_obj].set_val(self.keep_status) def __on_format_entry_keyrelease(self, widget, event, data=None): """ activated on all return's of an entry """ if event.keyval in [Gdk.KEY_Return]: obj_name = Gtk.Buildable.get_name(widget).split('_', 1)[0] obj_fmt = self.format_entries[obj_name].get_val() self.format_entries[obj_name].force_value(obj_fmt) self.start_entries[obj_name].update() obj_change = self.top.get_object('%s_change' % obj_name) obj_change.grab_focus() return False def __on_format_entry_focusout(self, widget, event, data=None): """ activated on all focus out of an entry """ obj_name = Gtk.Buildable.get_name(widget).split('_', 1)[0] obj_fmt = self.format_entries[obj_name].get_val() self.format_entries[obj_name].set_val(obj_fmt) self.start_entries[obj_name].update() return False def __on_start_entry_focusout(self, widget, event, data=None): """ activated on all focus out of an entry """ obj_name = Gtk.Buildable.get_name(widget).split('_', 1)[0] self.start_entries[obj_name].update() return False def __on_ok_button_clicked(self, widget=None): """ execute the reodering and close """ self._execute() self._update() self.close() def __on_cancel_button_clicked(self, widget=None): """ cancel the reodering and close """ self.close() def __on_help_button_clicked(self, widget=None): """ display the relevant portion of Gramps manual """ display_help(webpage=WIKI_HELP_PAGE, section=WIKI_HELP_SEC) def _display(self): """ organize Glade 'Reorder IDs' window """ # get the main window from glade self.top = Glade(toplevel="reorder-ids") window = self.top.toplevel # set gramps style title for the window self.set_window(window, self.top.get_object("title"), \ _("Reorder Gramps IDs")) # connect signals self.top.connect_signals({ "on_object_button_clicked": self.__on_object_button_clicked, "on_object_button_toggled": self.__on_object_button_toggled, "on_format_button_clicked": self.__on_format_button_clicked, "on_start_button_clicked": self.__on_start_button_clicked, "on_step_button_clicked": self.__on_step_button_clicked, "on_keep_button_clicked": self.__on_keep_button_clicked, "on_change_button_clicked": self.__on_change_button_clicked, "on_change_button_toggled": self.__on_change_button_toggled, "on_format_entry_keyrelease": self.__on_format_entry_keyrelease, "on_format_entry_focusout": self.__on_format_entry_focusout, "on_start_entry_focusout": self.__on_start_entry_focusout, "on_help_button_clicked": self.__on_help_button_clicked, "on_cancel_button_clicked": self.__on_cancel_button_clicked, "on_ok_button_clicked": self.__on_ok_button_clicked }) # Calculate all entries and update Glade window for prim_obj, tmp in self.xobjects: # populate Object, Actual & Quantity fields with values obj_active = self.top.get_object('%s_active' % prim_obj) self.active_entries[prim_obj] = MonitoredCheckbox( obj_active, obj_active, self.obj_values[prim_obj].set_active, self.obj_values[prim_obj].get_active) obj_actual = self.top.get_object('%s_actual' % prim_obj) obj_actual.set_text('%s' % self.obj_values[prim_obj].last_id()) obj_quant = self.top.get_object('%s_quant' % prim_obj) obj_quant.set_text('%s' % str(self.obj_values[prim_obj].quant_id)) # connect/populate Format, Start, Step, Keep & Change fields with GTK/values obj_format = self.top.get_object('%s_format' % prim_obj) self.format_entries[prim_obj] = MonitoredEntry( obj_format, self.obj_values[prim_obj].set_fmt, self.obj_values[prim_obj].get_fmt) obj_change = self.top.get_object('%s_change' % prim_obj) self.change_entries[prim_obj] = MonitoredCheckbox( obj_change, obj_change, self.obj_values[prim_obj].set_change, self.obj_values[prim_obj].get_change) obj_start = self.top.get_object('%s_start' % prim_obj) self.start_entries[prim_obj] = MonitoredEntry( obj_start, self.obj_values[prim_obj].set_id, self.obj_values[prim_obj].get_id) obj_step = self.top.get_object('%s_step' % prim_obj) self.step_entries[prim_obj] = MonitoredEntry( obj_step, self.obj_values[prim_obj].set_step, self.obj_values[prim_obj].get_step, changed=self.obj_values[prim_obj].change_step) obj_keep = self.top.get_object('%s_keep' % prim_obj) self.keep_entries[prim_obj] = MonitoredCheckbox( obj_keep, obj_keep, self.obj_values[prim_obj].set_keep, self.obj_values[prim_obj].get_keep, readonly=True) # fetch the popup menu self.menu = self.top.get_object("popup_menu") # ok, let's see what we've done self.show() def _update(self): """ store changed objects formats in DB """ update = False for prim_obj, tmp in self.xobjects: obj_value = self.obj_values[prim_obj] if obj_value.object_fmt != obj_value.stored_fmt: prefix = obj_value.object_prefix.lower() constant = 'preferences.%sprefix' % prefix config.set(constant, obj_value.object_fmt) update = True if update: config.save() self.dbstate.set_prefixes(config.get('preferences.iprefix'), config.get('preferences.oprefix'), config.get('preferences.fprefix'), config.get('preferences.sprefix'), config.get('preferences.cprefix'), config.get('preferences.pprefix'), config.get('preferences.eprefix'), config.get('preferences.rprefix'), config.get('preferences.nprefix')) def _execute(self): """ execute all primary objects and reorder if neccessary """ # Update progress calculation if self.uistate: self.progress = ProgressMeter(_('Reorder Gramps IDs'), '') else: total_objs = 0 for prim_obj, tmp in self.xobjects: if self.obj_values[prim_obj].active_obj: total_objs += self.obj_values[prim_obj].quant_id self.set_total(total_objs) # Update database self.dbstate.disable_signals() for prim_obj, prim_objs in self.xobjects: with DbTxn(_('Reorder %s IDs ...') % prim_obj, self.dbstate, batch=True) \ as self.trans: if self.obj_values[prim_obj].active_obj: if self.uistate: self.progress.set_pass(_('Reorder %s IDs ...') % \ _(prim_objs.title()), \ self.obj_values[prim_obj].quant_id) # Process reordering self._reorder(prim_obj) self.dbstate.enable_signals() self.dbstate.request_rebuild() # Update progress calculation if self.uistate: self.progress.close() else: print('\nDone.') # finds integer portion in a GrampsID _findint = re.compile('^[^\d]*(\d+)[^\d]*') def _reorder(self, prim_obj): """ reorders all selected objects with a (new) style, start & step """ dup_ids = [] # list of duplicate identifiers new_ids = {} # list of new identifiers class_type, iter_handles, commit, get_from_id, get_from_handle, next_from_id = \ self.obj_methods[prim_obj] prefix_fmt = self.obj_values[prim_obj].get_fmt() prefix = prefix_fmt.split('%', 1)[0] new_id = self.obj_values[prim_obj].get_id() keep_fmt = self.obj_values[prim_obj].get_keep() change = self.obj_values[prim_obj].get_change() formatmatch = _parseformat.match(prefix_fmt) index_max = int("9" * int(formatmatch.groups()[0])) for handle in iter_handles(): # Update progress if self.uistate: self.progress.step() else: self.update() # extract basic data out of the database obj = get_from_handle(handle) act_id = obj.get_gramps_id() if change: # update the defined ID numbers into objects under consideration # of keeping ID if format not matches prefix # (implication logical boolean operator below) if act_id.startswith(prefix) or not keep_fmt: obj.set_gramps_id(new_id) commit(obj, self.trans) new_id = self.obj_values[prim_obj].succ_id() else: # attempt to extract integer - if we can't, treat it as a duplicate try: match = _findint.match(act_id) if match: # get the integer, build the new handle. Make sure it # hasn't already been chosen. If it has, put this # in the duplicate handle list index = int(match.groups()[0]) if formatmatch: if index > index_max: new_id = next_from_id() else: new_id = prefix_fmt % index else: # prefix_fmt does not contain a number after %, eg I%d new_id = prefix_fmt % index if new_id == act_id: if new_id in new_ids: dup_ids.append(obj.get_handle()) else: new_ids[new_id] = act_id elif get_from_id(new_id) is not None: dup_ids.append(obj.get_handle()) else: obj.set_id(new_id) commit(obj, self.trans) new_ids[new_id] = act_id else: dup_ids.append(handle) except: dup_ids.append(handle) # go through the duplicates, looking for the first available # handle that matches the new scheme. if dup_ids: if self.uistate: self.progress.set_pass(_('Finding and assigning unused IDs.'), len(dup_ids)) for handle in dup_ids: obj = get_from_handle(handle) obj.set_gramps_id(next_from_id()) commit(obj, self.trans)
class DisplayChart(ManagedWindow): def __init__(self, dbstate, uistate, people_list, track): self.dbstate = dbstate self.uistate = uistate ManagedWindow.__init__(self, uistate, track, self) self.db = dbstate.db self.my_list = people_list self.row_data = [] self.save_form = None self.topDialog = Glade() self.topDialog.connect_signals( { "on_write_table": self.on_write_table, "destroy_passed_object": self.close, "on_help_clicked": self.on_help_clicked, "on_apply_clicked": self.__dummy, "on_editor_clicked": self.__dummy, } ) window = self.topDialog.toplevel self.set_window(window, self.topDialog.get_object("title"), _("Event Comparison Results")) self.eventlist = self.topDialog.get_object("treeview") self.sort = Sort(self.db) self.my_list.sort(key=self.sort.by_last_name_key) self.event_titles = self.make_event_titles() self.table_titles = [_("Person"), _("ID")] for event_name in self.event_titles: self.table_titles.append(_("%(event_name)s Date") % {"event_name": event_name}) self.table_titles.append("sort") # This won't be shown in a tree self.table_titles.append(_("%(event_name)s Place") % {"event_name": event_name}) self.build_row_data() self.draw_display() self.show() def __dummy(self, obj): """dummy callback, needed because widget is in same glade file as another widget, so callbacks must be defined to avoid warnings. """ pass def on_help_clicked(self, obj): """Display the relevant portion of GRAMPS manual""" display_help(webpage=WIKI_HELP_PAGE, section=WIKI_HELP_SEC) def build_menu_names(self, obj): return (_("Event Comparison Results"), None) def draw_display(self): model_index = 0 tree_index = 0 mylist = [] renderer = Gtk.CellRendererText() for title in self.table_titles: mylist.append(str) if title == "sort": # This will override the previously defined column self.eventlist.get_column(tree_index - 1).set_sort_column_id(model_index) else: column = Gtk.TreeViewColumn(title, renderer, text=model_index) column.set_sort_column_id(model_index) self.eventlist.append_column(column) # This one numbers the tree columns: increment on new column tree_index += 1 # This one numbers the model columns: always increment model_index += 1 model = Gtk.ListStore(*mylist) self.eventlist.set_model(model) self.progress_bar.set_pass(_("Building display"), len(self.row_data)) for data in self.row_data: model.append(row=list(data)) self.progress_bar.step() self.progress_bar.close() def build_row_data(self): self.progress_bar = ProgressMeter(_("Comparing Events"), "", parent=self.window) self.progress_bar.set_pass(_("Building data"), len(self.my_list)) for individual_id in self.my_list: individual = self.db.get_person_from_handle(individual_id) name = individual.get_primary_name().get_name() gid = individual.get_gramps_id() the_map = defaultdict(list) for ievent_ref in individual.get_event_ref_list(): ievent = self.db.get_event_from_handle(ievent_ref.ref) event_name = str(ievent.get_type()) the_map[event_name].append(ievent_ref.ref) first = True done = False while not done: added = False tlist = [name, gid] if first else ["", ""] for ename in self.event_titles: if ename in the_map and len(the_map[ename]) > 0: event_handle = the_map[ename][0] del the_map[ename][0] date = place = "" if event_handle: event = self.db.get_event_from_handle(event_handle) date = get_date(event) sortdate = "%09d" % (event.get_date_object().get_sort_value()) place_handle = event.get_place_handle() if place_handle: place = self.db.get_place_from_handle(place_handle).get_title() tlist += [date, sortdate, place] added = True else: tlist += [""] * 3 if first: first = False self.row_data.append(tlist) elif not added: done = True else: self.row_data.append(tlist) self.progress_bar.step() def make_event_titles(self): """ Create the list of unique event types, along with the person's name, birth, and death. This should be the column titles of the report. """ the_map = defaultdict(int) for individual_id in self.my_list: individual = self.db.get_person_from_handle(individual_id) for event_ref in individual.get_event_ref_list(): event = self.db.get_event_from_handle(event_ref.ref) name = str(event.get_type()) if not name: break the_map[name] += 1 unsort_list = sorted([(d, k) for k, d in the_map.items()], key=lambda x: x[0], reverse=True) sort_list = [item[1] for item in unsort_list] ## Presently there's no Birth and Death. Instead there's Birth Date and ## Birth Place, as well as Death Date and Death Place. ## # Move birth and death to the begining of the list ## if _("Death") in the_map: ## sort_list.remove(_("Death")) ## sort_list = [_("Death")] + sort_list ## if _("Birth") in the_map: ## sort_list.remove(_("Birth")) ## sort_list = [_("Birth")] + sort_list return sort_list def on_write_table(self, obj): f = Gtk.FileChooserDialog( _("Select filename"), parent=self.window, action=Gtk.FileChooserAction.SAVE, buttons=(_("_Cancel"), Gtk.ResponseType.CANCEL, _("_Save"), Gtk.ResponseType.OK), ) f.set_current_folder(get_curr_dir()) status = f.run() f.hide() if status == Gtk.ResponseType.OK: name = conv_to_unicode(f.get_filename()) doc = ODSTab(len(self.row_data)) doc.creator(self.db.get_researcher().get_name()) spreadsheet = TableReport(name, doc) new_titles = [] skip_columns = [] index = 0 for title in self.table_titles: if title == "sort": skip_columns.append(index) else: new_titles.append(title) index += 1 spreadsheet.initialize(len(new_titles)) spreadsheet.write_table_head(new_titles) index = 0 for top in self.row_data: spreadsheet.set_row(index % 2) index += 1 spreadsheet.write_table_data(top, skip_columns) spreadsheet.finalize() f.destroy()
class EventComparisonResults(ManagedWindow): def __init__(self, dbstate, uistate, people_list, track): self.dbstate = dbstate self.uistate = uistate ManagedWindow.__init__(self, uistate, track, self) self.db = dbstate.db self.my_list = people_list self.row_data = [] self.save_form = None self.topDialog = Glade(toplevel="eventcmp") self.topDialog.connect_signals({ "on_write_table": self.on_write_table, "destroy_passed_object": self.close, "on_help_clicked": self.on_help_clicked, "on_apply_clicked": self.__dummy, "on_editor_clicked": self.__dummy, }) window = self.topDialog.toplevel self.set_window(window, self.topDialog.get_object('title'), _('Event Comparison Results')) self.setup_configs('interface.eventcomparisonresults', 750, 400) self.eventlist = self.topDialog.get_object('treeview') self.sort = Sort(self.db) self.my_list.sort(key=self.sort.by_last_name_key) self.event_titles = self.make_event_titles() self.table_titles = [_("Person"), _("ID")] for event_name in self.event_titles: self.table_titles.append( _("%(event_name)s Date") % {'event_name': event_name}) self.table_titles.append('sort') # This won't be shown in a tree self.table_titles.append( _("%(event_name)s Place") % {'event_name': event_name}) self.build_row_data() self.draw_display() self.show() def __dummy(self, obj): """dummy callback, needed because widget is in same glade file as another widget, so callbacks must be defined to avoid warnings. """ pass def on_help_clicked(self, obj): """Display the relevant portion of Gramps manual""" display_help(webpage=WIKI_HELP_PAGE, section=WIKI_HELP_SEC) def build_menu_names(self, obj): return (_("Event Comparison Results"), None) def draw_display(self): model_index = 0 tree_index = 0 mylist = [] renderer = Gtk.CellRendererText() for title in self.table_titles: mylist.append(str) if title == 'sort': # This will override the previously defined column self.eventlist.get_column(tree_index - 1).set_sort_column_id(model_index) else: column = Gtk.TreeViewColumn(title, renderer, text=model_index) column.set_sort_column_id(model_index) self.eventlist.append_column(column) # This one numbers the tree columns: increment on new column tree_index += 1 # This one numbers the model columns: always increment model_index += 1 model = Gtk.ListStore(*mylist) self.eventlist.set_model(model) self.progress_bar.set_pass(_('Building display'), len(self.row_data)) for data in self.row_data: model.append(row=list(data)) self.progress_bar.step() self.progress_bar.close() def build_row_data(self): self.progress_bar = ProgressMeter(_('Comparing Events'), '', parent=self.uistate.window) self.progress_bar.set_pass(_('Building data'), len(self.my_list)) for individual_id in self.my_list: individual = self.db.get_person_from_handle(individual_id) name = individual.get_primary_name().get_name() gid = individual.get_gramps_id() the_map = defaultdict(list) for ievent_ref in individual.get_event_ref_list(): ievent = self.db.get_event_from_handle(ievent_ref.ref) event_name = str(ievent.get_type()) the_map[event_name].append(ievent_ref.ref) first = True done = False while not done: added = False tlist = [name, gid] if first else ["", ""] for ename in self.event_titles: if ename in the_map and len(the_map[ename]) > 0: event_handle = the_map[ename][0] del the_map[ename][0] date = place = "" if event_handle: event = self.db.get_event_from_handle(event_handle) date = get_date(event) sortdate = "%09d" % ( event.get_date_object().get_sort_value()) place_handle = event.get_place_handle() if place_handle: place = self.db.get_place_from_handle( place_handle).get_title() tlist += [date, sortdate, place] added = True else: tlist += [""] * 3 if first: first = False self.row_data.append(tlist) elif not added: done = True else: self.row_data.append(tlist) self.progress_bar.step() def make_event_titles(self): """ Create the list of unique event types, along with the person's name, birth, and death. This should be the column titles of the report. """ the_map = defaultdict(int) for individual_id in self.my_list: individual = self.db.get_person_from_handle(individual_id) for event_ref in individual.get_event_ref_list(): event = self.db.get_event_from_handle(event_ref.ref) name = str(event.get_type()) if not name: break the_map[name] += 1 unsort_list = sorted([(d, k) for k, d in the_map.items()], key=lambda x: x[0], reverse=True) sort_list = [item[1] for item in unsort_list] ## Presently there's no Birth and Death. Instead there's Birth Date and ## Birth Place, as well as Death Date and Death Place. ## # Move birth and death to the begining of the list ## if _("Death") in the_map: ## sort_list.remove(_("Death")) ## sort_list = [_("Death")] + sort_list ## if _("Birth") in the_map: ## sort_list.remove(_("Birth")) ## sort_list = [_("Birth")] + sort_list return sort_list def on_write_table(self, obj): f = Gtk.FileChooserDialog(_("Select filename"), parent=self.window, action=Gtk.FileChooserAction.SAVE, buttons=(_('_Cancel'), Gtk.ResponseType.CANCEL, _('_Save'), Gtk.ResponseType.OK)) f.set_current_folder(get_curr_dir()) status = f.run() f.hide() if status == Gtk.ResponseType.OK: name = f.get_filename() doc = ODSTab(len(self.row_data)) doc.creator(self.db.get_researcher().get_name()) spreadsheet = TableReport(name, doc) new_titles = [] skip_columns = [] index = 0 for title in self.table_titles: if title == 'sort': skip_columns.append(index) else: new_titles.append(title) index += 1 spreadsheet.initialize(len(new_titles)) spreadsheet.write_table_head(new_titles) index = 0 for top in self.row_data: spreadsheet.set_row(index % 2) index += 1 spreadsheet.write_table_data(top, skip_columns) spreadsheet.finalize() f.destroy()
def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate self.title = _('Find database loop') ManagedWindow.__init__(self, uistate, [], self.__class__) self.dbstate = dbstate self.uistate = uistate #self.db = CacheProxyDb(dbstate.db) self.db = dbstate.db top_dialog = Glade() top_dialog.connect_signals({ "destroy_passed_object" : self.close, "on_help_clicked" : self.on_help_clicked, "on_delete_event" : self.close, }) window = top_dialog.toplevel title = top_dialog.get_object("title") self.set_window(window, title, self.title) # start the progress indicator self.progress = ProgressMeter(self.title, _('Starting'), parent=uistate.window) self.progress.set_pass(_('Looking for possible loop for each person'), self.db.get_number_of_people()) self.model = Gtk.ListStore( GObject.TYPE_STRING, # 0==father id GObject.TYPE_STRING, # 1==father GObject.TYPE_STRING, # 2==son id GObject.TYPE_STRING, # 3==son GObject.TYPE_STRING, # 4==family gid GObject.TYPE_STRING) # 5==loop number self.model.set_sort_column_id( Gtk.TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, 0) self.treeview = top_dialog.get_object("treeview") self.treeview.set_model(self.model) col0 = Gtk.TreeViewColumn('', Gtk.CellRendererText(), text=5) col1 = Gtk.TreeViewColumn(_('Gramps ID'), Gtk.CellRendererText(), text=0) col2 = Gtk.TreeViewColumn(_('Parent'), Gtk.CellRendererText(), text=1) col3 = Gtk.TreeViewColumn(_('Gramps ID'), Gtk.CellRendererText(), text=2) col4 = Gtk.TreeViewColumn(_('Child'), Gtk.CellRendererText(), text=3) col5 = Gtk.TreeViewColumn(_('Family ID'), Gtk.CellRendererText(), text=4) col1.set_resizable(True) col2.set_resizable(True) col3.set_resizable(True) col4.set_resizable(True) col5.set_resizable(True) col1.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) col2.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) col3.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) col4.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) col5.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) self.treeview.append_column(col0) self.treeview.append_column(col1) self.treeview.append_column(col2) self.treeview.append_column(col3) self.treeview.append_column(col4) self.treeview.append_column(col5) self.treeselection = self.treeview.get_selection() self.treeview.connect('row-activated', self.rowactivated_cb) self.curr_fam = None people = self.db.get_person_handles() self.total = len(people) # total number of people to process. self.count = 0 # current number of people completely processed self.loop = 0 # Number of loops found for GUI pset = OrderedDict() # pset is the handle list of persons from the current start of # exploration path to the current limit. The use of OrderedDict # allows us to use it as a LIFO during recursion, as well as makes for # quick lookup. If we find a loop, pset provides a nice way to get # the loop path. self.done = set() # self.done is the handle set of people that have been fully explored # and do NOT have loops in the decendent tree. We use this to avoid # repeating work when we encounter one of these during the search. for person_handle in people: person = self.db.get_person_from_handle(person_handle) self.current = person self.parent = None self.descendants(person_handle, pset) # close the progress bar self.progress.close() self.show()
class ChangeGivenNames(tool.BatchTool, ManagedWindow): def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate self.label = _('Capitalization changes') self.dbstate = dbstate self.uistate = uistate self.cb = callback ManagedWindow.__init__(self,uistate,[],self.__class__) self.set_window(Gtk.Window(),Gtk.Label(),'') tool.BatchTool.__init__(self, dbstate, user, options_class, name) if self.fail: return given_name_dict = self.get_given_name_dict() self.progress = ProgressMeter(_('Checking Given Names'),'', parent=uistate.window) self.progress.set_pass(_('Searching given names'), len(given_name_dict.keys())) self.name_list = [] for name in given_name_dict.keys(): if name != capitalize(name): self.name_list.append((name, given_name_dict[name])) if uistate: self.progress.step() if self.name_list: self.display() else: self.progress.close() self.close() OkDialog(_('No modifications made'), _("No capitalization changes were detected."), parent=uistate.window) def get_given_name_dict(self): givennames = {} self.name_map = {} for person in self.db.iter_people(): allnames = [person.get_primary_name()] + person.get_alternate_names() allnames = set(name.get_first_name().strip() for name in allnames) for givenname in allnames: givennames[givenname] = givennames.get(givenname, 0) + 1 self.name_map[givenname] = self.name_map.get(givenname, set([])) self.name_map[givenname].add(person.handle) return givennames def display(self): if lin(): import locale, os locale.setlocale(locale.LC_ALL, '') # This is needed to make gtk.Builder work by specifying the # translations directory base = os.path.dirname(__file__) locale.bindtextdomain("addon", base + "/locale") self.glade = Gtk.Builder() self.glade.set_translation_domain("addon") path = base + "/changenames.glade" self.glade.add_from_file(path) #from gi.repository import GObject GObject.GObject.__init__(self.glade) self.top = self.glade.get_object('changenames') self.glade.connect_signals({ "destroy_passed_object" : self.close, "on_ok_clicked" : self.on_ok_clicked, "on_help_clicked" : self.on_help_clicked, "on_edit_clicked" : self.on_edit_clicked, "on_delete_event" : self.close, }) self.list = self.glade.get_object("list") self.set_window(self.top, self.glade.get_object('title'), self.label) else: self.top = Glade("changenames.glade") window = self.top.toplevel self.top.connect_signals({ "destroy_passed_object" : self.close, "on_ok_clicked" : self.on_ok_clicked, "on_help_clicked" : self.on_help_clicked, "on_edit_clicked" : self.on_edit_clicked, "on_delete_event" : self.close, }) self.list = self.top.get_object("list") self.set_window(window,self.top.get_object('title'),self.label) # selected, original name, changed, count self.model = Gtk.ListStore(GObject.TYPE_BOOLEAN, GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_INT) self.handles = {} r = Gtk.CellRendererToggle() r.connect('toggled',self.toggled) c = Gtk.TreeViewColumn(_('Select'),r,active=0) self.list.append_column(c) c = Gtk.TreeViewColumn(_('Original Name'), Gtk.CellRendererText(),text=1) self.list.append_column(c) c = Gtk.TreeViewColumn(_('Capitalization Change'), Gtk.CellRendererText(),text=2) self.list.append_column(c) c = Gtk.TreeViewColumn(_('Affected Names'), Gtk.CellRendererText(),text=3) self.list.append_column(c) self.list.set_model(self.model) self.iter_list = [] self.progress.set_pass(_('Building display'),len(self.name_list)) for name, count in self.name_list: handle = self.model.append() self.model.set_value(handle,0, False) self.model.set_value(handle,1, name) namecap = capitalize(name) self.model.set_value(handle,2, namecap) self.model.set_value(handle,3, count) self.iter_list.append(handle) self.progress.step() self.progress.close() self.show() def toggled(self,cell,path_string): path = tuple(map(int, path_string.split(':'))) row = self.model[path] row[0] = not row[0] def build_menu_names(self, obj): return (self.label,None) def on_help_clicked(self, obj): """Display the relevant portion of GRAMPS manual""" display_help(WIKI_HELP_PAGE , WIKI_HELP_SEC) def on_edit_clicked(self, button): """Edit the selected person""" from gramps.gui.editors import EditPerson selection = self.list.get_selection() store, paths = selection.get_selected_rows() tpath = paths[0] if len(paths) > 0 else None node = store.get_iter(tpath) if tpath else None if node: name = store.get_value(node, 1) for handle in self.name_map[name]: person = self.dbstate.db.get_person_from_handle(handle) EditPerson(self.dbstate, self.uistate, [], person) def on_ok_clicked(self, obj): with DbTxn(_("Capitalization changes"), self.db, batch=True ) as self.trans: self.db.disable_signals() changelist = set(self.model.get_value(node,1) for node in self.iter_list if self.model.get_value(node,0)) for handle in self.db.get_person_handles(False): person = self.db.get_person_from_handle(handle) change = False for name in [person.get_primary_name()] + person.get_alternate_names(): if name.first_name in changelist: change = True fname = capitalize(name.first_name) name.set_first_name(fname) if change: self.db.commit_person(person, self.trans) self.db.enable_signals() self.db.request_rebuild() self.close() self.cb()
class ChangeGivenNames(tool.BatchTool, ManagedWindow): def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate self.label = _('Capitalization changes') self.dbstate = dbstate self.uistate = uistate self.cb = callback ManagedWindow.__init__(self, uistate, [], self.__class__) self.set_window(Gtk.Window(), Gtk.Label(), '') tool.BatchTool.__init__(self, dbstate, user, options_class, name) if self.fail: return given_name_dict = self.get_given_name_dict() self.progress = ProgressMeter(_('Checking Given Names'), '', parent=uistate.window) self.progress.set_pass(_('Searching given names'), len(given_name_dict.keys())) self.name_list = [] for name in given_name_dict.keys(): if name != capitalize(name): self.name_list.append((name, given_name_dict[name])) if uistate: self.progress.step() if self.name_list: self.display() else: self.progress.close() self.close() OkDialog(_('No modifications made'), _("No capitalization changes were detected."), parent=uistate.window) def get_given_name_dict(self): givennames = {} self.name_map = {} for person in self.db.iter_people(): allnames = [person.get_primary_name() ] + person.get_alternate_names() allnames = set(name.get_first_name().strip() for name in allnames) for givenname in allnames: givennames[givenname] = givennames.get(givenname, 0) + 1 self.name_map[givenname] = self.name_map.get( givenname, set([])) self.name_map[givenname].add(person.handle) return givennames def display(self): if lin(): import locale, os locale.setlocale(locale.LC_ALL, '') # This is needed to make gtk.Builder work by specifying the # translations directory base = os.path.dirname(__file__) locale.bindtextdomain("addon", base + "/locale") self.glade = Gtk.Builder() self.glade.set_translation_domain("addon") path = base + "/changenames.glade" self.glade.add_from_file(path) #from gi.repository import GObject GObject.GObject.__init__(self.glade) self.top = self.glade.get_object('changenames') self.glade.connect_signals({ "destroy_passed_object": self.close, "on_ok_clicked": self.on_ok_clicked, "on_help_clicked": self.on_help_clicked, "on_edit_clicked": self.on_edit_clicked, "on_delete_event": self.close, }) self.list = self.glade.get_object("list") self.set_window(self.top, self.glade.get_object('title'), self.label) else: self.top = Glade("changenames.glade") window = self.top.toplevel self.top.connect_signals({ "destroy_passed_object": self.close, "on_ok_clicked": self.on_ok_clicked, "on_help_clicked": self.on_help_clicked, "on_edit_clicked": self.on_edit_clicked, "on_delete_event": self.close, }) self.list = self.top.get_object("list") self.set_window(window, self.top.get_object('title'), self.label) # selected, original name, changed, count self.model = Gtk.ListStore(GObject.TYPE_BOOLEAN, GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_INT) self.handles = {} r = Gtk.CellRendererToggle() r.connect('toggled', self.toggled) c = Gtk.TreeViewColumn(_('Select'), r, active=0) self.list.append_column(c) c = Gtk.TreeViewColumn(_('Original Name'), Gtk.CellRendererText(), text=1) self.list.append_column(c) c = Gtk.TreeViewColumn(_('Capitalization Change'), Gtk.CellRendererText(), text=2) self.list.append_column(c) c = Gtk.TreeViewColumn(_('Affected Names'), Gtk.CellRendererText(), text=3) self.list.append_column(c) self.list.set_model(self.model) self.iter_list = [] self.progress.set_pass(_('Building display'), len(self.name_list)) for name, count in self.name_list: handle = self.model.append() self.model.set_value(handle, 0, False) self.model.set_value(handle, 1, name) namecap = capitalize(name) self.model.set_value(handle, 2, namecap) self.model.set_value(handle, 3, count) self.iter_list.append(handle) self.progress.step() self.progress.close() self.show() def toggled(self, cell, path_string): path = tuple(map(int, path_string.split(':'))) row = self.model[path] row[0] = not row[0] def build_menu_names(self, obj): return (self.label, None) def on_help_clicked(self, obj): """Display the relevant portion of GRAMPS manual""" display_help(WIKI_HELP_PAGE, WIKI_HELP_SEC) def on_edit_clicked(self, button): """Edit the selected person""" from gramps.gui.editors import EditPerson selection = self.list.get_selection() store, paths = selection.get_selected_rows() tpath = paths[0] if len(paths) > 0 else None node = store.get_iter(tpath) if tpath else None if node: name = store.get_value(node, 1) for handle in self.name_map[name]: person = self.dbstate.db.get_person_from_handle(handle) EditPerson(self.dbstate, self.uistate, [], person) def on_ok_clicked(self, obj): with DbTxn(_("Capitalization changes"), self.db, batch=True) as self.trans: self.db.disable_signals() changelist = set( self.model.get_value(node, 1) for node in self.iter_list if self.model.get_value(node, 0)) for handle in self.db.get_person_handles(False): person = self.db.get_person_from_handle(handle) change = False for name in [person.get_primary_name() ] + person.get_alternate_names(): if name.first_name in changelist: change = True fname = capitalize(name.first_name) name.set_first_name(fname) if change: self.db.commit_person(person, self.trans) self.db.enable_signals() self.db.request_rebuild() self.close() self.cb()
class ExtractCity(tool.BatchTool, ManagedWindow): """ Extracts city, state, and zip code information from an place description if the title is empty and the description falls into the category of: New York, NY 10000 Sorry for those not in the US or Canada. I doubt this will work for any other locales. Works for Sweden if the decriptions is like Stockholm (A) where the letter A is the abbreviation letter for laen. Works for France if the description is like Paris, IDF 75000, FRA or Paris, ILE DE FRANCE 75000, FRA """ def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate self.label = _('Extract Place data') ManagedWindow.__init__(self, uistate, [], self.__class__) self.set_window(Gtk.Window(), Gtk.Label(), '') tool.BatchTool.__init__(self, dbstate, user, options_class, name) if not self.fail: uistate.set_busy_cursor(True) self.run(dbstate.db) uistate.set_busy_cursor(False) def run(self, db): """ Performs the actual extraction of information """ self.progress = ProgressMeter(_('Checking Place Titles'), '') self.progress.set_pass(_('Looking for place fields'), self.db.get_number_of_places()) self.name_list = [] self.place_import = PlaceImport(db) for place in db.iter_places(): descr = place_displayer.display(db, place) self.progress.step() loc = get_main_location(db, place) location = ((loc.get(PlaceType.STREET, '')), (loc.get(PlaceType.LOCALITY, '')), (loc.get(PlaceType.PARISH, '')), (loc.get(PlaceType.CITY, '')), (loc.get(PlaceType.COUNTY, '')), (loc.get(PlaceType.STATE, '')), (loc.get(PlaceType.COUNTRY, ''))) self.place_import.store_location(location, place.handle) if len(place.get_placeref_list()) == 0: match = CITY_STATE_ZIP.match(descr.strip()) if match: data = match.groups() city = data[0] state = data[2] postal = data[5] val = " ".join(state.strip().split()).upper() if state: new_state = STATE_MAP.get(val.upper()) if new_state: self.name_list.append( (place.handle, (city, new_state[0], postal, COUNTRY[new_state[1]]))) continue # Check if there is a left parant. in the string, might be Swedish laen. match = CITY_LAEN.match(descr.strip().replace(","," ")) if match: data = match.groups() city = data[0] state = '(' + data[1] + ')' postal = None val = " ".join(state.strip().split()).upper() if state: new_state = STATE_MAP.get(val.upper()) if new_state: self.name_list.append( (place.handle, (city, new_state[0], postal, COUNTRY[new_state[1]]))) continue match = CITY_STATE.match(descr.strip()) if match: data = match.groups() city = data[0] state = data[1] postal = None if state: m0 = STATE_ZIP.match(state) if m0: (state, postal) = m0.groups() val = " ".join(state.strip().split()).upper() if state: new_state = STATE_MAP.get(val.upper()) if new_state: self.name_list.append( (place.handle, (city, new_state[0], postal, COUNTRY[new_state[1]]))) continue val = " ".join(descr.strip().split()).upper() new_state = STATE_MAP.get(val) if new_state: self.name_list.append( (place.handle, (None, new_state[0], None, COUNTRY[new_state[1]]))) self.progress.close() if self.name_list: self.display() else: self.close() from gramps.gui.dialog import OkDialog OkDialog(_('No modifications made'), _("No place information could be extracted.")) def display(self): self.top = Glade("changenames.glade") window = self.top.toplevel self.top.connect_signals({ "destroy_passed_object" : self.close, "on_ok_clicked" : self.on_ok_clicked, "on_help_clicked" : self.on_help_clicked, "on_delete_event" : self.close, }) self.list = self.top.get_object("list") self.set_window(window, self.top.get_object('title'), self.label) lbl = self.top.get_object('info') lbl.set_line_wrap(True) lbl.set_text( _('Below is a list of Places with the possible data that can ' 'be extracted from the place title. Select the places you ' 'wish Gramps to convert.')) self.model = Gtk.ListStore(GObject.TYPE_BOOLEAN, GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_STRING) r = Gtk.CellRendererToggle() r.connect('toggled', self.toggled) c = Gtk.TreeViewColumn(_('Select'), r, active=0) self.list.append_column(c) for (title, col) in COLS: render = Gtk.CellRendererText() if col > 1: render.set_property('editable', True) render.connect('edited', self.__change_name, col) self.list.append_column( Gtk.TreeViewColumn(title, render, text=col)) self.list.set_model(self.model) self.iter_list = [] self.progress.set_pass(_('Building display'), len(self.name_list)) for (id, data) in self.name_list: place = self.db.get_place_from_handle(id) descr = place_displayer.display(self.db, place) handle = self.model.append() self.model.set_value(handle, 0, True) self.model.set_value(handle, 1, descr) if data[0]: self.model.set_value(handle, 2, data[0]) if data[1]: self.model.set_value(handle, 3, data[1]) if data[2]: self.model.set_value(handle, 4, data[2]) if data[3]: self.model.set_value(handle, 5, data[3]) self.model.set_value(handle, 6, id) self.iter_list.append(handle) self.progress.step() self.progress.close() self.show() def __change_name(self, text, path, new_text, col): self.model[path][col] = new_text return def toggled(self, cell, path_string): path = tuple(map(int, path_string.split(':'))) row = self.model[path] row[0] = not row[0] def build_menu_names(self, obj): return (self.label, None) def on_help_clicked(self, obj): """Display the relevant portion of GRAMPS manual""" display_help() def on_ok_clicked(self, obj): with DbTxn(_("Extract Place data"), self.db, batch=True) as self.trans: self.db.disable_signals() changelist = [node for node in self.iter_list if self.model.get_value(node, 0)] for change in changelist: row = self.model[change] place = self.db.get_place_from_handle(row[6]) location = ('', '', '', row[2], '', row[3], row[5]) self.place_import.store_location(location, place.handle) if row[2]: place.set_name(PlaceName(value=row[2])) place.set_type(PlaceType.CITY) if row[4]: place.set_code(row[4]) self.db.commit_place(place, self.trans) self.place_import.generate_hierarchy(self.trans) self.db.enable_signals() self.db.request_rebuild() self.close()
def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate self.title = _('Find database loop') ManagedWindow.__init__(self, uistate, [], self.__class__) self.dbstate = dbstate self.uistate = uistate #self.db = CacheProxyDb(dbstate.db) self.db = dbstate.db top_dialog = Glade() top_dialog.connect_signals({ "destroy_passed_object": self.close, "on_help_clicked": self.on_help_clicked, "on_delete_event": self.close, }) window = top_dialog.toplevel title = top_dialog.get_object("title") self.set_window(window, title, self.title) # start the progress indicator self.progress = ProgressMeter(self.title, _('Starting'), parent=uistate.window) self.progress.set_pass(_('Looking for possible loop for each person'), self.db.get_number_of_people()) self.model = Gtk.ListStore( GObject.TYPE_STRING, # 0==father id GObject.TYPE_STRING, # 1==father GObject.TYPE_STRING, # 2==son id GObject.TYPE_STRING, # 3==son GObject.TYPE_STRING, # 4==family gid GObject.TYPE_STRING) # 5==loop number self.model.set_sort_column_id( Gtk.TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, 0) self.treeview = top_dialog.get_object("treeview") self.treeview.set_model(self.model) col0 = Gtk.TreeViewColumn('', Gtk.CellRendererText(), text=5) col1 = Gtk.TreeViewColumn(_('Gramps ID'), Gtk.CellRendererText(), text=0) col2 = Gtk.TreeViewColumn(_('Parent'), Gtk.CellRendererText(), text=1) col3 = Gtk.TreeViewColumn(_('Gramps ID'), Gtk.CellRendererText(), text=2) col4 = Gtk.TreeViewColumn(_('Child'), Gtk.CellRendererText(), text=3) col5 = Gtk.TreeViewColumn(_('Family ID'), Gtk.CellRendererText(), text=4) col1.set_resizable(True) col2.set_resizable(True) col3.set_resizable(True) col4.set_resizable(True) col5.set_resizable(True) col1.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) col2.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) col3.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) col4.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) col5.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) self.treeview.append_column(col0) self.treeview.append_column(col1) self.treeview.append_column(col2) self.treeview.append_column(col3) self.treeview.append_column(col4) self.treeview.append_column(col5) self.treeselection = self.treeview.get_selection() self.treeview.connect('row-activated', self.rowactivated_cb) self.curr_fam = None people = self.db.get_person_handles() self.total = len(people) # total number of people to process. self.count = 0 # current number of people completely processed self.loop = 0 # Number of loops found for GUI pset = OrderedDict() # pset is the handle list of persons from the current start of # exploration path to the current limit. The use of OrderedDict # allows us to use it as a LIFO during recursion, as well as makes for # quick lookup. If we find a loop, pset provides a nice way to get # the loop path. self.done = set() # self.done is the handle set of people that have been fully explored # and do NOT have loops in the decendent tree. We use this to avoid # repeating work when we encounter one of these during the search. for person_handle in people: person = self.db.get_person_from_handle(person_handle) self.current = person self.parent = None self.descendants(person_handle, pset) # close the progress bar self.progress.close() self.show()
class ChangeTypes(tool.BatchTool, ManagedWindow): def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate self.user = user self.dbstate = dbstate tool.BatchTool.__init__(self, dbstate, user, options_class, name) if self.fail: return if uistate: self.title = _('Change Event Types') ManagedWindow.__init__(self, uistate, [], self.__class__) self.init_gui() else: self.run_tool() def init_gui(self): # Draw dialog and make it handle everything self.glade = Glade() self.auto1 = self.glade.get_object("original") self.auto2 = self.glade.get_object("new") # Need to display localized event names etype = EventType() custom_events = self.dbstate.db.get_event_types() event_names = sorted(etype.get_standard_names() + custom_events, key=glocale.sort_key) self.fill_combo(self.auto1, event_names) self.fill_combo(self.auto2, event_names) etype.set_from_xml_str(self.options.handler.options_dict['fromtype']) self.auto1.get_child().set_text(str(etype)) etype.set_from_xml_str(self.options.handler.options_dict['totype']) self.auto2.get_child().set_text(str(etype)) window = self.glade.toplevel self.set_window(window, self.glade.get_object('title'), self.title) self.setup_configs('interface.changetypes', 640, 260) self.glade.connect_signals({ "on_close_clicked": self.close, "on_apply_clicked": self.on_apply_clicked, "on_delete_event": self.close, }) self.show() def build_menu_names(self, obj): return (self.title, None) def run_tool(self, parent_window=None): # Run tool and return results # These are English names, no conversion needed fromtype = self.options.handler.options_dict['fromtype'] totype = self.options.handler.options_dict['totype'] modified = 0 with DbTxn(_('Change types'), self.db, batch=True) as self.trans: self.db.disable_signals() with self.user.progress(_('Analyzing Events'), '', self.db.get_number_of_events()) as step: for event_handle in self.db.get_event_handles(): event = self.db.get_event_from_handle(event_handle) if event.get_type().xml_str() == fromtype: event.type.set_from_xml_str(totype) modified += 1 self.db.commit_event(event, self.trans) step() self.db.enable_signals() self.db.request_rebuild() if modified == 0: msg = _("No event record was modified.") else: # Translators: leave all/any {...} untranslated msg = ngettext("{number_of} event record was modified.", "{number_of} event records were modified.", modified).format(number_of=modified) self.user.info(_('Change types'), msg, parent=parent_window) return (bool(modified), msg) def on_apply_clicked(self, obj): # Need to store English names for later comparison the_type = EventType() the_type.set(self.auto1.get_child().get_text()) self.options.handler.options_dict['fromtype'] = the_type.xml_str() the_type.set(self.auto2.get_child().get_text()) self.options.handler.options_dict['totype'] = the_type.xml_str() self.run_tool(self.parent_window) # Save options self.options.handler.save_options() self.close() def fill_combo(self, combo, data_list): """ Fill a combo box with completion data """ store = Gtk.ListStore(GObject.TYPE_STRING) for data in data_list: if data: store.append(row=[data]) combo.set_popup_fixed_width(False) combo.set_wrap_width(4) combo.set_model(store) combo.set_entry_text_column(0) completion = Gtk.EntryCompletion() completion.set_model(store) completion.set_minimum_key_length(1) completion.set_text_column(0) combo.get_child().set_completion(completion)
class ReorderIds(tool.BatchTool, ManagedWindow, UpdateCallback): """ Class for Reodering Gramps ID Tool """ xobjects = (('person', 'people'), ('family', 'families'), ('event', 'events'), ('place', 'places'), ('source', 'sources'), ('citation', 'citations'), ('repository', 'repositories'), ('media', 'media'), ('note', 'notes')) def build_menu_names_(self, widget=None): """ The menu name """ return (_('Main window'), _("Reorder Gramps IDs")) def __init__(self, dbstate, user, options_class, name, callback=None): self.uistate = user.uistate self.dbstate = dbstate.db if self.uistate: tool.BatchTool.__init__(self, dbstate, user, options_class, name) if self.fail: return # user denied to modify Gramps IDs ManagedWindow.__init__(self, self.uistate, [], self.__class__) if not self.uistate: UpdateCallback.__init__(self, user.callback) self.object_status = True self.change_status = False self.start_zero = True self.step_cnt, self.step_list = 0, ['1', '2', '5', '10'] self.keep_status = True self.obj_values = {} # enable access to all internal values self.active_entries, self.format_entries = {}, {} self.change_entries = {} self.start_entries, self.step_entries = {}, {} self.keep_entries = {} self.prim_methods, self.obj_methods = {}, {} for prim_obj, prim_objs in self.xobjects: class_type = prim_obj.title() table = "self.dbstate.%s_map" % prim_obj get_number_obj = "self.dbstate.get_number_of_%s" % prim_objs prefix_fmt = "self.dbstate.%s_prefix" % prim_obj get_from_id = "self.dbstate.get_%s_from_gramps_id" % prim_obj get_from_handle = "self.dbstate.get_%s_from_handle" % prim_obj next_from_id = "self.dbstate.find_next_%s_gramps_id" % prim_obj commit = "self.dbstate.commit_%s" % prim_obj self.prim_methods[prim_obj] = (eval(prefix_fmt), eval(get_number_obj)(), eval(next_from_id)()) self.obj_methods[prim_obj] = (eval(class_type), eval(table), eval(commit), eval(get_from_id), eval(get_from_handle), eval(next_from_id)) object_fmt, quant_id, next_id = self.prim_methods[prim_obj] obj_value = ReorderEntry(object_fmt, quant_id, next_id) self.obj_values[prim_obj] = obj_value if self.uistate: self._display() else: self._execute() def __on_object_button_clicked(self, widget=None): """ compute all primary objects and toggle the 'Active' attribute """ self.object_status = not self.object_status for prim_obj, tmp in self.xobjects: obj = self.top.get_object('%s_active' % prim_obj) obj.set_active(self.object_status) def __on_object_button_toggled(self, widget): """ compute the primary object and toggle the 'Sensitive' attribute """ obj_state = widget.get_active() obj_name = Gtk.Buildable.get_name(widget).split('_', 1)[0] self.active_entries[obj_name].set_val(obj_state) for obj_entry in ['actual', 'quant', 'format', 'change']: obj = self.top.get_object('%s_%s' % (obj_name, obj_entry)) obj.set_sensitive(obj_state) for obj_entry in ['start', 'step', 'keep']: obj = self.top.get_object('%s_change' % obj_name) if obj.get_active(): obj = self.top.get_object('%s_%s' % (obj_name, obj_entry)) obj.set_sensitive(obj_state) def __on_format_button_clicked(self, widget=None): """ compute all sensitive primary objects and sets the 'Format' scheme of identifiers """ for prim_obj, tmp in self.xobjects: obj_format = self.top.get_object('%s_format' % prim_obj) if not obj_format.get_sensitive(): continue obj_fmt = self.obj_values[prim_obj].res_fmt() self.format_entries[prim_obj].force_value(obj_fmt) if self.start_zero: obj_id = self.obj_values[prim_obj].zero_id() else: obj_id = self.obj_values[prim_obj].last_id() self.start_entries[prim_obj].force_value(obj_id) def __on_change_button_clicked(self, widget=None): """ compute all primary objects and toggle the 'Change' attribute """ self.change_status = not self.change_status for prim_obj, tmp in self.xobjects: obj_change = self.top.get_object('%s_change' % prim_obj) if not obj_change.get_sensitive(): continue self.change_entries[prim_obj].set_val(self.change_status) obj_change.set_active(self.change_status) def __on_change_button_toggled(self, widget): """ compute the primary object and toggle the 'Sensitive' attribute """ obj_state = widget.get_active() obj_name = Gtk.Buildable.get_name(widget).split('_', 1)[0] for obj_entry in ['start', 'step', 'keep']: obj = self.top.get_object('%s_%s' % (obj_name, obj_entry)) if obj_entry == 'keep': if self.obj_values[obj_name].stored_prefix != \ self.obj_values[obj_name].object_prefix: self.keep_entries[obj_name].set_val(False) else: obj.set_active(obj_state) self.keep_entries[obj_name].set_val(obj_state) obj.set_sensitive(obj_state) def __on_start_button_clicked(self, widget=None): """ compute all sensitive primary objects and sets the 'Start' values of identifiers """ self.start_zero = not self.start_zero for prim_obj, tmp in self.xobjects: obj = self.top.get_object('%s_start' % prim_obj) if not obj.get_sensitive(): continue if self.start_zero: obj_id = self.obj_values[prim_obj].zero_id() else: obj_id = self.obj_values[prim_obj].next_id() self.start_entries[prim_obj].force_value(obj_id) def __on_step_button_clicked(self, widget=None): """ compute all sensitive primary objects and sets the 'Step' width of identifiers """ self.step_cnt = self.step_cnt +1 if self.step_cnt < 3 else 0 for prim_obj, tmp in self.xobjects: obj = self.top.get_object('%s_step' % prim_obj) if not obj.get_sensitive(): continue step_val = self.step_list[self.step_cnt] self.step_entries[prim_obj].force_value(step_val) def __on_keep_button_clicked(self, widget=None): """ compute the primary object and toggle the 'Active' attribute """ self.keep_status = not self.keep_status for prim_obj, tmp in self.xobjects: obj = self.top.get_object('%s_change' % prim_obj) if not obj.get_active(): continue obj = self.top.get_object('%s_keep' % prim_obj) obj.set_active(self.keep_status) self.keep_entries[prim_obj].set_val(self.keep_status) def __on_format_entry_keyrelease(self, widget, event, data=None): """ activated on all return's of an entry """ if event.keyval in [Gdk.KEY_Return]: obj_name = Gtk.Buildable.get_name(widget).split('_', 1)[0] obj_fmt = self.format_entries[obj_name].get_val() self.format_entries[obj_name].force_value(obj_fmt) self.start_entries[obj_name].update() obj_change = self.top.get_object('%s_change' % obj_name) obj_change.grab_focus() return False def __on_format_entry_focusout(self, widget, event, data=None): """ activated on all focus out of an entry """ obj_name = Gtk.Buildable.get_name(widget).split('_', 1)[0] obj_fmt = self.format_entries[obj_name].get_val() self.format_entries[obj_name].set_val(obj_fmt) self.start_entries[obj_name].update() return False def __on_start_entry_focusout(self, widget, event, data=None): """ activated on all focus out of an entry """ obj_name = Gtk.Buildable.get_name(widget).split('_', 1)[0] self.start_entries[obj_name].update() return False def __on_ok_button_clicked(self, widget=None): """ execute the reodering and close """ self._execute() self._update() self.close() def __on_cancel_button_clicked(self, widget=None): """ cancel the reodering and close """ self.close() def __on_help_button_clicked(self, widget=None): """ display the relevant portion of Gramps manual """ display_help(webpage=WIKI_HELP_PAGE, section=WIKI_HELP_SEC) def _display(self): """ organize Glade 'Reorder IDs' window """ # get the main window from glade self.top = Glade(toplevel="reorder-ids") window = self.top.toplevel # set gramps style title for the window self.set_window(window, self.top.get_object("title"), \ _("Reorder Gramps IDs")) # connect signals self.top.connect_signals({ "on_object_button_clicked" : self.__on_object_button_clicked, "on_object_button_toggled" : self.__on_object_button_toggled, "on_format_button_clicked" : self.__on_format_button_clicked, "on_start_button_clicked" : self.__on_start_button_clicked, "on_step_button_clicked" : self.__on_step_button_clicked, "on_keep_button_clicked" : self.__on_keep_button_clicked, "on_change_button_clicked" : self.__on_change_button_clicked, "on_change_button_toggled" : self.__on_change_button_toggled, "on_format_entry_keyrelease" : self.__on_format_entry_keyrelease, "on_format_entry_focusout" : self.__on_format_entry_focusout, "on_start_entry_focusout" : self.__on_start_entry_focusout, "on_help_button_clicked" : self.__on_help_button_clicked, "on_cancel_button_clicked" : self.__on_cancel_button_clicked, "on_ok_button_clicked" : self.__on_ok_button_clicked }) # Calculate all entries and update Glade window for prim_obj, tmp in self.xobjects: # populate Object, Actual & Quantity fields with values obj_active = self.top.get_object('%s_active' % prim_obj) self.active_entries[prim_obj] = MonitoredCheckbox(obj_active, obj_active, self.obj_values[prim_obj].set_active, self.obj_values[prim_obj].get_active) obj_actual = self.top.get_object('%s_actual' % prim_obj) obj_actual.set_text('%s' % self.obj_values[prim_obj].last_id()) obj_quant = self.top.get_object('%s_quant' % prim_obj) obj_quant.set_text('%s' % str(self.obj_values[prim_obj].quant_id)) # connect/populate Format, Start, Step, Keep & Change fields with GTK/values obj_format = self.top.get_object('%s_format' % prim_obj) self.format_entries[prim_obj] = MonitoredEntry(obj_format, self.obj_values[prim_obj].set_fmt, self.obj_values[prim_obj].get_fmt) obj_change = self.top.get_object('%s_change' % prim_obj) self.change_entries[prim_obj] = MonitoredCheckbox(obj_change, obj_change, self.obj_values[prim_obj].set_change, self.obj_values[prim_obj].get_change) obj_start = self.top.get_object('%s_start' % prim_obj) self.start_entries[prim_obj] = MonitoredEntry(obj_start, self.obj_values[prim_obj].set_id, self.obj_values[prim_obj].get_id) obj_step = self.top.get_object('%s_step' % prim_obj) self.step_entries[prim_obj] = MonitoredEntry(obj_step, self.obj_values[prim_obj].set_step, self.obj_values[prim_obj].get_step, changed=self.obj_values[prim_obj].change_step) obj_keep = self.top.get_object('%s_keep' % prim_obj) self.keep_entries[prim_obj] = MonitoredCheckbox(obj_keep, obj_keep, self.obj_values[prim_obj].set_keep, self.obj_values[prim_obj].get_keep, readonly=True) # fetch the popup menu self.menu = self.top.get_object("popup_menu") # ok, let's see what we've done self.show() def _update(self): """ store changed objects formats in DB """ update = False for prim_obj, tmp in self.xobjects: obj_value = self.obj_values[prim_obj] if obj_value.object_fmt != obj_value.stored_fmt: prefix = obj_value.object_prefix.lower() constant = 'preferences.%sprefix' % prefix config.set(constant, obj_value.object_fmt) update = True if update: config.save() self.dbstate.set_prefixes( config.get('preferences.iprefix'), config.get('preferences.oprefix'), config.get('preferences.fprefix'), config.get('preferences.sprefix'), config.get('preferences.cprefix'), config.get('preferences.pprefix'), config.get('preferences.eprefix'), config.get('preferences.rprefix'), config.get('preferences.nprefix')) def _execute(self): """ execute all primary objects and reorder if neccessary """ # Update progress calculation if self.uistate: self.progress = ProgressMeter(_('Reorder Gramps IDs'), '') else: total_objs = 0 for prim_obj, tmp in self.xobjects: if self.obj_values[prim_obj].active_obj: total_objs += self.obj_values[prim_obj].quant_id self.set_total(total_objs) # Update database self.dbstate.disable_signals() for prim_obj, prim_objs in self.xobjects: with DbTxn(_('Reorder %s IDs ...') % prim_obj, self.dbstate, batch=True) \ as self.trans: if self.obj_values[prim_obj].active_obj: if self.uistate: self.progress.set_pass(_('Reorder %s IDs ...') % \ _(prim_objs.title()), \ self.obj_values[prim_obj].quant_id) # Process reordering self._reorder(prim_obj) self.dbstate.enable_signals() self.dbstate.request_rebuild() # Update progress calculation if self.uistate: self.progress.close() else: print('\nDone.') # finds integer portion in a GrampsID _findint = re.compile('^[^\d]*(\d+)[^\d]*') def _reorder(self, prim_obj): """ reorders all selected objects with a (new) style, start & step """ dup_ids = [] # list of duplicate identifiers new_ids = {} # list of new identifiers class_type, table, commit, get_from_id, get_from_handle, next_from_id = \ self.obj_methods[prim_obj] prefix_fmt = self.obj_values[prim_obj].get_fmt() prefix = prefix_fmt.split('%', 1)[0] new_id = self.obj_values[prim_obj].get_id() keep_fmt = self.obj_values[prim_obj].get_keep() change = self.obj_values[prim_obj].get_change() formatmatch = _parseformat.match(prefix_fmt) index_max = int("9" * int(formatmatch.groups()[0])) for handle in list(table.keys()): # Update progress if self.uistate: self.progress.step() else: self.update() # extract basic data out of the database table_data = table[handle] obj = class_type() obj.unserialize(table_data) act_id = obj.get_gramps_id() if change: # update the defined ID numbers into objects under consideration # of keeping ID if format not matches prefix # (implication logical boolean operator below) if act_id.startswith(prefix) or not keep_fmt: obj.set_gramps_id(new_id) commit(obj, self.trans) new_id = self.obj_values[prim_obj].succ_id() else: # attempt to extract integer - if we can't, treat it as a duplicate try: match = _findint.match(act_id) if match: # get the integer, build the new handle. Make sure it # hasn't already been chosen. If it has, put this # in the duplicate handle list index = int(match.groups()[0]) if formatmatch: if index > index_max: new_id = next_from_id() else: new_id = prefix_fmt % index else: # prefix_fmt does not contain a number after %, eg I%d new_id = prefix_fmt % index if new_id == act_id: if new_id in new_ids: dup_ids.append(obj.get_handle()) else: new_ids[new_id] = act_id elif get_from_id(new_id) is not None: dup_ids.append(obj.get_handle()) else: obj.set_id(new_id) commit(obj, self.trans) new_ids[new_id] = act_id else: dup_ids.append(handle) except: dup_ids.append(handle) # go through the duplicates, looking for the first available # handle that matches the new scheme. if dup_ids: if self.uistate: self.progress.set_pass(_('Finding and assigning unused IDs.'), len(dup_ids)) for handle in dup_ids: obj = get_from_handle(handle) obj.set_gramps_id(next_from_id()) commit(obj, self.trans)
def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate tool.ActivePersonTool.__init__(self, dbstate, uistate, options_class, name) if self.fail: # bug #2709 -- fail if we have no active person return person_handle = uistate.get_active('Person') person = dbstate.db.get_person_from_handle(person_handle) self.name = person.get_primary_name().get_regular_name() self.title = _('Not related to "%s"') % self.name ManagedWindow.__init__(self, uistate, [], self.__class__) self.dbstate = dbstate self.uistate = uistate self.db = dbstate.db topDialog = Glade() topDialog.connect_signals({ "destroy_passed_object" : self.close, "on_help_clicked" : self.on_help_clicked, "on_delete_event" : self.close, }) window = topDialog.toplevel title = topDialog.get_object("title") self.set_window(window, title, self.title) self.tagcombo = topDialog.get_object("tagcombo") tagmodel = Gtk.ListStore(str) self.tagcombo.set_model(tagmodel) self.tagcombo.set_entry_text_column(0) tagmodel.append((_('ToDo'),)) tagmodel.append((_('NotRelated'),)) self.tagcombo.set_sensitive(False) self.tagapply = topDialog.get_object("tagapply") self.tagapply.set_sensitive(False) self.tagapply.connect('clicked', self.applyTagClicked) # start the progress indicator self.progress = ProgressMeter(self.title,_('Starting'), parent=self.window) # setup the columns self.model = Gtk.TreeStore( GObject.TYPE_STRING, # 0==name GObject.TYPE_STRING, # 1==person gid GObject.TYPE_STRING, # 2==parents GObject.TYPE_STRING, # 3==tags GObject.TYPE_STRING) # 4==family gid (not shown to user) # note -- don't assign the model to the tree until it has been populated, # otherwise the screen updates are terribly slow while names are appended self.treeView = topDialog.get_object("treeview") col1 = Gtk.TreeViewColumn(_('Name'), Gtk.CellRendererText(), text=0) col2 = Gtk.TreeViewColumn(_('ID'), Gtk.CellRendererText(), text=1) col3 = Gtk.TreeViewColumn(_('Parents'), Gtk.CellRendererText(), text=2) col4 = Gtk.TreeViewColumn(_('Tags'), Gtk.CellRendererText(), text=3) col1.set_resizable(True) col2.set_resizable(True) col3.set_resizable(True) col4.set_resizable(True) col1.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) col2.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) col3.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) col4.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) col1.set_sort_column_id(0) # col2.set_sort_column_id(1) # col3.set_sort_column_id(2) col4.set_sort_column_id(3) self.treeView.append_column(col1) self.treeView.append_column(col2) self.treeView.append_column(col3) self.treeView.append_column(col4) self.treeSelection = self.treeView.get_selection() self.treeSelection.set_mode(Gtk.SelectionMode.MULTIPLE) self.treeSelection.set_select_function(self.selectIsAllowed, None) self.treeSelection.connect('changed', self.rowSelectionChanged) self.treeView.connect('row-activated', self.rowActivated) # initialize a few variables we're going to need self.numberOfPeopleInDatabase = self.db.get_number_of_people() self.numberOfRelatedPeople = 0 self.numberOfUnrelatedPeople = 0 # create the sets used to track related and unrelated people self.handlesOfPeopleToBeProcessed = set() self.handlesOfPeopleAlreadyProcessed = set() self.handlesOfPeopleNotRelated = set() # build a set of all people related to the selected person self.handlesOfPeopleToBeProcessed.add(person.get_handle()) self.findRelatedPeople() # now that we have our list of related people, find everyone # in the database who isn't on our list self.findUnrelatedPeople() # populate the treeview model with the names of unrelated people if self.numberOfUnrelatedPeople == 0: # feature request 2356: avoid genitive form title.set_text(_('Everyone in the database is related to %s') % self.name) else: self.populateModel() self.model.set_sort_column_id(0, Gtk.SortType.ASCENDING) self.treeView.set_model(self.model) # self.treeView.set_row_separator_func(self.iterIsSeparator, None) self.treeView.expand_all() # done searching through the database, so close the progress bar self.progress.close() self.show()
class ChangeTypes(tool.BatchTool, ManagedWindow): def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate self.user = user tool.BatchTool.__init__(self, dbstate, user, options_class, name) if self.fail: return if uistate: self.title = _('Change Event Types') ManagedWindow.__init__(self, uistate, [], self.__class__) self.init_gui() else: self.run_tool() def init_gui(self): # Draw dialog and make it handle everything self.glade = Glade() self.auto1 = self.glade.get_object("original") self.auto2 = self.glade.get_object("new") # Need to display localized event names etype = EventType() event_names = sorted(etype.get_standard_names(), key=glocale.sort_key) fill_combo(self.auto1, event_names) fill_combo(self.auto2, event_names) etype.set_from_xml_str(self.options.handler.options_dict['fromtype']) self.auto1.get_child().set_text(str(etype)) etype.set_from_xml_str(self.options.handler.options_dict['totype']) self.auto2.get_child().set_text(str(etype)) window = self.glade.toplevel self.set_window(window, self.glade.get_object('title'), self.title) self.glade.connect_signals({ "on_close_clicked": self.close, "on_apply_clicked": self.on_apply_clicked, "on_delete_event": self.close, }) self.show() def build_menu_names(self, obj): return (self.title, None) def run_tool(self, parent_window=None): # Run tool and return results # These are English names, no conversion needed fromtype = self.options.handler.options_dict['fromtype'] totype = self.options.handler.options_dict['totype'] modified = 0 with DbTxn(_('Change types'), self.db, batch=True) as self.trans: self.db.disable_signals() with self.user.progress(_('Analyzing Events'), '', self.db.get_number_of_events()) as step: for event_handle in self.db.get_event_handles(): event = self.db.get_event_from_handle(event_handle) if event.get_type().xml_str() == fromtype: event.type.set_from_xml_str(totype) modified += 1 self.db.commit_event(event, self.trans) step() self.db.enable_signals() self.db.request_rebuild() if modified == 0: msg = _("No event record was modified.") else: # translators: leave all/any {...} untranslated msg = ngettext("{number_of} event record was modified.", "{number_of} event records were modified.", modified).format(number_of=modified) self.user.info(_('Change types'), msg, parent_window) return (bool(modified), msg) def on_apply_clicked(self, obj): # Need to store English names for later comparison the_type = EventType() the_type.set(self.auto1.get_child().get_text()) self.options.handler.options_dict['fromtype'] = the_type.xml_str() the_type.set(self.auto2.get_child().get_text()) self.options.handler.options_dict['totype'] = the_type.xml_str() self.run_tool(self.window) # Save options self.options.handler.save_options() self.close()
class ReorderIds(tool.BatchTool, ManagedWindow, UpdateCallback): """ Class for Reodering Gramps ID Tool """ xobjects = (('person', 'people'), ('family', 'families'), ('event', 'events'), ('place', 'places'), ('source', 'sources'), ('citation', 'citations'), ('repository', 'repositories'), ('media', 'media'), ('note', 'notes')) def build_menu_names_(self, widget=None): """ The menu name """ return (_('Main window'), _("Reorder Gramps IDs")) def __init__(self, dbstate, user, options_class, name, callback=None): self.uistate = user.uistate self.db = dbstate.db if self.uistate: tool.BatchTool.__init__(self, dbstate, user, options_class, name) if self.fail: return # user denied to modify Gramps IDs ManagedWindow.__init__(self, self.uistate, [], self.__class__) if not self.uistate: UpdateCallback.__init__(self, user.callback) self.object_status = True self.change_status = False self.start_zero = True self.step_cnt, self.step_list = 0, ['1', '2', '5', '10'] self.keep_status = True self.obj_values = {} # enable access to all internal values self.active_entries, self.format_entries = {}, {} self.change_entries = {} self.start_entries, self.step_entries = {}, {} self.keep_entries = {} self.prim_methods, self.obj_methods = {}, {} for prim_obj, prim_objs in self.xobjects: get_handles = "get_%s_handles" % prim_obj get_number_obj = "get_number_of_%s" % prim_objs prefix_fmt = "%s_prefix" % prim_obj get_from_id = "get_%s_from_gramps_id" % prim_obj get_from_handle = "get_%s_from_handle" % prim_obj next_from_id = "find_next_%s_gramps_id" % prim_obj commit = "commit_%s" % prim_obj self.prim_methods[prim_obj] = (getattr(self.db, prefix_fmt), getattr(self.db, get_number_obj)(), getattr(self.db, next_from_id)()) self.obj_methods[prim_obj] = (getattr(self.db, get_handles), getattr(self.db, commit), getattr(self.db, get_from_id), getattr(self.db, get_from_handle), getattr(self.db, next_from_id)) object_fmt, quant_id, next_id = self.prim_methods[prim_obj] obj_value = ReorderEntry(object_fmt, quant_id, next_id, prim_obj) self.obj_values[prim_obj] = obj_value if self.uistate: self._display() else: self._execute() def __on_object_button_clicked(self, widget=None): """ compute all primary objects and toggle the 'Active' attribute """ self.object_status = not self.object_status for prim_obj, dummy in self.xobjects: obj = self.top.get_object('%s_active' % prim_obj) obj.set_active(self.object_status) def __on_object_button_toggled(self, widget): """ compute the primary object and toggle the 'Sensitive' attribute """ obj_state = widget.get_active() obj_name = Gtk.Buildable.get_name(widget).split('_', 1)[0] self.active_entries[obj_name].set_val(obj_state) for obj_entry in ['actual', 'quant', 'format', 'change']: obj = self.top.get_object('%s_%s' % (obj_name, obj_entry)) obj.set_sensitive(obj_state) for obj_entry in ['start', 'step', 'keep']: obj = self.top.get_object('%s_change' % obj_name) if obj.get_active(): obj = self.top.get_object('%s_%s' % (obj_name, obj_entry)) obj.set_sensitive(obj_state) def __on_format_button_clicked(self, widget=None): """ compute all sensitive primary objects and sets the 'Format' scheme of identifiers """ for prim_obj, dummy in self.xobjects: obj_format = self.top.get_object('%s_format' % prim_obj) if not obj_format.get_sensitive(): continue obj_fmt = self.obj_values[prim_obj].res_fmt() self.format_entries[prim_obj].force_value(obj_fmt) if self.start_zero: obj_id = self.obj_values[prim_obj].zero_id() else: obj_id = self.obj_values[prim_obj].last_id() self.start_entries[prim_obj].force_value(obj_id) def __on_change_button_clicked(self, widget=None): """ compute all primary objects and toggle the 'Change' attribute """ self.change_status = not self.change_status for prim_obj, dummy in self.xobjects: obj_change = self.top.get_object('%s_change' % prim_obj) if not obj_change.get_sensitive(): continue self.change_entries[prim_obj].set_val(self.change_status) obj_change.set_active(self.change_status) def __on_change_button_toggled(self, widget): """ compute the primary object and toggle the 'Sensitive' attribute """ obj_state = widget.get_active() obj_name = Gtk.Buildable.get_name(widget).split('_', 1)[0] for obj_entry in ['start', 'step', 'keep']: obj = self.top.get_object('%s_%s' % (obj_name, obj_entry)) if obj_entry == 'keep': if (self.obj_values[obj_name].stored_prefix != self.obj_values[obj_name].object_prefix and self.obj_values[obj_name].stored_suffix != self.obj_values[obj_name].object_suffix): self.keep_entries[obj_name].set_val(False) else: obj.set_active(obj_state) self.keep_entries[obj_name].set_val(obj_state) obj.set_sensitive(obj_state) def __on_start_button_clicked(self, widget=None): """ compute all sensitive primary objects and sets the 'Start' values of identifiers """ self.start_zero = not self.start_zero for prim_obj, dummy in self.xobjects: obj = self.top.get_object('%s_start' % prim_obj) if not obj.get_sensitive(): continue if self.start_zero: obj_id = self.obj_values[prim_obj].zero_id() else: obj_id = self.obj_values[prim_obj].next_id() self.start_entries[prim_obj].force_value(obj_id) def __on_step_button_clicked(self, widget=None): """ compute all sensitive primary objects and sets the 'Step' width of identifiers """ self.step_cnt = self.step_cnt + 1 if self.step_cnt < 3 else 0 for prim_obj, dummy in self.xobjects: obj = self.top.get_object('%s_step' % prim_obj) if not obj.get_sensitive(): continue step_val = self.step_list[self.step_cnt] self.step_entries[prim_obj].force_value(step_val) def __on_keep_button_clicked(self, widget=None): """ compute the primary object and toggle the 'Active' attribute """ self.keep_status = not self.keep_status for prim_obj, dummy in self.xobjects: obj = self.top.get_object('%s_change' % prim_obj) if not obj.get_active(): continue obj = self.top.get_object('%s_keep' % prim_obj) obj.set_active(self.keep_status) self.keep_entries[prim_obj].set_val(self.keep_status) def __on_format_entry_keyrelease(self, widget, event, data=None): """ activated on all return's of an entry """ if event.keyval in [Gdk.KEY_Return]: obj_name = Gtk.Buildable.get_name(widget).split('_', 1)[0] obj_fmt = self.format_entries[obj_name].get_val() self.format_entries[obj_name].force_value(obj_fmt) self.start_entries[obj_name].update() obj_change = self.top.get_object('%s_change' % obj_name) obj_change.grab_focus() return False def __on_format_entry_focusout(self, widget, event, data=None): """ activated on all focus out of an entry """ obj_name = Gtk.Buildable.get_name(widget).split('_', 1)[0] obj_fmt = self.format_entries[obj_name].get_val() self.format_entries[obj_name].set_text(obj_fmt) self.start_entries[obj_name].update() return False def __on_start_entry_focusout(self, widget, event, data=None): """ activated on all focus out of an entry """ obj_name = Gtk.Buildable.get_name(widget).split('_', 1)[0] self.start_entries[obj_name].update() return False def __on_ok_button_clicked(self, widget=None): """ execute the reodering and close """ self._execute() self._update() self.close() def __on_cancel_button_clicked(self, widget=None): """ cancel the reodering and close """ self.close() def __on_help_button_clicked(self, widget=None): """ display the relevant portion of Gramps manual """ display_help(webpage=WIKI_HELP_PAGE, section=WIKI_HELP_SEC) def _display(self): """ organize Glade 'Reorder IDs' window """ # get the main window from glade self.top = Glade(toplevel="reorder-ids") window = self.top.toplevel # set gramps style title for the window self.set_window(window, self.top.get_object("title"), _("Reorder Gramps IDs")) # connect signals self.top.connect_signals({ "on_object_button_clicked": self.__on_object_button_clicked, "on_object_button_toggled": self.__on_object_button_toggled, "on_format_button_clicked": self.__on_format_button_clicked, "on_start_button_clicked": self.__on_start_button_clicked, "on_step_button_clicked": self.__on_step_button_clicked, "on_keep_button_clicked": self.__on_keep_button_clicked, "on_change_button_clicked": self.__on_change_button_clicked, "on_change_button_toggled": self.__on_change_button_toggled, "on_format_entry_keyrelease": self.__on_format_entry_keyrelease, "on_format_entry_focusout": self.__on_format_entry_focusout, "on_start_entry_focusout": self.__on_start_entry_focusout, "on_help_button_clicked": self.__on_help_button_clicked, "on_cancel_button_clicked": self.__on_cancel_button_clicked, "on_ok_button_clicked": self.__on_ok_button_clicked }) # Calculate all entries and update Glade window for prim_obj, dummy in self.xobjects: # populate Object, Actual & Quantity fields with values obj_active = self.top.get_object('%s_active' % prim_obj) self.active_entries[prim_obj] = MonitoredCheckbox( obj_active, obj_active, self.obj_values[prim_obj].set_active, self.obj_values[prim_obj].get_active) obj_actual = self.top.get_object('%s_actual' % prim_obj) obj_actual.set_text('%s' % self.obj_values[prim_obj].last_id()) obj_quant = self.top.get_object('%s_quant' % prim_obj) obj_quant.set_text('%s' % str(self.obj_values[prim_obj].quant_id)) # connect/populate Format, Start, Step, Keep & Change fields # with GTK/values obj_format = self.top.get_object('%s_format' % prim_obj) self.format_entries[prim_obj] = MonitoredEntry( obj_format, self.obj_values[prim_obj].set_fmt, self.obj_values[prim_obj].get_fmt) obj_change = self.top.get_object('%s_change' % prim_obj) self.change_entries[prim_obj] = MonitoredCheckbox( obj_change, obj_change, self.obj_values[prim_obj].set_change, self.obj_values[prim_obj].get_change) obj_start = self.top.get_object('%s_start' % prim_obj) self.start_entries[prim_obj] = MonitoredEntry( obj_start, self.obj_values[prim_obj].set_id, self.obj_values[prim_obj].get_id) obj_step = self.top.get_object('%s_step' % prim_obj) self.step_entries[prim_obj] = MonitoredEntry( obj_step, self.obj_values[prim_obj].set_step, self.obj_values[prim_obj].get_step, changed=self.obj_values[prim_obj].change_step) obj_keep = self.top.get_object('%s_keep' % prim_obj) self.keep_entries[prim_obj] = MonitoredCheckbox( obj_keep, obj_keep, self.obj_values[prim_obj].set_keep, self.obj_values[prim_obj].get_keep, readonly=True) # fetch the popup menu self.menu = self.top.get_object("popup_menu") # ok, let's see what we've done self.window.resize(700, 410) self.show() def _update(self): """ store changed objects formats in DB """ update = False for prim_obj, dummy in self.xobjects: obj_value = self.obj_values[prim_obj] if obj_value.object_fmt != obj_value.stored_fmt: constant = 'preferences.%sprefix' % PREFIXES[prim_obj] config.set(constant, obj_value.object_fmt) update = True if update: config.save() self.db.set_prefixes(config.get('preferences.iprefix'), config.get('preferences.oprefix'), config.get('preferences.fprefix'), config.get('preferences.sprefix'), config.get('preferences.cprefix'), config.get('preferences.pprefix'), config.get('preferences.eprefix'), config.get('preferences.rprefix'), config.get('preferences.nprefix')) def _execute(self): """ execute all primary objects and reorder if neccessary """ # Update progress calculation if self.uistate: self.progress = ProgressMeter(_('Reorder Gramps IDs'), '') else: total_objs = 0 for prim_obj, dummy in self.xobjects: if self.obj_values[prim_obj].active_obj: total_objs += self.obj_values[prim_obj].quant_id self.set_total(total_objs) # Update database self.db.disable_signals() for prim_obj, prim_objs in self.xobjects: with DbTxn(_('Reorder %s IDs ...') % prim_obj, self.db, batch=True) as self.trans: if self.obj_values[prim_obj].active_obj: if self.uistate: self.progress.set_pass( _('Reorder %s IDs ...') % _(prim_objs.title()), self.obj_values[prim_obj].quant_id) # reset the db next_id index to zero so we restart new IDs # at lowest possible position setattr(self.db, DB_INDXES[prim_obj] + 'map_index', 0) # Process reordering self._reorder(prim_obj) self.db.enable_signals() self.db.request_rebuild() # Update progress calculation if self.uistate: self.progress.close() else: print('\nDone.') # finds integer portion in a GrampsID _findint = re.compile(r'^[^\d]*(\d+)[^\d]*$') # finds prefix, number, suffix of a Gramps ID ignoring a leading or # trailing space. The number must be at least three digits. _prob_id = re.compile(r'^ *([^\d]*)(\d{3,9})([^\d]*) *$') def _reorder(self, prim_obj): """ reorders all selected objects with a (new) style, start & step """ dup_ids = [] # list of duplicate identifiers new_ids = {} # list of new identifiers get_handles, commit, get_from_id, get_from_handle, next_from_id = \ self.obj_methods[prim_obj] prefix_fmt = self.obj_values[prim_obj].get_fmt() prefix = self.obj_values[prim_obj].object_prefix suffix = self.obj_values[prim_obj].object_suffix old_pref = self.obj_values[prim_obj].stored_prefix old_suff = self.obj_values[prim_obj].stored_suffix new_id = self.obj_values[prim_obj].get_id() keep_fmt = self.obj_values[prim_obj].get_keep() change = self.obj_values[prim_obj].get_change() index_max = int("9" * self.obj_values[prim_obj].width_fmt) do_same = False # Process in handle order, which is in order handles were created. # This makes renumberd IDs more consistant. handles = get_handles() handles.sort() for handle in handles: # Update progress if self.uistate: self.progress.step() else: self.update() # extract basic data out of the database obj = get_from_handle(handle) act_id = obj.get_gramps_id() # here we see if the ID looks like a new or previous or default # Gramps ID. # If not we ask user if he really wants to replace it. # This should allow user to protect a GetGov ID or similar match = self._prob_id.match(act_id) if not (match and (prefix == match.groups()[0] and suffix == match.groups()[2] or old_pref == match.groups()[0] and old_suff == match.groups()[2] or len(match.groups()[0]) == 1 and len(match.groups()[2]) == 0)) and not do_same: xml = Glade(toplevel='dialog') top = xml.toplevel # self.top.set_icon(ICON) top.set_title("%s - Gramps" % _("Reorder Gramps IDs")) apply_to_rest = xml.get_object('apply_to_rest') label1 = xml.get_object('toplabel') label1.set_text('<span weight="bold" size="larger">%s</span>' % _("Reorder Gramps IDs")) label1.set_use_markup(True) label2 = xml.get_object('mainlabel') label2.set_text(_("Do you want to replace %s?" % act_id)) top.set_transient_for(self.progress._ProgressMeter__dialog) self.progress._ProgressMeter__dialog.set_modal(False) top.show() response = top.run() do_same = apply_to_rest.get_active() top.destroy() self.progress._ProgressMeter__dialog.set_modal(True) if response != Gtk.ResponseType.YES: continue elif not match and do_same and response != Gtk.ResponseType.YES: continue if change: # update the defined ID numbers into objects under # consideration of keeping ID if format not matches prefix # (implication logical boolean operator below) if act_id.startswith(prefix) and act_id.endswith(suffix) or \ not keep_fmt: obj.set_gramps_id(new_id) commit(obj, self.trans) new_id = self.obj_values[prim_obj].succ_id() else: # attempt to extract integer - if we can't, treat it as a # duplicate try: match = self._findint.match(act_id) if match: # get the integer, build the new handle. Make sure it # hasn't already been chosen. If it has, put this # in the duplicate handle list index = int(match.groups()[0]) if index > index_max: new_id = next_from_id() else: new_id = prefix_fmt % index if new_id == act_id: if new_id in new_ids: dup_ids.append(obj.get_handle()) else: new_ids[new_id] = act_id elif get_from_id(new_id) is not None: dup_ids.append(obj.get_handle()) else: obj.set_gramps_id(new_id) commit(obj, self.trans) new_ids[new_id] = act_id else: dup_ids.append(handle) except: dup_ids.append(handle) # go through the duplicates, looking for the first available # handle that matches the new scheme. if dup_ids: if self.uistate: self.progress.set_pass(_('Finding and assigning unused IDs.'), len(dup_ids)) for handle in dup_ids: obj = get_from_handle(handle) obj.set_gramps_id(next_from_id()) commit(obj, self.trans)
class RemoveUnused(tool.Tool, ManagedWindow, UpdateCallback): MARK_COL = 0 OBJ_ID_COL = 1 OBJ_NAME_COL = 2 OBJ_TYPE_COL = 3 OBJ_HANDLE_COL = 4 def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate self.title = _('Unused Objects') tool.Tool.__init__(self, dbstate, options_class, name) if self.db.readonly: return ManagedWindow.__init__(self, uistate,[], self.__class__) UpdateCallback.__init__(self, self.uistate.pulse_progressbar) self.dbstate = dbstate self.uistate = uistate self.tables = { 'events' : {'get_func': self.db.get_event_from_handle, 'remove' : self.db.remove_event, 'get_text': self.get_event_text, 'editor' : 'EditEvent', 'icon' : 'gramps-event', 'name_ix' : 4}, 'sources' : {'get_func': self.db.get_source_from_handle, 'remove' : self.db.remove_source, 'get_text': None, 'editor' : 'EditSource', 'icon' : 'gramps-source', 'name_ix' : 2}, 'places' : {'get_func': self.db.get_place_from_handle, 'remove' : self.db.remove_place, 'get_text': None, 'editor' : 'EditPlace', 'icon' : 'gramps-place', 'name_ix' : 2}, 'media' : {'get_func': self.db.get_object_from_handle, 'remove' : self.db.remove_object, 'get_text': None, 'editor' : 'EditMedia', 'icon' : 'gramps-media', 'name_ix' : 4}, 'repos' : {'get_func': self.db.get_repository_from_handle, 'remove' : self.db.remove_repository, 'get_text': None, 'editor' : 'EditRepository', 'icon' : 'gramps-repository', 'name_ix' : 3}, 'notes' : {'get_func': self.db.get_note_from_handle, 'remove' : self.db.remove_note, 'get_text': self.get_note_text, 'editor' : 'EditNote', 'icon' : 'gramps-notes', 'name_ix' : 2}, } self.init_gui() def init_gui(self): self.top = Glade() window = self.top.toplevel self.set_window(window, self.top.get_object('title'), self.title) self.events_box = self.top.get_object('events_box') self.sources_box = self.top.get_object('sources_box') self.places_box = self.top.get_object('places_box') self.media_box = self.top.get_object('media_box') self.repos_box = self.top.get_object('repos_box') self.notes_box = self.top.get_object('notes_box') self.find_button = self.top.get_object('find_button') self.remove_button = self.top.get_object('remove_button') self.events_box.set_active(self.options.handler.options_dict['events']) self.sources_box.set_active( self.options.handler.options_dict['sources']) self.places_box.set_active( self.options.handler.options_dict['places']) self.media_box.set_active(self.options.handler.options_dict['media']) self.repos_box.set_active(self.options.handler.options_dict['repos']) self.notes_box.set_active(self.options.handler.options_dict['notes']) self.warn_tree = self.top.get_object('warn_tree') self.warn_tree.connect('button_press_event', self.double_click) self.selection = self.warn_tree.get_selection() self.mark_button = self.top.get_object('mark_button') self.mark_button.connect('clicked', self.mark_clicked) self.unmark_button = self.top.get_object('unmark_button') self.unmark_button.connect('clicked', self.unmark_clicked) self.invert_button = self.top.get_object('invert_button') self.invert_button.connect('clicked', self.invert_clicked) self.real_model = Gtk.ListStore(GObject.TYPE_BOOLEAN, GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_STRING) self.sort_model = self.real_model.sort_new_with_model() self.warn_tree.set_model(self.sort_model) self.renderer = Gtk.CellRendererText() self.img_renderer = Gtk.CellRendererPixbuf() self.bool_renderer = Gtk.CellRendererToggle() self.bool_renderer.connect('toggled', self.selection_toggled) # Add mark column mark_column = Gtk.TreeViewColumn(_('Mark'), self.bool_renderer, active=RemoveUnused.MARK_COL) mark_column.set_sort_column_id(RemoveUnused.MARK_COL) self.warn_tree.append_column(mark_column) # Add image column img_column = Gtk.TreeViewColumn(None, self.img_renderer ) img_column.set_cell_data_func(self.img_renderer, self.get_image) self.warn_tree.append_column(img_column) # Add column with object gramps_id id_column = Gtk.TreeViewColumn(_('ID'), self.renderer, text=RemoveUnused.OBJ_ID_COL) id_column.set_sort_column_id(RemoveUnused.OBJ_ID_COL) self.warn_tree.append_column(id_column) # Add column with object name name_column = Gtk.TreeViewColumn(_('Name'), self.renderer, text=RemoveUnused.OBJ_NAME_COL) name_column.set_sort_column_id(RemoveUnused.OBJ_NAME_COL) self.warn_tree.append_column(name_column) self.top.connect_signals({ "destroy_passed_object" : self.close, "on_remove_button_clicked": self.do_remove, "on_find_button_clicked" : self.find, "on_delete_event" : self.close, }) self.dc_label = self.top.get_object('dc_label') self.sensitive_list = [self.warn_tree, self.mark_button, self.unmark_button, self.invert_button, self.dc_label, self.remove_button] for item in self.sensitive_list: item.set_sensitive(False) self.show() def build_menu_names(self, obj): return (self.title, None) def find(self, obj): self.options.handler.options_dict.update( events = self.events_box.get_active(), sources = self.sources_box.get_active(), places = self.places_box.get_active(), media = self.media_box.get_active(), repos = self.repos_box.get_active(), notes = self.notes_box.get_active(), ) for item in self.sensitive_list: item.set_sensitive(True) self.uistate.set_busy_cursor(True) self.uistate.progress.show() self.window.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH)) self.real_model.clear() self.collect_unused() self.uistate.progress.hide() self.uistate.set_busy_cursor(False) self.window.get_window().set_cursor(None) self.reset() # Save options self.options.handler.save_options() def collect_unused(self): # Run through all requested tables and check all objects # for being referenced some place. If not, add_results on them. db = self.db tables = ( ('events', db.get_event_cursor, db.get_number_of_events), ('sources', db.get_source_cursor, db.get_number_of_sources), ('places', db.get_place_cursor, db.get_number_of_places), ('media', db.get_media_cursor, db.get_number_of_media_objects), ('repos', db.get_repository_cursor, db.get_number_of_repositories), ('notes', db.get_note_cursor, db.get_number_of_notes), ) for (the_type, cursor_func, total_func) in tables: if not self.options.handler.options_dict[the_type]: # This table was not requested. Skip it. continue with cursor_func() as cursor: self.set_total(total_func()) fbh = db.find_backlink_handles for handle, data in cursor: if not any(h for h in fbh(handle)): self.add_results((the_type, handle.decode('utf-8'), data)) self.update() self.reset() def do_remove(self, obj): with DbTxn(_("Remove unused objects"), self.db, batch=False) as trans: self.db.disable_signals() for row_num in range(len(self.real_model)-1, -1, -1): path = (row_num,) row = self.real_model[path] if not row[RemoveUnused.MARK_COL]: continue the_type = row[RemoveUnused.OBJ_TYPE_COL] handle = row[RemoveUnused.OBJ_HANDLE_COL] remove_func = self.tables[the_type]['remove'] remove_func(handle, trans) self.real_model.remove(row.iter) self.db.enable_signals() self.db.request_rebuild() def selection_toggled(self, cell, path_string): sort_path = tuple(map(int, path_string.split(':'))) real_path = self.sort_model.convert_path_to_child_path(Gtk.TreePath(sort_path)) row = self.real_model[real_path] row[RemoveUnused.MARK_COL] = not row[RemoveUnused.MARK_COL] self.real_model.row_changed(real_path, row.iter) def mark_clicked(self, mark_button): for row_num in range(len(self.real_model)): path = (row_num,) row = self.real_model[path] row[RemoveUnused.MARK_COL] = True def unmark_clicked(self, unmark_button): for row_num in range(len(self.real_model)): path = (row_num,) row = self.real_model[path] row[RemoveUnused.MARK_COL] = False def invert_clicked(self, invert_button): for row_num in range(len(self.real_model)): path = (row_num,) row = self.real_model[path] row[RemoveUnused.MARK_COL] = not row[RemoveUnused.MARK_COL] def double_click(self, obj, event): if event.type == Gdk.EventType._2BUTTON_PRESS and event.button == 1: (model, node) = self.selection.get_selected() if not node: return sort_path = self.sort_model.get_path(node) real_path = self.sort_model.convert_path_to_child_path(sort_path) row = self.real_model[real_path] the_type = row[RemoveUnused.OBJ_TYPE_COL] handle = row[RemoveUnused.OBJ_HANDLE_COL] self.call_editor(the_type, handle) def call_editor(self, the_type, handle): try: obj = self.tables[the_type]['get_func'](handle) editor_str = 'from gramps.gui.editors import %s as editor' % ( self.tables[the_type]['editor'] ) exec(editor_str, globals()) editor(self.dbstate, self.uistate, [], obj) except WindowActiveError: pass def get_image(self, column, cell, model, iter, user_data=None): the_type = model.get_value(iter, RemoveUnused.OBJ_TYPE_COL) the_icon = self.tables[the_type]['icon'] cell.set_property('icon-name', the_icon) def add_results(self, results): (the_type, handle, data) = results gramps_id = data[1] # if we have a function that will return to us some type # of text summary, then we should use it; otherwise we'll # use the generic field index provided in the tables above if self.tables[the_type]['get_text']: text = self.tables[the_type]['get_text'](the_type, handle, data) else: # grab the text field index we know about, and hope # it represents something useful to the user name_ix = self.tables[the_type]['name_ix'] text = data[name_ix] # insert a new row into the table self.real_model.append(row=[False, gramps_id, text, the_type, handle]) def get_event_text(self, the_type, handle, data): """ Come up with a short line of text that we can use as a summary to represent this event. """ # get the event: event = self.tables[the_type]['get_func'](handle) # first check to see if the event has a descriptive name text = event.get_description() # (this is rarely set for events) # if we don't have a description... if text == '': # ... then we merge together several fields # get the event type (marriage, birth, death, etc.) text = str(event.get_type()) # see if there is a date date = _dd.display(event.get_date_object()) if date != '': text += '; %s' % date # see if there is a place if event.get_place_handle(): text += '; %s' % _pd.display_event(self.db, event) return text def get_note_text(self, the_type, handle, data): """ We need just the first few words of a note as a summary. """ # get the note object note = self.tables[the_type]['get_func'](handle) # get the note text; this ignores (discards) formatting text = note.get() # convert whitespace to a single space text = " ".join(text.split()) # if the note is too long, truncate it if len(text) > 80: text = text[:80] + "..." return text
class EventComparison(tool.Tool, ManagedWindow): def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate self.dbstate = dbstate self.uistate = uistate tool.Tool.__init__(self, dbstate, options_class, name) ManagedWindow.__init__(self, uistate, [], self) self.qual = 0 self.filterDialog = Glade(toplevel="filters", also_load=["liststore1"]) self.filterDialog.connect_signals({ "on_apply_clicked": self.on_apply_clicked, "on_editor_clicked": self.filter_editor_clicked, "on_help_clicked": self.on_help_clicked, "destroy_passed_object": self.close, "on_write_table": self.__dummy, }) window = self.filterDialog.toplevel self.filters = self.filterDialog.get_object("filter_list") self.label = _('Event comparison filter selection') self.set_window(window, self.filterDialog.get_object('title'), self.label) self.setup_configs('interface.eventcomparison', 640, 220) self.on_filters_changed('Person') uistate.connect('filters-changed', self.on_filters_changed) self.show() def __dummy(self, obj): """dummy callback, needed because widget is in same glade file as another widget, so callbacks must be defined to avoid warnings. """ pass def on_filters_changed(self, name_space): if name_space == 'Person': all_filter = GenericFilter() all_filter.set_name(_("Entire Database")) all_filter.add_rule(rules.person.Everyone([])) self.filter_model = build_filter_model('Person', [all_filter]) self.filters.set_model(self.filter_model) self.filters.set_active(0) def on_help_clicked(self, obj): """Display the relevant portion of Gramps manual""" display_help(webpage=WIKI_HELP_PAGE, section=WIKI_HELP_SEC) def build_menu_names(self, obj): return (_("Filter selection"), _("Event Comparison tool")) def filter_editor_clicked(self, obj): try: FilterEditor('Person', CUSTOM_FILTERS, self.dbstate, self.uistate) except WindowActiveError: pass def on_apply_clicked(self, obj): cfilter = self.filter_model[self.filters.get_active()][1] progress_bar = ProgressMeter(_('Comparing events'), '', parent=self.window) progress_bar.set_pass(_('Selecting people'), 1) plist = cfilter.apply(self.db, self.db.iter_person_handles()) progress_bar.step() progress_bar.close() self.options.handler.options_dict['filter'] = self.filters.get_active() # Save options self.options.handler.save_options() if len(plist) == 0: WarningDialog(_("No matches were found"), parent=self.window) else: EventComparisonResults(self.dbstate, self.uistate, plist, self.track)
class ChangeTypes(tool.BatchTool, ManagedWindow): def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate self.user = user tool.BatchTool.__init__(self, dbstate, user, options_class, name) if self.fail: return if uistate: self.title = _('Change Event Types') ManagedWindow.__init__(self,uistate,[], self.__class__) self.init_gui() else: self.run_tool() def init_gui(self): # Draw dialog and make it handle everything self.glade = Glade() self.auto1 = self.glade.get_object("original") self.auto2 = self.glade.get_object("new") # Need to display localized event names etype = EventType() event_names = sorted(etype.get_standard_names(), key=glocale.sort_key) fill_combo(self.auto1,event_names) fill_combo(self.auto2,event_names) etype.set_from_xml_str(self.options.handler.options_dict['fromtype']) self.auto1.get_child().set_text(str(etype)) etype.set_from_xml_str(self.options.handler.options_dict['totype']) self.auto2.get_child().set_text(str(etype)) window = self.glade.toplevel self.set_window(window,self.glade.get_object('title'),self.title) self.glade.connect_signals({ "on_close_clicked" : self.close, "on_apply_clicked" : self.on_apply_clicked, "on_delete_event" : self.close, }) self.show() def build_menu_names(self, obj): return (self.title,None) def run_tool(self, parent_window = None): # Run tool and return results # These are English names, no conversion needed fromtype = self.options.handler.options_dict['fromtype'] totype = self.options.handler.options_dict['totype'] modified = 0 with DbTxn(_('Change types'), self.db, batch=True) as self.trans: self.db.disable_signals() with self.user.progress( _('Analyzing Events'), '', self.db.get_number_of_events()) as step: for event_handle in self.db.get_event_handles(): event = self.db.get_event_from_handle(event_handle) if event.get_type().xml_str() == fromtype: event.type.set_from_xml_str(totype) modified += 1 self.db.commit_event(event,self.trans) step() self.db.enable_signals() self.db.request_rebuild() if modified == 0: msg = _("No event record was modified.") else: # translators: leave all/any {...} untranslated msg = ngettext("{number_of} event record was modified.", "{number_of} event records were modified.", modified ).format(number_of=modified) self.user.info(_('Change types'), msg, parent_window) return (bool(modified),msg) def on_apply_clicked(self, obj): # Need to store English names for later comparison the_type = EventType() the_type.set(self.auto1.get_child().get_text()) self.options.handler.options_dict['fromtype'] = the_type.xml_str() the_type.set(self.auto2.get_child().get_text()) self.options.handler.options_dict['totype'] = the_type.xml_str() self.run_tool(self.window) # Save options self.options.handler.save_options() self.close()
class EventComparison(tool.Tool, ManagedWindow): def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate self.dbstate = dbstate self.uistate = uistate tool.Tool.__init__(self, dbstate, options_class, name) ManagedWindow.__init__(self, uistate, [], self) self.qual = 0 self.filterDialog = Glade(toplevel="filters") self.filterDialog.connect_signals( { "on_apply_clicked": self.on_apply_clicked, "on_editor_clicked": self.filter_editor_clicked, "on_help_clicked": self.on_help_clicked, "destroy_passed_object": self.close, "on_write_table": self.__dummy, } ) window = self.filterDialog.toplevel self.filters = self.filterDialog.get_object("filter_list") self.label = _("Event comparison filter selection") self.set_window(window, self.filterDialog.get_object("title"), self.label) self.on_filters_changed("Person") uistate.connect("filters-changed", self.on_filters_changed) self.show() def __dummy(self, obj): """dummy callback, needed because widget is in same glade file as another widget, so callbacks must be defined to avoid warnings. """ pass def on_filters_changed(self, name_space): if name_space == "Person": all_filter = GenericFilter() all_filter.set_name(_("Entire Database")) all_filter.add_rule(rules.person.Everyone([])) self.filter_model = build_filter_model("Person", [all_filter]) self.filters.set_model(self.filter_model) self.filters.set_active(0) def on_help_clicked(self, obj): """Display the relevant portion of GRAMPS manual""" display_help(webpage=WIKI_HELP_PAGE, section=WIKI_HELP_SEC) def build_menu_names(self, obj): return (_("Filter selection"), _("Event Comparison tool")) def filter_editor_clicked(self, obj): try: FilterEditor("Person", CUSTOM_FILTERS, self.dbstate, self.uistate) except WindowActiveError: pass def on_apply_clicked(self, obj): cfilter = self.filter_model[self.filters.get_active()][1] progress_bar = ProgressMeter(_("Comparing events"), "", parent=self.window) progress_bar.set_pass(_("Selecting people"), 1) plist = cfilter.apply(self.db, self.db.iter_person_handles()) progress_bar.step() progress_bar.close() self.options.handler.options_dict["filter"] = self.filters.get_active() # Save options self.options.handler.save_options() if len(plist) == 0: WarningDialog(_("No matches were found"), parent=self.window) else: DisplayChart(self.dbstate, self.uistate, plist, self.track)
class ReorderIds(tool.BatchTool, ManagedWindow, UpdateCallback): """ Class for Reodering Gramps ID Tool """ xobjects = (('person', 'people'), ('family', 'families'), ('event', 'events'), ('place', 'places'), ('source', 'sources'), ('citation', 'citations'), ('repository', 'repositories'), ('media', 'media'), ('note', 'notes')) def build_menu_names_(self, widget=None): """ The menu name """ return (_('Main window'), _("Reorder Gramps IDs")) def __init__(self, dbstate, user, options_class, name, callback=None): self.uistate = user.uistate self.db = dbstate.db if self.uistate: tool.BatchTool.__init__(self, dbstate, user, options_class, name) if self.fail: return # user denied to modify Gramps IDs ManagedWindow.__init__(self, self.uistate, [], self.__class__) if not self.uistate: UpdateCallback.__init__(self, user.callback) self.object_status = True self.change_status = False self.start_zero = True self.step_cnt, self.step_list = 0, ['1', '2', '5', '10'] self.keep_status = True self.obj_values = {} # enable access to all internal values self.active_entries, self.format_entries = {}, {} self.change_entries = {} self.start_entries, self.step_entries = {}, {} self.keep_entries = {} self.prim_methods, self.obj_methods = {}, {} for prim_obj, prim_objs in self.xobjects: iter_handles = "iter_%s_handles" % prim_obj get_number_obj = "get_number_of_%s" % prim_objs prefix_fmt = "%s_prefix" % prim_obj get_from_id = "get_%s_from_gramps_id" % prim_obj get_from_handle = "get_%s_from_handle" % prim_obj next_from_id = "find_next_%s_gramps_id" % prim_obj commit = "commit_%s" % prim_obj self.prim_methods[prim_obj] = (getattr(self.db, prefix_fmt), getattr(self.db, get_number_obj)(), getattr(self.db, next_from_id)()) self.obj_methods[prim_obj] = (getattr(self.db, iter_handles), getattr(self.db, commit), getattr(self.db, get_from_id), getattr(self.db, get_from_handle), getattr(self.db, next_from_id)) object_fmt, quant_id, next_id = self.prim_methods[prim_obj] obj_value = ReorderEntry(object_fmt, quant_id, next_id, prim_obj) self.obj_values[prim_obj] = obj_value if self.uistate: self._display() else: self._execute() def __on_object_button_clicked(self, widget=None): """ compute all primary objects and toggle the 'Active' attribute """ self.object_status = not self.object_status for prim_obj, dummy in self.xobjects: obj = self.top.get_object('%s_active' % prim_obj) obj.set_active(self.object_status) def __on_object_button_toggled(self, widget): """ compute the primary object and toggle the 'Sensitive' attribute """ obj_state = widget.get_active() obj_name = Gtk.Buildable.get_name(widget).split('_', 1)[0] self.active_entries[obj_name].set_val(obj_state) for obj_entry in ['actual', 'quant', 'format', 'change']: obj = self.top.get_object('%s_%s' % (obj_name, obj_entry)) obj.set_sensitive(obj_state) for obj_entry in ['start', 'step', 'keep']: obj = self.top.get_object('%s_change' % obj_name) if obj.get_active(): obj = self.top.get_object('%s_%s' % (obj_name, obj_entry)) obj.set_sensitive(obj_state) def __on_format_button_clicked(self, widget=None): """ compute all sensitive primary objects and sets the 'Format' scheme of identifiers """ for prim_obj, dummy in self.xobjects: obj_format = self.top.get_object('%s_format' % prim_obj) if not obj_format.get_sensitive(): continue obj_fmt = self.obj_values[prim_obj].res_fmt() self.format_entries[prim_obj].force_value(obj_fmt) if self.start_zero: obj_id = self.obj_values[prim_obj].zero_id() else: obj_id = self.obj_values[prim_obj].last_id() self.start_entries[prim_obj].force_value(obj_id) def __on_change_button_clicked(self, widget=None): """ compute all primary objects and toggle the 'Change' attribute """ self.change_status = not self.change_status for prim_obj, dummy in self.xobjects: obj_change = self.top.get_object('%s_change' % prim_obj) if not obj_change.get_sensitive(): continue self.change_entries[prim_obj].set_val(self.change_status) obj_change.set_active(self.change_status) def __on_change_button_toggled(self, widget): """ compute the primary object and toggle the 'Sensitive' attribute """ obj_state = widget.get_active() obj_name = Gtk.Buildable.get_name(widget).split('_', 1)[0] for obj_entry in ['start', 'step', 'keep']: obj = self.top.get_object('%s_%s' % (obj_name, obj_entry)) if obj_entry == 'keep': if (self.obj_values[obj_name].stored_prefix != self.obj_values[obj_name].object_prefix and self.obj_values[obj_name].stored_suffix != self.obj_values[obj_name].object_suffix): self.keep_entries[obj_name].set_val(False) else: obj.set_active(obj_state) self.keep_entries[obj_name].set_val(obj_state) obj.set_sensitive(obj_state) def __on_start_button_clicked(self, widget=None): """ compute all sensitive primary objects and sets the 'Start' values of identifiers """ self.start_zero = not self.start_zero for prim_obj, dummy in self.xobjects: obj = self.top.get_object('%s_start' % prim_obj) if not obj.get_sensitive(): continue if self.start_zero: obj_id = self.obj_values[prim_obj].zero_id() else: obj_id = self.obj_values[prim_obj].next_id() self.start_entries[prim_obj].force_value(obj_id) def __on_step_button_clicked(self, widget=None): """ compute all sensitive primary objects and sets the 'Step' width of identifiers """ self.step_cnt = self.step_cnt + 1 if self.step_cnt < 3 else 0 for prim_obj, dummy in self.xobjects: obj = self.top.get_object('%s_step' % prim_obj) if not obj.get_sensitive(): continue step_val = self.step_list[self.step_cnt] self.step_entries[prim_obj].force_value(step_val) def __on_keep_button_clicked(self, widget=None): """ compute the primary object and toggle the 'Active' attribute """ self.keep_status = not self.keep_status for prim_obj, dummy in self.xobjects: obj = self.top.get_object('%s_change' % prim_obj) if not obj.get_active(): continue obj = self.top.get_object('%s_keep' % prim_obj) obj.set_active(self.keep_status) self.keep_entries[prim_obj].set_val(self.keep_status) def __on_format_entry_keyrelease(self, widget, event, data=None): """ activated on all return's of an entry """ if event.keyval in [Gdk.KEY_Return]: obj_name = Gtk.Buildable.get_name(widget).split('_', 1)[0] obj_fmt = self.format_entries[obj_name].get_val() self.format_entries[obj_name].force_value(obj_fmt) self.start_entries[obj_name].update() obj_change = self.top.get_object('%s_change' % obj_name) obj_change.grab_focus() return False def __on_format_entry_focusout(self, widget, event, data=None): """ activated on all focus out of an entry """ obj_name = Gtk.Buildable.get_name(widget).split('_', 1)[0] obj_fmt = self.format_entries[obj_name].get_val() self.format_entries[obj_name].set_text(obj_fmt) self.start_entries[obj_name].update() return False def __on_start_entry_focusout(self, widget, event, data=None): """ activated on all focus out of an entry """ obj_name = Gtk.Buildable.get_name(widget).split('_', 1)[0] self.start_entries[obj_name].update() return False def __on_ok_button_clicked(self, widget=None): """ execute the reodering and close """ self._execute() self._update() self.close() def __on_cancel_button_clicked(self, widget=None): """ cancel the reodering and close """ self.close() def __on_help_button_clicked(self, widget=None): """ display the relevant portion of Gramps manual """ display_help(webpage=WIKI_HELP_PAGE, section=WIKI_HELP_SEC) def _display(self): """ organize Glade 'Reorder IDs' window """ # get the main window from glade self.top = Glade(toplevel="reorder-ids") window = self.top.toplevel # set gramps style title for the window self.set_window(window, self.top.get_object("title"), _("Reorder Gramps IDs")) # connect signals self.top.connect_signals({ "on_object_button_clicked" : self.__on_object_button_clicked, "on_object_button_toggled" : self.__on_object_button_toggled, "on_format_button_clicked" : self.__on_format_button_clicked, "on_start_button_clicked" : self.__on_start_button_clicked, "on_step_button_clicked" : self.__on_step_button_clicked, "on_keep_button_clicked" : self.__on_keep_button_clicked, "on_change_button_clicked" : self.__on_change_button_clicked, "on_change_button_toggled" : self.__on_change_button_toggled, "on_format_entry_keyrelease" : self.__on_format_entry_keyrelease, "on_format_entry_focusout" : self.__on_format_entry_focusout, "on_start_entry_focusout" : self.__on_start_entry_focusout, "on_help_button_clicked" : self.__on_help_button_clicked, "on_cancel_button_clicked" : self.__on_cancel_button_clicked, "on_ok_button_clicked" : self.__on_ok_button_clicked }) # Calculate all entries and update Glade window for prim_obj, dummy in self.xobjects: # populate Object, Actual & Quantity fields with values obj_active = self.top.get_object('%s_active' % prim_obj) self.active_entries[prim_obj] = MonitoredCheckbox( obj_active, obj_active, self.obj_values[prim_obj].set_active, self.obj_values[prim_obj].get_active) obj_actual = self.top.get_object('%s_actual' % prim_obj) obj_actual.set_text('%s' % self.obj_values[prim_obj].last_id()) obj_quant = self.top.get_object('%s_quant' % prim_obj) obj_quant.set_text('%s' % str(self.obj_values[prim_obj].quant_id)) # connect/populate Format, Start, Step, Keep & Change fields # with GTK/values obj_format = self.top.get_object('%s_format' % prim_obj) self.format_entries[prim_obj] = MonitoredEntry( obj_format, self.obj_values[prim_obj].set_fmt, self.obj_values[prim_obj].get_fmt) obj_change = self.top.get_object('%s_change' % prim_obj) self.change_entries[prim_obj] = MonitoredCheckbox( obj_change, obj_change, self.obj_values[prim_obj].set_change, self.obj_values[prim_obj].get_change) obj_start = self.top.get_object('%s_start' % prim_obj) self.start_entries[prim_obj] = MonitoredEntry( obj_start, self.obj_values[prim_obj].set_id, self.obj_values[prim_obj].get_id) obj_step = self.top.get_object('%s_step' % prim_obj) self.step_entries[prim_obj] = MonitoredEntry( obj_step, self.obj_values[prim_obj].set_step, self.obj_values[prim_obj].get_step, changed=self.obj_values[prim_obj].change_step) obj_keep = self.top.get_object('%s_keep' % prim_obj) self.keep_entries[prim_obj] = MonitoredCheckbox( obj_keep, obj_keep, self.obj_values[prim_obj].set_keep, self.obj_values[prim_obj].get_keep, readonly=True) # fetch the popup menu self.menu = self.top.get_object("popup_menu") # ok, let's see what we've done self.window.resize(700, 410) self.show() def _update(self): """ store changed objects formats in DB """ update = False for prim_obj, dummy in self.xobjects: obj_value = self.obj_values[prim_obj] if obj_value.object_fmt != obj_value.stored_fmt: constant = 'preferences.%sprefix' % PREFIXES[prim_obj] config.set(constant, obj_value.object_fmt) update = True if update: config.save() self.db.set_prefixes( config.get('preferences.iprefix'), config.get('preferences.oprefix'), config.get('preferences.fprefix'), config.get('preferences.sprefix'), config.get('preferences.cprefix'), config.get('preferences.pprefix'), config.get('preferences.eprefix'), config.get('preferences.rprefix'), config.get('preferences.nprefix')) def _execute(self): """ execute all primary objects and reorder if neccessary """ # Update progress calculation if self.uistate: self.progress = ProgressMeter(_('Reorder Gramps IDs'), '') else: total_objs = 0 for prim_obj, dummy in self.xobjects: if self.obj_values[prim_obj].active_obj: total_objs += self.obj_values[prim_obj].quant_id self.set_total(total_objs) # Update database self.db.disable_signals() for prim_obj, prim_objs in self.xobjects: with DbTxn(_('Reorder %s IDs ...') % prim_obj, self.db, batch=True) as self.trans: if self.obj_values[prim_obj].active_obj: if self.uistate: self.progress.set_pass( _('Reorder %s IDs ...') % _(prim_objs.title()), self.obj_values[prim_obj].quant_id) # Process reordering self._reorder(prim_obj) self.db.enable_signals() self.db.request_rebuild() # Update progress calculation if self.uistate: self.progress.close() else: print('\nDone.') # finds integer portion in a GrampsID _findint = re.compile('^[^\d]*(\d+)[^\d]*$') # finds prefix, number, suffix of a Gramps ID ignoring a leading or # trailing space. The number must be at least three digits. _prob_id = re.compile('^ *([^\d]*)(\d{3,9})([^\d]*) *$') def _reorder(self, prim_obj): """ reorders all selected objects with a (new) style, start & step """ dup_ids = [] # list of duplicate identifiers new_ids = {} # list of new identifiers iter_handles, commit, get_from_id, get_from_handle, next_from_id = \ self.obj_methods[prim_obj] prefix_fmt = self.obj_values[prim_obj].get_fmt() prefix = self.obj_values[prim_obj].object_prefix suffix = self.obj_values[prim_obj].object_suffix old_pref = self.obj_values[prim_obj].stored_prefix old_suff = self.obj_values[prim_obj].stored_suffix new_id = self.obj_values[prim_obj].get_id() keep_fmt = self.obj_values[prim_obj].get_keep() change = self.obj_values[prim_obj].get_change() index_max = int("9" * self.obj_values[prim_obj].width_fmt) do_same = False for handle in iter_handles(): # Update progress if self.uistate: self.progress.step() else: self.update() # extract basic data out of the database obj = get_from_handle(handle) act_id = obj.get_gramps_id() # here we see if the ID looks like a new or previous or default # Gramps ID. # If not we ask user if he really wants to replace it. # This should allow user to protect a GetGov ID or similar match = self._prob_id.match(act_id) if not (match and (prefix == match.groups()[0] and suffix == match.groups()[2] or old_pref == match.groups()[0] and old_suff == match.groups()[2] or len(match.groups()[0]) == 1 and len(match.groups()[2]) == 0)) and not do_same: xml = Glade(toplevel='dialog') top = xml.toplevel # self.top.set_icon(ICON) top.set_title("%s - Gramps" % _("Reorder Gramps IDs")) apply_to_rest = xml.get_object('apply_to_rest') label1 = xml.get_object('toplabel') label1.set_text('<span weight="bold" size="larger">%s</span>' % _("Reorder Gramps IDs")) label1.set_use_markup(True) label2 = xml.get_object('mainlabel') label2.set_text(_("Do you want to replace %s?" % act_id)) top.set_transient_for(self.progress._ProgressMeter__dialog) self.progress._ProgressMeter__dialog.set_modal(False) top.show() response = top.run() do_same = apply_to_rest.get_active() top.destroy() self.progress._ProgressMeter__dialog.set_modal(True) if response != Gtk.ResponseType.YES: continue elif not match and do_same and response != Gtk.ResponseType.YES: continue if change: # update the defined ID numbers into objects under # consideration of keeping ID if format not matches prefix # (implication logical boolean operator below) if act_id.startswith(prefix) and act_id.endswith(suffix) or \ not keep_fmt: obj.set_gramps_id(new_id) commit(obj, self.trans) new_id = self.obj_values[prim_obj].succ_id() else: # attempt to extract integer - if we can't, treat it as a # duplicate try: match = self._findint.match(act_id) if match: # get the integer, build the new handle. Make sure it # hasn't already been chosen. If it has, put this # in the duplicate handle list index = int(match.groups()[0]) if index > index_max: new_id = next_from_id() else: new_id = prefix_fmt % index if new_id == act_id: if new_id in new_ids: dup_ids.append(obj.get_handle()) else: new_ids[new_id] = act_id elif get_from_id(new_id) is not None: dup_ids.append(obj.get_handle()) else: obj.set_gramps_id(new_id) commit(obj, self.trans) new_ids[new_id] = act_id else: dup_ids.append(handle) except: dup_ids.append(handle) # go through the duplicates, looking for the first available # handle that matches the new scheme. if dup_ids: if self.uistate: self.progress.set_pass(_('Finding and assigning unused IDs.'), len(dup_ids)) for handle in dup_ids: obj = get_from_handle(handle) obj.set_gramps_id(next_from_id()) commit(obj, self.trans)
class RemoveUnused(tool.Tool, ManagedWindow, UpdateCallback): MARK_COL = 0 OBJ_ID_COL = 1 OBJ_NAME_COL = 2 OBJ_TYPE_COL = 3 OBJ_HANDLE_COL = 4 BUSY_CURSOR = Gdk.Cursor.new_for_display(Gdk.Display.get_default(), Gdk.CursorType.WATCH) def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate self.title = _('Unused Objects') tool.Tool.__init__(self, dbstate, options_class, name) if self.db.readonly: return ManagedWindow.__init__(self, uistate, [], self.__class__) UpdateCallback.__init__(self, self.uistate.pulse_progressbar) self.dbstate = dbstate self.uistate = uistate self.tables = { 'events': { 'get_func': self.db.get_event_from_handle, 'remove': self.db.remove_event, 'get_text': self.get_event_text, 'editor': 'EditEvent', 'icon': 'gramps-event', 'name_ix': 4 }, 'sources': { 'get_func': self.db.get_source_from_handle, 'remove': self.db.remove_source, 'get_text': None, 'editor': 'EditSource', 'icon': 'gramps-source', 'name_ix': 2 }, 'citations': { 'get_func': self.db.get_citation_from_handle, 'remove': self.db.remove_citation, 'get_text': None, 'editor': 'EditCitation', 'icon': 'gramps-citation', 'name_ix': 3 }, 'places': { 'get_func': self.db.get_place_from_handle, 'remove': self.db.remove_place, 'get_text': None, 'editor': 'EditPlace', 'icon': 'gramps-place', 'name_ix': 2 }, 'media': { 'get_func': self.db.get_media_from_handle, 'remove': self.db.remove_media, 'get_text': None, 'editor': 'EditMedia', 'icon': 'gramps-media', 'name_ix': 4 }, 'repos': { 'get_func': self.db.get_repository_from_handle, 'remove': self.db.remove_repository, 'get_text': None, 'editor': 'EditRepository', 'icon': 'gramps-repository', 'name_ix': 3 }, 'notes': { 'get_func': self.db.get_note_from_handle, 'remove': self.db.remove_note, 'get_text': self.get_note_text, 'editor': 'EditNote', 'icon': 'gramps-notes', 'name_ix': 2 }, } self.init_gui() def init_gui(self): self.top = Glade() window = self.top.toplevel self.set_window(window, self.top.get_object('title'), self.title) self.events_box = self.top.get_object('events_box') self.sources_box = self.top.get_object('sources_box') self.citations_box = self.top.get_object('citations_box') self.places_box = self.top.get_object('places_box') self.media_box = self.top.get_object('media_box') self.repos_box = self.top.get_object('repos_box') self.notes_box = self.top.get_object('notes_box') self.find_button = self.top.get_object('find_button') self.remove_button = self.top.get_object('remove_button') self.events_box.set_active(self.options.handler.options_dict['events']) self.sources_box.set_active( self.options.handler.options_dict['sources']) self.citations_box.set_active( self.options.handler.options_dict['citations']) self.places_box.set_active(self.options.handler.options_dict['places']) self.media_box.set_active(self.options.handler.options_dict['media']) self.repos_box.set_active(self.options.handler.options_dict['repos']) self.notes_box.set_active(self.options.handler.options_dict['notes']) self.warn_tree = self.top.get_object('warn_tree') self.warn_tree.connect('button_press_event', self.double_click) self.selection = self.warn_tree.get_selection() self.mark_button = self.top.get_object('mark_button') self.mark_button.connect('clicked', self.mark_clicked) self.unmark_button = self.top.get_object('unmark_button') self.unmark_button.connect('clicked', self.unmark_clicked) self.invert_button = self.top.get_object('invert_button') self.invert_button.connect('clicked', self.invert_clicked) self.real_model = Gtk.ListStore(GObject.TYPE_BOOLEAN, GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_STRING) self.sort_model = self.real_model.sort_new_with_model() self.warn_tree.set_model(self.sort_model) self.renderer = Gtk.CellRendererText() self.img_renderer = Gtk.CellRendererPixbuf() self.bool_renderer = Gtk.CellRendererToggle() self.bool_renderer.connect('toggled', self.selection_toggled) # Add mark column mark_column = Gtk.TreeViewColumn(_('Mark'), self.bool_renderer, active=RemoveUnused.MARK_COL) mark_column.set_sort_column_id(RemoveUnused.MARK_COL) self.warn_tree.append_column(mark_column) # Add image column img_column = Gtk.TreeViewColumn(None, self.img_renderer) img_column.set_cell_data_func(self.img_renderer, self.get_image) self.warn_tree.append_column(img_column) # Add column with object gramps_id id_column = Gtk.TreeViewColumn(_('ID'), self.renderer, text=RemoveUnused.OBJ_ID_COL) id_column.set_sort_column_id(RemoveUnused.OBJ_ID_COL) self.warn_tree.append_column(id_column) # Add column with object name name_column = Gtk.TreeViewColumn(_('Name'), self.renderer, text=RemoveUnused.OBJ_NAME_COL) name_column.set_sort_column_id(RemoveUnused.OBJ_NAME_COL) self.warn_tree.append_column(name_column) self.top.connect_signals({ "destroy_passed_object": self.close, "on_remove_button_clicked": self.do_remove, "on_find_button_clicked": self.find, "on_delete_event": self.close, }) self.dc_label = self.top.get_object('dc_label') self.sensitive_list = [ self.warn_tree, self.mark_button, self.unmark_button, self.invert_button, self.dc_label, self.remove_button ] for item in self.sensitive_list: item.set_sensitive(False) self.show() def build_menu_names(self, obj): return (self.title, None) def find(self, obj): self.options.handler.options_dict.update( events=self.events_box.get_active(), sources=self.sources_box.get_active(), citations=self.citations_box.get_active(), places=self.places_box.get_active(), media=self.media_box.get_active(), repos=self.repos_box.get_active(), notes=self.notes_box.get_active(), ) for item in self.sensitive_list: item.set_sensitive(True) self.uistate.set_busy_cursor(True) self.uistate.progress.show() self.window.get_window().set_cursor(self.BUSY_CURSOR) self.real_model.clear() self.collect_unused() self.uistate.progress.hide() self.uistate.set_busy_cursor(False) self.window.get_window().set_cursor(None) self.reset() # Save options self.options.handler.save_options() def collect_unused(self): # Run through all requested tables and check all objects # for being referenced some place. If not, add_results on them. db = self.db tables = ( ('events', db.get_event_cursor, db.get_number_of_events), ('sources', db.get_source_cursor, db.get_number_of_sources), ('citations', db.get_citation_cursor, db.get_number_of_citations), ('places', db.get_place_cursor, db.get_number_of_places), ('media', db.get_media_cursor, db.get_number_of_media), ('repos', db.get_repository_cursor, db.get_number_of_repositories), ('notes', db.get_note_cursor, db.get_number_of_notes), ) # bug 7619 : don't select notes from to do list. # notes associated to the todo list doesn't have references. # get the todo list (from get_note_list method of the todo gramplet ) all_notes = self.dbstate.db.get_note_handles() FilterClass = GenericFilterFactory('Note') filter1 = FilterClass() filter1.add_rule(rules.note.HasType(["To Do"])) todo_list = filter1.apply(self.dbstate.db, all_notes) filter2 = FilterClass() filter2.add_rule(rules.note.HasType(["Link"])) link_list = filter2.apply(self.dbstate.db, all_notes) for (the_type, cursor_func, total_func) in tables: if not self.options.handler.options_dict[the_type]: # This table was not requested. Skip it. continue with cursor_func() as cursor: self.set_total(total_func()) fbh = db.find_backlink_handles for handle, data in cursor: if not any(h for h in fbh(handle)): if handle not in todo_list and handle not in link_list: self.add_results( (the_type, handle.decode('utf-8'), data)) self.update() self.reset() def do_remove(self, obj): with DbTxn(_("Remove unused objects"), self.db, batch=False) as trans: self.db.disable_signals() for row_num in range(len(self.real_model) - 1, -1, -1): path = (row_num, ) row = self.real_model[path] if not row[RemoveUnused.MARK_COL]: continue the_type = row[RemoveUnused.OBJ_TYPE_COL] handle = row[RemoveUnused.OBJ_HANDLE_COL] remove_func = self.tables[the_type]['remove'] remove_func(handle, trans) self.real_model.remove(row.iter) self.db.enable_signals() self.db.request_rebuild() def selection_toggled(self, cell, path_string): sort_path = tuple(map(int, path_string.split(':'))) real_path = self.sort_model.convert_path_to_child_path( Gtk.TreePath(sort_path)) row = self.real_model[real_path] row[RemoveUnused.MARK_COL] = not row[RemoveUnused.MARK_COL] self.real_model.row_changed(real_path, row.iter) def mark_clicked(self, mark_button): for row_num in range(len(self.real_model)): path = (row_num, ) row = self.real_model[path] row[RemoveUnused.MARK_COL] = True def unmark_clicked(self, unmark_button): for row_num in range(len(self.real_model)): path = (row_num, ) row = self.real_model[path] row[RemoveUnused.MARK_COL] = False def invert_clicked(self, invert_button): for row_num in range(len(self.real_model)): path = (row_num, ) row = self.real_model[path] row[RemoveUnused.MARK_COL] = not row[RemoveUnused.MARK_COL] def double_click(self, obj, event): if event.type == Gdk.EventType._2BUTTON_PRESS and event.button == 1: (model, node) = self.selection.get_selected() if not node: return sort_path = self.sort_model.get_path(node) real_path = self.sort_model.convert_path_to_child_path(sort_path) row = self.real_model[real_path] the_type = row[RemoveUnused.OBJ_TYPE_COL] handle = row[RemoveUnused.OBJ_HANDLE_COL] self.call_editor(the_type, handle) def call_editor(self, the_type, handle): try: obj = self.tables[the_type]['get_func'](handle) editor_str = 'from gramps.gui.editors import %s as editor' % ( self.tables[the_type]['editor']) exec(editor_str, globals()) editor(self.dbstate, self.uistate, [], obj) except WindowActiveError: pass def get_image(self, column, cell, model, iter, user_data=None): the_type = model.get_value(iter, RemoveUnused.OBJ_TYPE_COL) the_icon = self.tables[the_type]['icon'] cell.set_property('icon-name', the_icon) def add_results(self, results): (the_type, handle, data) = results gramps_id = data[1] # if we have a function that will return to us some type # of text summary, then we should use it; otherwise we'll # use the generic field index provided in the tables above if self.tables[the_type]['get_text']: text = self.tables[the_type]['get_text'](the_type, handle, data) else: # grab the text field index we know about, and hope # it represents something useful to the user name_ix = self.tables[the_type]['name_ix'] text = data[name_ix] # insert a new row into the table self.real_model.append(row=[False, gramps_id, text, the_type, handle]) def get_event_text(self, the_type, handle, data): """ Come up with a short line of text that we can use as a summary to represent this event. """ # get the event: event = self.tables[the_type]['get_func'](handle) # first check to see if the event has a descriptive name text = event.get_description() # (this is rarely set for events) # if we don't have a description... if text == '': # ... then we merge together several fields # get the event type (marriage, birth, death, etc.) text = str(event.get_type()) # see if there is a date date = _dd.display(event.get_date_object()) if date != '': text += '; %s' % date # see if there is a place if event.get_place_handle(): text += '; %s' % _pd.display_event(self.db, event) return text def get_note_text(self, the_type, handle, data): """ We need just the first few words of a note as a summary. """ # get the note object note = self.tables[the_type]['get_func'](handle) # get the note text; this ignores (discards) formatting text = note.get() # convert whitespace to a single space text = " ".join(text.split()) # if the note is too long, truncate it if len(text) > 80: text = text[:80] + "..." return text
def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate self.title = _('Find database loop') ManagedWindow.__init__(self, uistate, [], self.__class__) self.dbstate = dbstate self.uistate = uistate self.db = dbstate.db top_dialog = Glade() top_dialog.connect_signals({ "destroy_passed_object" : self.close, "on_help_clicked" : self.on_help_clicked, "on_delete_event" : self.close, }) window = top_dialog.toplevel title = top_dialog.get_object("title") self.set_window(window, title, self.title) # start the progress indicator self.progress = ProgressMeter(self.title, _('Starting'), # parent-OK parent=self.window) self.progress.set_pass(_('Looking for possible loop for each person'), self.db.get_number_of_people()) self.model = Gtk.ListStore( GObject.TYPE_STRING, # 0==father id GObject.TYPE_STRING, # 1==father GObject.TYPE_STRING, # 2==son id GObject.TYPE_STRING, # 3==son GObject.TYPE_STRING) # 4==family gid self.treeview = top_dialog.get_object("treeview") self.treeview.set_model(self.model) col1 = Gtk.TreeViewColumn(_('Gramps ID'), Gtk.CellRendererText(), text=0) col2 = Gtk.TreeViewColumn(_('Ancestor'), Gtk.CellRendererText(), text=1) col3 = Gtk.TreeViewColumn(_('Gramps ID'), Gtk.CellRendererText(), text=2) col4 = Gtk.TreeViewColumn(_('Descendant'), Gtk.CellRendererText(), text=3) col5 = Gtk.TreeViewColumn(_('Family ID'), Gtk.CellRendererText(), text=4) col1.set_resizable(True) col2.set_resizable(True) col3.set_resizable(True) col4.set_resizable(True) col5.set_resizable(True) col1.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) col2.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) col3.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) col4.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) col5.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) col1.set_sort_column_id(0) col2.set_sort_column_id(1) col3.set_sort_column_id(2) col4.set_sort_column_id(3) col5.set_sort_column_id(4) self.treeview.append_column(col1) self.treeview.append_column(col2) self.treeview.append_column(col3) self.treeview.append_column(col4) self.treeview.append_column(col5) self.treeselection = self.treeview.get_selection() self.treeview.connect('row-activated', self.rowactivated_cb) self.curr_fam = None people = self.db.get_person_handles() count = 0 for person_handle in people: person = self.db.get_person_from_handle(person_handle) count += 1 self.current = person self.parent = None self.descendants(person_handle, set()) self.progress.set_header("%d/%d" % (count, len(people))) self.progress.step() # close the progress bar self.progress.close() self.show()
def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate tool.ActivePersonTool.__init__(self, dbstate, uistate, options_class, name) if self.fail: # bug #2709 -- fail if we have no active person return person_handle = uistate.get_active('Person') person = dbstate.db.get_person_from_handle(person_handle) self.name = person.get_primary_name().get_regular_name() self.title = _('Not related to "%s"') % self.name ManagedWindow.__init__(self, uistate, [], self.__class__) self.dbstate = dbstate self.uistate = uistate self.db = dbstate.db topDialog = Glade() topDialog.connect_signals({ "destroy_passed_object": self.close, "on_help_clicked": self.on_help_clicked, "on_delete_event": self.close, }) window = topDialog.toplevel title = topDialog.get_object("title") self.set_window(window, title, self.title) self.tagcombo = topDialog.get_object("tagcombo") tagmodel = Gtk.ListStore(str) self.tagcombo.set_model(tagmodel) self.tagcombo.set_entry_text_column(0) tagmodel.append((_('ToDo'), )) tagmodel.append((_('NotRelated'), )) self.tagcombo.set_sensitive(False) self.tagapply = topDialog.get_object("tagapply") self.tagapply.set_sensitive(False) self.tagapply.connect('clicked', self.applyTagClicked) # start the progress indicator self.progress = ProgressMeter(self.title, _('Starting'), parent=self.window) # setup the columns self.model = Gtk.TreeStore( GObject.TYPE_STRING, # 0==name GObject.TYPE_STRING, # 1==person gid GObject.TYPE_STRING, # 2==parents GObject.TYPE_STRING, # 3==tags GObject.TYPE_STRING) # 4==family gid (not shown to user) # note -- don't assign the model to the tree until it has been populated, # otherwise the screen updates are terribly slow while names are appended self.treeView = topDialog.get_object("treeview") col1 = Gtk.TreeViewColumn(_('Name'), Gtk.CellRendererText(), text=0) col2 = Gtk.TreeViewColumn(_('ID'), Gtk.CellRendererText(), text=1) col3 = Gtk.TreeViewColumn(_('Parents'), Gtk.CellRendererText(), text=2) col4 = Gtk.TreeViewColumn(_('Tags'), Gtk.CellRendererText(), text=3) col1.set_resizable(True) col2.set_resizable(True) col3.set_resizable(True) col4.set_resizable(True) col1.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) col2.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) col3.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) col4.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) col1.set_sort_column_id(0) # col2.set_sort_column_id(1) # col3.set_sort_column_id(2) col4.set_sort_column_id(3) self.treeView.append_column(col1) self.treeView.append_column(col2) self.treeView.append_column(col3) self.treeView.append_column(col4) self.treeSelection = self.treeView.get_selection() self.treeSelection.set_mode(Gtk.SelectionMode.MULTIPLE) self.treeSelection.set_select_function(self.selectIsAllowed, None) self.treeSelection.connect('changed', self.rowSelectionChanged) self.treeView.connect('row-activated', self.rowActivated) # initialize a few variables we're going to need self.numberOfPeopleInDatabase = self.db.get_number_of_people() self.numberOfRelatedPeople = 0 self.numberOfUnrelatedPeople = 0 # create the sets used to track related and unrelated people self.handlesOfPeopleToBeProcessed = set() self.handlesOfPeopleAlreadyProcessed = set() self.handlesOfPeopleNotRelated = set() # build a set of all people related to the selected person self.handlesOfPeopleToBeProcessed.add(person.get_handle()) self.findRelatedPeople() # now that we have our list of related people, find everyone # in the database who isn't on our list self.findUnrelatedPeople() # populate the treeview model with the names of unrelated people if self.numberOfUnrelatedPeople == 0: # feature request 2356: avoid genitive form title.set_text( _('Everyone in the database is related to %s') % self.name) else: self.populateModel() self.model.set_sort_column_id(0, Gtk.SortType.ASCENDING) self.treeView.set_model(self.model) # self.treeView.set_row_separator_func(self.iterIsSeparator, None) self.treeView.expand_all() # done searching through the database, so close the progress bar self.progress.close() self.show()
class ProgenOptions(ManagedWindow): """ Class for Pro-Gen files import optons""" def __init__(self, database, filename, user): """ Useful options for Pro-Gen import """ self.dbase = database self.fname = filename self.user = user self.uistate = user.uistate self.option = {} # default: Pro-Gen import failed self.fail = True # initial values text = "Pro-Gen Import" fname = os.path.basename(filename).split('\\')[-1] date = time.strftime('%Y-%m-%d', time.localtime()) # add import source title/confidence # citation page/confidence/privacy/attribute self.import_methods = {} dflt = config.get('preferences.default-source') if config.get('preferences.tag-on-import'): dflt_text = config.get('preferences.tag-on-import-format') else: dflt_text = '%s %s' % (text, date) self.imp_values = ImportSourceCitation \ (dflt, dflt_text, text, fname, date) # add default text / filename / current date self.default_methods = {} self.default_values = ImportTagTextDefault(text, fname) # add tagobjects text / filename / date self.tagobj_status = True self.tagobj_values, self.tagobj_methods = {}, {} self.tagtext_methods = {} self.tagfname_status, self.tagfname_methods = True, {} self.tagdate_status, self.tagdate_methods = True, {} for obj in libprogen.TAGOBJECTS: self.tagobj_values[obj] = ImportTagText(self.default_values) # add primary object values self.primobj_values, self.primobj_methods = {}, {} for obj in libprogen.PRIMOBJECTS: self.primobj_values[obj] = ImportValue(True) # add options values self.option_values, self.option_methods = {}, {} for obj in libprogen.OPTOBJECTS: if obj in ['person-ident', 'family-ident', \ 'surname-female', 'death-cause']: self.option_values[obj] = ImportValue(True) else: self.option_values[obj] = ImportValue(False) # prepare option dictionary self._collect() # display window if GUI active if self.uistate: ManagedWindow.__init__(self, self.uistate, [], self.__class__, modal=True) self._display() def __on_source_button_toggled(self, widget): """ compute the source button and toggle the 'Sensitive' attribute """ obj_source_state = widget.get_active() for obj in ['priv', 'title', 'attr']: imp_obj = self.glade.get_object('imp_source_%s' % obj) imp_obj.set_sensitive(obj_source_state) # Check if Source enabled and syncronizing Citation self.glade.get_object('imp_citation_btn').set_active(obj_source_state) self.glade.get_object('imp_citation_btn').set_sensitive( obj_source_state) def __on_citation_button_toggled(self, widget): """ compute the citation button and toggle the 'Sensitive' attribute """ # Check if Source enabled and syncronizing Citation obj_source_state = self.glade.get_object('imp_source_btn').get_active() obj_citation_state = widget.get_active() and obj_source_state for obj in ['priv', 'conf', 'page', 'attr']: imp_obj = self.glade.get_object('imp_citation_%s' % obj) imp_obj.set_sensitive(obj_citation_state) def __on_import_entry_keyrelease(self, widget, event, data=None): """ activated on all return's of an entry""" if event.keyval in [Gdk.KEY_Return]: obj_name = Gtk.Buildable.get_name(widget).split('_', 1)[1] if obj_name == 'citation_page': obj_next = self.glade.get_object('imp_citation_attr') obj_next.grab_focus() def __on_object_button_clicked(self, widget=None): """ compute all primary objects and toggle the 'Active' attribute """ self.tagobj_status = not self.tagobj_status for obj in libprogen.TAGOBJECTS: tag_obj = self.glade.get_object('tag_%s_obj' % obj) tag_obj.set_active(self.tagobj_status) def __on_object_button_toggled(self, widget): """ compute the primary object and toggle the 'Sensitive' attribute """ obj_state = widget.get_active() obj_name = Gtk.Buildable.get_name(widget) obj_name = obj_name.split('_', 1)[1].split('_', 1)[0] for obj in ['text', 'fname', 'date']: tag_obj = self.glade.get_object('tag_%s_%s' % (obj_name, obj)) tag_obj.set_sensitive(obj_state) def __on_text_button_clicked(self, widget=None): """ compute all primary objects and flush the 'text' field """ self.__on_tagtext_entry_resume() # Resume tag text def __on_tagtext_entry_keyrelease(self, widget, event, data=None): """ activated on all return's of an entry """ if event.keyval in [Gdk.KEY_Return]: obj_name = Gtk.Buildable.get_name(widget) obj_name = obj_name.split('_', 1)[1].split('_', 1)[0] obj_index = libprogen.TAGOBJECTS.index(obj_name) if obj_index < len(libprogen.TAGOBJECTS) - 1: obj_index = obj_index + 1 obj_next = self.glade.get_object('tag_%s_text' % \ libprogen.TAGOBJECTS[obj_index]) obj_next.grab_focus() def __on_tagtext_entry_resume(self): """ resume new tagtext from old + file & date variables""" for obj in libprogen.TAGOBJECTS: tag_obj = self.glade.get_object('tag_%s_text' % obj) if not tag_obj.get_sensitive(): continue obj_entry = self.tagobj_values[obj].get_dflttext() self.tagobj_values[obj].tag_text.set_entry(obj_entry) self.tagtext_methods[obj].update() def __on_fname_button_clicked(self, widget=None): """ compute all primary objects and toggle the 'file' attribute """ self.tagfname_status = not self.tagfname_status for obj in libprogen.TAGOBJECTS: tag_obj = self.glade.get_object('tag_%s_fname' % obj) if not tag_obj.get_sensitive(): continue self.tagfname_methods[obj].set_val(self.tagfname_status) tag_obj.set_active(self.tagfname_status) self.__on_tagtext_entry_resume() # Resume tag text def __on_fname_button_toggled(self, widget): """ compute the primary object and toggle the 'Sensitive' attribute """ self.__on_tagtext_entry_resume() # switch focus forward obj_name = Gtk.Buildable.get_name(widget) obj_name = obj_name.split('_', 1)[1].split('_', 1)[0] obj_index = libprogen.TAGOBJECTS.index(obj_name) if obj_index < len(libprogen.TAGOBJECTS) - 1: obj_index = obj_index + 1 obj_next = self.glade.get_object('tag_%s_fname' % \ libprogen.TAGOBJECTS[obj_index]) obj_next.grab_focus() def __on_date_button_clicked(self, widget=None): """ compute all primary objects and toggle the 'date' attribute """ self.tagdate_status = not self.tagdate_status for obj in libprogen.TAGOBJECTS: tag_obj = self.glade.get_object('tag_%s_date' % obj) if not tag_obj.get_sensitive(): continue self.tagdate_methods[obj].set_val(self.tagdate_status) tag_obj.set_active(self.tagdate_status) self.__on_tagtext_entry_resume() # Resume tag text def __on_date_button_toggled(self, widget): """ compute the primary object and toggle the 'Sensitive' attribute """ self.__on_tagtext_entry_resume() # switch focus forward obj_name = Gtk.Buildable.get_name(widget) obj_name = obj_name.split('_', 1)[1].split('_', 1)[0] obj_index = libprogen.TAGOBJECTS.index(obj_name) if obj_index < len(libprogen.TAGOBJECTS) - 1: obj_index = obj_index + 1 obj_next = self.glade.get_object('tag_%s_date' % \ libprogen.TAGOBJECTS[obj_index]) obj_next.grab_focus() def __on_primobj_button_toggled(self, widget): """ compute all primary objects and toggle the 'primobj' attribute """ obj_name = Gtk.Buildable.get_name(widget) obj_name = obj_name.split('_', 1)[1].split('_', 1)[0] for i, obj_i in enumerate(libprogen.PRIMOBJECTS): if obj_name == libprogen.PRIMOBJECTS[i]: prim_obj = self.glade.get_object('prim_%s_btn' % obj_i) if not prim_obj.get_active(): # Prim. object deactivated: # check all in list below and deactivate for obj_ii in libprogen.PRIMOBJECTS[(i + 1):]: sec_obj = self.glade.get_object('prim_%s_btn' % obj_ii) sec_obj.set_active(False) break else: # Prim. object activated: check all in list above # if one prim. object is deactive: # deactivate this prim. object too for obj_ii in libprogen.PRIMOBJECTS[:i]: sec_obj = self.glade.get_object('prim_%s_btn' % obj_ii) if not sec_obj.get_active(): prim_obj.set_active(False) break def __on_surname_button_toggled(self, widget): """ compute surname objects and """ obj_name = Gtk.Buildable.get_name(widget) obj_name = obj_name.split('_', 1)[1].split('_', 1)[0] obj_status = widget.get_active() if (obj_name == 'name-surmale') and (obj_status == True): sec_obj = self.glade.get_object('opt_surname-female_btn') sec_obj.set_active(False) if (obj_name == 'name-surfemale') and (obj_status == True): sec_obj = self.glade.get_object('opt_surname-male_btn') sec_obj.set_active(False) def __on_x_button_clicked(self, widget=None): """ cancel the import and close """ self.fail = True # Pro-Gen import canceled def __on_ok_button_clicked(self, widget=None): """ execute the import and close """ self._collect() self.close() self.fail = False # Pro-Gen import proceed def __on_cancel_button_clicked(self, widget=None): """ cancel the import and close """ self.close() self.fail = True # Pro-Gen import canceled def __on_help_button_clicked(self, widget=None): """ display the relevant portion of Gramps manual """ self.fail = True display_help(webpage=WIKI_HELP_PAGE, section=WIKI_HELP_SEC) def build_menu_names_(self, widget=None): """ The menu name """ return (_('Main window'), _("Import Pro-Gen")) def _display(self): """ organize Glade 'Import Pro-Gen' window """ # get the main window from glade self.glade = Glade('importprogen.glade') self.set_window(self.glade.toplevel, self.glade.get_object('title'), _('Import Pro-Gen')) # calculate all entries and update Glade window # Text for Source / Citation objects for obj in ('source_btn', 'citation_btn'): widget = self.glade.get_object('imp_%s' % obj) set_import = eval('self.imp_values.%s.set_value' % obj) get_import = eval('self.imp_values.%s.get_value' % obj) self.import_methods[obj] = MonitoredCheckbox(\ widget, widget, set_import, get_import, self.dbase.readonly) for obj in ('source_title', 'source_attr', 'citation_page', 'citation_attr'): widget = self.glade.get_object('imp_%s' % obj) set_import = eval('self.imp_values.%s.set_entry' % obj) get_import = eval('self.imp_values.%s.get_entry' % obj) self.import_methods[obj] = MonitoredEntry(\ widget, set_import, get_import, self.dbase.readonly) widget = self.glade.get_object('imp_citation_conf') self.import_methods['conf'] = MonitoredMenu( widget, self.imp_values.citation_conf.set_value, self.imp_values.citation_conf.get_value, [(_('Very Low'), Citation.CONF_VERY_LOW), (_('Low'), Citation.CONF_LOW), (_('Normal'), Citation.CONF_NORMAL), (_('High'), Citation.CONF_HIGH), (_('Very High'), Citation.CONF_VERY_HIGH)], self.dbase.readonly) widget = self.glade.get_object('imp_source_priv') get_import = eval('self.imp_values.source_priv') self.import_methods['source_priv'] = PrivacyButton(\ widget, get_import, self.dbase.readonly) widget = self.glade.get_object('imp_citation_priv') get_import = eval('self.imp_values.citation_priv') self.import_methods['citation_priv'] = PrivacyButton(\ widget, get_import, self.dbase.readonly) # Text (w. Defaults) for Tags for obj in ('text', 'fname'): widget = self.glade.get_object('tag_default_%s' % obj) set_import = eval('self.default_values.%s.set_entry' % obj) get_import = eval('self.default_values.%s.get_entry' % obj) self.default_methods[obj] = MonitoredEntry(\ widget, set_import, get_import, self.dbase.readonly) date = Today() datebase = DateBase() datebase.set_date_object(date) self.default_methods['date'] = MonitoredDate(\ self.glade.get_object('tag_default_date'), self.glade.get_object('tag_default_date_btn'), datebase.get_date_object(), self.uistate, [], self.dbase.readonly) for obj in libprogen.TAGOBJECTS: # populate object fields with values widget = self.glade.get_object('tag_%s_obj' % obj) self.tagobj_methods[obj] = MonitoredCheckbox( widget, widget, self.tagobj_values[obj].tag_obj.set_value, self.tagobj_values[obj].tag_obj.get_value) widget = self.glade.get_object('tag_%s_text' % obj) self.tagtext_methods[obj] = MonitoredEntry( widget, self.tagobj_values[obj].tag_text.set_entry, self.tagobj_values[obj].tag_text.get_entry) widget = self.glade.get_object('tag_%s_fname' % obj) self.tagfname_methods[obj] = MonitoredCheckbox( widget, widget, self.tagobj_values[obj].tag_fname.set_value, self.tagobj_values[obj].tag_fname.get_value) widget = self.glade.get_object('tag_%s_date' % obj) self.tagdate_methods[obj] = MonitoredCheckbox( widget, widget, self.tagobj_values[obj].tag_date.set_value, self.tagobj_values[obj].tag_date.get_value) # button's for primary objects for obj in libprogen.PRIMOBJECTS: # populate pirm. Object buttons with values widget = self.glade.get_object('prim_%s_btn' % obj) set_import = eval("self.primobj_values['%s'].set_value" % obj) get_import = eval("self.primobj_values['%s'].get_value" % obj) self.primobj_methods[obj] = MonitoredCheckbox(\ widget, widget, set_import, get_import, self.dbase.readonly) # button's for miscallaneous option's for obj in libprogen.OPTOBJECTS: # populate option buttons with values widget = self.glade.get_object('opt_%s_btn' % obj) set_import = eval("self.option_values['%s'].set_value" % obj) get_import = eval("self.option_values['%s'].get_value" % obj) self.option_methods[obj] = MonitoredCheckbox(\ widget, widget, set_import, get_import, self.dbase.readonly) # connect signals self.glade.connect_signals({ "on_source_button_toggled": self.__on_source_button_toggled, "on_citation_button_toggled": self.__on_citation_button_toggled, "on_import_entry_keyrelease": self.__on_import_entry_keyrelease, "on_tagtext_entry_keyrelease": self.__on_tagtext_entry_keyrelease, "on_object_button_clicked": self.__on_object_button_clicked, "on_object_button_toggled": self.__on_object_button_toggled, "on_text_button_clicked": self.__on_text_button_clicked, "on_fname_button_clicked": self.__on_fname_button_clicked, "on_fname_button_toggled": self.__on_fname_button_toggled, "on_date_button_clicked": self.__on_date_button_clicked, "on_date_button_toggled": self.__on_date_button_toggled, "on_primobj_button_toggled": self.__on_primobj_button_toggled, "on_surname_button_toggled": self.__on_surname_button_toggled, "on_x_button_clicked": self.__on_x_button_clicked, "on_help_button_clicked": self.__on_help_button_clicked, "on_cancel_button_clicked": self.__on_cancel_button_clicked, "on_ok_button_clicked": self.__on_ok_button_clicked }) # state of two objects trigged form configuration widget = self.glade.get_object('imp_source_btn') self.__on_source_button_toggled(widget) widget = self.glade.get_object('imp_citation_btn') self.__on_citation_button_toggled(widget) widget = self.glade.get_object('import_ok') widget.grab_focus() # creates a modal window and display immediatly! self.show() self.glade.toplevel.run() def _collect(self): """ collect all options """ self.option['imp_source'] = self.imp_values.source_btn.get_value() self.option['imp_source_priv'] = self.imp_values.source_priv.get_privacy() \ if self.option['imp_source'] else False if self.option['imp_source']: self.option[ 'imp_source_title'] = self.imp_values.source_title.get_entry() sourceattr = self.imp_values.source_attr.get_entry() # Expand if exists possible strftime directives if ('%Y' or '%m' or '%d' or '%H' or '%M' or '%S') in sourceattr: sourceattr = time.strftime(sourceattr) self.option['imp_source_attr'] = sourceattr else: self.option['imp_source_title'] = '' self.option['imp_source_attr'] = '' self.option['imp_citation'] = self.imp_values.citation_btn.get_value() self.option['imp_citation_conf'] = self.imp_values.citation_conf.get_value() \ if self.option['imp_citation'] else Citation.CONF_HIGH self.option['imp_citation_priv'] = self.imp_values.citation_priv.get_privacy() \ if self.option['imp_citation'] else False if self.option['imp_citation']: citationpage = self.imp_values.citation_page.get_entry() if ('%Y' or '%m' or '%d' or '%H' or '%M' or '%S') in citationpage: citationpage = time.strftime(citationpage) self.option['imp_citation_page'] = citationpage citationattr = self.imp_values.citation_attr.get_entry() if ('%Y' or '%m' or '%d' or '%H' or '%M' or '%S') in citationattr: citationattr = time.strftime(citationattr) self.option['imp_citation_attr'] = citationattr else: self.option['imp_citation_page'] = '' self.option['imp_citation_attr'] = '' for obj in libprogen.TAGOBJECTS: if self.tagobj_values[obj].tag_obj.get_value(): tagtext = self.tagobj_values[obj].tag_text.get_entry() if ('%Y' or '%m' or '%d' or '%H' or '%M' or '%S') in tagtext: tagtext = time.strftime(tagtext) self.option['tag_{}'.format(obj)] = tagtext else: self.option['tag_{}'.format(obj)] = '' for obj in libprogen.PRIMOBJECTS: self.option['prim_{}'.format(obj)] = \ self.primobj_values[obj].get_value() for obj in libprogen.OPTOBJECTS: self.option['opt_{}'.format(obj)] = \ self.option_values[obj].get_value() self.fail = False # Pro-Gen import proceed
def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate self.title = _('Find database loop') ManagedWindow.__init__(self, uistate, [], self.__class__) self.dbstate = dbstate self.uistate = uistate self.db = dbstate.db topDialog = Glade() topDialog.connect_signals({ "destroy_passed_object" : self.close, "on_help_clicked" : self.on_help_clicked, "on_delete_event" : self.close, }) window = topDialog.toplevel title = topDialog.get_object("title") self.set_window(window, title, self.title) # start the progress indicator self.progress = ProgressMeter(self.title,_('Starting'), parent=self.window) self.progress.set_pass(_('Looking for possible loop for each person'), self.db.get_number_of_people()) self.model = Gtk.ListStore( GObject.TYPE_STRING, # 0==father id GObject.TYPE_STRING, # 1==father GObject.TYPE_STRING, # 2==son id GObject.TYPE_STRING, # 3==son GObject.TYPE_STRING) # 4==family gid self.treeView = topDialog.get_object("treeview") self.treeView.set_model(self.model) col1 = Gtk.TreeViewColumn(_('Gramps ID'), Gtk.CellRendererText(), text=0) col2 = Gtk.TreeViewColumn(_('Ancestor'), Gtk.CellRendererText(), text=1) col3 = Gtk.TreeViewColumn(_('Gramps ID'), Gtk.CellRendererText(), text=2) col4 = Gtk.TreeViewColumn(_('Descendant'), Gtk.CellRendererText(), text=3) col5 = Gtk.TreeViewColumn(_('Family ID'), Gtk.CellRendererText(), text=4) col1.set_resizable(True) col2.set_resizable(True) col3.set_resizable(True) col4.set_resizable(True) col5.set_resizable(True) col1.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) col2.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) col3.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) col4.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) col5.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) col1.set_sort_column_id(0) col2.set_sort_column_id(1) col3.set_sort_column_id(2) col4.set_sort_column_id(3) col5.set_sort_column_id(4) self.treeView.append_column(col1) self.treeView.append_column(col2) self.treeView.append_column(col3) self.treeView.append_column(col4) self.treeView.append_column(col5) self.treeSelection = self.treeView.get_selection() self.treeView.connect('row-activated', self.rowactivated) people = self.db.get_person_handles() count = 0 for person_handle in people: person = self.db.get_person_from_handle(person_handle) count += 1 self.current = person self.parent = None self.descendants(person_handle, set()) self.progress.set_header("%d/%d" % (count, len(people))) self.progress.step() # close the progress bar self.progress.close() self.show()
class PatchNames(tool.BatchTool, ManagedWindow): titleid = 1 nickid = 2 pref1id = 3 compid = 4 def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate self.label = _('Name and title extraction tool') ManagedWindow.__init__(self, uistate, [], self.__class__) self.set_window(Gtk.Window(), Gtk.Label(), '') tool.BatchTool.__init__(self, dbstate, user, options_class, name) if self.fail: return winprefix = Gtk.Dialog(_("Default prefix and connector settings"), self.uistate.window, Gtk.DialogFlags.MODAL|Gtk.DialogFlags.DESTROY_WITH_PARENT, (_('_OK'), Gtk.ResponseType.ACCEPT)) winprefix.vbox.set_spacing(5) hboxpref = Gtk.Box() label = Gtk.Label(label=_('Prefixes to search for:')) hboxpref.pack_start(label, False, False, 5) self.prefixbox = Gtk.Entry() self.prefixbox.set_text(', '.join(PREFIX_LIST)) hboxpref.pack_start(self.prefixbox, True, True, 0) winprefix.vbox.pack_start(hboxpref, True, True, 0) hboxcon = Gtk.Box() label = Gtk.Label(label=_('Connectors splitting surnames:')) hboxcon.pack_start(label, False, False, 5) self.conbox = Gtk.Entry() self.conbox.set_text(', '.join(CONNECTOR_LIST)) hboxcon.pack_start(self.conbox, True, True, 0) winprefix.vbox.pack_start(hboxcon, True, True, 0) hboxconns = Gtk.Box() label = Gtk.Label(label=_('Connectors not splitting surnames:')) hboxconns.pack_start(label, False, False, 5) self.connsbox = Gtk.Entry() self.connsbox.set_text(', '.join(CONNECTOR_LIST_NONSPLIT)) hboxconns.pack_start(self.connsbox, True, True, 0) winprefix.vbox.pack_start(hboxconns, True, True, 0) winprefix.show_all() winprefix.resize(700, 100) response = winprefix.run() self.prefix_list = self.prefixbox.get_text().split(',') self.prefix_list = list(map(strip, self.prefix_list)) self.prefixbox = None self.connector_list = self.conbox.get_text().split(',') self.connector_list = list(map(strip, self.connector_list)) self.conbox = None self.connector_list_nonsplit = self.connsbox.get_text().split(',') self.connector_list_nonsplit = list(map(strip, self.connector_list_nonsplit)) self.connsbox = None # Find a prefix in the first_name self._fn_prefix_re = re.compile("(\S+)\s+(%s)\s*$" % '|'.join(self.prefix_list), re.IGNORECASE) # Find a prefix in the surname self._sn_prefix_re = re.compile("^\s*(%s)\s+(.+)" % '|'.join(self.prefix_list), re.IGNORECASE) # Find a connector in the surname self._sn_con_re = re.compile("^\s*(.+)\s+(%s)\s+(.+)" % '|'.join(self.connector_list), re.IGNORECASE) winprefix.destroy() self.cb = callback self.handle_to_action = {} self.progress = ProgressMeter( _('Extracting Information from Names'), '', parent=self.uistate.window) self.progress.set_pass(_('Analyzing names'), self.db.get_number_of_people()) for person in self.db.iter_people(): key = person.handle name = person.get_primary_name() first = name.get_first_name() sname = name.get_surname() old_prefix = [] old_surn = [] old_con = [] old_prim = [] old_orig = [] for surn in name.get_surname_list(): old_prefix.append(surn.get_prefix()) old_surn.append(surn.get_surname()) old_con.append(surn.get_connector()) old_prim.append(surn.get_primary()) old_orig.append(surn.get_origintype()) if name.get_title(): old_title = [name.get_title()] else: old_title = [] new_title = [] match = _title_re.match(first) while match: groups = match.groups() first = groups[1] new_title.append(groups[0]) match = _title_re.match(first) matchnick = _nick_re.match(first) if new_title: titleval = (" ".join(old_title+new_title), first) if key in self.handle_to_action: self.handle_to_action[key][self.titleid] = titleval else: self.handle_to_action[key] = {self.titleid: titleval} elif matchnick: # we check for nick, which changes given name like title groups = matchnick.groups() nickval = (groups[0], groups[1]) if key in self.handle_to_action: self.handle_to_action[key][self.nickid] = nickval else: self.handle_to_action[key] = {self.nickid: nickval} else: # Try to find the name prefix in the given name, also this # changes given name match = self._fn_prefix_re.match(first) if match: groups = match.groups() if old_prefix[0]: # Put the found prefix before the old prefix new_prefix = " ".join([groups[1], old_prefix[0]]) else: new_prefix = groups[1] pref1val = (groups[0], new_prefix, groups[1]) if key in self.handle_to_action: self.handle_to_action[key][self.pref1id] = pref1val else: self.handle_to_action[key] = {self.pref1id: pref1val} #check for Gedcom import of compound surnames if len(old_surn) == 1 and old_con[0] == '': prefixes = old_prefix[0].split(',') surnames = old_surn[0].split(',') if len(prefixes) > 1 and len(prefixes) == len(surnames): #assume a list of prefix and a list of surnames prefixes = list(map(strip, prefixes)) surnames = list(map(strip, surnames)) primaries = [False] * len(prefixes) primaries[0] = True origs = [] for ind in range(len(prefixes)): origs.append(NameOriginType()) origs[0] = old_orig[0] compoundval = (surnames, prefixes, ['']*len(prefixes), primaries, origs) if key in self.handle_to_action: self.handle_to_action[key][self.compid] = compoundval else: self.handle_to_action[key] = {self.compid: compoundval} #we cannot check compound surnames, so continue the loop continue # Next, try to split surname in compounds: prefix surname connector found = False new_prefix_list = [] new_surname_list = [] new_connector_list = [] new_prim_list = [] new_orig_list = [] ind = 0 cont = True for pref, surn, con, prim, orig in zip(old_prefix, old_surn, old_con, old_prim, old_orig): surnval = surn.split() if surnval == []: new_prefix_list.append(pref) new_surname_list.append('') new_connector_list.append(con) new_prim_list.append(prim) new_orig_list.append(orig) cont = False continue val = surnval.pop(0) while cont: new_prefix_list.append(pref) new_surname_list.append('') new_connector_list.append(con) new_prim_list.append(prim) new_orig_list.append(orig) while cont and (val.lower() in self.prefix_list): found = True if new_prefix_list[-1]: new_prefix_list[-1] += ' ' + val else: new_prefix_list[-1] = val try: val = surnval.pop(0) except IndexError: val = '' cont = False #after prefix we have a surname if cont: new_surname_list[-1] = val try: val = surnval.pop(0) except IndexError: val = '' cont = False #if value after surname indicates continue, then continue while cont and (val.lower() in self.connector_list_nonsplit): #add this val to the current surname new_surname_list[-1] += ' ' + val try: val = surnval.pop(0) except IndexError: val = '' cont = False # if previous is non-splitting connector, then add new val to # current surname if cont and (new_surname_list[-1].split()[-1].lower() in self.connector_list_nonsplit): new_surname_list[-1] += ' ' + val try: val = surnval.pop(0) except IndexError: val = '' cont = False #if next is a connector, add it to the surname if cont and val.lower() in self.connector_list: found = True if new_connector_list[-1]: new_connector_list[-1] = ' ' + val else: new_connector_list[-1] = val try: val = surnval.pop(0) except IndexError: val = '' cont = False #initialize for a next surname in case there are still #val if cont: found = True # we split surname pref='' con = '' prim = False orig = NameOriginType() ind += 1 if found: compoundval = (new_surname_list, new_prefix_list, new_connector_list, new_prim_list, new_orig_list) if key in self.handle_to_action: self.handle_to_action[key][self.compid] = compoundval else: self.handle_to_action[key] = {self.compid: compoundval} self.progress.step() if self.handle_to_action: self.display() else: self.progress.close() self.close() OkDialog(_('No modifications made'), _("No titles, nicknames or prefixes were found"), parent=self.uistate.window) def build_menu_names(self, obj): return (self.label, None) def toggled(self, cell, path_string): path = tuple(map(int, path_string.split(':'))) row = self.model[path] row[0] = not row[0] self.model.row_changed(path, row.iter) def display(self): self.top = Glade() window = self.top.toplevel self.top.connect_signals({ "destroy_passed_object" : self.close, "on_ok_clicked" : self.on_ok_clicked, "on_help_clicked" : self.on_help_clicked, "on_delete_event" : self.close, }) self.list = self.top.get_object("list") self.set_window(window, self.top.get_object('title'), self.label) self.model = Gtk.ListStore(GObject.TYPE_BOOLEAN, GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_STRING) r = Gtk.CellRendererToggle() r.connect('toggled', self.toggled) c = Gtk.TreeViewColumn(_('Select'), r, active=0) self.list.append_column(c) c = Gtk.TreeViewColumn(_('ID'), Gtk.CellRendererText(), text=1) self.list.append_column(c) c = Gtk.TreeViewColumn(_('Type'), Gtk.CellRendererText(), text=2) self.list.append_column(c) c = Gtk.TreeViewColumn(_('Value'), Gtk.CellRendererText(), text=3) self.list.append_column(c) c = Gtk.TreeViewColumn(_('Current Name'), Gtk.CellRendererText(), text=4) self.list.append_column(c) self.list.set_model(self.model) self.nick_hash = {} self.title_hash = {} self.prefix1_hash = {} self.compound_hash = {} self.progress.set_pass(_('Building display'), len(list(self.handle_to_action.keys()))) for key, data in self.handle_to_action.items(): p = self.db.get_person_from_handle(key) gid = p.get_gramps_id() if self.nickid in data: given, nick = data[self.nickid] handle = self.model.append() self.model.set_value(handle, 0, 1) self.model.set_value(handle, 1, gid) self.model.set_value(handle, 2, _('Nickname')) self.model.set_value(handle, 3, nick) self.model.set_value(handle, 4, p.get_primary_name().get_name()) self.nick_hash[key] = handle if self.titleid in data: title, given = data[self.titleid] handle = self.model.append() self.model.set_value(handle, 0, 1) self.model.set_value(handle, 1, gid) self.model.set_value(handle, 2, _('Person|Title')) self.model.set_value(handle, 3, title) self.model.set_value(handle, 4, p.get_primary_name().get_name()) self.title_hash[key] = handle if self.pref1id in data: given, prefixtotal, new_prefix = data[self.pref1id] handle = self.model.append() self.model.set_value(handle, 0, 1) self.model.set_value(handle, 1, gid) self.model.set_value(handle, 2, _('Prefix in given name')) self.model.set_value(handle, 3, prefixtotal) self.model.set_value(handle, 4, p.get_primary_name().get_name()) self.prefix1_hash[key] = handle if self.compid in data: surn_list, pref_list, con_list, prims, origs = data[self.compid] handle = self.model.append() self.model.set_value(handle, 0, 1) self.model.set_value(handle, 1, gid) self.model.set_value(handle, 2, _('Compound surname')) newval = '' for sur, pre, con in zip(surn_list, pref_list, con_list): if newval: newval += '-[' else: newval = '[' newval += pre + ',' + sur if con: newval += ',' + con + ']' else: newval += ']' self.model.set_value(handle, 3, newval) self.model.set_value(handle, 4, p.get_primary_name().get_name()) self.compound_hash[key] = handle self.progress.step() self.progress.close() self.show() def on_help_clicked(self, obj): """Display the relevant portion of GRAMPS manual""" display_help(webpage=WIKI_HELP_PAGE, section=WIKI_HELP_SEC) def on_ok_clicked(self, obj): with DbTxn(_("Extract information from names"), self.db, batch=True ) as trans: self.db.disable_signals() for key, data in self.handle_to_action.items(): p = self.db.get_person_from_handle(key) if self.nickid in data: modelhandle = self.nick_hash[key] val = self.model.get_value(modelhandle, 0) if val: given, nick = data[self.nickid] name = p.get_primary_name() name.set_first_name(given.strip()) name.set_nick_name(nick.strip()) if self.titleid in data: modelhandle = self.title_hash[key] val = self.model.get_value(modelhandle, 0) if val: title, given = data[self.titleid] name = p.get_primary_name() name.set_first_name(given.strip()) name.set_title(title.strip()) if self.pref1id in data: modelhandle = self.prefix1_hash[key] val = self.model.get_value(modelhandle, 0) if val: given, prefixtotal, prefix = data[self.pref1id] name = p.get_primary_name() name.set_first_name(given.strip()) oldpref = name.get_surname_list()[0].get_prefix().strip() if oldpref == '' or oldpref == prefix.strip(): name.get_surname_list()[0].set_prefix(prefix) else: name.get_surname_list()[0].set_prefix('%s %s' % (prefix, oldpref)) if self.compid in data: modelhandle = self.compound_hash[key] val = self.model.get_value(modelhandle, 0) if val: surns, prefs, cons, prims, origs = data[self.compid] name = p.get_primary_name() new_surn_list = [] for surn, pref, con, prim, orig in zip(surns, prefs, cons, prims, origs): new_surn_list.append(Surname()) new_surn_list[-1].set_surname(surn.strip()) new_surn_list[-1].set_prefix(pref.strip()) new_surn_list[-1].set_connector(con.strip()) new_surn_list[-1].set_primary(prim) new_surn_list[-1].set_origintype(orig) name.set_surname_list(new_surn_list) self.db.commit_person(p, trans) self.db.enable_signals() self.db.request_rebuild() self.close() self.cb()
class ChangeNames(tool.BatchTool, ManagedWindow): def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate self.label = _('Capitalization changes') self.cb = callback ManagedWindow.__init__(self,uistate,[],self.__class__) self.set_window(Gtk.Window(),Gtk.Label(),'') tool.BatchTool.__init__(self, dbstate, user, options_class, name) if self.fail: return self.progress = ProgressMeter(_('Checking Family Names'),'') self.progress.set_pass(_('Searching family names'), len(self.db.get_surname_list())) self.name_list = [] for name in self.db.get_surname_list(): name.strip() namesplitSP= name.split() lSP = len(namesplitSP) namesplitHY= name.split('-') lHY = len(namesplitHY) if lSP == lHY == 1: if name != name.capitalize(): # Single surname without hyphen(s) self.name_list.append(name) #if lSP == 1 and lHY > 1: #print "LSP==1", name, name.capitalize() #if name != name.capitalize(): # Single surname with hyphen(s) #self.name_list.append(name) if lSP>1 and lHY == 1: # more than one string in surname but no hyphen # check if first string is in prefix_list, if so test for cap in rest s1 = 0 if namesplitSP[0].lower() in prefix_list: s1 = 1 for x in range(len(namesplitSP)-s1): # check if any subsurname is not cap notcap = False if namesplitSP[s1+x] != namesplitSP[s1+x].capitalize(): notcap = True break if notcap: # Multiple surnames possibly after prefix self.name_list.append(name) if lHY > 1: # more than one string in surname but hyphen(s) exists # check if first string is in prefix_list, if so test for cap if namesplitSP[0].lower() in prefix_list: namesplitHY[0] = namesplitHY[0].replace(namesplitSP[0],'').strip() for x in range(len(namesplitHY)): # check if any subsurname is not cap notcap = False if namesplitHY[x] != namesplitHY[x].capitalize(): notcap = True break if notcap: # Multiple surnames possibly after frefix self.name_list.append(name) if uistate: self.progress.step() if self.name_list: self.display() else: self.progress.close() self.close() OkDialog(_('No modifications made'), _("No capitalization changes were detected."), parent=uistate.window) def name_cap(self, name): name.strip() namesplitSP = name.split() lSP = len(namesplitSP) lHY = len(name.split('-')) namesep = ' ' if lHY > 1: namesep = '-' namesplitSP = name.replace(namesep,' ').split() lSP= len(namesplitSP) if lSP == lHY == 1: #if name != name.capitalize(): # Single surname without space(s) or hyphen(s), normal case return name.capitalize() else: # more than one string in surname but no hyphen # check if first string is in prefix_list, if so CAP the rest # Names like (von) Kohl(-)Brandt result = "" s1 = 0 if namesplitSP[0].lower() in prefix_list: s1 = 1 result = namesplitSP[0].lower()+ ' ' for x in range(lSP-s1): # CAP all subsurnames result = result + namesplitSP[s1+x].capitalize() + namesep return result[:-1] def display(self): self.top = Glade() window = self.top.toplevel self.top.connect_signals({ "destroy_passed_object" : self.close, "on_ok_clicked" : self.on_ok_clicked, "on_help_clicked" : self.on_help_clicked, "on_delete_event" : self.close, }) self.list = self.top.get_object("list") self.set_window(window,self.top.get_object('title'),self.label) self.model = Gtk.ListStore(GObject.TYPE_BOOLEAN, GObject.TYPE_STRING, GObject.TYPE_STRING) r = Gtk.CellRendererToggle() r.connect('toggled',self.toggled) c = Gtk.TreeViewColumn(_('Select'),r,active=0) self.list.append_column(c) c = Gtk.TreeViewColumn(_('Original Name'), Gtk.CellRendererText(),text=1) self.list.append_column(c) c = Gtk.TreeViewColumn(_('Capitalization Change'), Gtk.CellRendererText(),text=2) self.list.append_column(c) self.list.set_model(self.model) self.iter_list = [] self.progress.set_pass(_('Building display'),len(self.name_list)) for name in self.name_list: handle = self.model.append() self.model.set_value(handle,0,True) self.model.set_value(handle,1, name) namecap = self.name_cap(name) self.model.set_value(handle,2, namecap) self.iter_list.append(handle) self.progress.step() self.progress.close() self.show() def toggled(self,cell,path_string): path = tuple(map(int, path_string.split(':'))) row = self.model[path] row[0] = not row[0] def build_menu_names(self, obj): return (self.label,None) def on_help_clicked(self, obj): """Display the relevant portion of GRAMPS manual""" display_help(WIKI_HELP_PAGE , WIKI_HELP_SEC) def on_ok_clicked(self, obj): with DbTxn(_("Capitalization changes"), self.db, batch=True ) as self.trans: self.db.disable_signals() changelist = set(self.model.get_value(node,1) for node in self.iter_list if self.model.get_value(node,0)) #with self.db.get_person_cursor(update=True, commit=True) as cursor: # for handle, data in cursor: for handle in self.db.get_person_handles(False): person = self.db.get_person_from_handle(handle) #person = Person(data) change = False for name in [person.get_primary_name()] + person.get_alternate_names(): sname = find_surname_name(handle, name.serialize()) if sname in changelist: change = True for surn in name.get_surname_list(): sname = self.name_cap(surn.get_surname()) surn.set_surname(sname) if change: #cursor.update(handle, person.serialize()) self.db.commit_person(person, transaction=self.trans) self.db.enable_signals() self.db.request_rebuild() # FIXME: this probably needs to be removed, and bookmarks # should always be rebuilt on a commit_person via signals # self.parent.bookmarks.redraw() self.close() self.cb()
class ChangeNames(tool.BatchTool, ManagedWindow): def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate self.label = _('Capitalization changes') self.cb = callback ManagedWindow.__init__(self, uistate, [], self.__class__) self.set_window(Gtk.Window(), Gtk.Label(), '') tool.BatchTool.__init__(self, dbstate, user, options_class, name) if self.fail: return self.progress = ProgressMeter( # parent-OK _('Checking Family Names'), '', parent=uistate.window) self.progress.set_pass(_('Searching family names'), len(self.db.get_surname_list())) self.name_list = [] for name in self.db.get_surname_list(): name.strip() namesplitSP = name.split() lSP = len(namesplitSP) namesplitHY = name.split('-') lHY = len(namesplitHY) if lSP == lHY == 1: if name != name.capitalize(): # Single surname without hyphen(s) self.name_list.append(name) #if lSP == 1 and lHY > 1: #print "LSP==1", name, name.capitalize() #if name != name.capitalize(): # Single surname with hyphen(s) #self.name_list.append(name) if lSP > 1 and lHY == 1: # more than one string in surname but no hyphen # check if first string is in prefix_list, if so test for cap in rest s1 = 0 if namesplitSP[0].lower() in prefix_list: s1 = 1 for x in range(len(namesplitSP) - s1): # check if any subsurname is not cap notcap = False if namesplitSP[s1 + x] != namesplitSP[s1 + x].capitalize(): notcap = True break if notcap: # Multiple surnames possibly after prefix self.name_list.append(name) if lHY > 1: # more than one string in surname but hyphen(s) exists # check if first string is in prefix_list, if so test for cap if namesplitSP[0].lower() in prefix_list: namesplitHY[0] = namesplitHY[0].replace( namesplitSP[0], '').strip() for x in range(len(namesplitHY)): # check if any subsurname is not cap notcap = False if namesplitHY[x] != namesplitHY[x].capitalize(): notcap = True break if notcap: # Multiple surnames possibly after frefix self.name_list.append(name) if uistate: self.progress.step() if self.name_list: self.display() else: self.progress.close() self.close() OkDialog( _('No modifications made'), # parent-OK _("No capitalization changes were detected."), parent=uistate.window) def name_cap(self, name): name.strip() namesplitSP = name.split() lSP = len(namesplitSP) lHY = len(name.split('-')) namesep = ' ' if lHY > 1: namesep = '-' namesplitSP = name.replace(namesep, ' ').split() lSP = len(namesplitSP) if lSP == lHY == 1: #if name != name.capitalize(): # Single surname without space(s) or hyphen(s), normal case return name.capitalize() else: # more than one string in surname but no hyphen # check if first string is in prefix_list, if so CAP the rest # Names like (von) Kohl(-)Brandt result = "" s1 = 0 if namesplitSP[0].lower() in prefix_list: s1 = 1 result = namesplitSP[0].lower() + ' ' for x in range(lSP - s1): # CAP all subsurnames result = result + namesplitSP[s1 + x].capitalize() + namesep return result[:-1] def display(self): self.top = Glade() window = self.top.toplevel self.top.connect_signals({ "destroy_passed_object": self.close, "on_ok_clicked": self.on_ok_clicked, "on_help_clicked": self.on_help_clicked, "on_delete_event": self.close, }) self.list = self.top.get_object("list") self.set_window(window, self.top.get_object('title'), self.label) self.model = Gtk.ListStore(GObject.TYPE_BOOLEAN, GObject.TYPE_STRING, GObject.TYPE_STRING) r = Gtk.CellRendererToggle() r.connect('toggled', self.toggled) c = Gtk.TreeViewColumn(_('Select'), r, active=0) self.list.append_column(c) c = Gtk.TreeViewColumn(_('Original Name'), Gtk.CellRendererText(), text=1) self.list.append_column(c) c = Gtk.TreeViewColumn(_('Capitalization Change'), Gtk.CellRendererText(), text=2) self.list.append_column(c) self.list.set_model(self.model) self.iter_list = [] self.progress.set_pass(_('Building display'), len(self.name_list)) for name in self.name_list: handle = self.model.append() self.model.set_value(handle, 0, True) self.model.set_value(handle, 1, name) namecap = self.name_cap(name) self.model.set_value(handle, 2, namecap) self.iter_list.append(handle) self.progress.step() self.progress.close() self.show() def toggled(self, cell, path_string): path = tuple(map(int, path_string.split(':'))) row = self.model[path] row[0] = not row[0] def build_menu_names(self, obj): return (self.label, None) def on_help_clicked(self, obj): """Display the relevant portion of GRAMPS manual""" display_help(WIKI_HELP_PAGE, WIKI_HELP_SEC) def on_ok_clicked(self, obj): with DbTxn(_("Capitalization changes"), self.db, batch=True) as self.trans: self.db.disable_signals() changelist = set( self.model.get_value(node, 1) for node in self.iter_list if self.model.get_value(node, 0)) #with self.db.get_person_cursor(update=True, commit=True) as cursor: # for handle, data in cursor: for handle in self.db.get_person_handles(False): person = self.db.get_person_from_handle(handle) #person = Person(data) change = False for name in [person.get_primary_name() ] + person.get_alternate_names(): sname = find_surname_name(handle, name.serialize()) if sname in changelist: change = True for surn in name.get_surname_list(): sname = self.name_cap(surn.get_surname()) surn.set_surname(sname) if change: #cursor.update(handle, person.serialize()) self.db.commit_person(person, self.trans) self.db.enable_signals() self.db.request_rebuild() # FIXME: this probably needs to be removed, and bookmarks # should always be rebuilt on a commit_person via signals # self.parent.bookmarks.redraw() self.close() self.cb()