def __build_window(self): """Build the window from Glade. """ from glade import Glade glade_xml = Glade() self._window = glade_xml.toplevel #self._window.set_transient_for(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)
class SoundGen(tool.Tool, ManagedWindow.ManagedWindow): def __init__(self, dbstate, uistate, options_class, name, callback=None): self.label = _('SoundEx code generator') tool.Tool.__init__(self, dbstate, options_class, name) ManagedWindow.ManagedWindow.__init__(self, uistate, [], self.__class__) self.glade = Glade() self.glade.connect_signals({ "destroy_passed_object": self.close, "on_help_clicked": self.on_help_clicked, "on_delete_event": self.close, }) window = self.glade.toplevel self.set_window(window, self.glade.get_object('title'), self.label) self.value = self.glade.get_object("value") self.autocomp = self.glade.get_object("name_list") self.name = self.autocomp.child self.name.connect('changed', self.on_apply_clicked) names = [] person = None for person in self.db.iter_people(): lastname = person.get_primary_name().get_surname() if lastname not in names: names.append(lastname) names.sort() AutoComp.fill_combo(self.autocomp, names) if person: n = person.get_primary_name().get_surname() self.name.set_text(n) try: se_text = soundex.soundex(n) except UnicodeEncodeError: se_text = soundex.soundex('') self.value.set_text(se_text) else: self.name.set_text("") self.show() def on_help_clicked(self, obj): """Display the relevant portion of GRAMPS manual""" GrampsDisplay.help(WIKI_HELP_PAGE, WIKI_HELP_SEC) def build_menu_names(self, obj): return (self.label, None) def on_apply_clicked(self, obj): try: se_text = soundex.soundex(unicode(obj.get_text())) except UnicodeEncodeError: se_text = soundex.soundex('') self.value.set_text(se_text)
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")) # 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()
class Eval(tool.Tool,ManagedWindow.ManagedWindow): def __init__(self,dbstate, uistate, options_class, name, callback=None): self.title = _("Python evaluation window") tool.Tool.__init__(self,dbstate, options_class, name) ManagedWindow.ManagedWindow.__init__(self,uistate,[],self.__class__) self.glade = Glade() window = self.glade.toplevel self.dbuf = self.glade.get_object("display").get_buffer() self.ebuf = self.glade.get_object("ebuf").get_buffer() self.error = self.glade.get_object("error").get_buffer() self.dbstate = dbstate self.glade.connect_signals({ "on_apply_clicked" : self.apply_clicked, "on_close_clicked" : self.close, "on_clear_clicked" : self.clear_clicked, "on_delete_event" : self.close, }) self.set_window(window,self.glade.get_object('title'),self.title) self.show() def build_menu_names(self, obj): return (self.title,None) def apply_clicked(self, obj): text = unicode(self.ebuf.get_text(self.ebuf.get_start_iter(), self.ebuf.get_end_iter(),False)) outtext = cStringIO.StringIO() errtext = cStringIO.StringIO() sys.stdout = outtext sys.stderr = errtext try: exec(text) except: traceback.print_exc() self.dbuf.set_text(outtext.getvalue()) self.error.set_text(errtext.getvalue()) sys.stdout = sys.__stdout__ sys.stderr = sys.__stderr__ def clear_clicked(self, obj): self.dbuf.set_text("") self.ebuf.set_text("") self.error.set_text("")
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.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.")) 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 ChangeNames(tool.BatchTool, ManagedWindow.ManagedWindow): def __init__(self, dbstate, uistate, options_class, name, callback=None): self.label = _('Capitalization changes') self.cb = callback ManagedWindow.ManagedWindow.__init__(self, uistate, [], self.__class__) self.set_window(gtk.Window(), gtk.Label(), '') tool.BatchTool.__init__(self, dbstate, uistate, 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 xrange(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 xrange(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""" GrampsDisplay.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 BookReportSelector(ManagedWindow.ManagedWindow): """ Interface into a dialog setting up the book. Allows the user to add/remove/reorder/setup items for the current book and to clear/load/save/edit whole books. """ def __init__(self, dbstate, uistate): self.db = dbstate.db self.dbstate = dbstate self.uistate = uistate self.title = _('Book Report') self.file = "books.xml" ManagedWindow.ManagedWindow.__init__(self, uistate, [], self.__class__) self.xml = Glade(toplevel="top") window = self.xml.toplevel title_label = self.xml.get_object('title') self.set_window(window, title_label, self.title) window.show() self.xml.connect_signals({ "on_add_clicked": self.on_add_clicked, "on_remove_clicked": self.on_remove_clicked, "on_up_clicked": self.on_up_clicked, "on_down_clicked": self.on_down_clicked, "on_setup_clicked": self.on_setup_clicked, "on_clear_clicked": self.on_clear_clicked, "on_save_clicked": self.on_save_clicked, "on_open_clicked": self.on_open_clicked, "on_edit_clicked": self.on_edit_clicked, "on_book_ok_clicked": self.on_book_ok_clicked, "destroy_passed_object": self.close, # Insert dummy handlers for second top level in the glade file "on_booklist_ok_clicked": lambda _: None, "on_booklist_delete_clicked": lambda _: None, "on_booklist_cancel_clicked": lambda _: None, "on_booklist_ok_clicked": lambda _: None, "on_booklist_ok_clicked": lambda _: None, }) self.avail_tree = self.xml.get_object("avail_tree") self.book_tree = self.xml.get_object("book_tree") self.avail_tree.connect('button-press-event', self.avail_button_press) self.book_tree.connect('button-press-event', self.book_button_press) self.name_entry = self.xml.get_object("name_entry") self.name_entry.set_text(_('New Book')) avail_label = self.xml.get_object('avail_label') avail_label.set_text("<b>%s</b>" % _("_Available items")) avail_label.set_use_markup(True) avail_label.set_use_underline(True) book_label = self.xml.get_object('book_label') book_label.set_text("<b>%s</b>" % _("Current _book")) book_label.set_use_underline(True) book_label.set_use_markup(True) avail_titles = [(_('Name'), 0, 230), (_('Type'), 1, 80), ('', -1, 0)] book_titles = [(_('Item name'), -1, 230), (_('Type'), -1, 80), ('', -1, 0), (_('Subject'), -1, 50)] self.avail_nr_cols = len(avail_titles) self.book_nr_cols = len(book_titles) self.avail_model = ListModel.ListModel(self.avail_tree, avail_titles) self.book_model = ListModel.ListModel(self.book_tree, book_titles) self.draw_avail_list() self.book = Book() def build_menu_names(self, obj): return (_("Book selection list"), self.title) def draw_avail_list(self): """ Draw the list with the selections available for the book. The selections are read from the book item registry. """ pmgr = GuiPluginManager.get_instance() regbi = pmgr.get_reg_bookitems() if not regbi: return available_reports = [] for pdata in regbi: category = _UNSUPPORTED if pdata.supported and pdata.category in book_categories: category = book_categories[pdata.category] available_reports.append([pdata.name, category, pdata.id]) for data in sorted(available_reports): new_iter = self.avail_model.add(data) self.avail_model.connect_model() if new_iter: self.avail_model.selection.select_iter(new_iter) path = self.avail_model.model.get_path(new_iter) col = self.avail_tree.get_column(0) self.avail_tree.scroll_to_cell(path, col, 1, 1, 0.0) def open_book(self, book): """ Open the book: set the current set of selections to this book's items. book: the book object to load. """ if book.get_dbname() == self.db.get_save_path(): same_db = 1 else: same_db = 0 WarningDialog( _('Different database'), _('This book was created with the references to database ' '%s.\n\n This makes references to the central person ' 'saved in the book invalid.\n\n' 'Therefore, the central person for each item is being set ' 'to the active person of the currently opened database.') % book.get_dbname()) self.book.clear() self.book_model.clear() for saved_item in book.get_item_list(): name = saved_item.get_name() item = BookItem(self.db, name) item.option_class = saved_item.option_class # The option values were loaded magically by the book parser. # But they still need to be applied to the menu options. opt_dict = item.option_class.handler.options_dict menu = item.option_class.menu for optname in opt_dict: menu_option = menu.get_option_by_name(optname) if menu_option: menu_option.set_value(opt_dict[optname]) _initialize_options(item.option_class, self.dbstate, self.uistate) item.set_style_name(saved_item.get_style_name()) self.book.append_item(item) data = [ item.get_translated_name(), item.get_category(), item.get_name() ] data[2] = _get_subject(item.option_class, self.db) self.book_model.add(data) def on_add_clicked(self, obj): """ Add an item to the current selections. Use the selected available item to get the item's name in the registry. """ store, the_iter = self.avail_model.get_selected() if not the_iter: return data = self.avail_model.get_data(the_iter, range(self.avail_nr_cols)) item = BookItem(self.db, data[2]) _initialize_options(item.option_class, self.dbstate, self.uistate) data[2] = _get_subject(item.option_class, self.db) self.book_model.add(data) self.book.append_item(item) def on_remove_clicked(self, obj): """ Remove the item from the current list of selections. """ store, the_iter = self.book_model.get_selected() if not the_iter: return row = self.book_model.get_selected_row() self.book.pop_item(row) self.book_model.remove(the_iter) def on_clear_clicked(self, obj): """ Clear the whole current book. """ self.book_model.clear() self.book.clear() def on_up_clicked(self, obj): """ Move the currently selected item one row up in the selection list. """ row = self.book_model.get_selected_row() if not row or row == -1: return store, the_iter = self.book_model.get_selected() data = self.book_model.get_data(the_iter, range(self.book_nr_cols)) self.book_model.remove(the_iter) self.book_model.insert(row - 1, data, None, 1) item = self.book.pop_item(row) self.book.insert_item(row - 1, item) def on_down_clicked(self, obj): """ Move the currently selected item one row down in the selection list. """ row = self.book_model.get_selected_row() if row + 1 >= self.book_model.count or row == -1: return store, the_iter = self.book_model.get_selected() data = self.book_model.get_data(the_iter, range(self.book_nr_cols)) self.book_model.remove(the_iter) self.book_model.insert(row + 1, data, None, 1) item = self.book.pop_item(row) self.book.insert_item(row + 1, item) def on_setup_clicked(self, obj): """ Configure currently selected item. """ store, the_iter = self.book_model.get_selected() if not the_iter: WarningDialog(_('No selected book item'), _('Please select a book item to configure.')) return data = self.book_model.get_data(the_iter, range(self.book_nr_cols)) row = self.book_model.get_selected_row() item = self.book.get_item(row) option_class = item.option_class option_class.handler.set_default_stylesheet_name(item.get_style_name()) item.is_from_saved_book = bool(self.book.get_name()) item_dialog = BookItemDialog(self.dbstate, self.uistate, item, self.track) while True: response = item_dialog.window.run() if response == gtk.RESPONSE_OK: # dialog will be closed by connect, now continue work while # rest of dialog is unresponsive, release when finished style = option_class.handler.get_default_stylesheet_name() item.set_style_name(style) subject = _get_subject(option_class, self.db) self.book_model.model.set_value(the_iter, 2, subject) self.book.set_item(row, item) item_dialog.close() break elif response == gtk.RESPONSE_CANCEL: item_dialog.close() break elif response == gtk.RESPONSE_DELETE_EVENT: #just stop, in ManagedWindow, delete-event is already coupled to #correct action. break def book_button_press(self, obj, event): """ Double-click on the current book selection is the same as setup. Right click evokes the context menu. """ if event.type == gtk.gdk._2BUTTON_PRESS and event.button == 1: self.on_setup_clicked(obj) elif gui.utils.is_right_click(event): self.build_book_context_menu(event) def avail_button_press(self, obj, event): """ Double-click on the available selection is the same as add. Right click evokes the context menu. """ if event.type == gtk.gdk._2BUTTON_PRESS and event.button == 1: self.on_add_clicked(obj) elif gui.utils.is_right_click(event): self.build_avail_context_menu(event) def build_book_context_menu(self, event): """Builds the menu with item-centered and book-centered options.""" store, the_iter = self.book_model.get_selected() if the_iter: sensitivity = 1 else: sensitivity = 0 entries = [ (gtk.STOCK_GO_UP, self.on_up_clicked, sensitivity), (gtk.STOCK_GO_DOWN, self.on_down_clicked, sensitivity), (_("Setup"), self.on_setup_clicked, sensitivity), (gtk.STOCK_REMOVE, self.on_remove_clicked, sensitivity), (None, None, 0), (gtk.STOCK_CLEAR, self.on_clear_clicked, 1), (gtk.STOCK_SAVE, self.on_save_clicked, 1), (gtk.STOCK_OPEN, self.on_open_clicked, 1), (_("Edit"), self.on_edit_clicked, 1), ] menu = gtk.Menu() menu.set_title(_('Book Menu')) for stock_id, callback, sensitivity in entries: item = gtk.ImageMenuItem(stock_id) if callback: item.connect("activate", callback) item.set_sensitive(sensitivity) item.show() menu.append(item) menu.popup(None, None, None, event.button, event.time) def build_avail_context_menu(self, event): """Builds the menu with the single Add option.""" store, the_iter = self.avail_model.get_selected() if the_iter: sensitivity = 1 else: sensitivity = 0 entries = [ (gtk.STOCK_ADD, self.on_add_clicked, sensitivity), ] menu = gtk.Menu() menu.set_title(_('Available Items Menu')) for stock_id, callback, sensitivity in entries: item = gtk.ImageMenuItem(stock_id) if callback: item.connect("activate", callback) item.set_sensitive(sensitivity) item.show() menu.append(item) menu.popup(None, None, None, event.button, event.time) def on_book_ok_clicked(self, obj): """ Run final BookReportDialog with the current book. """ if self.book.item_list: BookReportDialog(self.dbstate, self.uistate, self.book, BookOptions) else: WarningDialog(_('No items'), _('This book has no items.')) return self.close() def on_save_clicked(self, obj): """ Save the current book in the xml booklist file. """ self.book_list = BookList(self.file, self.db) name = unicode(self.name_entry.get_text()) if not name: WarningDialog( _('No book name'), _('You are about to save away a book with no name.\n\n' 'Please give it a name before saving it away.')) return if name in self.book_list.get_book_names(): from QuestionDialog import QuestionDialog2 q = QuestionDialog2( _('Book name already exists'), _('You are about to save away a ' 'book with a name which already exists.'), _('Proceed'), _('Cancel')) if q.run(): self.book.set_name(name) else: return else: self.book.set_name(name) self.book.set_dbname(self.db.get_save_path()) self.book_list.set_book(name, self.book) self.book_list.save() def on_open_clicked(self, obj): """ Run the BookListDisplay dialog to present the choice of books to open. """ self.book_list = BookList(self.file, self.db) booklistdisplay = BookListDisplay(self.book_list, 1, 0) booklistdisplay.top.destroy() book = booklistdisplay.selection if book: self.open_book(book) self.name_entry.set_text(book.get_name()) self.book.set_name(book.get_name()) def on_edit_clicked(self, obj): """ Run the BookListDisplay dialog to present the choice of books to delete. """ self.book_list = BookList(self.file, self.db) booklistdisplay = BookListDisplay(self.book_list, 0, 1) booklistdisplay.top.destroy()
class BookListDisplay(object): """ Interface into a dialog with the list of available books. Allows the user to select and/or delete a book from the list. """ def __init__(self, booklist, nodelete=0, dosave=0): """ Create a BookListDisplay object that displays the books in BookList. booklist: books that are displayed nodelete: if not 0 then the Delete button is hidden dosave: if 1 then the book list is saved on hitting OK """ self.booklist = booklist self.dosave = dosave self.xml = Glade() self.top = self.xml.toplevel self.unsaved_changes = False ManagedWindow.set_titles(self.top, self.xml.get_object('title'), _('Available Books')) if nodelete: delete_button = self.xml.get_object("delete_button") delete_button.hide() self.xml.connect_signals({ "on_booklist_cancel_clicked": self.on_booklist_cancel_clicked, "on_booklist_ok_clicked": self.on_booklist_ok_clicked, "on_booklist_delete_clicked": self.on_booklist_delete_clicked, "on_book_ok_clicked": self.do_nothing, "destroy_passed_object": self.do_nothing, "on_setup_clicked": self.do_nothing, "on_down_clicked": self.do_nothing, "on_up_clicked": self.do_nothing, "on_remove_clicked": self.do_nothing, "on_add_clicked": self.do_nothing, "on_edit_clicked": self.do_nothing, "on_open_clicked": self.do_nothing, "on_save_clicked": self.do_nothing, "on_clear_clicked": self.do_nothing }) title_label = self.xml.get_object('title') title_label.set_text(Utils.title(_('Book List'))) title_label.set_use_markup(True) self.blist = ListModel.ListModel( self.xml.get_object("list"), [('Name', -1, 10)], ) self.redraw() self.selection = None self.top.run() def redraw(self): """Redraws the list of currently available books""" self.blist.model.clear() names = self.booklist.get_book_names() if not len(names): return for name in names: the_iter = self.blist.add([name]) if the_iter: self.blist.selection.select_iter(the_iter) def on_booklist_ok_clicked(self, obj): """Return selected book. Saves the current list into xml file.""" store, the_iter = self.blist.get_selected() if the_iter: data = self.blist.get_data(the_iter, [0]) self.selection = self.booklist.get_book(unicode(data[0])) if self.dosave: self.booklist.save() def on_booklist_delete_clicked(self, obj): """ Deletes selected book from the list. This change is not final. OK button has to be clicked to save the list. """ store, the_iter = self.blist.get_selected() if not the_iter: return data = self.blist.get_data(the_iter, [0]) self.booklist.delete_book(unicode(data[0])) self.blist.remove(the_iter) self.unsaved_changes = True self.top.run() def on_booklist_cancel_clicked(self, obj): if self.unsaved_changes: from QuestionDialog import QuestionDialog2 q = QuestionDialog2( _('Discard Unsaved Changes'), _('You have made changes which have not been saved.'), _('Proceed'), _('Cancel')) if q.run(): return else: self.top.run() def do_nothing(self, object): pass
class DisplayChart(ManagedWindow.ManagedWindow): def __init__(self, dbstate, uistate, people_list, track): self.dbstate = dbstate self.uistate = uistate ManagedWindow.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 window.show() self.set_window(window, self.topDialog.get_object('title'), _('Event Comparison Results')) self.eventlist = self.topDialog.get_object('treeview') self.sort = Sort.Sort(self.db) self.my_list.sort(self.sort.by_last_name) 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""" GrampsDisplay.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'), '') 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 = DateHandler.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.iteritems()], by_value) 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"), action=gtk.FILE_CHOOSER_ACTION_SAVE, buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE, gtk.RESPONSE_OK)) f.set_current_folder(os.getcwd()) status = f.run() f.hide() if status == gtk.RESPONSE_OK: name = Utils.get_unicode_path_from_file_chooser(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 EventComparison(tool.Tool, ManagedWindow.ManagedWindow): def __init__(self, dbstate, uistate, options_class, name, callback=None): self.dbstate = dbstate self.uistate = uistate tool.Tool.__init__(self, dbstate, options_class, name) ManagedWindow.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 window.show() 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""" GrampsDisplay.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', const.CUSTOM_FILTERS, self.dbstate, self.uistate) except Errors.WindowActiveError: pass def on_apply_clicked(self, obj): cfilter = self.filter_model[self.filters.get_active()][1] progress_bar = ProgressMeter(_('Comparing events'), '') 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")) else: DisplayChart(self.dbstate, self.uistate, plist, self.track)
class ExtractCity(tool.BatchTool, ManagedWindow.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, uistate, options_class, name, callback=None): self.label = _('Extract Place data') ManagedWindow.ManagedWindow.__init__(self, uistate, [], self.__class__) self.set_window(gtk.Window(), gtk.Label(), '') tool.BatchTool.__init__(self, dbstate, uistate, 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 = [] for place in db.iter_places(): descr = place.get_title() loc = place.get_main_location() self.progress.step() if loc.get_street() == loc.get_city() == \ loc.get_state() == loc.get_postal_code() == "": 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 QuestionDialog 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.get_title() 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""" GrampsDisplay.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]) (city, state, postal, country) = (row[2], row[3], row[4], row[5]) if city: place.get_main_location().set_city(city) if state: place.get_main_location().set_state(state) if postal: place.get_main_location().set_postal_code(postal) if country: place.get_main_location().set_country(country) self.db.commit_place(place, self.trans) self.db.enable_signals() self.db.request_rebuild() self.close()
class Leak(tool.Tool, ManagedWindow.ManagedWindow): def __init__(self,dbstate, uistate, options_class, name, callback=None): self.title = _('Uncollected Objects Tool') tool.Tool.__init__(self,dbstate, options_class, name) ManagedWindow.ManagedWindow.__init__(self,uistate,[],self.__class__) self.glade = Glade() self.window = self.glade.toplevel self.scroll = self.glade.get_object("scrolledwindow1") #add a listview to the scrollable self.list = gtk.TreeView() self.list.set_headers_visible(True) self.list.connect('button-press-event', self._button_press) self.scroll.add(self.list) #make a model self.modeldata = [] self.model = gtk.ListStore(int, str) self.list.set_model(self.model) #set the colums self.renderer = gtk.CellRendererText() column = gtk.TreeViewColumn(_('Number'), self.renderer, text=0) column.set_resizable(True) column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) self.list.append_column(column) column = gtk.TreeViewColumn(_('Uncollected object'), self.renderer, text=1) column.set_resizable(True) column.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE) self.list.append_column(column) self.selection = self.list.get_selection() gc.set_debug(gc.DEBUG_UNCOLLECTABLE|gc.DEBUG_OBJECTS|gc.DEBUG_SAVEALL) self.set_window(self.window, self.glade.get_object('title'), self.title) self.glade.connect_signals({ "on_apply_clicked" : self.apply_clicked, "on_close_clicked" : self.close, "on_delete_event" : self.close, }) self.display() self.show() def build_menu_names(self, obj): return (self.title,None) def _button_press(self, obj, event): if event.type == gtk.gdk._2BUTTON_PRESS and event.button == 1: self.referenced_in() return True elif gui.utils.is_right_click(event): self.refers_to() return True def referenced_in(self): model, iter = self.selection.get_selected() if iter is not None: count = model.get_value(iter, 0) referrers = gc.get_referrers(self.modeldata[count]) text = "" for referrer in referrers: text += str(referrer) + '\n' InfoDialog(_('Referrers of %d') % count, text, parent=self.window) def refers_to(self): model, iter = self.selection.get_selected() if iter is not None: count = model.get_value(iter, 0) referents = gc.get_referents(self.modeldata[count]) text = "" for referent in referents: text += str(referent) + '\n' InfoDialog(_('%d refers to') % count, text, parent=self.window) def display(self): gc.collect(2) self.model.clear() count = 0 if len(gc.garbage): for each in gc.garbage: try: self.modeldata.append(each) self.model.append((count, str(each))) except DBError: self.modeldata.append(each) self.model.append((count, 'db.DB instance at %s' % id(each))) count += 1 self.glade.get_object('label2').set_text(_('Uncollected Objects: %s') % str(len(gc.garbage))) def apply_clicked(self, obj): self.display()
class StyleListDisplay(object): """ Shows the available paragraph/font styles. Allows the user to select, add, edit, and delete styles from a StyleSheet. """ def __init__(self, stylesheetlist, callback, parent_window): """ Create a StyleListDisplay object that displays the styles in the StyleSheet. stylesheetlist - styles that can be editied callback - task called with an object has been added. """ self.callback = callback self.sheetlist = stylesheetlist self.top = Glade(toplevel='styles') self.window = self.top.toplevel ManagedWindow.set_titles(self.window, self.top.get_object('title'), _('Document Styles')) self.top.connect_signals({ "destroy_passed_object": self.__close, "on_ok_clicked": self.on_ok_clicked, "on_add_clicked": self.on_add_clicked, "on_delete_clicked": self.on_delete_clicked, "on_button_press": self.on_button_press, "on_edit_clicked": self.on_edit_clicked, "on_save_style_clicked": dummy_callback, }) title_label = self.top.get_object('title') title_label.set_text(Utils.title(_('Style Editor'))) title_label.set_use_markup(True) self.list = ListModel.ListModel( self.top.get_object("list"), [(_('Style'), -1, 10)], ) self.redraw() if parent_window: self.window.set_transient_for(parent_window) self.window.run() self.window.destroy() def __close(self, obj): self.top.destroy() def redraw(self): """Redraws the list of styles that are current available""" self.list.model.clear() self.list.add([_("default")]) index = 1 for style in self.sheetlist.get_style_names(): if style == "default": continue self.list.add([style]) index += 1 def on_add_clicked(self, obj): """Called with the ADD button is clicked. Invokes the StyleEditor to create a new style""" style = self.sheetlist.get_style_sheet("default") StyleEditor(_("New Style"), style, self) def on_ok_clicked(self, obj): """Called with the OK button is clicked; Calls the callback task, then saves the stylesheet.""" if self.callback is not None: self.callback() try: self.sheetlist.save() except IOError, msg: from QuestionDialog import ErrorDialog ErrorDialog(_("Error saving stylesheet"), str(msg)) except:
class StyleEditor(object): """ Edits the current style definition. Presents a dialog allowing the values of the paragraphs in the style to be altered. """ def __init__(self, name, style, parent): """ Create the StyleEditor. name - name of the style that is to be edited style - style object that is to be edited parent - StyleListDisplay object that called the editor """ self.current_p = None self.current_name = None self.style = StyleSheet(style) self.parent = parent self.top = Glade(toplevel='editor') self.window = self.top.toplevel self.top.connect_signals({ "on_save_style_clicked": self.on_save_style_clicked, "destroy_passed_object": self.__close, "on_ok_clicked": dummy_callback, "on_add_clicked": dummy_callback, "on_delete_clicked": dummy_callback, "on_button_press": dummy_callback, "on_edit_clicked": dummy_callback, }) self.pname = self.top.get_object('pname') self.pdescription = self.top.get_object('pdescription') ManagedWindow.set_titles(self.window, self.top.get_object('title'), _('Style editor')) self.top.get_object("label6").set_text(_("point size|pt")) titles = [(_('Paragraph'), 0, 130)] self.plist = ListModel.ListModel(self.top.get_object("ptree"), titles, self.change_display) self.top.get_object('color').connect('color-set', self.fg_color_set) self.top.get_object('bgcolor').connect('color-set', self.bg_color_set) self.top.get_object("style_name").set_text(name) names = self.style.get_paragraph_style_names() names.reverse() for p_name in names: self.plist.add([p_name], self.style.get_paragraph_style(p_name)) self.plist.select_row(0) if self.parent: self.window.set_transient_for(parent.window) self.window.run() self.window.destroy() def __close(self, obj): self.window.destroy() def draw(self): """Updates the display with the selected paragraph.""" p = self.current_p self.pname.set_text('<span size="larger" weight="bold">%s</span>' % self.current_name) self.pname.set_use_markup(True) descr = p.get_description() self.pdescription.set_text(descr or _("No description available")) font = p.get_font() self.top.get_object("size").set_value(font.get_size()) if font.get_type_face() == FONT_SERIF: self.top.get_object("roman").set_active(1) else: self.top.get_object("swiss").set_active(1) self.top.get_object("bold").set_active(font.get_bold()) self.top.get_object("italic").set_active(font.get_italic()) self.top.get_object("underline").set_active(font.get_underline()) if p.get_alignment() == PARA_ALIGN_LEFT: self.top.get_object("lalign").set_active(1) elif p.get_alignment() == PARA_ALIGN_RIGHT: self.top.get_object("ralign").set_active(1) elif p.get_alignment() == PARA_ALIGN_CENTER: self.top.get_object("calign").set_active(1) else: self.top.get_object("jalign").set_active(1) self.top.get_object("rmargin").set_value(p.get_right_margin()) self.top.get_object("lmargin").set_value(p.get_left_margin()) self.top.get_object("pad").set_value(p.get_padding()) self.top.get_object("tmargin").set_value(p.get_top_margin()) self.top.get_object("bmargin").set_value(p.get_bottom_margin()) self.top.get_object("indent").set_value(p.get_first_indent()) self.top.get_object("tborder").set_active(p.get_top_border()) self.top.get_object("lborder").set_active(p.get_left_border()) self.top.get_object("rborder").set_active(p.get_right_border()) self.top.get_object("bborder").set_active(p.get_bottom_border()) self.fg_color = font.get_color() c = Color(self.fg_color[0] << 8, self.fg_color[1] << 8, self.fg_color[2] << 8) self.top.get_object("color").set_color(c) self.top.get_object('color_code').set_text("#%02X%02X%02X" % self.fg_color) self.bg_color = p.get_background_color() c = Color(self.bg_color[0] << 8, self.bg_color[1] << 8, self.bg_color[2] << 8) self.top.get_object("bgcolor").set_color(c) self.top.get_object('bgcolor_code').set_text("#%02X%02X%02X" % self.bg_color) def bg_color_set(self, x): c = x.get_color() self.bg_color = (c.red >> 8, c.green >> 8, c.blue >> 8) self.top.get_object('bgcolor_code').set_text("#%02X%02X%02X" % self.bg_color) def fg_color_set(self, x): c = x.get_color() self.fg_color = (c.red >> 8, c.green >> 8, c.blue >> 8) self.top.get_object('color_code').set_text("#%02X%02X%02X" % self.fg_color) def save_paragraph(self): """Saves the current paragraph displayed on the dialog""" p = self.current_p font = p.get_font() font.set_size(self.top.get_object("size").get_value_as_int()) if self.top.get_object("roman").get_active(): font.set_type_face(FONT_SERIF) else: font.set_type_face(FONT_SANS_SERIF) font.set_bold(self.top.get_object("bold").get_active()) font.set_italic(self.top.get_object("italic").get_active()) font.set_underline(self.top.get_object("underline").get_active()) if self.top.get_object("lalign").get_active(): p.set_alignment(PARA_ALIGN_LEFT) elif self.top.get_object("ralign").get_active(): p.set_alignment(PARA_ALIGN_RIGHT) elif self.top.get_object("calign").get_active(): p.set_alignment(PARA_ALIGN_CENTER) else: p.set_alignment(PARA_ALIGN_JUSTIFY) p.set_right_margin(self.top.get_object("rmargin").get_value()) p.set_left_margin(self.top.get_object("lmargin").get_value()) p.set_top_margin(self.top.get_object("tmargin").get_value()) p.set_bottom_margin(self.top.get_object("bmargin").get_value()) p.set_padding(self.top.get_object("pad").get_value()) p.set_first_indent(self.top.get_object("indent").get_value()) p.set_top_border(self.top.get_object("tborder").get_active()) p.set_left_border(self.top.get_object("lborder").get_active()) p.set_right_border(self.top.get_object("rborder").get_active()) p.set_bottom_border(self.top.get_object("bborder").get_active()) font.set_color(self.fg_color) p.set_background_color(self.bg_color) self.style.add_paragraph_style(self.current_name, self.current_p) def on_save_style_clicked(self, obj): """ Saves the current style sheet and causes the parent to be updated with the changes. """ name = unicode(self.top.get_object("style_name").get_text()) self.save_paragraph() self.style.set_name(name) self.parent.sheetlist.set_style_sheet(name, self.style) self.parent.redraw() self.window.destroy() def change_display(self, obj): """Called when the paragraph selection has been changed. Saves the old paragraph, then draws the newly selected paragraph""" # Don't save until current_name is defined # If it's defined, save under the current paragraph name if self.current_name: self.save_paragraph() # Then change to new paragraph objs = self.plist.get_selected_objects() store, node = self.plist.get_selected() self.current_name = store.get_value(node, 0) self.current_p = objs[0] self.draw()
def __init__(self, dbstate, uistate, options_class, name, callback=None): 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.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_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')) # 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.TREE_VIEW_COLUMN_AUTOSIZE) col2.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE) col3.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE) col4.set_sizing(gtk.TREE_VIEW_COLUMN_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.SELECTION_MULTIPLE) self.treeSelection.set_select_function(self.selectIsAllowed, full=True) 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.SORT_ASCENDING) self.treeView.set_model(self.model) # self.treeView.set_row_separator_func(self.iterIsSeparator) self.treeView.expand_all() # done searching through the database, so close the progress bar self.progress.close() self.show()
class PatchNames(tool.BatchTool, ManagedWindow.ManagedWindow): titleid = 1 nickid = 2 pref1id = 3 compid = 4 def __init__(self, dbstate, uistate, options_class, name, callback=None): self.label = _('Name and title extraction tool') ManagedWindow.ManagedWindow.__init__(self, uistate, [], self.__class__) self.set_window(gtk.Window(), gtk.Label(), '') tool.BatchTool.__init__(self, dbstate, uistate, options_class, name) if self.fail: return winprefix = gtk.Dialog( _("Default prefix and connector settings"), self.uistate.window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_OK, gtk.RESPONSE_ACCEPT)) winprefix.set_has_separator(False) winprefix.vbox.set_spacing(5) hboxpref = gtk.HBox() hboxpref.pack_start(gtk.Label(_('Prefixes to search for:')), expand=False, padding=5) self.prefixbox = gtk.Entry() self.prefixbox.set_text(', '.join(PREFIX_LIST)) hboxpref.pack_start(self.prefixbox) winprefix.vbox.pack_start(hboxpref) hboxcon = gtk.HBox() hboxcon.pack_start(gtk.Label(_('Connectors splitting surnames:')), expand=False, padding=5) self.conbox = gtk.Entry() self.conbox.set_text(', '.join(CONNECTOR_LIST)) hboxcon.pack_start(self.conbox) winprefix.vbox.pack_start(hboxcon) hboxconns = gtk.HBox() hboxconns.pack_start(gtk.Label( _('Connectors not splitting surnames:')), expand=False, padding=5) self.connsbox = gtk.Entry() self.connsbox.set_text(', '.join(CONNECTOR_LIST_NONSPLIT)) hboxconns.pack_start(self.connsbox) winprefix.vbox.pack_start(hboxconns) winprefix.show_all() winprefix.resize(700, 100) response = winprefix.run() self.prefix_list = self.prefixbox.get_text().split(',') self.prefix_list = map(strip, self.prefix_list) self.prefixbox = None self.connector_list = self.conbox.get_text().split(',') self.connector_list = map(strip, self.connector_list) self.conbox = None self.connector_list_nonsplit = self.connsbox.get_text().split(',') self.connector_list_nonsplit = map(strip, self.connector_list_nonsplit) self.connsbox = None # Find a prefix in the first_name self._fn_prefix_re = re.compile( "(\S+)\s+(%s)\s*$" % '|'.join(self.prefix_list), re.IGNORECASE) # Find a prefix in the surname self._sn_prefix_re = re.compile( "^\s*(%s)\s+(.+)" % '|'.join(self.prefix_list), re.IGNORECASE) # Find a connector in the surname self._sn_con_re = re.compile( "^\s*(.+)\s+(%s)\s+(.+)" % '|'.join(self.connector_list), re.IGNORECASE) winprefix.destroy() self.cb = callback self.handle_to_action = {} self.progress = ProgressMeter(_('Extracting Information from Names'), '') 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 = map(strip, prefixes) surnames = map(strip, surnames) primaries = [False] * len(prefixes) primaries[0] = True origs = [] for ind in range(len(prefixes)): origs.append(gen.lib.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 = gen.lib.NameOriginType() ind += 1 if found: compoundval = (new_surname_list, new_prefix_list, new_connector_list, new_prim_list, new_orig_list) if key in self.handle_to_action: self.handle_to_action[key][self.compid] = compoundval else: self.handle_to_action[key] = {self.compid: compoundval} self.progress.step() if self.handle_to_action: self.display() else: self.progress.close() self.close() OkDialog(_('No modifications made'), _("No titles, nicknames or prefixes were found")) 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(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""" GrampsDisplay.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(gen.lib.Surname()) new_surn_list[-1].set_surname(surn.strip()) new_surn_list[-1].set_prefix(pref.strip()) new_surn_list[-1].set_connector(con.strip()) new_surn_list[-1].set_primary(prim) new_surn_list[-1].set_origintype(orig) name.set_surname_list(new_surn_list) self.db.commit_person(p, trans) self.db.enable_signals() self.db.request_rebuild() self.close() self.cb()
class DesBrowse(tool.ActivePersonTool, ManagedWindow.ManagedWindow): def __init__(self, dbstate, uistate, options_class, name, callback=None): tool.ActivePersonTool.__init__(self, dbstate, uistate, options_class, name) if self.fail: return self.dbstate = dbstate active_handle = uistate.get_active('Person') self.active = dbstate.db.get_person_from_handle(active_handle) self.callback = callback self.active_name = _("Descendant Browser: %s") % ( name_displayer.display(self.active) ) ManagedWindow.ManagedWindow.__init__(self, uistate, [], self) self.glade = Glade() self.glade.connect_signals({ "destroy_passed_object" : self.close, "on_help_clicked" : self.on_help_clicked, "on_delete_event" : self.close, }) window = self.glade.toplevel self.set_window(window,self.glade.get_object('title'), self.active_name) self.tree = self.glade.get_object("tree1") col = gtk.TreeViewColumn('',gtk.CellRendererText(),text=0) self.tree.append_column(col) self.tree.set_rules_hint(True) self.tree.set_headers_visible(False) self.tree.connect('event',self.button_press_event) self.make_new_model() self.show() def build_menu_names(self, obj): return (self.active_name,_("Descendant Browser tool")) def make_new_model(self): self.model = gtk.TreeStore(str, object) self.tree.set_model(self.model) self.add_to_tree(None, None, self.active.get_handle()) self.tree.expand_all() def on_help_clicked(self, obj): """Display the relevant portion of GRAMPS manual""" GrampsDisplay.help(webpage=WIKI_HELP_PAGE, section=WIKI_HELP_SEC) def add_to_tree(self, parent_id, sib_id, person_handle): item_id = self.model.insert_after(parent_id, sib_id) person = self.db.get_person_from_handle(person_handle) self.model.set(item_id, 0, name_displayer.display(person)) self.model.set(item_id, 1, person_handle) prev_id = None for family_handle in person.get_family_handle_list(): family = self.db.get_family_from_handle(family_handle) for child_ref in family.get_child_ref_list(): prev_id = self.add_to_tree(item_id, prev_id, child_ref.ref) return item_id def button_press_event(self, obj,event): if event.type == gtk.gdk._2BUTTON_PRESS and event.button == 1: store, node = self.tree.get_selection().get_selected() if node: person_handle = store.get_value(node, 1) person = self.db.get_person_from_handle(person_handle) EditPerson(self.dbstate, self.uistate, self.track, person, self.this_callback) def this_callback(self, obj): self.callback() self.make_new_model()
class ChangeTypes(tool.BatchTool, ManagedWindow.ManagedWindow): def __init__(self, dbstate, uistate, options_class, name, callback=None): tool.BatchTool.__init__(self, dbstate, uistate, options_class, name) if self.fail: return if uistate: self.title = _('Change Event Types') ManagedWindow.ManagedWindow.__init__(self, uistate, [], self.__class__) self.init_gui() else: self.run_tool(cli=True) 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=locale.strxfrm) AutoComp.fill_combo(self.auto1, event_names) AutoComp.fill_combo(self.auto2, event_names) etype.set_from_xml_str(self.options.handler.options_dict['fromtype']) self.auto1.child.set_text(str(etype)) etype.set_from_xml_str(self.options.handler.options_dict['totype']) self.auto2.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, cli=False): # 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() if not cli: progress = ProgressMeter(_('Analyzing Events'), '') progress.set_pass('', self.db.get_number_of_events()) 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) if not cli: progress.step() if not cli: progress.close() self.db.enable_signals() self.db.request_rebuild() if modified == 0: msg = _("No event record was modified.") else: msg = ngettext("%d event record was modified.", "%d event records were modified.", modified) % modified if cli: print "Done: ", msg 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.child.get_text()) self.options.handler.options_dict['fromtype'] = the_type.xml_str() the_type.set(self.auto2.child.get_text()) self.options.handler.options_dict['totype'] = the_type.xml_str() modified, msg = self.run_tool(cli=False) OkDialog(_('Change types'), msg, self.window) # Save options self.options.handler.save_options() self.close()