def applyTagClicked(self, button): progress = None rows = self.treeSelection.count_selected_rows() tag_name = unicode(self.tagcombo.get_active_text()) # start the db transaction with DbTxn("Tag not related", self.db) as transaction: tag = self.db.get_tag_from_name(tag_name) if not tag: # create the tag if it doesn't already exist tag = Tag() tag.set_name(tag_name) tag.set_priority(self.db.get_number_of_tags()) tag_handle = self.db.add_tag(tag, transaction) else: tag_handle = tag.get_handle() # if more than 1 person is selected, use a progress indicator if rows > 1: progress = ProgressMeter(self.title, _('Starting')) #TRANS: no singular form needed, as rows is always > 1 progress.set_pass( ngettext("Setting tag for %d person", "Setting tag for %d people", rows) % rows, rows) # iterate through all of the selected rows (model, paths) = self.treeSelection.get_selected_rows() for path in paths: if progress: progress.step() # for the current row, get the GID and the person from the database iter = self.model.get_iter(path) personGid = self.model.get_value(iter, 1) person = self.db.get_person_from_gramps_id(personGid) # add the tag to the person person.add_tag(tag_handle) # save this change self.db.commit_person(person, transaction) # refresh the tags column self.treeView.set_model(None) for path in paths: iter = self.model.get_iter(path) personGid = self.model.get_value(iter, 1) person = self.db.get_person_from_gramps_id(personGid) self.model.set_value(iter, 3, self.get_tag_list(person)) self.treeView.set_model(self.model) self.treeView.expand_all() if progress: progress.close()
def __get_addon_top(self, obj): """ Toplevel method to get an addon. """ from gui.utils import ProgressMeter pm = ProgressMeter(_("Installing Addon"), message_area=True) pm.set_pass(total=2, header=_("Reading gramps-project.org...")) pm.step() self.__get_addon(obj, callback=pm.append_message) pm.step() pm.message_area_ok.set_sensitive(True)
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)
def prepare(self, db): root_person_id = self.list[0] root_person = db.get_person_from_gramps_id(root_person_id) progress = ProgressMeter(_('Finding relationship paths')) progress.set_pass(header=_('Evaluating people'), mode=ProgressMeter.MODE_ACTIVITY) filter_name = self.list[1] target_people = filter_database(db, progress, filter_name) paths = find_deep_relations(db, progress, root_person, [], [], target_people) progress.close() progress = None self.__matches = set() map(self.__matches.update, paths)
def __get_all_addons(self, obj): """ Get all addons from the wiki and install them. """ import urllib from gui.utils import ProgressMeter pm = ProgressMeter(_("Install all Addons"), _("Installing..."), message_area=True) pm.set_pass(total=len(self.addon_model)) for row in self.addon_model: pm.step() (help_name, name, ptype, image, desc, use, rating, contact, download, url) = row load_addon_file(url, callback=pm.append_message) self.uistate.viewmanager.do_reg_plugins(self.dbstate, self.uistate) pm.message_area_ok.set_sensitive(True) self.__rebuild_load_list() self.__rebuild_reg_list()
def parse(self, filehandle): """ Prepare the database and parse the input file. :param filehandle: open file handle positioned at start of the file """ data = self.read_csv(filehandle) progress = ProgressMeter(_('CSV Import')) progress.set_pass(_('Reading data...'), 1) progress.set_pass(_('Importing data...'), len(data)) tym = time.time() self.db.disable_signals() with DbTxn(_("CSV import"), self.db, batch=True) as self.trans: self._parse_csv_data(data, progress) self.db.enable_signals() self.db.request_rebuild() tym = time.time() - tym msg = ngettext('Import Complete: %d second', 'Import Complete: %d seconds', tym ) % tym LOG.debug(msg) LOG.debug("New Families: %d" % self.fam_count) LOG.debug("New Individuals: %d" % self.indi_count) progress.close()
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)
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 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 MergeCitations(tool.BatchTool,ManagedWindow.ManagedWindow): def __init__(self, dbstate, uistate, options_class, name, callback=None): ManagedWindow.ManagedWindow.__init__(self, uistate, [], self.__class__) self.dbstate = dbstate 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() uistate.set_busy_cursor(False) 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() def cancel(self, obj): """ on cancel, update the saved values of the options. """ fields = self.menu.get_model()[self.menu.get_active()][1] dont_merge_notes = int(self.notes_obj.get_active()) LOG.debug("cancel fields %d dont_merge_notes %d" % (fields, dont_merge_notes)) self.options.handler.options_dict['fields'] = fields self.options.handler.options_dict['dont_merge_notes'] = dont_merge_notes # Save options self.options.handler.save_options() self.close(obj) def build_menu_names(self, obj): return (_("Tool settings"),_("Merge citations tool")) def on_help_clicked(self, obj): """Display the relevant portion of GRAMPS manual""" GrampsDisplay.help(WIKI_HELP_PAGE , WIKI_HELP_SEC) def on_merge_ok_clicked(self, obj): """ Performs the actual merge of citations (Derived from ExtractCity) """ fields = self.menu.get_model()[self.menu.get_active()][1] dont_merge_notes = int(self.notes_obj.get_active()) LOG.debug("fields %d dont_merge_notes %d" % (fields, dont_merge_notes)) self.options.handler.options_dict['fields'] = fields self.options.handler.options_dict['dont_merge_notes'] = dont_merge_notes # Save options self.options.handler.save_options() self.progress = ProgressMeter(_('Checking Sources'), '') self.progress.set_pass(_('Looking for citation fields'), self.db.get_number_of_citations()) db = self.dbstate.db db.disable_signals() num_merges = 0 for handle in db.iter_source_handles(): dict = {} citation_handle_list = list(db.find_backlink_handles(handle)) for (class_name, citation_handle) in citation_handle_list: if class_name <> Citation.__name__: raise MergeError("Encountered an object of type %s " "that has a citation reference." % class_name) citation = db.get_citation_from_handle(citation_handle) key = citation.get_page() if fields <> IGNORE_DATE and fields <> IGNORE_BOTH: key += "\n" + DateHandler.get_date(citation) if fields <> IGNORE_CONFIDENCE and fields <> IGNORE_BOTH: key += "\n" + \ confidence[citation.get_confidence_level()] if key in dict and \ (not dont_merge_notes or len(citation.note_list) == 0): citation_match_handle = dict[key] citation_match = \ db.get_citation_from_handle(citation_match_handle) try: query = MergeCitationQuery( self.dbstate, citation_match, citation) query.execute() except AssertionError: print "Tool/Family Tree processing/MergeCitations", \ "citation1 gramps_id", citation_match.get_gramps_id(), \ "citation2 gramps_id", citation.get_gramps_id() , \ "citation backlink handles", \ list(db.find_backlink_handles(citation.get_handle())) num_merges += 1 elif (not dont_merge_notes or len(citation.note_list) == 0): dict[key] = citation_handle self.progress.step() db.enable_signals() db.request_rebuild() self.progress.close() OkDialog( _("Number of merges done"), ngettext("%(num)d citation merged", "%(num)d citations merged", num_merges) % {'num': num_merges}) self.close(obj)
class ReorderIds(tool.BatchTool): def __init__(self, dbstate, uistate, options_class, name, callback=None): tool.BatchTool.__init__(self, dbstate, uistate, options_class, name) if self.fail: return db = dbstate.db self.uistate = uistate if uistate: self.progress = ProgressMeter(_('Reordering Gramps IDs'), '') else: print "Reordering Gramps IDs..." with DbTxn(_("Reorder Gramps IDs"), db, batch=True) as self.trans: db.disable_signals() if uistate: self.progress.set_pass(_('Reordering People IDs'), db.get_number_of_people()) self.reorder(gen.lib.Person, db.get_person_from_gramps_id, db.get_person_from_handle, db.find_next_person_gramps_id, db.person_map, db.commit_person, db.person_prefix) if uistate: self.progress.set_pass(_('Reordering Family IDs'), db.get_number_of_families()) self.reorder(gen.lib.Family, db.get_family_from_gramps_id, db.get_family_from_handle, db.find_next_family_gramps_id, db.family_map, db.commit_family, db.family_prefix) if uistate: self.progress.set_pass(_('Reordering Event IDs'), db.get_number_of_events()) self.reorder(gen.lib.Event, db.get_event_from_gramps_id, db.get_event_from_handle, db.find_next_event_gramps_id, db.event_map, db.commit_event, db.event_prefix) if uistate: self.progress.set_pass(_('Reordering Media Object IDs'), db.get_number_of_media_objects()) self.reorder(gen.lib.MediaObject, db.get_object_from_gramps_id, db.get_object_from_handle, db.find_next_object_gramps_id, db.media_map, db.commit_media_object, db.mediaobject_prefix) if uistate: self.progress.set_pass(_('Reordering Source IDs'), db.get_number_of_sources()) self.reorder(gen.lib.Source, db.get_source_from_gramps_id, db.get_source_from_handle, db.find_next_source_gramps_id, db.source_map, db.commit_source, db.source_prefix) if uistate: self.progress.set_pass(_('Reordering Citation IDs'), db.get_number_of_citations()) self.reorder(gen.lib.Citation, db.get_citation_from_gramps_id, db.get_citation_from_handle, db.find_next_citation_gramps_id, db.citation_map, db.commit_citation, db.citation_prefix) if uistate: self.progress.set_pass(_('Reordering Place IDs'), db.get_number_of_places()) self.reorder(gen.lib.Place, db.get_place_from_gramps_id, db.get_place_from_handle, db.find_next_place_gramps_id, db.place_map, db.commit_place, db.place_prefix) if uistate: self.progress.set_pass(_('Reordering Repository IDs'), db.get_number_of_repositories()) self.reorder(gen.lib.Repository, db.get_repository_from_gramps_id, db.get_repository_from_handle, db.find_next_repository_gramps_id, db.repository_map, db.commit_repository, db.repository_prefix) #add reorder notes ID if uistate: self.progress.set_pass(_('Reordering Note IDs'), db.get_number_of_notes()) self.reorder(gen.lib.Note, db.get_note_from_gramps_id, db.get_note_from_handle, db.find_next_note_gramps_id, db.note_map, db.commit_note, db.note_prefix) if uistate: self.progress.close() else: print "Done." db.enable_signals() db.request_rebuild() def reorder(self, class_type, find_from_id, find_from_handle, find_next_id, table, commit, prefix): dups = [] newids = {} formatmatch = _parseformat.match(prefix) for handle in table.keys(): if self.uistate: self.progress.step() sdata = table[handle] obj = class_type() obj.unserialize(sdata) gramps_id = obj.get_gramps_id() # attempt to extract integer, if we can't, treat it as a # duplicate try: match = _findint.match(gramps_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 = match.groups()[0] if formatmatch: if int(index) > int( "9" * int(formatmatch.groups()[0])): newgramps_id = find_next_id() else: newgramps_id = prefix % int(index) else: # the prefix does not contain a number after %, eg I%d newgramps_id = prefix % int(index) if newgramps_id == gramps_id: if newgramps_id in newids: dups.append(obj.get_handle()) else: newids[newgramps_id] = gramps_id elif find_from_id(newgramps_id) is not None: dups.append(obj.get_handle()) else: obj.set_gramps_id(newgramps_id) commit(obj, self.trans) newids[newgramps_id] = gramps_id else: dups.append(handle) except: dups.append(handle) # go through the duplicates, looking for the first available # handle that matches the new scheme. if self.uistate: self.progress.set_pass(_('Finding and assigning unused IDs'), len(dups)) for handle in dups: if self.uistate: self.progress.step() obj = find_from_handle(handle) obj.set_gramps_id(find_next_id()) commit(obj, self.trans)
class NotRelated(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: # 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() def iterIsSeparator(self, model, iter): # return True only if the row is to be treated as a separator if self.model.get_value(iter, 1) == '': # does the row have a GID? return True return False def selectIsAllowed(self, selection, model, path, isSelected): # return True/False depending on if the row being selected is a leaf node iter = self.model.get_iter(path) if self.model.get_value(iter, 1) == '': # does the row have a GID? return False return True def rowSelectionChanged(self, selection): state = selection.count_selected_rows() > 0 self.tagcombo.set_sensitive(state) self.tagapply.set_sensitive(state) def rowActivated(self, treeView, path, column): # first we need to check that the row corresponds to a person iter = self.model.get_iter(path) personGid = self.model.get_value(iter, 1) familyGid = self.model.get_value(iter, 4) if familyGid != '': # do we have a family? # get the parent family for this person family = self.db.get_family_from_gramps_id(familyGid) if family: try: EditFamily(self.dbstate, self.uistate, [], family) except Errors.WindowActiveError: pass elif personGid != '': # do we have a person? # get the person that corresponds to this GID person = self.db.get_person_from_gramps_id(personGid) if person: try: EditPerson(self.dbstate, self.uistate, [], person) except Errors.WindowActiveError: pass def on_help_clicked(self, obj): """Display the relevant portion of GRAMPS manual""" GrampsDisplay.help(WIKI_HELP_PAGE, WIKI_HELP_SEC) def applyTagClicked(self, button): progress = None rows = self.treeSelection.count_selected_rows() tag_name = unicode(self.tagcombo.get_active_text()) # start the db transaction with DbTxn("Tag not related", self.db) as transaction: tag = self.db.get_tag_from_name(tag_name) if not tag: # create the tag if it doesn't already exist tag = Tag() tag.set_name(tag_name) tag.set_priority(self.db.get_number_of_tags()) tag_handle = self.db.add_tag(tag, transaction) else: tag_handle = tag.get_handle() # if more than 1 person is selected, use a progress indicator if rows > 1: progress = ProgressMeter(self.title, _('Starting')) #TRANS: no singular form needed, as rows is always > 1 progress.set_pass( ngettext("Setting tag for %d person", "Setting tag for %d people", rows) % rows, rows) # iterate through all of the selected rows (model, paths) = self.treeSelection.get_selected_rows() for path in paths: if progress: progress.step() # for the current row, get the GID and the person from the database iter = self.model.get_iter(path) personGid = self.model.get_value(iter, 1) person = self.db.get_person_from_gramps_id(personGid) # add the tag to the person person.add_tag(tag_handle) # save this change self.db.commit_person(person, transaction) # refresh the tags column self.treeView.set_model(None) for path in paths: iter = self.model.get_iter(path) personGid = self.model.get_value(iter, 1) person = self.db.get_person_from_gramps_id(personGid) self.model.set_value(iter, 3, self.get_tag_list(person)) self.treeView.set_model(self.model) self.treeView.expand_all() if progress: progress.close() def findRelatedPeople(self): #TRANS: No singular form is needed. self.progress.set_pass( ngettext("Finding relationships between %d person", "Finding relationships between %d people", self.numberOfPeopleInDatabase) % self.numberOfPeopleInDatabase, self.numberOfPeopleInDatabase) # as long as we have people we haven't processed yet, keep looping while len(self.handlesOfPeopleToBeProcessed) > 0: handle = self.handlesOfPeopleToBeProcessed.pop() ### DEBUG DEBUG DEBUG # if len(self.handlesOfPeopleAlreadyProcessed) > 50: # break ### # see if we've already processed this person if handle in self.handlesOfPeopleAlreadyProcessed: continue person = self.db.get_person_from_handle(handle) # if we get here, then we're dealing with someone new self.progress.step() # remember that we've now seen this person self.handlesOfPeopleAlreadyProcessed.add(handle) # we have 4 things to do: find (1) spouses, (2) parents, siblings(3), and (4) children # step 1 -- spouses for familyHandle in person.get_family_handle_list(): family = self.db.get_family_from_handle(familyHandle) spouseHandle = ReportUtils.find_spouse(person, family) if spouseHandle and \ spouseHandle not in self.handlesOfPeopleAlreadyProcessed: self.handlesOfPeopleToBeProcessed.add(spouseHandle) # step 2 -- parents for familyHandle in person.get_parent_family_handle_list(): family = self.db.get_family_from_handle(familyHandle) fatherHandle = family.get_father_handle() motherHandle = family.get_mother_handle() if fatherHandle and \ fatherHandle not in self.handlesOfPeopleAlreadyProcessed: self.handlesOfPeopleToBeProcessed.add(fatherHandle) if motherHandle and \ motherHandle not in self.handlesOfPeopleAlreadyProcessed: self.handlesOfPeopleToBeProcessed.add(motherHandle) # step 3 -- siblings for familyHandle in person.get_parent_family_handle_list(): family = self.db.get_family_from_handle(familyHandle) for childRef in family.get_child_ref_list(): childHandle = childRef.ref if childHandle and \ childHandle not in self.handlesOfPeopleAlreadyProcessed: self.handlesOfPeopleToBeProcessed.add(childHandle) # step 4 -- children for familyHandle in person.get_family_handle_list(): family = self.db.get_family_from_handle(familyHandle) for childRef in family.get_child_ref_list(): childHandle = childRef.ref if childHandle and \ childHandle not in self.handlesOfPeopleAlreadyProcessed: self.handlesOfPeopleToBeProcessed.add(childHandle) def findUnrelatedPeople(self): # update our numbers self.numberOfRelatedPeople = len(self.handlesOfPeopleAlreadyProcessed) self.numberOfUnrelatedPeople = (self.numberOfPeopleInDatabase - self.numberOfRelatedPeople) if self.numberOfUnrelatedPeople > 0: # we have at least 1 "unrelated" person to find self.progress.set_pass( ngettext("Looking for %d person", "Looking for %d people", self.numberOfUnrelatedPeople) % self.numberOfUnrelatedPeople, self.numberOfPeopleInDatabase) # loop through everyone in the database for handle in self.db.iter_person_handles(): self.progress.step() # if this person is related, then skip to the next one if handle in self.handlesOfPeopleAlreadyProcessed: continue ### DEBUG DEBUG DEBUG # if len(self.handlesOfPeopleNotRelated) > 10: # break ### # if we get here, we have someone who is "not related" self.handlesOfPeopleNotRelated.add(handle) def populateModel(self): self.progress.set_pass( ngettext("Looking up the name of %d person", "Looking up the names of %d people", self.numberOfUnrelatedPeople) % self.numberOfUnrelatedPeople, self.numberOfUnrelatedPeople) # loop through the entire list of unrelated people for handle in self.handlesOfPeopleNotRelated: self.progress.step() person = self.db.get_person_from_handle(handle) primaryname = person.get_primary_name() surname = primaryname.get_surname() name = primaryname.get_name() gid = person.get_gramps_id() # Retrieve the sorted tag list tag_list = self.get_tag_list(person) # find the names of the parents familygid = '' parentNames = '' parentFamilyHandle = person.get_main_parents_family_handle() if parentFamilyHandle: parentFamily = self.db.get_family_from_handle( parentFamilyHandle) familygid = parentFamily.get_gramps_id() fatherName = None motherName = None fatherHandle = parentFamily.get_father_handle() if fatherHandle: father = self.db.get_person_from_handle(fatherHandle) fatherName = father.get_primary_name().get_first_name() motherHandle = parentFamily.get_mother_handle() if motherHandle: mother = self.db.get_person_from_handle(motherHandle) motherName = mother.get_primary_name().get_first_name() # now that we have the names, come up with a label we can use if fatherName: parentNames += fatherName if fatherName and motherName: parentNames += ' & ' if motherName: parentNames += motherName # get the surname node (or create it if it doesn't exist) # start with the root iter = self.model.get_iter_root() # look for a node with a matching surname while iter: if self.model.get_value(iter, 0) == surname: break iter = self.model.iter_next(iter) # if we don't have a valid iter, then create a new top-level node if not iter: iter = self.model.append(None, [surname, '', '', '', '']) # finally, we now get to add this person to the model self.model.append(iter, [name, gid, parentNames, tag_list, familygid]) def build_menu_names(self, obj): return (self.title, None) def get_tag_list(self, person): """ Return a sorted list of tag names for the given person. """ tags = [] for handle in person.get_tag_list(): tag = self.db.get_tag_from_handle(handle) tags.append(tag.get_name()) tags.sort(key=locale.strxfrm) return ', '.join(tags)
def __refresh_addon_list(self, obj): """ Reloads the addons from the wiki into the list. """ import urllib from gui.utils import ProgressMeter URL = "%s%s" % (const.URL_WIKISTRING, const.WIKI_EXTRAPLUGINS_RAWDATA) try: fp = urllib.urlopen(URL) except: print "Error: cannot open %s" % URL return pm = ProgressMeter(_("Refreshing Addon List")) pm.set_pass(header=_("Reading gramps-project.org...")) state = "read" rows = [] row = [] lines = fp.readlines() pm.set_pass(total=len(lines), header=_("Reading gramps-project.org...")) for line in lines: pm.step() if line.startswith("|-") or line.startswith("|}"): if row != []: rows.append(row) state = "row" row = [] elif state == "row": if line.startswith("|"): row.append(line[1:].strip()) else: state = "read" fp.close() rows.sort(key=lambda row: (row[1], row[0])) self.addon_model.clear() # clear the config list: config.get('plugin.addonplugins')[:] = [] pm.set_pass(total=len(rows), header=_("Checking addon...")) for row in rows: pm.step() try: # from wiki: help_name, ptype, image, desc, use, rating, contact, download = row except: continue help_url = _("Unknown Help URL") if help_name.startswith("[[") and help_name.endswith("]]"): name = help_name[2:-2] if "|" in name: help_url, name = name.split("|", 1) elif help_name.startswith("[") and help_name.endswith("]"): name = help_name[1:-1] if " " in name: help_url, name = name.split(" ", 1) else: name = help_name url = _("Unknown URL") if download.startswith("[[") and download.endswith("]]"): # Not directly possible to get the URL: url = download[2:-2] if "|" in url: url, text = url.split("|", 1) # need to get a page that says where it is: fp = urllib.urlopen( "%s%s%s" % (const.URL_WIKISTRING, url, "&action=edit&externaledit=true&mode=file")) for line in fp: if line.startswith("URL="): junk, url = line.split("=", 1) break fp.close() elif download.startswith("[") and download.endswith("]"): url = download[1:-1] if " " in url: url, text = url.split(" ", 1) if (url.endswith(".zip") or url.endswith(".ZIP") or url.endswith(".tar.gz") or url.endswith(".tgz")): # Then this is ok: self.addon_model.append(row=[ help_name, name, ptype, image, desc, use, rating, contact, download, url ]) config.get('plugin.addonplugins').append([ help_name, name, ptype, image, desc, use, rating, contact, download, url ]) pm.close() config.save()
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 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 User(gen.user.User): """ This class provides a means to interact with the user via GTK. It implements the interface in gen.user.User() """ def __init__(self): self.progress = None def begin_progress(self, title, message, steps): """ Start showing a progress indicator to the user. @param title: the title of the progress meter @type title: str @param message: the message associated with the progress meter @type message: str @param steps: the total number of steps for the progress meter. a value of 0 indicates that the ending is unknown and the meter should just show activity. @type steps: int @returns: none """ self.progress = ProgressMeter(title) if steps > 0: self.progress.set_pass(message, steps, ProgressMeter.MODE_FRACTION) else: self.progress.set_pass(message, mode=ProgressMeter.MODE_ACTIVITY) def step_progress(self): """ Advance the progress meter. """ if self.progress: self.progress.step() def end_progress(self): """ Stop showing the progress indicator to the user. """ if self.progress: self.progress.close() self.progress = None def prompt(self, title, question): """ Ask the user a question. The answer must be "yes" or "no". The user will be forced to answer the question before proceeding. @param title: the title of the question @type title: str @param question: the question @type question: str @returns: the user's answer to the question @rtype: bool """ return False def warn(self, title, warning=""): """ Warn the user. @param title: the title of the warning @type title: str @param warning: the warning @type warning: str @returns: none """ WarningDialog(title, warning) def notify_error(self, title, error=""): """ Notify the user of an error. @param title: the title of the error @type title: str @param error: the error message @type error: str @returns: none """ ErrorDialog(title, error)