class SaveDialog(object): def __init__(self, msg1, msg2, task1, task2, parent=None): self.xml = Glade(toplevel='savedialog') self.top = self.xml.toplevel self.top.set_icon(ICON) self.top.set_title("%s - Gramps" % msg1) self.dontask = self.xml.get_object('dontask') self.task1 = task1 self.task2 = task2 label1 = self.xml.get_object('sd_label1') label1.set_text('<span weight="bold" size="larger">%s</span>' % msg1) label1.set_use_markup(True) label2 = self.xml.get_object('sd_label2') label2.set_text(msg2) label2.set_use_markup(True) if parent: self.top.set_transient_for(parent) self.top.show() response = self.top.run() if response == Gtk.ResponseType.NO: self.task1() elif response == Gtk.ResponseType.YES: self.task2() config.set('interface.dont-ask', self.dontask.get_active()) self.top.destroy()
class InfoDialog(object): """ Non modal dialog to show selectable info in a scrolled window """ def __init__(self, msg1, infotext, parent=None, monospaced=False): self.xml = Glade(toplevel='infodialog') self.top = self.xml.toplevel self.top.set_icon(ICON) self.top.set_title("%s - Gramps" % msg1) label = self.xml.get_object('toplabel') label.set_text('<span weight="bold" size="larger">%s</span>' % msg1) label.set_use_markup(True) infoview = self.xml.get_object('infoview') infobuffer = Gtk.TextBuffer() infobuffer.set_text(infotext) if monospaced: startiter, enditer = infobuffer.get_bounds() tag = infobuffer.create_tag(family="Monospace") infobuffer.apply_tag(tag, startiter, enditer) infoview.set_buffer(infobuffer) if parent: self.top.set_transient_for(parent) self.top.connect('response', self.destroy) self.top.show() def destroy(self, dialog, response_id): #no matter how it finishes, destroy dialog dialog.destroy()
class MessageHideDialog(object): def __init__(self, title, message, key, parent=None): self.xml = Glade(toplevel='hidedialog') self.top = self.xml.toplevel self.top.set_icon(ICON) self.top.set_title("%s - Gramps" % title) dont_show = self.xml.get_object('dont_show') dont_show.set_active(config.get(key)) title_label = self.xml.get_object('title') title_label.set_text( '<span size="larger" weight="bold">%s</span>' % title) title_label.set_use_markup(True) self.xml.get_object('message').set_text(message) dont_show.connect('toggled', self.update_checkbox, key) self.top.run() self.top.destroy() def update_checkbox(self, obj, constant): config.set(constant, obj.get_active()) config.save()
class QuestionDialog2(object): def __init__(self, msg1, msg2, label_msg1, label_msg2, parent=None): self.xml = Glade(toplevel='questiondialog') self.top = self.xml.toplevel self.top.set_icon(ICON) self.top.set_title("%s - Gramps" % msg1) label1 = self.xml.get_object('qd_label1') label1.set_text('<span weight="bold" size="larger">%s</span>' % msg1) label1.set_use_markup(True) label2 = self.xml.get_object('qd_label2') # see https://github.com/emesene/emesene/issues/723 label2.connect('activate-link', on_activate_link) label2.set_text(msg2) label2.set_use_markup(True) self.xml.get_object('okbutton').set_label(label_msg1) self.xml.get_object('okbutton').set_use_underline(True) self.xml.get_object('no').set_label(label_msg2) self.xml.get_object('no').set_use_underline(True) if parent: self.top.set_transient_for(parent) self.top.show() def run(self): response = self.top.run() self.top.destroy() return (response == Gtk.ResponseType.ACCEPT)
class OptionDialog(object): def __init__(self, msg1, msg2, btnmsg1, task1, btnmsg2, task2, parent=None): self.xml = Glade(toplevel='optiondialog') self.top = self.xml.toplevel self.top.set_icon(ICON) self.top.set_title("%s - Gramps" % msg1) label1 = self.xml.get_object('od_label1') label1.set_text('<span weight="bold" size="larger">%s</span>' % msg1) label1.set_use_markup(True) label2 = self.xml.get_object('od_label2') label2.set_text(msg2) label2.set_use_markup(True) self.xml.get_object('option1').set_label(btnmsg1) self.xml.get_object('option2').set_label(btnmsg2) if parent: self.top.set_transient_for(parent) self.top.show() self.response = self.top.run() if self.response == Gtk.ResponseType.NO: if task1: task1() else: if task2: task2() self.top.destroy() def get_response(self): return self.response
class QuestionDialog(object): def __init__(self, msg1, msg2, label, task, parent=None): self.xml = Glade(toplevel='questiondialog') self.top = self.xml.toplevel self.top.set_icon(ICON) self.top.set_title("%s - Gramps" % msg1) label1 = self.xml.get_object('qd_label1') label1.set_text('<span weight="bold" size="larger">%s</span>' % msg1) label1.set_use_markup(True) label2 = self.xml.get_object('qd_label2') label2.set_text(msg2) label2.set_use_markup(True) self.xml.get_object('okbutton').set_label(label) if parent: self.top.set_transient_for(parent) self.top.show() response = self.top.run() self.top.destroy() if response == Gtk.ResponseType.ACCEPT: task()
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)
class MissingMediaDialog: def __init__(self, msg1, msg2, task1, task2, task3, parent=None): self.xml = Glade(toplevel='missmediadialog') self.top = self.xml.toplevel self.top.set_icon(ICON) self.top.set_title("%s - Gramps" % msg1) self.task1 = task1 self.task2 = task2 self.task3 = task3 label1 = self.xml.get_object('label4') label1.set_text('<span weight="bold" size="larger">%s</span>' % msg1) label1.set_use_markup(True) label2 = self.xml.get_object('label3') label2.set_text(msg2) label2.set_use_markup(True) check_button = self.xml.get_object('use_always') if parent: self.top.set_transient_for(parent) parent_modal = parent.get_modal() if parent_modal: parent.set_modal(False) self.top.show() self.top.connect('delete_event', self.warn) response = Gtk.ResponseType.DELETE_EVENT # Need some magic here, because an attempt to close the dialog # with the X button not only emits the 'delete_event' signal # but also exits with the RESPONSE_DELETE_EVENT while response == Gtk.ResponseType.DELETE_EVENT: response = self.top.run() if response == 1: self.task1() elif response == 2: self.task2() elif response == 3: self.task3() if check_button.get_active(): self.default_action = response else: self.default_action = 0 self.top.destroy() if parent and parent_modal: parent.set_modal(True) def warn(self, obj, obj2): WarningDialog( _("Attempt to force closing the dialog"), _("Please do not force closing this important dialog.\n" "Instead select one of the available options"), parent=self.top) return True
def birth_editor(self, widget, data=None): """ Experimental call of the birth editor (see rather 'birth.py') """ glade_file = os.path.join(USER_PLUGINS, "SourceIndex", "birth.glade") if gramps.gen.constfunc.lin(): import locale locale.setlocale(locale.LC_ALL, '') # This is needed to make gtk.Builder work by specifying the # translations directory locale.bindtextdomain("addon", self.base + "/locale") self.glade = Gtk.Builder() self.glade.set_translation_domain("addon") self.glade.add_from_file(glade_file) from gi.repository import GObject GObject.GObject.__init__(self.glade) b = self.glade.get_object('edit_birth') self.set_window(b, self.glade.get_object('title'), self.label) #self.wit_button = self.glade.get_object('add_wit') self.ok_button = self.glade.get_object('ok') self.quit_button = self.glade.get_object('cancel') else: # Glade class from gui/glade.py and gui/managedwindow.py top = Glade(glade_file) b = top.toplevel self.set_window(b, title=None, text=glade_file) #self.wit_button = top.get_object('add_wit') self.ok_button = top.get_object('ok') self.quit_button = top.get_object('cancel') #self.wit_button.connect('clicked', GtkHandlers.on_witness_clicked) self.ok_button.connect('clicked', self.close) self.quit_button.connect('clicked', self.close) #add_item() #close_item() #close_track() #b.connect('delete-event', GladeHandlers.on_quit_clicked) #b.hide() b.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): # 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, "on_delete_event": self.close, }) # fetch the popup menu self.menu = topDialog.get_object("popup_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')) 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 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 marriage_editor(self, widget, data=None): """ Experimental call of the marriage editor (see rather 'marriage.py') """ glade_file = os.path.join(USER_PLUGINS, "SourceIndex", "marriage.glade") if gramps.gen.constfunc.lin(): import locale locale.setlocale(locale.LC_ALL, '') # This is needed to make gtk.Builder work by specifying the # translations directory locale.bindtextdomain("addon", self.base + "/locale") self.glade = Gtk.Builder() self.glade.set_translation_domain("addon") self.glade.add_from_file(glade_file) from gi.repository import GObject GObject.GObject.__init__(self.glade) m = self.glade.get_object('edit_marriage') self.set_window(m, self.glade.get_object('title'), self.label) #self.wit_button = self.glade.get_object('add_wit') self.ok_button = self.glade.get_object('ok') self.quit_button = self.glade.get_object('cancel') else: # Glade class from gui/glade.py and gui/managedwindow.py top = Glade(glade_file) m = top.toplevel self.set_window(m, title=None, text=glade_file) #self.wit_button = top.get_object('add_wit') self.ok_button = top.get_object('ok') self.quit_button = top.get_object('cancel') #self.wit_button.connect('clicked', GtkHandlers.on_witness_clicked) self.ok_button.connect('clicked', self.close) self.quit_button.connect('clicked', self.close) #m.hide() m.show()
class OptionDialog: def __init__(self, msg1, msg2, btnmsg1, task1, btnmsg2, task2, parent=None): self.xml = Glade(toplevel='optiondialog') self.top = self.xml.toplevel self.top.set_icon(ICON) self.top.set_title("%s - Gramps" % msg1) label1 = self.xml.get_object('od_label1') label1.set_text('<span weight="bold" size="larger">%s</span>' % msg1) label1.set_use_markup(True) label2 = self.xml.get_object('od_label2') label2.set_text(msg2) label2.set_use_markup(True) self.xml.get_object('option1').set_label(btnmsg1) self.xml.get_object('option2').set_label(btnmsg2) if parent: self.top.set_transient_for(parent) parent_modal = parent.get_modal() if parent_modal: parent.set_modal(False) self.top.show() self.response = self.top.run() if self.response == Gtk.ResponseType.NO: if task1: task1() else: if task2: task2() self.top.destroy() if parent and parent_modal: parent.set_modal(True) def get_response(self): return self.response
def census_editor(self, widget, data=None): """ Experimental call of the census editor (see rather 'census.py') """ glade_file = os.path.join(USER_PLUGINS, "SourceIndex", "census.glade") if gramps.gen.constfunc.lin(): import locale locale.setlocale(locale.LC_ALL, '') # This is needed to make gtk.Builder work by specifying the # translations directory locale.bindtextdomain("addon", self.base + "/locale") self.glade = Gtk.Builder() self.glade.set_translation_domain("addon") self.glade.add_from_file(glade_file) from gi.repository import GObject GObject.GObject.__init__(self.glade) c = self.glade.get_object('edit_census') self.set_window(c, self.glade.get_object('title'), self.label) self.ok_button = self.glade.get_object('ok') self.quit_button = self.glade.get_object('cancel') else: # Glade class from gui/glade.py and gui/managedwindow.py top = Glade(glade_file) c = top.toplevel self.set_window(c, title=None, text=glade_file) self.ok_button = top.get_object('ok') self.quit_button = top.get_object('cancel') self.ok_button.connect('clicked', self.close) self.quit_button.connect('clicked', self.close) #c.hide() c.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 __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", 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 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()
class QuestionDialog2: def __init__(self, msg1, msg2, label_msg1, label_msg2, parent=None): self.xml = Glade(toplevel='questiondialog') self.top = self.xml.toplevel self.top.set_icon(ICON) self.top.set_title("%s - Gramps" % msg1) label1 = self.xml.get_object('qd_label1') label1.set_text('<span weight="bold" size="larger">%s</span>' % msg1) label1.set_use_markup(True) label2 = self.xml.get_object('qd_label2') # see https://github.com/emesene/emesene/issues/723 label2.connect('activate-link', on_activate_link) label2.set_text(msg2) label2.set_use_markup(True) self.xml.get_object('okbutton').set_label(label_msg1) self.xml.get_object('okbutton').set_use_underline(True) self.xml.get_object('no').set_label(label_msg2) self.xml.get_object('no').set_use_underline(True) self.parent = parent if parent: self.top.set_transient_for(parent) self.parent_modal = parent.get_modal() if self.parent_modal: parent.set_modal(False) self.top.show() def run(self): response = self.top.run() self.top.destroy() if self.parent and self.parent_modal: self.parent.set_modal(True) return (response == Gtk.ResponseType.ACCEPT)
class MessageHideDialog(object): def __init__(self, title, message, key, parent=None): self.xml = Glade(toplevel='hidedialog') self.top = self.xml.toplevel self.top.set_icon(ICON) self.top.set_title("%s - Gramps" % title) dont_show = self.xml.get_object('dont_show') dont_show.set_active(config.get(key)) title_label = self.xml.get_object('title') title_label.set_text('<span size="larger" weight="bold">%s</span>' % title) title_label.set_use_markup(True) self.xml.get_object('message').set_text(message) dont_show.connect('toggled', self.update_checkbox, key) self.top.run() self.top.destroy() def update_checkbox(self, obj, constant): config.set(constant, obj.get_active()) config.save()
def __init__(self, database): self.db = database self.url = None self.connector = None top = Glade("phpgedview.glade") self.url_entry = top.get_object('url_entry') self.version_label = top.get_object('version_label') self.version_label.set_text("") self.file_combo = top.get_object('file_combo') self.file_combo.hide() self.username_entry = top.get_object('username_entry') self.username_entry.hide() self.password_entry = top.get_object('password_entry') self.password_entry.hide() self.ok_button = top.get_object('ok_button') self.ok_button.connect("activate", self.on_next_pressed_cb) self.ok_button.connect("button_release_event", self.on_next_pressed_cb) self.progressbar = top.get_object('progressbar') self.dialog = top.toplevel self.dialog.show()
def __init__(self, database): self.db = database self.url = None self.connector = None top = Glade("phpgedview.glade") self.url_entry = top.get_object('url_entry') self.version_label = top.get_object('version_label') self.version_label.set_text("") self.file_combo = top.get_object('file_combo') self.file_combo.hide() self.username_entry = top.get_object('username_entry') self.username_entry.hide() self.password_entry = top.get_object('password_entry') self.password_entry.hide() self.ok_button = top.get_object('ok_button') self.ok_button.connect("activate", self.on_next_pressed_cb) self.ok_button.connect("button_release_event", self.on_next_pressed_cb) self.progressbar = top.get_object('progressbar') self.dialog = top.toplevel self.dialog.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 RelCalc(tool.Tool, ManagedWindow): def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate """ Relationship calculator class. """ tool.Tool.__init__(self, dbstate, options_class, name) ManagedWindow.__init__(self,uistate,[],self.__class__) #set the columns to see for data in BasePersonView.CONFIGSETTINGS: if data[0] == 'columns.rank': colord = data[1] elif data[0] == 'columns.visible': colvis = data[1] elif data[0] == 'columns.size': colsize = data[1] self.colord = [] for col, size in zip(colord, colsize): if col in colvis: self.colord.append((1, col, size)) else: self.colord.append((0, col, size)) self.dbstate = dbstate self.relationship = get_relationship_calculator(glocale) self.relationship.connect_db_signals(dbstate) self.glade = Glade() self.person = self.db.get_person_from_handle( uistate.get_active('Person')) name = '' if self.person: name = name_displayer.display(self.person) self.title = _('Relationship calculator: %(person_name)s' ) % {'person_name' : name} window = self.glade.toplevel self.titlelabel = self.glade.get_object('title') self.set_window(window, self.titlelabel, _('Relationship to %(person_name)s' ) % {'person_name' : name}, self.title) self.setup_configs('interface.relcalc', 600, 400) self.tree = self.glade.get_object("peopleList") self.text = self.glade.get_object("text1") self.textbuffer = Gtk.TextBuffer() self.text.set_buffer(self.textbuffer) self.model = PersonTreeModel(self.db, uistate) self.tree.set_model(self.model) self.tree.connect('key-press-event', self._key_press) self.selection = self.tree.get_selection() self.selection.set_mode(Gtk.SelectionMode.SINGLE) #keep reference of column so garbage collection works self.columns = [] for pair in self.colord: if not pair[0]: continue name = column_names[pair[1]] column = Gtk.TreeViewColumn(name, Gtk.CellRendererText(), markup=pair[1]) column.set_resizable(True) column.set_min_width(60) column.set_sizing(Gtk.TreeViewColumnSizing.GROW_ONLY) self.tree.append_column(column) #keep reference of column so garbage collection works self.columns.append(column) self.sel = self.tree.get_selection() self.changedkey = self.sel.connect('changed',self.on_apply_clicked) self.closebtn = self.glade.get_object("button5") self.closebtn.connect('clicked', self.close) if not self.person: self.window.hide() ErrorDialog(_('Active person has not been set'), _('You must select an active person for this ' 'tool to work properly.'), parent=uistate.window) self.close() return self.show() def close(self, *obj): """ Close relcalc tool. Remove non-gtk connections so garbage collection can do its magic. """ self.relationship.disconnect_db_signals(self.dbstate) self.sel.disconnect(self.changedkey) ManagedWindow.close(self, *obj) def build_menu_names(self, obj): return (_("Relationship Calculator tool"),None) def on_apply_clicked(self, obj): model, iter_ = self.tree.get_selection().get_selected() if not iter_: return other_person = None handle = model.get_handle_from_iter(iter_) if handle: other_person = self.db.get_person_from_handle(handle) if other_person is None: self.textbuffer.set_text("") return #now determine the relation, and print it out rel_strings, common_an = self.relationship.get_all_relationships( self.db, self.person, other_person) p1 = name_displayer.display(self.person) p2 = name_displayer.display(other_person) text = [] if other_person is None: pass elif self.person.handle == other_person.handle: rstr = _("%(person)s and %(active_person)s are the same person.") % { 'person': p1, 'active_person': p2 } text.append((rstr, "")) elif len(rel_strings) == 0: rstr = _("%(person)s and %(active_person)s are not related.") % { 'person': p2, 'active_person': p1 } text.append((rstr, "")) for rel_string, common in zip(rel_strings, common_an): rstr = _("%(person)s is the %(relationship)s of %(active_person)s." ) % {'person': p2, 'relationship': rel_string, 'active_person': p1 } length = len(common) if length == 1: person = self.db.get_person_from_handle(common[0]) if common[0] in [other_person.handle, self.person.handle]: commontext = '' else : name = name_displayer.display(person) commontext = " " + _("Their common ancestor is %s.") % name elif length == 2: p1c = self.db.get_person_from_handle(common[0]) p2c = self.db.get_person_from_handle(common[1]) p1str = name_displayer.display(p1c) p2str = name_displayer.display(p2c) commontext = " " + _("Their common ancestors are %(ancestor1)s and %(ancestor2)s.") % { 'ancestor1': p1str, 'ancestor2': p2str } elif length > 2: index = 0 commontext = " " + _("Their common ancestors are: ") for person_handle in common: person = self.db.get_person_from_handle(person_handle) if index: # TODO for Arabic, should the next comma be translated? commontext += ", " commontext += name_displayer.display(person) index += 1 commontext += "." else: commontext = "" text.append((rstr, commontext)) textval = "" for val in text: textval += "%s %s\n" % (val[0], val[1]) self.textbuffer.set_text(textval) def _key_press(self, obj, event): if event.keyval in (Gdk.KEY_Return, Gdk.KEY_KP_Enter): store, paths = self.selection.get_selected_rows() if paths and len(paths[0]) == 1 : if self.tree.row_expanded(paths[0]): self.tree.collapse_row(paths[0]) else: self.tree.expand_row(paths[0], 0) return True return False
class MarriageIndex(tool.Tool, ManagedWindow): def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate self.label = _('Sources Index') self.base = os.path.dirname(__file__) ManagedWindow.__init__(self, uistate, [], self.__class__) self.set_window(Gtk.Window(), Gtk.Label(), '') tool.Tool.__init__(self, dbstate, options_class, name) glade_file = os.path.join(USER_PLUGINS, "SourceIndex", "marriage.glade") if gramps.gen.constfunc.lin(): import locale locale.setlocale(locale.LC_ALL, '') # This is needed to make gtk.Builder work by specifying the # translations directory locale.bindtextdomain("addon", self.base + "/locale") self.glade = Gtk.Builder() self.glade.set_translation_domain("addon") self.glade.add_from_file(glade_file) from gi.repository import GObject GObject.GObject.__init__(self.glade) window = self.glade.get_object('edit_marriage') #self.glade.connect_signals({ #}) self.set_window(window, self.glade.get_object('title'), self.label) #self.wit_button = self.glade.get_object('add_wit') self.ok_button = self.glade.get_object('ok') self.quit_button = self.glade.get_object('cancel') else: # Glade class from gui/glade.py and gui/managedwindow.py self.top = Glade() window = self.top.toplevel self.set_window(window, None, glade_file) #self.wit_button = self.top.get_object('add_wit') self.ok_button = self.top.get_object('ok') self.quit_button = self.top.get_object('cancel') #self.wit_button.connect('clicked', GtkHandlers.on_witness_clicked) self.ok_button.connect('clicked', self.close) self.quit_button.connect('clicked', self.close) self.window.show() # tests filename = os.path.join(USER_PLUGINS, 'SourceIndex', 'test_marriage.xml') self.write_xml(filename, 'M0001', 'DATE') self.parse_xml(filename) def __getitem__(self, key): return self.glade.get_widget(key) def _setup_fields(self): r''' Gramps XML storage means ability to also import/manage alone records /!\ some attributes are translated keys see data_item keys and eventref types of attribute ''' #/database/repositories/repository/rname/text() self.rinfo = MonitoredEntry(self.top.get_object("rinfo"), self.obj.set_rinfo, self.obj.get_rinfo, self.db.readonly) # date of transcription/search self.rdate = MonitoredEntry(self.top.get_object("rdate"), self.obj.set_rdate, self.obj.get_rdate, self.db.readonly) #/database/repositories/repository/@handle self.rid = MonitoredEntry(self.top.get_object("rid"), self.obj.set_rid, self.obj.get_rid, self.db.readonly) #/database/sources/source/stitle/text() self.aname = MonitoredEntry(self.top.get_object("aname"), self.obj.set_aname, self.obj.get_aname, self.db.readonly) #/database/sources/source/@handle self.aid = MonitoredEntry(self.top.get_object("aid"), self.obj.set_aid, self.obj.get_aid, self.db.readonly) #/database/citations/citation/@handle self.aref = MonitoredEntry(self.top.get_object("aref"), self.obj.set_aref, self.obj.get_aref, self.db.readonly) #/database/citations/citation/page # hardcoded /database/citations/citation/confidence self.avol = MonitoredEntry(self.top.get_object("avol"), self.obj.set_avol, self.obj.get_avol, self.db.readonly) #/database/people/person/gender self.gen = MonitoredEntry(self.top.get_object("gen"), self.obj.set_gen, self.obj.get_gen, self.db.readonly) #/database/people/person/childof/@hlink #/database/people/person/name/surname/surname/text() self.pname = MonitoredEntry(self.top.get_object("pname"), self.obj.set_pname, self.obj.get_pname, self.db.readonly) #/database/people/person/name/first/text() self.pfname = MonitoredEntry(self.top.get_object("pfname"), self.obj.set_pfname, self.obj.get_pfname, self.db.readonly) #/database/people/person/eventref/@hlink #/database/events/event/dateval/@val self.pbdate = MonitoredEntry(self.top.get_object("pbdate"), self.obj.set_pbdate, self.obj.get_pbdate, self.db.readonly) #/database/people/person/eventref/@hlink #/database/events/event/place/@hlink #/database/places/placeobj/ptitle/text() self.pblace = MonitoredEntry(self.top.get_object("pblace"), self.obj.set_pblace, self.obj.get_pblace, self.db.readonly) #/database/people/person/eventref/@hlink #/database/events/event/dateval/@val self.pdate = MonitoredEntry(self.top.get_object("pdate"), self.obj.set_pdate, self.obj.get_pdate, self.db.readonly) #/database/people/person/eventref/@hlink #/database/events/event/place/@hlink #/database/places/placeobj/ptitle/text() self.pplace = MonitoredEntry(self.top.get_object("pplace"), self.obj.set_pplace, self.obj.get_pplace, self.db.readonly) #/database/people/person/eventref/noteref/@hlink #/database/notes/note/text/text() self.pnote = MonitoredEntry(self.top.get_object("pnote"), self.obj.set_pnote, self.obj.get_pnote, self.db.readonly) #/database/objects/object/file/@src self.fname = MonitoredEntry(self.top.get_object("fname"), self.obj.set_fname, self.obj.get_fname, self.db.readonly) #/database/people/person/parentin/@hlink #/database/people/person/name/first/text() self.ffname = MonitoredEntry(self.top.get_object("ffname"), self.obj.set_ffname, self.obj.get_ffname, self.db.readonly) #/database/people/person/eventref/attribute/@type #/database/people/person/eventref/attribute/@value self.fage = MonitoredEntry(self.top.get_object("fage"), self.obj.set_fage, self.obj.get_fage, self.db.readonly) #/database/people/person/eventref/@hlink #/database/events/event/place/@hlink #/database/places/placeobj/ptitle/text() self.forig = MonitoredEntry(self.top.get_object("forig"), self.obj.set_forig, self.obj.get_forig, self.db.readonly) #/database/people/person/eventref/@hlink #/database/events/event/description/text() self.foccu = MonitoredEntry(self.top.get_object("foccu"), self.obj.set_foccu, self.obj.get_foccu, self.db.readonly) #/database/people/person/eventref/@hlink #/database/events/event/dateval/@val #/database/events/event/description/text() self.flive = MonitoredEntry(self.top.get_object("flive"), self.obj.set_flive, self.obj.get_flive, self.db.readonly) #/database/people/person/parentin/@hlink #/database/people/person/name/first/text() self.mname = MonitoredEntry(self.top.get_object("mname"), self.obj.set_mname, self.obj.get_mname, self.db.readonly) self.mfname = MonitoredEntry(self.top.get_object("mfname"), self.obj.set_mfname, self.obj.get_mfname, self.db.readonly) self.mage = MonitoredEntry(self.top.get_object("mage"), self.obj.set_mage, self.obj.get_mage, self.db.readonly) self.morigin = MonitoredEntry(self.top.get_object("morigin"), self.obj.set_morigin, self.obj.get_morigin, self.db.readonly) self.moccu = MonitoredEntry(self.top.get_object("moccu"), self.obj.set_moccu, self.obj.get_moccu, self.db.readonly) self.mlive = MonitoredEntry(self.top.get_object("mlive"), self.obj.set_mlive, self.obj.get_mlive, self.db.readonly) self.msname = MonitoredEntry(self.top.get_object("msname"), self.obj.set_msname, self.obj.get_msname, self.db.readonly) self.mdpdate = MonitoredEntry(self.top.get_object("mdpdate"), self.obj.set_mdpdate, self.obj.get_mdpdate, self.db.readonly) self.mmdate = MonitoredEntry(self.top.get_object("mmdate"), self.obj.set_mmdate, self.obj.get_mmdate, self.db.readonly) self.mdplace = MonitoredEntry(self.top.get_object("mdplace"), self.obj.set_mdplace, self.obj.get_mdplace, self.db.readonly) self.mmplace = MonitoredEntry(self.top.get_object("mmplace"), self.obj.set_mmplace, self.obj.get_mmplace, self.db.readonly) self.mnote = MonitoredEntry(self.top.get_object("mnote"), self.obj.set_mnote, self.obj.get_mnote, self.db.readonly) #/database/people/person/parentin/@hlink #/database/families/family/mother #/database/families/family/father self.spname = MonitoredEntry(self.top.get_object("spname"), self.obj.set_spname, self.obj.get_spname, self.db.readonly) #/database/families/family/eventref/@hlink #/database/events/event/dateval/@val self.spmdate = MonitoredEntry(self.top.get_object("bannsdate"), self.obj.set_spmdate, self.obj.get_spmdate, self.db.readonly) #/database/families/family/eventref/@hlink #/database/events/event/place/@hlink #/database/places/placeobj/ptitle/text() self.spmplace = MonitoredEntry(self.top.get_object("bannsplace"), self.obj.set_spmplace, self.obj.get_spmplace, self.db.readonly) # PyXMLFAQ -- Python XML Frequently Asked Questions # Author: Dave Kuhlman # [email protected] # http://www.rexx.com/~dkuhlman def walk_tree(self, node, level): fill = self.show_level(level) print('%sElement name: %s' % ( fill, node.tag, )) for (name, value) in node.attrib.items(): print('%s Attr -- Name: %s Value: %s' % ( fill, name, value, )) if node.attrib.get('ID') is not None: print('%s ID: %s' % ( fill, node.attrib.get('ID').value, )) children = node.getchildren() for child in children: self.walk_tree(child, level + 1) def show_level(self, level): s1 = '\t' * level return s1 def parse_xml(self, filename): tree = ElementTree.parse(filename) root = tree.getroot() self.walk_tree(root, 0) def write_xml(self, filename, id, date): """ Write the content of data filled into the form (currently only a test; no levels) """ ''' <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE database PUBLIC "-//Gramps//DTD Gramps XML 1.5.0//EN" "http://gramps-project.org/xml/1.5.0/grampsxml.dtd"> <database xmlns="http://gramps-project.org/xml/1.5.0/"> <header> <created date="2012-07-04" version="3.5.0-0.SVNexported"/> <researcher> </researcher> </header> ... ''' node = ElementTree.Element('marriage') node.set('id', id) node.set('collection', filename) node.set('uri', 'file://..') #/database/people/person/eventref/@hlink #/database/events/event/dateval/@val node1 = ElementTree.SubElement(node, 'dateval') node1.text = date outfile = open(filename, 'w') self.outfile = codecs.getwriter("utf8")(outfile) self.outfile.write(ElementTree.tostring(node, encoding="UTF-8")) self.outfile.close()
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()
class Witness(tool.Tool, ManagedWindow): def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate self.label = _('Sources Index') self.base = os.path.dirname(__file__) ManagedWindow.__init__(self, uistate, [], self.__class__) self.set_window(Gtk.Window(), Gtk.Label(), '') tool.Tool.__init__(self, dbstate, options_class, name) glade_file = os.path.join(USER_PLUGINS, "SourceIndex", "witness.glade") if gramps.gen.constfunc.lin(): import locale locale.setlocale(locale.LC_ALL, '') # This is needed to make gtk.Builder work by specifying the # translations directory locale.bindtextdomain("addon", self.base + "/locale") self.glade = Gtk.Builder() self.glade.set_translation_domain("addon") self.glade.add_from_file(glade_file) from gi.repository import GObject GObject.GObject.__init__(self.glade) window = self.glade.get_object('witness_editor') self.set_window(window, self.glade.get_object('title'), self.label) self.ok_button = self.glade.get_object('ok') self.quit_button = self.glade.get_object('cancel') else: # Glade class from gui/glade.py and gui/managedwindow.py self.top = Glade() window = self.top.toplevel self.set_window(window, None, glade_file) self.ok_button = self.top.get_object('ok') self.quit_button = self.top.get_object('cancel') self.ok_button.connect('clicked', self.close) self.quit_button.connect('clicked', self.close) self.window.show() def __getitem__(self, key): return self.glade.get_widget(key) def _setup_fields(self): r''' Gramps XML storage means ability to also import/manage alone records /!\ some attributes are translated keys see data_item keys and eventref types of attribute ''' #/database/people/person/name/surname/surname/text() self.wname = MonitoredEntry(self.top.get_object("wname"), self.obj.set_wname, self.obj.get_wname, self.db.readonly) #/database/people/person/name/first/text() self.wfname = MonitoredEntry(self.top.get_object("wfname"), self.obj.set_wfname, self.obj.get_wfname, self.db.readonly) #/database/people/person/eventref/attribute/@type #/database/people/person/eventref/attribute/@value self.wage = MonitoredEntry(self.top.get_object("wage"), self.obj.set_wage, self.obj.get_wage, self.db.readonly) #/database/people/person/eventref/@hlink #/database/events/event/place/@hlink #/database/places/placeobj/ptitle/text() self.worig = MonitoredEntry(self.top.get_object("worig"), self.obj.set_worig, self.obj.get_worig, self.db.readonly) #/database/people/person/eventref/@hlink #/database/events/event/description/text() self.woccu = MonitoredEntry(self.top.get_object("woccu"), self.obj.set_woccu, self.obj.get_woccu, self.db.readonly) #/database/people/person/eventref/@hlink #/database/events/event/dateval/@val #/database/events/event/description/text() self.wlive = MonitoredEntry(self.top.get_object("wlive"), self.obj.set_wlive, self.obj.get_wlive, self.db.readonly) #/database/people/person/personref/@hlink #/database/people/person/@handle #/database/people/person/personref/@rel self.wrelation = MonitoredEntry(self.top.get_object("wrelation"), self.obj.set_wrelation, self.obj.get_wrelation, self.db.readonly)
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 RelCalc(tool.Tool, ManagedWindow): def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate """ Relationship calculator class. """ tool.Tool.__init__(self, dbstate, options_class, name) ManagedWindow.__init__(self,uistate,[],self.__class__) #set the columns to see for data in BasePersonView.CONFIGSETTINGS: if data[0] == 'columns.rank': colord = data[1] elif data[0] == 'columns.visible': colvis = data[1] elif data[0] == 'columns.size': colsize = data[1] self.colord = [] for col, size in zip(colord, colsize): if col in colvis: self.colord.append((1, col, size)) else: self.colord.append((0, col, size)) self.dbstate = dbstate self.relationship = get_relationship_calculator(glocale) self.relationship.connect_db_signals(dbstate) self.glade = Glade() self.person = self.db.get_person_from_handle( uistate.get_active('Person')) name = '' if self.person: name = name_displayer.display(self.person) self.title = _('Relationship calculator: %(person_name)s' ) % {'person_name' : name} window = self.glade.toplevel self.titlelabel = self.glade.get_object('title') self.set_window(window, self.titlelabel, _('Relationship to %(person_name)s' ) % {'person_name' : name}, self.title) self.setup_configs('interface.relcalc', 600, 400) self.tree = self.glade.get_object("peopleList") self.text = self.glade.get_object("text1") self.textbuffer = Gtk.TextBuffer() self.text.set_buffer(self.textbuffer) self.model = PersonTreeModel(self.db) self.tree.set_model(self.model) self.tree.connect('key-press-event', self._key_press) self.selection = self.tree.get_selection() self.selection.set_mode(Gtk.SelectionMode.SINGLE) #keep reference of column so garbage collection works self.columns = [] for pair in self.colord: if not pair[0]: continue name = column_names[pair[1]] column = Gtk.TreeViewColumn(name, Gtk.CellRendererText(), markup=pair[1]) column.set_resizable(True) column.set_min_width(60) column.set_sizing(Gtk.TreeViewColumnSizing.GROW_ONLY) self.tree.append_column(column) #keep reference of column so garbage collection works self.columns.append(column) self.sel = self.tree.get_selection() self.changedkey = self.sel.connect('changed',self.on_apply_clicked) self.closebtn = self.glade.get_object("button5") self.closebtn.connect('clicked', self.close) if not self.person: self.window.hide() ErrorDialog(_('Active person has not been set'), _('You must select an active person for this ' 'tool to work properly.'), parent=uistate.window) self.close() return self.show() def close(self, *obj): """ Close relcalc tool. Remove non-gtk connections so garbage collection can do its magic. """ self.relationship.disconnect_db_signals(self.dbstate) self.sel.disconnect(self.changedkey) ManagedWindow.close(self, *obj) def build_menu_names(self, obj): return (_("Relationship Calculator tool"),None) def on_apply_clicked(self, obj): model, iter_ = self.tree.get_selection().get_selected() if not iter_: return other_person = None handle = model.get_handle_from_iter(iter_) if handle: other_person = self.db.get_person_from_handle(handle) if other_person is None: self.textbuffer.set_text("") return #now determine the relation, and print it out rel_strings, common_an = self.relationship.get_all_relationships( self.db, self.person, other_person) p1 = name_displayer.display(self.person) p2 = name_displayer.display(other_person) text = [] if other_person is None: pass elif self.person.handle == other_person.handle: rstr = _("%(person)s and %(active_person)s are the same person.") % { 'person': p1, 'active_person': p2 } text.append((rstr, "")) elif len(rel_strings) == 0: rstr = _("%(person)s and %(active_person)s are not related.") % { 'person': p2, 'active_person': p1 } text.append((rstr, "")) for rel_string, common in zip(rel_strings, common_an): rstr = _("%(person)s is the %(relationship)s of %(active_person)s." ) % {'person': p2, 'relationship': rel_string, 'active_person': p1 } length = len(common) if length == 1: person = self.db.get_person_from_handle(common[0]) if common[0] in [other_person.handle, self.person.handle]: commontext = '' else : name = name_displayer.display(person) commontext = " " + _("Their common ancestor is %s.") % name elif length == 2: p1c = self.db.get_person_from_handle(common[0]) p2c = self.db.get_person_from_handle(common[1]) p1str = name_displayer.display(p1c) p2str = name_displayer.display(p2c) commontext = " " + _("Their common ancestors are %(ancestor1)s and %(ancestor2)s.") % { 'ancestor1': p1str, 'ancestor2': p2str } elif length > 2: index = 0 commontext = " " + _("Their common ancestors are: ") for person_handle in common: person = self.db.get_person_from_handle(person_handle) if index: commontext += ", " commontext += name_displayer.display(person) index += 1 commontext += "." else: commontext = "" text.append((rstr, commontext)) textval = "" for val in text: textval += "%s %s\n" % (val[0], val[1]) self.textbuffer.set_text(textval) def _key_press(self, obj, event): if event.keyval in (Gdk.KEY_Return, Gdk.KEY_KP_Enter): store, paths = self.selection.get_selected_rows() if paths and len(paths[0]) == 1 : if self.tree.row_expanded(paths[0]): self.tree.collapse_row(paths[0]) else: self.tree.expand_row(paths[0], 0) return True return False
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)
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 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 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()
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()
def importData(database, filename, user): """ Try to handle ANSEL encoded files that are not really ANSEL encoded """ if DbMixin not in database.__class__.__bases__: database.__class__.__bases__ = (DbMixin,) + \ database.__class__.__bases__ try: ifile = open(filename, "rb") except IOError: return ansel = False gramps = False for index in range(50): # Treat the file as though it is UTF-8 since this is the more modern # option; and anyway it doesn't really matter as we are only trying to # detect a CHAR or SOUR line which is only 7-bit ASCII anyway, and we # ignore anything that can't be translated. line = ifile.readline() line = line.decode(encoding='utf-8', errors='replace') line = line.split() if len(line) == 0: break if len(line) > 2 and line[1][0:4] == 'CHAR' and line[2] == "ANSEL": ansel = True if len(line) > 2 and line[1][0:4] == 'SOUR' and line[2] == "GRAMPS": gramps = True ifile.close() if not gramps and ansel: top = Glade() code = top.get_object('codeset') code.set_active(0) dialog = top.toplevel dialog.run() enc = ['ANSEL', 'ANSEL', 'ANSI', 'ASCII', 'UTF-8'] code_set = enc[ code.get_active()] dialog.destroy() else: code_set = "" assert(isinstance(code_set, str)) try: ifile = open(filename, "rb") stage_one = libgedcom.GedcomStageOne(ifile) stage_one.parse() if code_set: stage_one.set_encoding(code_set) ifile.seek(0) if database.get_feature("skip-import-additions"): # don't add source or tags gedparse = libgedcom.GedcomParser( database, ifile, filename, user, stage_one, None, None) else: gedparse = libgedcom.GedcomParser( database, ifile, filename, user, stage_one, config.get('preferences.default-source'), (config.get('preferences.tag-on-import-format') if config.get('preferences.tag-on-import') else None)) except IOError as msg: user.notify_error(_("%s could not be opened\n") % filename, str(msg)) return except GedcomError as msg: user.notify_error(_("Invalid GEDCOM file"), _("%s could not be imported") % filename + "\n" + str(msg)) return try: read_only = database.readonly database.readonly = False database.prepare_import() gedparse.parse_gedcom_file(False) database.commit_import() database.readonly = read_only ifile.close() except IOError as msg: msg = _("%s could not be opened\n") % filename user.notify_error(msg, str(msg)) return except DbError as msg: user.notify_db_error(str(msg.value)) return except GedcomError as msg: user.notify_error(_('Error reading GEDCOM file'), str(msg)) return return ImportInfo({_("Results"): _("done")})
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 MultiSelectDialog: # parent-OK def __init__(self, msg1_func, msg2_func, items, lookup, cancel_func=None, no_func=None, yes_func=None, parent=None): """ """ self.xml = Glade(toplevel='multiselectdialog') self.top = self.xml.toplevel self.top.set_icon(ICON) self.msg1_func = msg1_func self.msg2_func = msg2_func self.items = items self.lookup = lookup self.cancel_func = cancel_func self.no_func = no_func self.yes_func = yes_func label1 = self.xml.get_object('label6') label2 = self.xml.get_object('label5') check_button = self.xml.get_object('apply_to_rest') if parent: self.top.set_transient_for(parent) self.top.connect('delete_event', self.warn) default_action = 0 for selected in items: item = self.lookup(selected) if default_action == 0: msg1 = self.msg1_func(item) msg2 = self.msg2_func(item) self.top.set_title("%s - Gramps" % msg1) label1.set_text('<span weight="bold" size="larger">%s</span>' % msg1) label1.set_use_markup(True) label2.set_text(msg2) label2.set_use_markup(True) self.top.show() # Need some magic here, because an attempt to close the dialog # with the X button not only emits the 'delete_event' signal # but also exits with the RESPONSE_DELETE_EVENT response = Gtk.ResponseType.DELETE_EVENT while response == Gtk.ResponseType.DELETE_EVENT: response = self.top.run() if check_button.get_active(): default_action = response else: response = default_action ### Now do it if response == 1: # Cancel if self.cancel_func: self.cancel_func(item) break elif response == 2: # No if self.no_func: self.no_func(item) elif response == 3: # Yes if self.yes_func: self.yes_func(item) self.top.destroy() def warn(self, obj, obj2): WarningDialog( # parent-OK _("Attempt to force closing the dialog"), _("Please do not force closing this important dialog.\n" "Instead select one of the available options"), parent=self.top) return True
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 CensusIndex(tool.Tool, ManagedWindow): def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate self.label = _('Sources Index') self.base = os.path.dirname(__file__) ManagedWindow.__init__(self, uistate,[], self.__class__) self.set_window(Gtk.Window(),Gtk.Label(),'') tool.Tool.__init__(self, dbstate, options_class, name) glade_file = os.path.join(USER_PLUGINS, "SourceIndex", "census.glade") if gramps.gen.constfunc.lin(): import locale locale.setlocale(locale.LC_ALL, '') # This is needed to make gtk.Builder work by specifying the # translations directory locale.bindtextdomain("addon", self.base + "/locale") self.glade = Gtk.Builder() self.glade.set_translation_domain("addon") self.glade.add_from_file(glade_file) from gi.repository import GObject GObject.GObject.__init__(self.glade) window = self.glade.get_object('edit_census') self.set_window(window, self.glade.get_object('title'), self.label) self.ok_button = self.glade.get_object('ok') self.quit_button = self.glade.get_object('cancel') else: # Glade class from gui/glade.py and gui/managedwindow.py self.top = Glade() window = self.top.toplevel self.set_window(window, None, glade_file) self.ok_button = self.top.get_object('ok') self.quit_button = self.top.get_object('cancel') self.ok_button.connect('clicked', self.close) self.quit_button.connect('clicked', self.close) self.window.show() # tests filename = os.path.join(USER_PLUGINS, 'SourceIndex', 'test_census.xml') self.pname = self.pfname = 'éàèôÖàçèœ' self.write_xml( filename, 'C0001', '', self.pfname, self.pname ) self.parse_xml(filename) def __getitem__(self, key): return self.glade.get_widget(key) def _setup_fields(self): r''' Gramps XML storage means ability to also import/manage alone records /!\ some attributes are translated keys see data_item keys and eventref types of attribute ''' #/database/repositories/repository/rname/text() self.rinfo = MonitoredEntry( self.top.get_object("rinfo"), self.obj.set_rinfo, self.obj.get_rinfo, self.db.readonly) # date of transcription/search self.rdate = MonitoredEntry( self.top.get_object("rdate"), self.obj.set_rdate, self.obj.get_rdate, self.db.readonly) #/database/repositories/repository/@handle self.rid = MonitoredEntry( self.top.get_object("rid"), self.obj.set_rid, self.obj.get_rid, self.db.readonly) #/database/sources/source/stitle/text() self.aname = MonitoredEntry( self.top.get_object("aname"), self.obj.set_aname, self.obj.get_aname, self.db.readonly) #/database/sources/source/@handle self.aid = MonitoredEntry( self.top.get_object("aid"), self.obj.set_aid, self.obj.get_aid, self.db.readonly) #/database/citations/citation/@handle self.aref = MonitoredEntry( self.top.get_object("aref"), self.obj.set_aref, self.obj.get_aref, self.db.readonly) #/database/citations/citation/page # hardcoded /database/citations/citation/confidence self.avol = MonitoredEntry( self.top.get_object("avol"), self.obj.set_avol, self.obj.get_avol, self.db.readonly) #/database/people/person/gender self.gen = MonitoredEntry( self.top.get_object("gen"), self.obj.set_gen, self.obj.get_gen, self.db.readonly) #/database/people/person/name/surname/surname/text() self.pname = MonitoredEntry( self.top.get_object("pname"), self.obj.set_pname, self.obj.get_pname, self.db.readonly) #/database/people/person/eventref/@hlink #/database/events/event/dateval/@val self.pbdate = MonitoredEntry( self.top.get_object("pbdate"), self.obj.set_pbdate, self.obj.get_pbdate, self.db.readonly) #/database/people/person/eventref/@hlink #/database/places/placeobj/@handle self.pbplace = MonitoredEntry( self.top.get_object("pbplace"), self.obj.set_pbplace, self.obj.get_pbplace, self.db.readonly) #/database/people/person/name/first/text() self.pfname = MonitoredEntry( self.top.get_object("pfname"), self.obj.set_pfname, self.obj.get_pfname, self.db.readonly) #/database/people/person/eventref/noteref/@hlink #/database/notes/note/text/text() self.pnote = MonitoredEntry( self.top.get_object("pnote"), self.obj.set_pnote, self.obj.get_pnote, self.db.readonly) # Residence event #/database/people/person/eventref/@hlink #/database/events/event/description/text() self.address = MonitoredEntry( self.top.get_object("address"), self.obj.set_address, self.obj.get_address, self.db.readonly) #/database/people/person/eventref/@hlink #/database/events/event/description/text() self.occupation = MonitoredEntry( self.top.get_object("occupation"), self.obj.set_occupation, self.obj.get_occupation, self.db.readonly) #/database/people/person/eventref/attribute/@type #/database/people/person/eventref/attribute/@value self.age = MonitoredEntry( self.top.get_object("age"), self.obj.set_age, self.obj.get_age, self.db.readonly) # PyXMLFAQ -- Python XML Frequently Asked Questions # Author: Dave Kuhlman # [email protected] # http://www.rexx.com/~dkuhlman def walk_tree(self, node, level): fill = self.show_level(level) print('%sElement name: %s' % (fill, node.tag, )) for (name, value) in node.attrib.items(): print('%s Attr -- Name: %s Value: %s' % (fill, name, value,)) if node.attrib.get('ID') is not None: print('%s ID: %s' % (fill, node.attrib.get('ID').value, )) children = node.getchildren() for child in children: self.walk_tree(child, level + 1) def show_level(self, level): s1 = '\t' * level return s1 def parse_xml(self, filename): tree = ElementTree.parse(filename) root = tree.getroot() self.walk_tree(root, 0) def write_xml(self, filename, id , status, first, surname): """ Write the content of data filled into the form (currently only a test; no levels) """ ''' <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE database PUBLIC "-//Gramps//DTD Gramps XML 1.5.0//EN" "http://gramps-project.org/xml/1.5.0/grampsxml.dtd"> <database xmlns="http://gramps-project.org/xml/1.5.0/"> <header> <created date="2012-07-04" version="3.5.0-0.SVNexported"/> <researcher> </researcher> </header> <events> <event handle="_abaa318b6d61a120c1b" change="1341403790" id="E0000"> <type>Birth</type> <dateval val="1845" type="about"/> <place hlink="_abaa31688b11e7d1526"/> <citationref hlink="_c3332ee70e06bd6867c"/> </event> <event handle="_abaa342890d322922f7" change="1341403823" id="E0001"> <type>Census</type> <dateval val="1871-04-02"/> <place hlink="_abaa340f64a3aa3010e"/> <citationref hlink="_c3332ee70e06bd6867c"/> </event> </events> <people> <person handle="_abaa31d494e56aba1c1" change="1341403686" id="I0000"> <gender>M</gender> <name type="Birth Name"> <first>Martin</first> <surname>John</surname> </name> <eventref hlink="_abaa318b6d61a120c1b" role="Primary"/> <eventref hlink="_abaa342890d322922f7" role="Primary"> <attribute priv="1" type="Rang" value="1"/> <attribute type="Relation" value="Husband"/> <attribute type="Statut familial" value="Head"/> <attribute type="Age" value="25 years"/> <attribute type="Profession" value="Worker"/> <attribute type="Lieu de naissance" value="Wednesbury"/> </eventref> </person> </people> <citations> <citation handle="_c3332ee70e06bd6867c" change="1341403810" id="C0001"> <dateval val="1871-04-02"/> <page>17/27</page> <confidence>2</confidence> <sourceref hlink="_abaa371c73f5a827b6f"/> </citation> </citations> <sources> <source handle="_abaa371c73f5a827b6f" change="1341403810" id="S0000"> <stitle>Wednesbury Census between 1871 and 1881</stitle> <sauthor>UK Governement</sauthor> <spubinfo>www.ancestv.co.uk</spubinfo> <data_item key="Recensement" value="UK1871"/> <reporef hlink="_abaa3714e242ea05aee" callno="RG 11/2854" medium="Card"/> </source> </sources> <places> <placeobj handle="_abaa31688b11e7d1526" change="1179671725" id="P0000"> <ptitle>Wednesbury Staffordshire</ptitle> <location city="Wednesbury" parish="Staffordshire" country="UK"/> </placeobj> <placeobj handle="_abaa340f64a3aa3010e" change="1179671913" id="P0001"> <ptitle>Wednesbury Staffordshire, Hope Terrace 17</ptitle> <location street="Hope Terrace 17" city="Wednesbury" parish="Staffordshire" country="UK"/> </placeobj> </places> <repositories> <repository handle="_abaa3714e242ea05aee" change="1341402429" id="R0000"> <rname>Civil Parish Wednesbury</rname> <type>Library</type> </repository> </repositories> </database> ''' node = ElementTree.Element('census') node.set('id', id) node.set('collection', filename) node.set('uri', 'file://..') node1 = ElementTree.SubElement(node, 'status') node1.text = status #/database/people/person/name/first/text() node1 = ElementTree.SubElement(node, 'first') node1.text = first #/database/people/person/name/surname/surname/text() node1 = ElementTree.SubElement(node, 'surname') node1.text = surname outfile = open(filename, 'w') self.outfile = codecs.getwriter("utf8")(outfile) self.outfile.write(ElementTree.tostring(node, encoding="UTF-8")) self.outfile.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", 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)
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 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 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 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 importData(database, filename, user): """ Try to handle ANSEL encoded files that are not really ANSEL encoded """ if DbMixin not in database.__class__.__bases__: database.__class__.__bases__ = (DbMixin,) + \ database.__class__.__bases__ try: # Opening in utf-8 with universal newline to allow cr, lf, and crlf # If the file is really UTF16 or a varient, the next block code will not # find anything even if it is there, but this is ok since it won't be # ANSEL, or is inconsistent... with open(filename, "r", encoding='utf-8', errors='replace', newline=None) as ifile: ansel = False gramps = False for index in range(50): # Treat the file as though it is UTF-8 since this is the more # modern option; and anyway it doesn't really matter as we are # only trying to detect a CHAR or SOUR line which is only # 7-bit ASCII anyway, and we ignore anything that can't be # translated. line = ifile.readline() line = line.split() if len(line) == 0: break if len(line) > 2 and line[1][0:4] == 'CHAR' \ and line[2] == "ANSEL": ansel = True if len(line) > 2 and line[1][0:4] == 'SOUR' \ and line[2] == "GRAMPS": gramps = True except IOError: return if not gramps and ansel and user.uistate: top = Glade() code = top.get_object('codeset') code.set_active(0) dialog = top.toplevel dialog.set_transient_for(user.uistate.window) dialog.run() enc = ['ANSEL', 'ANSEL', 'ANSI', 'ASCII', 'UTF-8'] code_set = enc[code.get_active()] dialog.destroy() else: code_set = "" assert (isinstance(code_set, str)) try: ifile = open(filename, "rb") stage_one = libgedcom.GedcomStageOne(ifile) stage_one.parse() if code_set: stage_one.set_encoding(code_set) ifile.seek(0) if database.get_feature( "skip-import-additions"): # don't add source or tags gedparse = libgedcom.GedcomParser(database, ifile, filename, user, stage_one, None, None) else: gedparse = libgedcom.GedcomParser( database, ifile, filename, user, stage_one, config.get('preferences.default-source'), (config.get('preferences.tag-on-import-format') if config.get('preferences.tag-on-import') else None)) except IOError as msg: user.notify_error(_("%s could not be opened\n") % filename, str(msg)) return except GedcomError as msg: user.notify_error( _("Invalid GEDCOM file"), _("%s could not be imported") % filename + "\n" + str(msg)) return try: read_only = database.readonly database.readonly = False gedparse.parse_gedcom_file(False) database.readonly = read_only ifile.close() except IOError as msg: msg = _("%s could not be opened\n") % filename user.notify_error(msg, str(msg)) return except DbError as msg: user.notify_db_error(str(msg.value)) return except GedcomError as msg: user.notify_error(_('Error reading GEDCOM file'), str(msg)) return ## a "GEDCOM import report" happens in GedcomParser so this is not needed: ## (but the imports_test.py unittest currently requires it, so here it is) return ImportInfo({_("Results"): _("done")})
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)
def importData(database, filename, user): """ Try to handle ANSEL encoded files that are not really ANSEL encoded """ if DbMixin not in database.__class__.__bases__: database.__class__.__bases__ = (DbMixin,) + \ database.__class__.__bases__ try: with open(filename, "rb") as ifile: ansel = False gramps = False for index in range(50): # Treat the file as though it is UTF-8 since this is the more modern # option; and anyway it doesn't really matter as we are only trying to # detect a CHAR or SOUR line which is only 7-bit ASCII anyway, and we # ignore anything that can't be translated. line = ifile.readline() line = line.decode(encoding='utf-8', errors='replace') line = line.split() if len(line) == 0: break if len(line ) > 2 and line[1][0:4] == 'CHAR' and line[2] == "ANSEL": ansel = True if len(line) > 2 and line[1][0:4] == 'SOUR' and line[ 2] == "GRAMPS": gramps = True except IOError: return if not gramps and ansel: top = Glade() code = top.get_object('codeset') code.set_active(0) dialog = top.toplevel dialog.run() enc = ['ANSEL', 'ANSEL', 'ANSI', 'ASCII', 'UTF-8'] code_set = enc[code.get_active()] dialog.destroy() else: code_set = "" assert (isinstance(code_set, str)) try: ifile = open(filename, "rb") stage_one = libgedcom.GedcomStageOne(ifile) stage_one.parse() if code_set: stage_one.set_encoding(code_set) ifile.seek(0) if database.get_feature( "skip-import-additions"): # don't add source or tags gedparse = libgedcom.GedcomParser(database, ifile, filename, user, stage_one, None, None) else: gedparse = libgedcom.GedcomParser( database, ifile, filename, user, stage_one, config.get('preferences.default-source'), (config.get('preferences.tag-on-import-format') if config.get('preferences.tag-on-import') else None)) except IOError as msg: user.notify_error(_("%s could not be opened\n") % filename, str(msg)) return except GedcomError as msg: user.notify_error( _("Invalid GEDCOM file"), _("%s could not be imported") % filename + "\n" + str(msg)) return try: read_only = database.readonly database.readonly = False gedparse.parse_gedcom_file(False) database.readonly = read_only ifile.close() except IOError as msg: msg = _("%s could not be opened\n") % filename user.notify_error(msg, str(msg)) return except DbError as msg: user.notify_db_error(str(msg.value)) return except GedcomError as msg: user.notify_error(_('Error reading GEDCOM file'), str(msg)) return return ImportInfo({_("Results"): _("done")})
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 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()
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 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 BirthIndex(tool.Tool, ManagedWindow): def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate self.label = _('Sources Index') self.base = os.path.dirname(__file__) ManagedWindow.__init__(self, uistate,[], self.__class__) self.set_window(Gtk.Window(),Gtk.Label(),'') tool.Tool.__init__(self, dbstate, options_class, name) glade_file = os.path.join(USER_PLUGINS, "SourceIndex", "birth.glade") if gramps.gen.constfunc.lin(): import locale locale.setlocale(locale.LC_ALL, '') # This is needed to make gtk.Builder work by specifying the # translations directory locale.bindtextdomain("addon", self.base + "/locale") self.glade = Gtk.Builder() self.glade.set_translation_domain("addon") #self.glade = GladeWidgetsWrapper(glade_file, self) self.glade.add_from_file(glade_file) from gi.repository import GObject GObject.GObject.__init__(self.glade) window = self.glade.get_object('edit_birth') self.set_window(window, self.glade.get_object('title'), self.label) #self.wit_button = self.glade.get_object('add_wit') self.ok_button = self.glade.get_object('ok') self.quit_button = self.glade.get_object('cancel') else: # Glade class from gui/glade.py and gui/managedwindow.py self.glade = Glade(glade_file) #self.glade = GladeWidgetsWrapper(glade_file, self) self.top = Glade() window = self.top.toplevel self.set_window(window, None, glade_file) #self.wit_button = self.top.get_object('add_wit') self.ok_button = self.top.get_object('ok') self.quit_button = self.top.get_object('cancel') #self.wit_button.connect('clicked', GtkHandlers.on_witness_clicked) self.ok_button.connect('clicked', self.close) self.quit_button.connect('clicked', self.close) #GObject.__init__() takes exactly 0 arguments #self.text = Gtk.EntryBuffer('Gtk.Entry._get...', 5) # tests path = os.path.join(USER_PLUGINS, 'SourceIndex') self.rinfo = 'Library of usercity' callnumber = 'BX42_xzertra58364' # inherited or seizure source_handle = '_123456789' # or call the source title citation_handle = '_987654321' # or call any id self.avol = 'Page 105 n°56' self.aname = 'Civil book (Birth 1650)' separator = 'ↄ' name = self.rinfo + separator + callnumber + separator \ + source_handle + separator + citation_handle + separator \ + self.avol + separator + self.aname + '.xml' filename = os.path.join(path, name) self.write_xml( filename, 'B0001', 'DATE', 'PRÉNOM' ) #self._setup_fields() self.window.show() self.parse_xml(filename) def _setup_fields(self): ''' Gramps XML storage means ability to also import/manage alone records /!\ some attributes are translated keys see data_item keys and eventref types of attribute ''' #/database/repositories/repository/rname/text() self.rinfo = MonitoredText( self.top.get_object("rinfo"), self.top.get_object("rinfo").set_text(self.rinfo), self.top.get_object("rinfo").get_text, True) # date of transcription/search self.rdate = MonitoredText( self.top.get_object("rdate"), self.top.get_object("rdate").set_text(str(date.Today())), #self.top.get_object("rdate").get_date_object(), #uistate, #track, True) #/database/repositories/repository/@handle self.rid = MonitoredEntry( self.top.get_object("rid"), self.top.get_object("rid").set_text, self.top.get_object("rid").get_text, True) #/database/sources/source/stitle/text() self.aname = MonitoredText( self.top.get_object("aname"), self.top.get_object("aname").set_text(self.aname), self.top.get_object("aname").get_text, True) #/database/sources/source/@handle self.aid = MonitoredEntry( self.top.get_object("aid"), self.top.get_object("aid").set_text, self.top.get_object("aid").get_text, True) #/database/citations/citation/@handle self.aref = MonitoredEntry( self.top.get_object("aref"), self.top.get_object("aref").set_text, self.top.get_object("aref").get_text, True) #/database/citations/citation/dateval/@val #self.adate = MonitoredDate( #self.top.get_object("adate"), #self.top.get_object("adate").set_text, #self.top.get_object("adate").get_date_object(), #uistate, #track, #True) #/database/citations/citation/page # hardcoded /database/citations/citation/confidence self.avol = MonitoredEntry( self.top.get_object("avol"), self.top.get_object("avol").set_text(self.avol), self.top.get_object("avol").get_text, True) #/database/people/person/gender #self.gen = MonitoredType( #self.top.get_object("gen"), #self.top.get_object("gen").set_text, #self.top.get_object("gen").get_text, #True) #/database/people/person/childof/@hlink #/database/people/person/name/surname/surname/text() self.pname = MonitoredEntry( self.top.get_object("pname"), self.top.get_object("pname").set_text, self.top.get_object("pname").get_text, True) #/database/people/person/name/first/text() self.pfname = MonitoredText( self.top.get_object("pfname"), self.top.get_object("pfname").set_text, self.top.get_object("pfname").get_text, True) #/database/people/person/eventref/@hlink #/database/events/event/dateval/@val #self.pdate = MonitoredDate( #self.top.get_object("pdate"), #self.top.get_object("pdate_stat"), #self.top.get_object("pdate").get_date_object(), #uistate, #track, #True) #/database/people/person/eventref/@hlink #/database/events/event/place/@hlink #/database/places/placeobj/ptitle/text() #self.pplace = PlaceEntry( #dbstate, uistate, track, #self.top.get_object("pplace"), #self.top.get_object("pplace").set_place_handle, #self.top.get_object("pplace").get_place_handle, #self.top.get_object('add_del_place'), #self.top.get_object('select_place')) #/database/people/person/eventref/noteref/@hlink #/database/notes/note/text/text() #self.pnote = NoteEntry( #dbstate, uistate, track, #self.top.get_object("pnote"), #self.top.get_object("pnote").set_note_handle, #self.top.get_object("pnote").get_note_handle, #self.top.get_object('add_del_note'), #self.top.get_object('select_note')) #/database/objects/object/file/@src #self.fname = MediaEntry( #dbstate, uistate, track, #self.top.get_object("fname"), #self.top.get_object("fname").set_media_path, #self.top.get_object("fname").get_media_path, #self.top.get_object('add_del_path'), #self.top.get_object('select_path')) #/database/people/person/parentin/@hlink #/database/people/person/name/first/text() self.ffname = MonitoredText( self.top.get_object("ffname"), self.top.get_object("ffname").set_text, self.top.get_object("ffname").get_text, True) #/database/people/person/eventref/attribute/@type #/database/people/person/eventref/attribute/@value self.fage = MonitoredEntry( self.top.get_object("fage"), self.top.get_object("fage").set_text, self.top.get_object("fage").get_text, True) #/database/people/person/eventref/@hlink #/database/events/event/place/@hlink #/database/places/placeobj/ptitle/text() #self.forig = PlaceEntry( #dbstate, uistate, track, #self.top.get_object("forig"), #self.top.get_object("forig").set_place_handle, #self.top.get_object("forig").get_place_handle, #self.top.get_object('add_del_place'), #self.top.get_object('select_place')) #/database/people/person/eventref/@hlink #/database/events/event/description/text() self.foccu = MonitoredEntry( self.top.get_object("foccu"), self.top.get_object("foccu").set_text, self.top.get_object("foccu").get_text, True) #/database/people/person/eventref/@hlink #/database/events/event/dateval/@val #/database/events/event/description/text() self.flive = MonitoredEntry( self.top.get_object("flive"), self.top.get_object("flive").set_text, self.top.get_object("flive").get_text, True) #/database/people/person/parentin/@hlink #/database/people/person/name/first/text() self.mname = MonitoredText( self.top.get_object("mname"), self.top.get_object("mname").set_text, self.top.get_object("mname").get_text, True) self.mfname = MonitoredText( self.top.get_object("mfname"), self.top.get_object("mfname").set_text, self.top.get_object("mfname").get_text, True) self.mage = MonitoredText( self.top.get_object("mage"), self.top.get_object("mage").set_text, self.top.get_object("mage").get_text, True) #self.morigin = PlaceEntry( #dbstate, uistate, track, #self.top.get_object("morigin"), #self.top.get_object("morigin").set_place_handle, #self.top.get_object("morigin").get_place_handle, #self.top.get_object('add_del_place'), #self.top.get_object('select_place')) self.moccu = MonitoredText( self.top.get_object("moccu"), self.top.get_object("moccu").set_text, self.top.get_object("moccu").get_text, True) self.mlive = MonitoredEntry( self.top.get_object("mlive"), self.top.get_object("mlive").set_text, self.top.get_object("mlive").get_text, True) self.msname = MonitoredText( self.top.get_object("msname"), self.top.get_object("msname").set_text, self.top.get_object("msname").get_text, True) #self.mdpdate = MonitoredDate( #self.top.get_object("mdpdate"), #self.top.get_object("mdpdate_stat"), #self.top.get_object("mdpdate").get_date_object(), #uistate, #track, #True) #self.mmdate = MonitoredDate( #self.top.get_object("mmdate"), #self.top.get_object("mmdate_stat"), #self.top.get_object("mmdate").get_date_object(), #uistate, #track, #True) #self.mdplace = PlaceEntry( #dbstate, uistate, track, #self.top.get_object("mdplace"), #self.top.get_object("mdplace").set_place_handle, #self.top.get_object("mdplace").get_place_handle, #self.top.get_object('add_del_place'), #self.top.get_object('select_place')) #self.mmplace = PlaceEntry( #dbstate, uistate, track, #self.top.get_object("mmplace"), #self.top.get_object("mmplace").set_place_handle, #self.top.get_object("mmplace").get_place_handle, #self.top.get_object('add_del_place'), #self.top.get_object('select_place')) #self.mnote = NoteEntry( #dbstate, uistate, track, #self.top.get_object("mnote"), #self.top.get_object("mnote").set_note_handle, #self.top.get_object("mnote").get_note_handle, #self.top.get_object('add_del_note'), #self.top.get_object('select_note')) #/database/people/person/parentin/@hlink #/database/families/family/mother #/database/families/family/father #self.spname = MonitoredText( #self.top.get_object("spname"), #self.top.get_object("spname").set_text, #self.top.get_object("spname").get_text, #True) #/database/families/family/eventref/@hlink #/database/events/event/dateval/@val #self.spmdate = MonitoredEntry( #self.top.get_object("spmdate"), #self.top.get_object("spmdate").set_text, #self.top.get_object("spmdate").get_text, #True) #/database/families/family/eventref/@hlink #/database/events/event/place/@hlink #/database/places/placeobj/ptitle/text() #self.spmplace = PlaceEntry( #dbstate, uistate, track, #self.top.get_object("spmplace"), #self.top.get_object("spmplace").set_place_handle, #self.top.get_object("spmplace").get_place_handle, #self.top.get_object('add_del_place'), #self.top.get_object('select_place')) def call_witness(self, obj): pass # PyXMLFAQ -- Python XML Frequently Asked Questions # Author: Dave Kuhlman # [email protected] # http://www.rexx.com/~dkuhlman def walk_tree(self, node, level): fill = self.show_level(level) print '%sElement name: %s' % (fill, node.tag, ) for (name, value) in node.attrib.items(): print '%s Attr -- Name: %s Value: %s' % (fill, name, value,) if node.attrib.get('ID') is not None: print '%s ID: %s' % (fill, node.attrib.get('ID').value, ) children = node.getchildren() for child in children: self.walk_tree(child, level + 1) def show_level(self, level): s1 = '\t' * level return s1 def parse_xml(self, filename): """ Load and parse the XML filename """ tree = ElementTree.parse(filename) root = tree.getroot() self.walk_tree(root, 0) def write_xml(self, filename, id , date, given): """ Write the content of data filled into the form (currently only a test; no levels) """ ''' <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE database PUBLIC "-//Gramps//DTD Gramps XML 1.5.0//EN" "http://gramps-project.org/xml/1.5.0/grampsxml.dtd"> <database xmlns="http://gramps-project.org/xml/1.5.0/"> <header> <created date="2012-07-04" version="3.5.0-0.SVNexported"/> <researcher> </researcher> </header> ... ''' node = ElementTree.Element('birth') node.set('id', id) node.set('collection', filename) node.set('uri', 'file://..') gramps = ElementTree.SubElement(node, 'database') gramps.set('xmlns', 'http://gramps-project.org/xml/1.5.0/') #/database/people/person/eventref/@hlink #/database/events/event/dateval/@val events = ElementTree.SubElement(gramps, 'events') event = ElementTree.SubElement(events, 'event') dateval = ElementTree.SubElement(event, 'dateval') dateval.set('val', date) #/database/people/person/name/first/text() people = ElementTree.SubElement(gramps, 'people') person = ElementTree.SubElement(people, 'person') name = ElementTree.SubElement(person, 'name') first = ElementTree.SubElement(name, 'first') first.text = given outfile = open(filename, 'w') self.outfile = codecs.getwriter("utf8")(outfile) self.outfile.write(ElementTree.tostring(node, encoding="UTF-8")) self.outfile.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: 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 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()