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 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 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 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)
class ToolManagedWindowBase(ManagedWindow.ManagedWindow): """ Copied from src/ReportBase/_BareReportDialog.py BareReportDialog """ border_pad = 6 HELP_TOPIC = None def __init__(self, dbstate, uistate, option_class, name, callback=None): self.name = name ManagedWindow.ManagedWindow.__init__(self, uistate, [], self) self.extra_menu = None self.widgets = [] self.frame_names = [] self.frames = {} self.format_menu = None self.style_button = None window = gtk.Dialog('Tool') self.set_window(window, None, self.get_title()) #self.window.set_has_separator(False) #self.window.connect('response', self.close) self.cancel = self.window.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_CANCEL) self.cancel.connect('clicked', self.close) self.ok = self.window.add_button(gtk.STOCK_EXECUTE, gtk.RESPONSE_OK) self.ok.connect('clicked', self.on_ok_clicked) self.window.set_default_size(600, -1) # Set up and run the dialog. These calls are not in top down # order when looking at the dialog box as there is some # interaction between the various frames. self.setup_title() self.setup_header() #self.tbl = gtk.Table(4, 4, False) #self.tbl.set_col_spacings(12) #self.tbl.set_row_spacings(6) #self.tbl.set_border_width(6) #self.col = 0 #self.window.vbox.add(self.tbl) # Build the list of widgets that are used to extend the Options # frame and to create other frames self.add_user_options() self.notebook = gtk.Notebook() self.notebook.set_border_width(6) self.window.vbox.add(self.notebook) self.results_text = gtk.TextView() self.results_text.connect('button-press-event', self.on_button_press) self.results_text.connect('motion-notify-event', self.on_motion) self.tags = [] self.link_cursor = gtk.gdk.Cursor(gtk.gdk.LEFT_PTR) self.standard_cursor = gtk.gdk.Cursor(gtk.gdk.XTERM) self.setup_other_frames() self.set_current_frame(self.initial_frame()) self.show() #------------------------------------------------------------------------ # # Callback functions from the dialog # #------------------------------------------------------------------------ def on_cancel(self, *obj): pass # cancel just closes def on_ok_clicked(self, obj): """ The user is satisfied with the dialog choices. Parse all options and run the tool. """ # Save options self.options.parse_user_options() self.options.handler.save_options() self.pre_run() self.run() # activate results tab self.post_run() def initial_frame(self): return None def on_motion(self, view, event): buffer_location = view.window_to_buffer_coords(gtk.TEXT_WINDOW_TEXT, int(event.x), int(event.y)) iter = view.get_iter_at_location(*buffer_location) for (tag, person_handle) in self.tags: if iter.has_tag(tag): _window = view.get_window(gtk.TEXT_WINDOW_TEXT) _window.set_cursor(self.link_cursor) return False # handle event further, if necessary view.get_window(gtk.TEXT_WINDOW_TEXT).set_cursor(self.standard_cursor) return False # handle event further, if necessary def on_button_press(self, view, event): buffer_location = view.window_to_buffer_coords(gtk.TEXT_WINDOW_TEXT, int(event.x), int(event.y)) iter = view.get_iter_at_location(*buffer_location) for (tag, person_handle) in self.tags: if iter.has_tag(tag): person = self.db.get_person_from_handle(person_handle) if event.button == 1: if event.type == gtk.gdk._2BUTTON_PRESS: try: EditPerson(self.dbstate, self.uistate, [], person) except Errors.WindowActiveError: pass else: self.uistate.set_active(person_handle, 'Person') return True # handled event return False # did not handle event def results_write_link(self, text, person, person_handle): self.results_write(" ") buffer = self.results_text.get_buffer() iter = buffer.get_end_iter() offset = buffer.get_char_count() self.results_write(text) start = buffer.get_iter_at_offset(offset) end = buffer.get_end_iter() self.tags.append((LinkTag(person_handle, buffer), person_handle)) buffer.apply_tag(self.tags[-1][0], start, end) def results_write(self, text): buffer = self.results_text.get_buffer() mark = buffer.create_mark("end", buffer.get_end_iter()) self.results_text.scroll_to_mark(mark, 0) buffer.insert_at_cursor(text) buffer.delete_mark_by_name("end") def write_to_page(self, page, text): buffer = page.get_buffer() mark = buffer.create_mark("end", buffer.get_end_iter()) self.results_text.scroll_to_mark(mark, 0) buffer.insert_at_cursor(text) buffer.delete_mark_by_name("end") def clear(self, text): # Remove all tags and clear text buffer = text.get_buffer() tag_table = buffer.get_tag_table() start = buffer.get_start_iter() end = buffer.get_end_iter() for (tag, handle) in self.tags: buffer.remove_tag(tag, start, end) tag_table.remove(tag) self.tags = [] buffer.set_text("") def results_clear(self): # Remove all tags and clear text buffer = self.results_text.get_buffer() tag_table = buffer.get_tag_table() start = buffer.get_start_iter() end = buffer.get_end_iter() for (tag, handle) in self.tags: buffer.remove_tag(tag, start, end) tag_table.remove(tag) self.tags = [] buffer.set_text("") def pre_run(self): from gui.utils import ProgressMeter self.progress = ProgressMeter(self.get_title()) def run(self): raise NotImplementedError, "tool needs to define a run() method" def post_run(self): self.progress.close() #------------------------------------------------------------------------ # # Functions related to setting up the dialog window. # #------------------------------------------------------------------------ def get_title(self): """The window title for this dialog""" return "Tool" # self.title def get_header(self, name): """The header line to put at the top of the contents of the dialog box. By default this will just be the name of the selected person. Most subclasses will customize this to give some indication of what the report will be, i.e. 'Descendant Report for %s'.""" return self.get_title() def setup_title(self): """Set up the title bar of the dialog. This function relies on the get_title() customization function for what the title should be.""" self.window.set_title(self.get_title()) def setup_header(self): """Set up the header line bar of the dialog. This function relies on the get_header() customization function for what the header line should read. If no customization function is supplied by the subclass, the default is to use the full name of the currently selected person.""" title = self.get_header(self.get_title()) label = gtk.Label('<span size="larger" weight="bold">%s</span>' % title) label.set_use_markup(True) self.window.vbox.pack_start(label, False, False, self.border_pad) def add_frame_option(self, frame_name, label_text, widget): """Similar to add_option this method takes a frame_name, a text string and a Gtk Widget. When the interface is built, all widgets with the same frame_name are grouped into a GtkFrame. This allows the subclass to create its own sections, filling them with its own widgets. The subclass is reponsible for all managing of the widgets, including extracting the final value before the report executes. This task should only be called in the add_user_options task.""" if frame_name in self.frames: self.frames[frame_name].append((label_text, widget)) else: self.frames[frame_name] = [(label_text, widget)] self.frame_names.append(frame_name) def set_current_frame(self, name): if name is None: self.notebook.set_current_page(0) else: for frame_name in self.frame_names: if name == frame_name: if len(self.frames[frame_name]) > 0: fname, child = self.frames[frame_name][0] page = self.notebook.page_num(child) self.notebook.set_current_page(page) return def add_results_frame(self, frame_name="Results"): if frame_name not in self.frames: window = gtk.ScrolledWindow() window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) window.add(self.results_text) window.set_shadow_type(gtk.SHADOW_IN) self.frames[frame_name] = [[frame_name, window]] self.frame_names.append(frame_name) l = gtk.Label("<b>%s</b>" % _(frame_name)) l.set_use_markup(True) self.notebook.append_page(window, l) self.notebook.show_all() else: self.results_clear() return self.results_text def add_page(self, frame_name="Help"): if frame_name not in self.frames: text = gtk.TextView() text.set_wrap_mode(gtk.WRAP_WORD) window = gtk.ScrolledWindow() window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) window.add(text) window.set_shadow_type(gtk.SHADOW_IN) self.frames[frame_name] = [[frame_name, window]] self.frame_names.append(frame_name) l = gtk.Label("<b>%s</b>" % _(frame_name)) l.set_use_markup(True) self.notebook.append_page(window, l) self.notebook.show_all() else: # FIXME: get text # text = self.frames[frame_name][0][1].something return text def setup_other_frames(self): """Similar to add_option this method takes a frame_name, a text string and a Gtk Widget. When the interface is built, all widgets with the same frame_name are grouped into a GtkFrame. This allows the subclass to create its own sections, filling them with its own widgets. The subclass is reponsible for all managing of the widgets, including extracting the final value before the report executes. This task should only be called in the add_user_options task.""" for key in self.frame_names: flist = self.frames[key] table = gtk.Table(3, len(flist)) table.set_col_spacings(12) table.set_row_spacings(6) table.set_border_width(6) l = gtk.Label("<b>%s</b>" % key) l.set_use_markup(True) self.notebook.append_page(table, l) row = 0 for (text, widget) in flist: if text: text_widget = gtk.Label('%s:' % text) text_widget.set_alignment(0.0, 0.5) table.attach(text_widget, 1, 2, row, row + 1, gtk.SHRINK | gtk.FILL, gtk.SHRINK) table.attach(widget, 2, 3, row, row + 1, yoptions=gtk.SHRINK) else: table.attach(widget, 2, 3, row, row + 1, yoptions=gtk.SHRINK) row += 1 self.notebook.show_all() #------------------------------------------------------------------------ # # Functions related to extending the options # #------------------------------------------------------------------------ def add_user_options(self): """Called to allow subclasses add widgets to the dialog form. It is called immediately before the window is displayed. All calls to add_option or add_frame_option should be called in this task.""" add_gui_options(self) def build_menu_names(self, obj): return (_('Main window'), self.get_title())
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)