def generate_md5(self, button): """ Generate md5 hashes for media files. """ self.clear_models() progress = ProgressMeter(self.window_name, can_cancel=True, parent=self.window) length = self.db.get_number_of_media() progress.set_pass(_('Generating media hashes'), length) with DbTxn(_("Set media hashes"), self.db, batch=True) as trans: for handle in self.db.get_media_handles(): media = self.db.get_media_from_handle(handle) full_path = media_path_full(self.db, media.get_path()) md5sum = create_checksum(full_path) if not md5sum: error_msg = 'IOError: %s' % full_path self.models[5].append((error_msg, None)) progress.step() continue media.set_checksum(md5sum) self.db.commit_media(media, trans) progress.step() if progress.get_cancelled(): break self.show_tabs() progress.close()
def _execute(self): """ execute all primary objects and reorder if neccessary """ # Update progress calculation if self.uistate: self.progress = ProgressMeter(_('Reorder Gramps IDs'), '') else: total_objs = 0 for prim_obj, tmp in self.xobjects: if self.obj_values[prim_obj].active_obj: total_objs += self.obj_values[prim_obj].quant_id self.set_total(total_objs) # Update database self.dbstate.disable_signals() for prim_obj, prim_objs in self.xobjects: with DbTxn(_('Reorder %s IDs ...') % prim_obj, self.dbstate, batch=True) \ as self.trans: if self.obj_values[prim_obj].active_obj: if self.uistate: self.progress.set_pass(_('Reorder %s IDs ...') % \ _(prim_objs.title()), \ self.obj_values[prim_obj].quant_id) # Process reordering self._reorder(prim_obj) self.dbstate.enable_signals() self.dbstate.request_rebuild() # Update progress calculation if self.uistate: self.progress.close() else: print('\nDone.')
def draw_page(self, operation, context, page_nr): if page_nr == 0: self.progress = ProgressMeter(_("Printing the tree"), can_cancel=True, cancel_callback=self.cancel_print, parent=self.uistate.window) message = _('Need to print %(pages)s pages (%(format)s format)') self.progress.set_pass( message % { 'pages': self.nb_pages, 'format': self.format }, self.nb_pages) cr = context.get_cairo_context() x = y = 0 x = ((page_nr % self.pages_per_row) * self.width_used) if page_nr > 0 else 0 y = (int(page_nr / self.pages_per_row) * self.height_used) cr.save() cr.translate(-x, -y) cr.scale(self.print_zoom, self.print_zoom) self.canvas.draw(cr) cr.restore() if page_nr == self.nb_pages - 1: self.progress.close() self.progress.step()
def progress(self, title1, title2, count): self._progress = ProgressMeter(title1, can_cancel=True) self._progress.set_pass(title2, count, ProgressMeter.MODE_FRACTION) try: yield self._progress.step finally: self._progress.close()
def on_accept_all(self, dummy, easy=False): """ Button: Accept all or all the 'easy' ones, depending """ self.progress = ProgressMeter(TITLE, '', parent=self.window) length = self.easy_count if easy else len(self.fam_liststore) self.progress.set_pass(_("Processing..."), length) with DbTxn(_("Edit Families"), self.db) as trans: for row in self.fam_liststore: self.progress.step() if easy and not row[0]: continue self.fam_h = row[4] self.family = self.db.get_family_from_handle(self.fam_h) dummy, sorted_ch_list = self.sort_family_pr(self.fam_h) orig_refs = self.family.get_child_ref_list() sort_ref_list = list(orig_refs[ch[3]] for ch in sorted_ch_list) self.family.set_child_ref_list(sort_ref_list) self.db.commit_family(self.family, trans) self.fam_liststore.remove(row.iter) self.progress.close() spath = Gtk.TreePath.new_first() self.fam_sel.select_path(spath) if len(self.fam_liststore) == 0: self.kill_buttons() self.ch_liststore.clear() self.ch_liststore_s.clear()
def on_ok_clicked(self): """ Method that is run when you click the OK button. """ downloaded = {} # Get a directory to put the media files in. If the media path in # preferences is not just the user's home, then we will use that. If it # is the user's home, we create a new directory below that, so we don't # splatter files into home. media_path = self.db.get_mediapath() if media_path == USER_HOME or media_path == "" or media_path == None: media_path = os.path.join(USER_HOME, "mediadir") if not os.path.isdir(media_path): os.makedirs(media_path) # Many thanks to 'sirex' from whom I have taken the code he submitted as # part of bug 0003553: Import media files from GEDCOM file_pattern = re.compile(r'.*\.(png|jpg|jpeg|gif)$') def fetch_file(url, filename): LOG.debug("Downloading url %s to file %s" % (url, filename)) fr = urlopen(url) fw = open(filename, 'wb') for block in fr: fw.write(block) fw.close() fr.close() self.progress = ProgressMeter(_('Downloading files'), '') self.progress.set_pass(_('Downloading files'), self.db.get_number_of_media_objects()) self.db.disable_signals() with DbTxn('Download files', self.db) as trans: for media_handle in self.db.media_map.keys(): media = self.db.get_object_from_handle(media_handle) url = media.get_path() res = urlparse(url) LOG.debug(res) if res.scheme == "http" or res.scheme == "https": if file_pattern.match(url): if url in downloaded: full_path = downloaded[url] else: filename = url.split('/')[-1] full_path = os.path.join(media_path, filename) fetch_file(url, full_path) downloaded[url] = full_path self.num_downloads += 1 media.set_path(full_path) media.set_mime_type(get_type(full_path)) self.db.commit_media_object(media, trans) self.progress.step() self.db.enable_signals() self.db.request_rebuild() self.progress.close()
def begin_progress(self, title, message, steps): # Parameter "can_cancel" added to ProgressMeter creation. from gramps.gui.utils import ProgressMeter self._progress = ProgressMeter(title, parent=self.parent, can_cancel=True) if steps > 0: self._progress.set_pass(message, steps, ProgressMeter.MODE_FRACTION) else: self._progress.set_pass(message, mode=ProgressMeter.MODE_ACTIVITY)
def saveit(self, button): """ Commit the changes to the database """ self.update_changelist() progress = ProgressMeter(self.window_name, can_cancel=True, parent=self.window) length = len(self.changelist) progress.set_pass(_('Saving Notes'), length) with DbTxn(_("Saving Cleaned Notes"), self.db, batch=False) as trans: for changed in self.changelist: note = self.db.get_note_from_handle(changed[0]) note.set_styledtext(changed[2]) self.db.commit_note(note, trans) msg = _("Note Cleanup") trans.set_description(msg) progress.step() if progress.get_cancelled(): break self.clear_models() self.show_tabs() progress.close()
def find_potentials(self): """ look for possible out of order families """ self.progress = ProgressMeter(TITLE, _('Looking for children birth order'), parent=self.window) length = self.db.get_number_of_families() self.progress.set_pass(_('Pass 1: Building preliminary lists'), length) self.easy_count = 0 for fam_h in self.db.iter_family_handles(): self.progress.step() fam = self.db.get_family_from_handle(fam_h) child_ref_list = fam.get_child_ref_list() prev_date = 0 need_sort = False easy = '*' for child_ref in child_ref_list: child = self.db.get_person_from_handle(child_ref.ref) b_date = 0 birth = get_birth_or_fallback(self.db, child) if birth: b_date = birth.get_date_object().get_sort_value() if not b_date: easy = '' continue elif b_date >= prev_date: prev_date = b_date continue else: # we need to put this one in list need_sort = True if not need_sort: continue if easy: self.easy_count += 1 fam_f = fam.get_father_handle() fam_m = fam.get_mother_handle() if fam_f: father = self.db.get_person_from_handle(fam_f) father_name = name_displayer.display(father) else: father_name = '' if fam_m: mother = self.db.get_person_from_handle(fam_m) mother_name = name_displayer.display(mother) else: mother_name = '' fam_data = (easy, fam.get_gramps_id(), father_name, mother_name, fam_h) self.fam_liststore.append(row=fam_data) if len(self.fam_liststore) != 0: spath = Gtk.TreePath.new_first() self.fam_sel.select_path(spath) self.ch_s_sel.select_path(spath) self.progress.close()
def build_row_data(self): self.progress_bar = ProgressMeter(_('Comparing Events'), '', parent=self.uistate.window) self.progress_bar.set_pass(_('Building data'), len(self.my_list)) for individual_id in self.my_list: individual = self.db.get_person_from_handle(individual_id) name = individual.get_primary_name().get_name() gid = individual.get_gramps_id() the_map = defaultdict(list) for ievent_ref in individual.get_event_ref_list(): ievent = self.db.get_event_from_handle(ievent_ref.ref) event_name = str(ievent.get_type()) the_map[event_name].append(ievent_ref.ref) first = True done = False while not done: added = False tlist = [name, gid] if first else ["", ""] for ename in self.event_titles: if ename in the_map and len(the_map[ename]) > 0: event_handle = the_map[ename][0] del the_map[ename][0] date = place = "" if event_handle: event = self.db.get_event_from_handle(event_handle) date = get_date(event) sortdate = "%09d" % ( event.get_date_object().get_sort_value()) place_handle = event.get_place_handle() if place_handle: place = self.db.get_place_from_handle( place_handle).get_title() tlist += [date, sortdate, place] added = True else: tlist += [""] * 3 if first: first = False self.row_data.append(tlist) elif not added: done = True else: self.row_data.append(tlist) self.progress_bar.step()
def cleanup(self, _button): """ Cleanup Notes. """ self.clear_models() StyledText.__getitem__ = MyStyled.__getitem__ # patch in slice func progress = ProgressMeter(self.window_name, can_cancel=True, parent=self.window) length = self.db.get_number_of_notes() progress.set_pass(_('Scanning Notes'), length) for handle in self.db.get_note_handles(): note = self.db.get_note_from_handle(handle) g_id = note.gramps_id stext = note.get_styledtext() optype = -1 # find the notes and do cleanup #if not stext.tags: text = StyledText(stext._string, stext._tags) # make a copy result = self.convert_to_styled(text) indx = len(self.changelist) for styledtext_tag in result.tags: if (int(styledtext_tag.name) == StyledTextTagType.HIGHLIGHT and '#FFFF00' == styledtext_tag.value): optype = ISSUE break elif int(styledtext_tag.name) == StyledTextTagType.LINK: optype = LINK while True: if optype == ISSUE: # make list of notes with errors self.models[ISSUE].append((self.preview(stext, g_id), indx)) elif stext._string != result._string: # Make list of edited notes self.models[CLEANED].append((self.preview(stext, g_id), indx)) elif optype == LINK: # make list of notes with only links self.models[LINK].append((self.preview(stext, g_id), indx)) else: break self.changelist.append((handle, stext, result)) break progress.step() if progress.get_cancelled(): break self.show_tabs() progress.close()
def model_load(self): """ populate the tree with types """ r_indx = 0 self.model.clear() for (attr, name, _obj, _srcobj) in self.t_table: # 99 is indicator that row is a title row row = (name, 0, 99) iter_ = self.model.append(None, row) # get custom types from db types = getattr(self.db, attr, None) if types is None: continue for indx, cust_type in enumerate(types): # update right model row = (cust_type, indx, r_indx) self.model.append(iter_, row) # create refs list for the custom type self.types_dict[_obj][cust_type] = [] r_indx += 1 progress = ProgressMeter(self.window_name, can_cancel=False, parent=self.window) # find total of db objects total = 0 for obj_type in self.primary_objects_pl: total += self.db.method('get_number_of_%s', obj_type)() # scan db objects and record all custom GrampsTypes found as references progress.set_pass(_("Reading database..."), total) for obj_type in self.primary_objects: for hndl in self.db.method('get_%s_handles', obj_type)(): obj = self.db.method('get_%s_from_handle', obj_type)(hndl) self.do_recurse(obj, obj_type, hndl) progress.step() progress.close()
def applyTagClicked(self, button): progress = None rows = self.treeSelection.count_selected_rows() tag_name = str(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')) progress.set_pass( # translators: leave all/any {...} untranslated #TRANS: no singular form needed, as rows is always > 1 ngettext("Setting tag for {number_of} person", "Setting tag for {number_of} people", rows).format(number_of=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_ok_clicked(self): """ Method that is run when you click the OK button. The numbers of sources and citations are retrieved from the entry box and used to govern the amount of data generated """ num_sources_text = self.sources_entry.get_text() try: num_sources = int(num_sources_text) except: return num_citations_text = self.citations_entry.get_text() num_citations = int(num_citations_text) self.progress = ProgressMeter( 'Generating data', '') self.progress.set_pass('Generating data', num_sources*num_citations) LOG.debug("sources %04d citations %04d" % (num_sources, num_citations)) source = Source() citation = Citation() self.db.disable_signals() with DbTxn('Populate sources and citations', self.db) as trans: for i in range(num_sources): source.gramps_id = None source.handle = None source.title = "Source %04d" % (i + 1) source_handle = self.db.add_source(source, trans) for j in range(num_citations): citation.gramps_id = None citation.handle = None citation.source_handle = source_handle citation.page = "Page %04d" % (j + 1) self.db.add_citation(citation, trans) self.progress.step() LOG.debug("sources and citations added") self.db.enable_signals() self.db.request_rebuild() self.progress.close() self.options.handler.options_dict['sources'] = num_sources self.options.handler.options_dict['citations'] = num_citations # Save options self.options.handler.save_options()
def display(self): try: from bsddb3.db import DBError except: class DBError(Exception): """ Dummy. """ self.parent = self.top.get_toplevel() progress = ProgressMeter( _('Updating display...'), '', parent=self.parent) self.model.clear() self.junk = [] gc.collect(2) self.junk = gc.garbage self.label.set_text(_('Uncollected Objects: %s') % str(len(self.junk))) progress.set_pass(_('Updating display...'), len(self.junk)) for count in range(0, len(self.junk)): progress.step() try: refs = [] referrers = gc.get_referrers(self.junk[count]) for referrer in referrers: try: if referrer is not self.junk: for indx in range(0, len(self.junk)): if referrer is self.junk[indx]: refs.append(str(indx) + ' ') break except: print(sys.exc_info()) if len(refs) > 3: ref = ' '.join(refs[0:2]) + "..." else: ref = ' '.join(refs) try: self.model.append((count, ref, str(self.junk[count]))) except DBError: self.model.append((count, ref, 'db.DB instance at %s' % id(self.junk[count]))) except ReferenceError: self.model.append(( count, ref, 'weakly-referenced object no longer exists %s' % type(self.junk[count]))) except TypeError: self.model.append(( count, ref, 'Object cannot be displayed %s' % type(self.junk[count]))) except: print(sys.exc_info()) except ReferenceError: InfoDialog(_('Reference Error'), "Refresh to correct", parent=self.parent) progress.close()
def _execute(self): """ execute all primary objects and reorder if neccessary """ # Update progress calculation if self.uistate: self.progress = ProgressMeter(_('Reorder Gramps IDs'), '') else: total_objs = 0 for prim_obj, dummy in self.xobjects: if self.obj_values[prim_obj].active_obj: total_objs += self.obj_values[prim_obj].quant_id self.set_total(total_objs) # Update database self.db.disable_signals() for prim_obj, prim_objs in self.xobjects: with DbTxn(_('Reorder %s IDs ...') % prim_obj, self.db, batch=True) as self.trans: if self.obj_values[prim_obj].active_obj: if self.uistate: self.progress.set_pass( _('Reorder %s IDs ...') % _(prim_objs.title()), self.obj_values[prim_obj].quant_id) # Process reordering self._reorder(prim_obj) self.db.enable_signals() self.db.request_rebuild() # Update progress calculation if self.uistate: self.progress.close() else: print('\nDone.')
def on_ok_clicked(self): """ Method that is run when you click the OK button. """ downloaded = {} # Get a directory to put the media files in. If the media path in # preferences is not just the user's home, then we will use that. If it # is the user's home, we create a new directory below that, so we don't # splatter files into home. media_path = self.db.get_mediapath() if media_path == USER_HOME or media_path == "" or media_path == None: media_path = os.path.join(USER_HOME, "mediadir") if not os.path.isdir(media_path): os.makedirs(media_path) # Many thanks to 'sirex' from whom I have taken the code he submitted as # part of bug 0003553: Import media files from GEDCOM file_pattern = re.compile(r'.*\.(png|jpg|jpeg|gif)$') def fetch_file(url, filename): LOG.debug("Downloading url %s to file %s" % (url, filename)) fr = urlopen(url) fw = open(filename, 'wb') for block in fr: fw.write(block) fw.close() fr.close() self.progress = ProgressMeter( _('Downloading files'), '') self.progress.set_pass(_('Downloading files'), self.db.get_number_of_media_objects()) self.db.disable_signals() with DbTxn('Download files', self.db) as trans: for media_handle in self.db.media_map.keys(): media = self.db.get_object_from_handle(media_handle) url = media.get_path() res = urlparse(url) LOG.debug(res) if res.scheme == "http" or res.scheme == "https": if file_pattern.match(url): if url in downloaded: full_path = downloaded[url] else: filename = url.split('/')[-1] full_path = os.path.join(media_path, filename) fetch_file(url, full_path) downloaded[url] = full_path self.num_downloads += 1 media.set_path(full_path) media.set_mime_type(get_type(full_path)) self.db.commit_media_object(media, trans) self.progress.step() self.db.enable_signals() self.db.request_rebuild() self.progress.close()
def generate_md5(self, button): """ Generate md5 hashes for media files and attach them as attributes to media objects. """ self.clear_models() progress = ProgressMeter(self.window_name, can_cancel=True, parent=self.window) length = self.db.get_number_of_media_objects() progress.set_pass(_('Generating media hashes'), length) with DbTxn(_("Set media hashes"), self.db, batch=True) as trans: for handle in self.db.get_media_object_handles(): media = self.db.get_object_from_handle(handle) full_path = media_path_full(self.db, media.get_path()) try: with io.open(full_path, 'rb') as media_file: md5sum = hashlib.md5(media_file.read()).hexdigest() except IOError as err: error_msg = '%s: %s' % (err.strerror, full_path) self.models[5].append((error_msg, None)) progress.step() continue for attr in media.get_attribute_list(): if str(attr.get_type()) == 'md5': media.remove_attribute(attr) break attr = Attribute() attr.set_type(AttributeType('md5')) attr.set_value(md5sum) media.add_attribute(attr) self.db.commit_media_object(media, trans) progress.step() if progress.get_cancelled(): break self.show_tabs() progress.close()
def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate self.label = _('Check Place title') tool.BatchTool.__init__(self, dbstate, user, options_class, name) if self.fail: return ManagedWindow.__init__(self, uistate, [], self.__class__) self.set_window(Gtk.Window(), Gtk.Label(), '') # retrieve options CLI? #copy = self.options.handler.options_dict['copy'] #clean = self.options.handler.options_dict['clean'] self.db = dbstate.db self.total = self.db.get_number_of_places() self.progress = ProgressMeter(_('Checking Place Titles'), '', parent=uistate.window) self.progress.set_pass(_('Looking for place fields'), self.total) self.name_list = [] count = 0 for handle in self.db.get_place_handles(True): self.progress.step() place = self.db.get_place_from_handle(handle) title = place.title descr = place_displayer.display(self.db, place) if title != (descr and ""): count += 1 if title != "": self.name_list.append((handle.decode('utf8'), title, descr)) self.progress.close() if self.name_list: self.display() OkDialog(_('Differences'), '%s/%s' % (count, self.total), parent=uistate.window) else: self.progress.close() self.close() OkDialog(_('No need modifications'), _("No changes need."), parent=uistate.window)
class User2: """ Helper class to provide "can_cancel" functionality to the progress indicator used by gramps.gen.filters._genericfilter.GenericFilter.apply(). Replaces the gramps.gui.user.User class for this case. Code copied from gramps/gui/user.py. """ def __init__(self, user): self.parent = user.parent self.uistate = user.uistate self.parent = user.parent def begin_progress(self, title, message, steps): # Parameter "can_cancel" added to ProgressMeter creation. from gramps.gui.utils import ProgressMeter self._progress = ProgressMeter(title, parent=self.parent, can_cancel=True) 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): res = self._progress.step() if res: self.end_progress() raise StopIteration def end_progress(self): self._progress.close() self._progress = None
def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate tool.BatchTool.__init__(self, dbstate, user, options_class, name) if self.fail: return if dbstate.db.readonly: return self.progress = ProgressMeter(_("Fix Coordinates"), _('Starting'), parent=uistate.window) uistate.set_busy_cursor(True) dbstate.db.disable_signals() steps = dbstate.db.get_number_of_places() self.progress.set_pass( _('Looking for possible coords with ","' ' characters'), steps) with DbTxn(_("Fix coords"), dbstate.db, batch=False) as trans: for place_handle in dbstate.db.get_place_handles(): self.progress.step() place = dbstate.db.get_place_from_handle(place_handle) place_name = place.get_name() pname = place_name.get_value() found = False if pname != pname.strip(): found = True place_name.set_value(pname.strip()) plat = place.get_latitude() if plat != plat.strip().replace(',', '.'): found = True place.set_latitude(plat.strip().replace(',', '.')) plon = place.get_longitude() if plon != plon.strip().replace(',', '.'): found = True place.set_longitude(plon.strip().replace(',', '.')) if found: dbstate.db.commit_place(place, trans) uistate.set_busy_cursor(False) # close the progress bar self.progress.close() dbstate.db.enable_signals() dbstate.db.request_rebuild()
def prepare(self, db): # FIXME: this should user the User class from gramps.gui.utils import ProgressMeter 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() list(map(self.__matches.update, paths))
def _createmap(self): """ Create all markers for each people's event in the database which has a lat/lon. """ dbstate = self.dbstate self.cal = config.get('preferences.calendar-format-report') self.place_list = [] self.event_list = [] self.place_without_coordinates = [] self.places_found = [] self.minlat = self.maxlat = self.minlon = self.maxlon = 0.0 self.minyear = 9999 self.maxyear = 0 self.already_done = [] self.nbplaces = 0 self.nbmarkers = 0 self.message_layer.clear_messages() self.kml_layer.clear() person_handle = self.uistate.get_active('Person') person = None if person_handle: person = dbstate.db.get_person_from_handle(person_handle) if person is not None: # For each event, if we have a place, set a marker. self.window_name = _("Ancestors places for %s" % _nd.display(person)) self.message_layer.add_message(self.window_name) self.nb_evts = 0 self.progress = ProgressMeter(self.window_name, can_cancel=False, parent=self.uistate.window) self.progress.set_pass(_('Counting all places'), self.nb_evts) self.person_count(person) self.event_list = [] self.progress.set_pass(_('Showing all places'), self.nb_evts) self.show_one_person(person) self.progress.close() self.sort = sorted(self.place_list, key=operator.itemgetter(3, 4, 6)) self._create_markers()
def write_report(self): """ The routine the actually creates the report. At this point, the document is opened and ready for writing. """ # Create progress meter bar self.progress = ProgressMeter(_("Liste Eclair"), '') # Write the title line. Set in INDEX marker so that this section will be # identified as a major category if this is included in a Book report. title = _("Liste Eclair") mark = IndexMark(title, INDEX_TYPE_TOC, 1) self.doc.start_paragraph("Eclair-ReportTitle") self.doc.write_text(title, mark) self.doc.end_paragraph() self.__write_all_places() # Close the progress meter self.progress.close()
def cleanup(self, button): """ Cleanup Notes. """ self.clear_models() progress = ProgressMeter(self.window_name, can_cancel=True, parent=self.window) length = self.db.get_number_of_notes() progress.set_pass(_('Scanning Notes'), length) for handle in self.db.get_note_handles(): note = self.db.get_note_from_handle(handle) g_id = note.gramps_id stext = note.get_styledtext() handle = handle.decode('utf-8') optype = -1 ## find the notes and do cleanup if not stext.tags: result = self.convert_to_styled(stext.string) indx = len(self.changelist) for styledtext_tag in result.tags: if int(styledtext_tag.name) == StyledTextTagType.HIGHLIGHT: optype = ISSUE break elif int(styledtext_tag.name) == StyledTextTagType.LINK: optype = LINK while True: if optype == ISSUE: # make list of notes with errors self.models[ISSUE].append((self.preview(stext, g_id), indx)) elif stext.string != result.string: # Make list of edited notes self.models[CLEANED].append((self.preview(stext, g_id), indx)) elif optype == LINK: # make list of notes with only links self.models[LINK].append((self.preview(stext, g_id), indx)) else: break self.changelist.append((handle, stext, result)) break progress.step() if progress.get_cancelled(): break self.show_tabs() progress.close()
def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate self.label = _('Capitalization changes') self.dbstate = dbstate self.uistate = uistate self.cb = callback ManagedWindow.__init__(self, uistate, [], self.__class__) self.set_window(Gtk.Window(), Gtk.Label(), '') tool.BatchTool.__init__(self, dbstate, user, options_class, name) if self.fail: return given_name_dict = self.get_given_name_dict() self.progress = ProgressMeter(_('Checking Given Names'), '', parent=uistate.window) self.progress.set_pass(_('Searching given names'), len(given_name_dict.keys())) self.name_list = [] for name in given_name_dict.keys(): if name != capitalize(name): self.name_list.append((name, given_name_dict[name])) if uistate: self.progress.step() if self.name_list: self.display() else: self.progress.close() self.close() OkDialog(_('No modifications made'), _("No capitalization changes were detected."), parent=uistate.window)
def build_row_data(self): self.progress_bar = ProgressMeter(_('Comparing Events'),'', parent=self.window) self.progress_bar.set_pass(_('Building data'),len(self.my_list)) for individual_id in self.my_list: individual = self.db.get_person_from_handle(individual_id) name = individual.get_primary_name().get_name() gid = individual.get_gramps_id() the_map = defaultdict(list) for ievent_ref in individual.get_event_ref_list(): ievent = self.db.get_event_from_handle(ievent_ref.ref) event_name = str(ievent.get_type()) the_map[event_name].append(ievent_ref.ref) first = True done = False while not done: added = False tlist = [name, gid] if first else ["", ""] for ename in self.event_titles: if ename in the_map and len(the_map[ename]) > 0: event_handle = the_map[ename][0] del the_map[ename][0] date = place = "" if event_handle: event = self.db.get_event_from_handle(event_handle) date = get_date(event) sortdate = "%09d" % ( event.get_date_object().get_sort_value() ) place_handle = event.get_place_handle() if place_handle: place = self.db.get_place_from_handle( place_handle).get_title() tlist += [date, sortdate, place] added = True else: tlist += [""]*3 if first: first = False self.row_data.append(tlist) elif not added: done = True else: self.row_data.append(tlist) self.progress_bar.step()
def write_report(self): """ Overridden function to generate the report. """ self.progress = ProgressMeter(_("PUK Export"), '') self.doc.start_paragraph("SRC-ReportTitle") title = self.title_string mark = IndexMark(title, INDEX_TYPE_TOC, 1) self.doc.write_text(title, mark) self.doc.end_paragraph() self.doc.start_paragraph("SRC-ReportTitle") title = self.subtitle_string mark = IndexMark(title, INDEX_TYPE_TOC, 1) self.doc.write_text(title, mark) self.doc.end_paragraph() self.listpersonref() self.doc.start_paragraph('SRC-Footer') self.doc.write_text(self.footer_string) self.doc.end_paragraph() self.progress.close()
def _execute(self): """ execute all primary objects and reorder if neccessary """ # Update progress calculation if self.uistate: self.progress = ProgressMeter(_('Reorder Gramps IDs'), '') else: total_objs = 0 for prim_obj, dummy in self.xobjects: if self.obj_values[prim_obj].active_obj: total_objs += self.obj_values[prim_obj].quant_id self.set_total(total_objs) # Update database self.db.disable_signals() for prim_obj, prim_objs in self.xobjects: with DbTxn(_('Reorder %s IDs ...') % prim_obj, self.db, batch=True) as self.trans: if self.obj_values[prim_obj].active_obj: if self.uistate: self.progress.set_pass( _('Reorder %s IDs ...') % _(prim_objs.title()), self.obj_values[prim_obj].quant_id) # reset the db next_id index to zero so we restart new IDs # at lowest possible position setattr(self.db, DB_INDXES[prim_obj] + 'map_index', 0) # Process reordering self._reorder(prim_obj) self.db.enable_signals() self.db.request_rebuild() # Update progress calculation if self.uistate: self.progress.close() else: print('\nDone.')
def on_ok_clicked(self): """ Method that is run when you click the OK button. The numbers of sources and citations are retrieved from the entry box and used to govern the amount of data generated """ num_sources_text = self.sources_entry.get_text() try: num_sources = int(num_sources_text) except: return num_citations_text = self.citations_entry.get_text() num_citations = int(num_citations_text) self.progress = ProgressMeter( 'Generating data', '', parent=self.uistate.window) self.progress.set_pass('Generating data', num_sources*num_citations) LOG.debug("sources %04d citations %04d" % (num_sources, num_citations)) source = Source() citation = Citation() self.db.disable_signals() with DbTxn('Populate sources and citations', self.db) as trans: for i in range(num_sources): source.gramps_id = None source.handle = None source.title = "Source %04d" % (i + 1) source_handle = self.db.add_source(source, trans) for j in range(num_citations): citation.gramps_id = None citation.handle = None citation.source_handle = source_handle citation.page = "Page %04d" % (j + 1) self.db.add_citation(citation, trans) self.progress.step() LOG.debug("sources and citations added") self.db.enable_signals() self.db.request_rebuild() self.progress.close() self.options.handler.options_dict['sources'] = num_sources self.options.handler.options_dict['citations'] = num_citations # Save options self.options.handler.save_options()
def generate_md5(self, button): """ Generate md5 hashes for media files. """ self.clear_models() progress = ProgressMeter(self.window_name, can_cancel=True, parent=self.window) length = self.db.get_number_of_media() progress.set_pass(_('Generating media hashes'), length) with DbTxn(_("Set media hashes"), self.db, batch=True) as trans: for handle in self.db.get_media_handles(): media = self.db.get_media_from_handle(handle) full_path = media_path_full(self.db, media.get_path()) try: with io.open(full_path, 'rb') as media_file: md5sum = hashlib.md5(media_file.read()).hexdigest() except IOError as err: error_msg = '%s: %s' % (err.strerror, full_path) self.models[5].append((error_msg, None)) progress.step() continue media.set_checksum(md5sum) self.db.commit_media(media, trans) progress.step() if progress.get_cancelled(): break self.show_tabs() 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 __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate self.label = _('Check Place title') tool.BatchTool.__init__(self, dbstate, user, options_class, name) if self.fail: return ManagedWindow.__init__(self,uistate,[], self.__class__) self.set_window(Gtk.Window(),Gtk.Label(),'') # retrieve options CLI? #copy = self.options.handler.options_dict['copy'] #clean = self.options.handler.options_dict['clean'] self.db = dbstate.db self.total = self.db.get_number_of_places() self.progress = ProgressMeter(_('Checking Place Titles'), '', parent=uistate.window) self.progress.set_pass(_('Looking for place fields'), self.total) self.name_list = [] count = 0 for handle in self.db.get_place_handles(True): self.progress.step() place = self.db.get_place_from_handle(handle) title = place.title descr = place_displayer.display(self.db, place) if title != (descr and ""): count += 1 if title != "": self.name_list.append((handle.decode('utf8'), title, descr)) self.progress.close() if self.name_list: self.display() OkDialog(_('Differences'), '%s/%s' % (count, self.total), parent=uistate.window) else: self.progress.close() self.close() OkDialog(_('No need modifications'), _("No changes need."), parent=uistate.window)
def fix_media(self, button): """ Fix paths to moved media files. """ progress = ProgressMeter(self.window_name, can_cancel=True, parent=self.window) progress.set_pass(_('Fixing file paths'), len(self.moved_files)) with DbTxn(_("Fix media paths"), self.db, batch=True) as trans: for handle, new_path in self.moved_files: media = self.db.get_media_from_handle(handle) media.set_path(new_path) self.db.commit_media(media, trans) progress.step() if progress.get_cancelled(): break self.models[0].clear() self.show_tabs() progress.close()
def draw_page(self, operation, context, page_nr): if page_nr == 0: self.progress = ProgressMeter( _("Printing the tree"), can_cancel=True, cancel_callback=self.cancel_print, parent=self.uistate.window ) message = _("Need to print %(pages)s pages (%(format)s format)") self.progress.set_pass(message % {"pages": self.nb_pages, "format": self.format}, self.nb_pages) cr = context.get_cairo_context() x = y = 0 x = ((page_nr % self.pages_per_row) * self.width_used) if page_nr > 0 else 0 y = int(page_nr / self.pages_per_row) * self.height_used cr.save() cr.translate(-x, -y) cr.scale(self.print_zoom, self.print_zoom) self.canvas.draw(cr) cr.restore() if page_nr == self.nb_pages - 1: self.progress.close() self.progress.step()
def on_apply_clicked(self, obj): cfilter = self.filter_model[self.filters.get_active()][1] progress_bar = ProgressMeter(_("Comparing events"), "", parent=self.window) progress_bar.set_pass(_("Selecting people"), 1) plist = cfilter.apply(self.db, self.db.iter_person_handles()) progress_bar.step() progress_bar.close() self.options.handler.options_dict["filter"] = self.filters.get_active() # Save options self.options.handler.save_options() if len(plist) == 0: WarningDialog(_("No matches were found"), parent=self.window) else: DisplayChart(self.dbstate, self.uistate, plist, self.track)
def fix_media(self, button): """ Fix paths to moved media files. """ progress = ProgressMeter(self.window_name, can_cancel=True, parent=self.window) progress.set_pass(_('Fixing file paths'), len(self.moved_files)) with DbTxn(_("Fix media paths"), self.db, batch=True) as trans: for handle, new_path in self.moved_files: media = self.db.get_object_from_handle(handle) media.set_path(new_path) self.db.commit_media_object(media, trans) progress.step() if progress.get_cancelled(): break self.models[0].clear() self.show_tabs() progress.close()
def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate self.label = _('Capitalization changes') self.dbstate = dbstate self.uistate = uistate self.cb = callback ManagedWindow.__init__(self,uistate,[],self.__class__) self.set_window(Gtk.Window(),Gtk.Label(),'') tool.BatchTool.__init__(self, dbstate, user, options_class, name) if self.fail: return given_name_dict = self.get_given_name_dict() self.progress = ProgressMeter(_('Checking Given Names'),'', parent=uistate.window) self.progress.set_pass(_('Searching given names'), len(given_name_dict.keys())) self.name_list = [] for name in given_name_dict.keys(): if name != capitalize(name): self.name_list.append((name, given_name_dict[name])) if uistate: self.progress.step() if self.name_list: self.display() else: self.progress.close() self.close() OkDialog(_('No modifications made'), _("No capitalization changes were detected."), parent=uistate.window)
class DuplicatePeopleTool(tool.Tool, ManagedWindow): def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate tool.Tool.__init__(self, dbstate, options_class, name) ManagedWindow.__init__(self, uistate, [], self.__class__) self.dbstate = dbstate self.uistate = uistate self.map = {} self.list = [] self.index = 0 self.merger = None self.mergee = None self.removed = {} self.update = callback self.use_soundex = 1 top = Glade(toplevel="finddupes", also_load=["liststore1"]) # retrieve options threshold = self.options.handler.options_dict['threshold'] use_soundex = self.options.handler.options_dict['soundex'] my_menu = Gtk.ListStore(str, object) for val in sorted(_val2label): my_menu.append([_val2label[val], val]) self.soundex_obj = top.get_object("soundex") self.soundex_obj.set_active(use_soundex) self.soundex_obj.show() self.menu = top.get_object("menu") self.menu.set_model(my_menu) self.menu.set_active(0) window = top.toplevel self.set_window(window, top.get_object('title'), _('Find Possible Duplicate People')) self.setup_configs('interface.duplicatepeopletool', 350, 220) top.connect_signals({ "on_do_merge_clicked": self.__dummy, "on_help_show_clicked": self.__dummy, "on_delete_show_event": self.__dummy, "on_merge_ok_clicked": self.on_merge_ok_clicked, "destroy_passed_object": self.close, "on_help_clicked": self.on_help_clicked, "on_delete_merge_event": self.close, "on_delete_event": self.close, }) self.show() def build_menu_names(self, obj): return (_("Tool settings"), _("Find Duplicates tool")) def on_help_clicked(self, obj): """Display the relevant portion of Gramps manual""" display_help(WIKI_HELP_PAGE, WIKI_HELP_SEC) def ancestors_of(self, p1_id, id_list): if (not p1_id) or (p1_id in id_list): return id_list.append(p1_id) p1 = self.db.get_person_from_handle(p1_id) f1_id = p1.get_main_parents_family_handle() if f1_id: f1 = self.db.get_family_from_handle(f1_id) self.ancestors_of(f1.get_father_handle(), id_list) self.ancestors_of(f1.get_mother_handle(), id_list) def on_merge_ok_clicked(self, obj): threshold = self.menu.get_model()[self.menu.get_active()][1] self.use_soundex = int(self.soundex_obj.get_active()) try: self.find_potentials(threshold) except AttributeError as msg: RunDatabaseRepair(str(msg), parent=self.window) return self.options.handler.options_dict['threshold'] = threshold self.options.handler.options_dict['soundex'] = self.use_soundex # Save options self.options.handler.save_options() if len(self.map) == 0: OkDialog(_("No matches found"), _("No potential duplicate people were found"), parent=self.window) else: try: DuplicatePeopleToolMatches(self.dbstate, self.uistate, self.track, self.list, self.map, self.update) except WindowActiveError: pass def find_potentials(self, thresh): self.progress = ProgressMeter(_('Find Duplicates'), _('Looking for duplicate people'), parent=self.window) index = 0 males = {} females = {} self.map = {} length = self.db.get_number_of_people() self.progress.set_pass(_('Pass 1: Building preliminary lists'), length) for p1_id in self.db.iter_person_handles(): self.progress.step() p1 = self.db.get_person_from_handle(p1_id) key = self.gen_key(get_surnames(p1.get_primary_name())) if p1.get_gender() == Person.MALE: if key in males: males[key].append(p1_id) else: males[key] = [p1_id] else: if key in females: females[key].append(p1_id) else: females[key] = [p1_id] self.progress.set_pass(_('Pass 2: Calculating potential matches'), length) for p1key in self.db.iter_person_handles(): self.progress.step() p1 = self.db.get_person_from_handle(p1key) key = self.gen_key(get_surnames(p1.get_primary_name())) if p1.get_gender() == Person.MALE: remaining = males[key] else: remaining = females[key] #index = 0 for p2key in remaining: #index += 1 if p1key == p2key: continue p2 = self.db.get_person_from_handle(p2key) if p2key in self.map: (v, c) = self.map[p2key] if v == p1key: continue chance = self.compare_people(p1, p2) if chance >= thresh: if p1key in self.map: val = self.map[p1key] if val[1] > chance: self.map[p1key] = (p2key, chance) else: self.map[p1key] = (p2key, chance) self.list = sorted(self.map) self.length = len(self.list) self.progress.close() def gen_key(self, val): if self.use_soundex: try: return soundex(val) except UnicodeEncodeError: return val else: return val def compare_people(self, p1, p2): name1 = p1.get_primary_name() name2 = p2.get_primary_name() chance = self.name_match(name1, name2) if chance == -1: return -1 birth1_ref = p1.get_birth_ref() if birth1_ref: birth1 = self.db.get_event_from_handle(birth1_ref.ref) else: birth1 = Event() death1_ref = p1.get_death_ref() if death1_ref: death1 = self.db.get_event_from_handle(death1_ref.ref) else: death1 = Event() birth2_ref = p2.get_birth_ref() if birth2_ref: birth2 = self.db.get_event_from_handle(birth2_ref.ref) else: birth2 = Event() death2_ref = p2.get_death_ref() if death2_ref: death2 = self.db.get_event_from_handle(death2_ref.ref) else: death2 = Event() value = self.date_match(birth1.get_date_object(), birth2.get_date_object()) if value == -1: return -1 chance += value value = self.date_match(death1.get_date_object(), death2.get_date_object()) if value == -1: return -1 chance += value value = self.place_match(birth1.get_place_handle(), birth2.get_place_handle()) if value == -1: return -1 chance += value value = self.place_match(death1.get_place_handle(), death2.get_place_handle()) if value == -1: return -1 chance += value ancestors = [] self.ancestors_of(p1.get_handle(), ancestors) if p2.get_handle() in ancestors: return -1 ancestors = [] self.ancestors_of(p2.get_handle(), ancestors) if p1.get_handle() in ancestors: return -1 f1_id = p1.get_main_parents_family_handle() f2_id = p2.get_main_parents_family_handle() if f1_id and f2_id: f1 = self.db.get_family_from_handle(f1_id) f2 = self.db.get_family_from_handle(f2_id) dad1_id = f1.get_father_handle() if dad1_id: dad1 = get_name_obj(self.db.get_person_from_handle(dad1_id)) else: dad1 = None dad2_id = f2.get_father_handle() if dad2_id: dad2 = get_name_obj(self.db.get_person_from_handle(dad2_id)) else: dad2 = None value = self.name_match(dad1, dad2) if value == -1: return -1 chance += value mom1_id = f1.get_mother_handle() if mom1_id: mom1 = get_name_obj(self.db.get_person_from_handle(mom1_id)) else: mom1 = None mom2_id = f2.get_mother_handle() if mom2_id: mom2 = get_name_obj(self.db.get_person_from_handle(mom2_id)) else: mom2 = None value = self.name_match(mom1, mom2) if value == -1: return -1 chance += value for f1_id in p1.get_family_handle_list(): f1 = self.db.get_family_from_handle(f1_id) for f2_id in p2.get_family_handle_list(): f2 = self.db.get_family_from_handle(f2_id) if p1.get_gender() == Person.FEMALE: father1_id = f1.get_father_handle() father2_id = f2.get_father_handle() if father1_id and father2_id: if father1_id == father2_id: chance += 1 else: father1 = self.db.get_person_from_handle( father1_id) father2 = self.db.get_person_from_handle( father2_id) fname1 = get_name_obj(father1) fname2 = get_name_obj(father2) value = self.name_match(fname1, fname2) if value != -1: chance += value else: mother1_id = f1.get_mother_handle() mother2_id = f2.get_mother_handle() if mother1_id and mother2_id: if mother1_id == mother2_id: chance += 1 else: mother1 = self.db.get_person_from_handle( mother1_id) mother2 = self.db.get_person_from_handle( mother2_id) mname1 = get_name_obj(mother1) mname2 = get_name_obj(mother2) value = self.name_match(mname1, mname2) if value != -1: chance += value return chance def name_compare(self, s1, s2): if self.use_soundex: try: return compare(s1, s2) except UnicodeEncodeError: return s1 == s2 else: return s1 == s2 def date_match(self, date1, date2): if date1.is_empty() or date2.is_empty(): return 0 if date1.is_equal(date2): return 1 if date1.is_compound() or date2.is_compound(): return self.range_compare(date1, date2) if date1.get_year() == date2.get_year(): if date1.get_month() == date2.get_month(): return 0.75 if not date1.get_month_valid() or not date2.get_month_valid(): return 0.75 else: return -1 else: return -1 def range_compare(self, date1, date2): start_date_1 = date1.get_start_date()[0:3] start_date_2 = date2.get_start_date()[0:3] stop_date_1 = date1.get_stop_date()[0:3] stop_date_2 = date2.get_stop_date()[0:3] if date1.is_compound() and date2.is_compound(): if (start_date_2 <= start_date_1 <= stop_date_2 or start_date_1 <= start_date_2 <= stop_date_1 or start_date_2 <= stop_date_1 <= stop_date_2 or start_date_1 <= stop_date_2 <= stop_date_1): return 0.5 else: return -1 elif date2.is_compound(): if start_date_2 <= start_date_1 <= stop_date_2: return 0.5 else: return -1 else: if start_date_1 <= start_date_2 <= stop_date_1: return 0.5 else: return -1 def name_match(self, name, name1): if not name1 or not name: return 0 srn1 = get_surnames(name) sfx1 = name.get_suffix() srn2 = get_surnames(name1) sfx2 = name1.get_suffix() if not self.name_compare(srn1, srn2): return -1 if sfx1 != sfx2: if sfx1 != "" and sfx2 != "": return -1 if name.get_first_name() == name1.get_first_name(): return 1 else: list1 = name.get_first_name().split() list2 = name1.get_first_name().split() if len(list1) < len(list2): return self.list_reduce(list1, list2) else: return self.list_reduce(list2, list1) def place_match(self, p1_id, p2_id): if p1_id == p2_id: return 1 if not p1_id: name1 = "" else: p1 = self.db.get_place_from_handle(p1_id) name1 = p1.get_title() if not p2_id: name2 = "" else: p2 = self.db.get_place_from_handle(p2_id) name2 = p2.get_title() if not (name1 and name2): return 0 if name1 == name2: return 1 list1 = name1.replace(",", " ").split() list2 = name2.replace(",", " ").split() value = 0 for name in list1: for name2 in list2: if name == name2: value += 0.5 elif name[0] == name2[0] and self.name_compare(name, name2): value += 0.25 return min(value, 1) if value else -1 def list_reduce(self, list1, list2): value = 0 for name in list1: for name2 in list2: if is_initial(name) and name[0] == name2[0]: value += 0.25 elif is_initial(name2) and name2[0] == name[0]: value += 0.25 elif name == name2: value += 0.5 elif name[0] == name2[0] and self.name_compare(name, name2): value += 0.25 return min(value, 1) if value else -1 def __dummy(self, obj): """dummy callback, needed because a shared glade file is used for both toplevel windows and all signals must be handled. """ pass
def find_potentials(self, thresh): self.progress = ProgressMeter(_('Find Duplicates'), _('Looking for duplicate people'), parent=self.window) index = 0 males = {} females = {} self.map = {} length = self.db.get_number_of_people() self.progress.set_pass(_('Pass 1: Building preliminary lists'), length) for p1_id in self.db.iter_person_handles(): self.progress.step() p1 = self.db.get_person_from_handle(p1_id) key = self.gen_key(get_surnames(p1.get_primary_name())) if p1.get_gender() == Person.MALE: if key in males: males[key].append(p1_id) else: males[key] = [p1_id] else: if key in females: females[key].append(p1_id) else: females[key] = [p1_id] self.progress.set_pass(_('Pass 2: Calculating potential matches'), length) for p1key in self.db.iter_person_handles(): self.progress.step() p1 = self.db.get_person_from_handle(p1key) key = self.gen_key(get_surnames(p1.get_primary_name())) if p1.get_gender() == Person.MALE: remaining = males[key] else: remaining = females[key] #index = 0 for p2key in remaining: #index += 1 if p1key == p2key: continue p2 = self.db.get_person_from_handle(p2key) if p2key in self.map: (v, c) = self.map[p2key] if v == p1key: continue chance = self.compare_people(p1, p2) if chance >= thresh: if p1key in self.map: val = self.map[p1key] if val[1] > chance: self.map[p1key] = (p2key, chance) else: self.map[p1key] = (p2key, chance) self.list = sorted(self.map) self.length = len(self.list) self.progress.close()
class DownloadMedia(tool.Tool, ManagedWindow): """ Gramplet that downloads media from the internet. """ def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate self.label = _('Download media') ManagedWindow.__init__(self, uistate, [], self.__class__) self.set_window(Gtk.Window(), Gtk.Label(), '') tool.Tool.__init__(self, dbstate, options_class, name) self.num_downloads = 0 dialog = self.display() response = dialog.run() dialog.destroy() if response == Gtk.ResponseType.ACCEPT: self.on_ok_clicked() OkDialog(_('Media downloaded'), _("%d media files downloaded") % self.num_downloads) self.close() def display(self): """ Constructs the GUI, consisting of a message, and fields to enter the name and password (commented out for now) """ # GUI setup: dialog = Gtk.Dialog(_("Download media tool"), self.uistate.window, Gtk.DialogFlags.MODAL| Gtk.DialogFlags.DESTROY_WITH_PARENT, (Gtk.STOCK_CANCEL, Gtk.ResponseType.REJECT, Gtk.STOCK_OK, Gtk.ResponseType.ACCEPT)) label = Gtk.Label(_("Make sure you are connected to the internet " "before starting this tool.")) label.set_line_wrap(True) vbox = Gtk.VBox() vbox.pack_start(label, True, True, 0) # hbox1 = Gtk.HBox() # label_name = Gtk.Label(_("Name") + ":") # self.name_entry = Gtk.Entry() # self.name_entry.set_text("%s" % name) # hbox1.pack_start(label_name, False, False, 0) # hbox1.pack_start(self.name_entry, True, True, 0) # vbox.pack_start(hbox1, False) # # hbox2 = Gtk.HBox() # label_password = Gtk.Label(_("Password") + ":") # self.password_entry = Gtk.Entry() # self.password_entry.set_text("%s" % password) # hbox2.pack_start(label_password, False, False, 0) # hbox2.pack_start(self.password_entry, True, True, 0) # vbox.pack_start(hbox2, False) dialog.vbox.set_spacing(10) dialog.vbox.pack_start(vbox, True, True, 0) dialog.show_all() return dialog def on_ok_clicked(self): """ Method that is run when you click the OK button. """ downloaded = {} # Get a directory to put the media files in. If the media path in # preferences is not just the user's home, then we will use that. If it # is the user's home, we create a new directory below that, so we don't # splatter files into home. media_path = self.db.get_mediapath() if media_path == USER_HOME or media_path == "" or media_path == None: media_path = os.path.join(USER_HOME, "mediadir") if not os.path.isdir(media_path): os.makedirs(media_path) # Many thanks to 'sirex' from whom I have taken the code he submitted as # part of bug 0003553: Import media files from GEDCOM file_pattern = re.compile(r'.*\.(png|jpg|jpeg|gif)$') def fetch_file(url, filename): LOG.debug("Downloading url %s to file %s" % (url, filename)) fr = urlopen(url) fw = open(filename, 'wb') for block in fr: fw.write(block) fw.close() fr.close() self.progress = ProgressMeter( _('Downloading files'), '') self.progress.set_pass(_('Downloading files'), self.db.get_number_of_media_objects()) self.db.disable_signals() with DbTxn('Download files', self.db) as trans: for media_handle in self.db.media_map.keys(): media = self.db.get_object_from_handle(media_handle) url = media.get_path() res = urlparse(url) LOG.debug(res) if res.scheme == "http" or res.scheme == "https": if file_pattern.match(url): if url in downloaded: full_path = downloaded[url] else: filename = url.split('/')[-1] full_path = os.path.join(media_path, filename) fetch_file(url, full_path) downloaded[url] = full_path self.num_downloads += 1 media.set_path(full_path) media.set_mime_type(get_type(full_path)) self.db.commit_media_object(media, trans) self.progress.step() self.db.enable_signals() self.db.request_rebuild() self.progress.close()
class MergeCitations(tool.BatchTool, ManagedWindow): def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate ManagedWindow.__init__(self, uistate, [], self.__class__) self.dbstate = dbstate self.set_window(Gtk.Window(), Gtk.Label(), '') tool.BatchTool.__init__(self, dbstate, user, options_class, name) if not self.fail: uistate.set_busy_cursor(True) self.run() 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""" display_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) if citation is None: continue key = citation.get_page() if fields != IGNORE_DATE and fields != IGNORE_BOTH: key += "\n" + get_date(citation) if fields != IGNORE_CONFIDENCE and fields != IGNORE_BOTH: key += "\n" + \ conf_strings[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"), # translators: leave all/any {...} untranslated ngettext("{number_of} citation merged", "{number_of} citations merged", num_merges).format(number_of=num_merges)) self.close(obj)
class FindLoop(ManagedWindow): """ Find loops in the family tree. """ def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate self.title = _('Find database loop') ManagedWindow.__init__(self, uistate, [], self.__class__) self.dbstate = dbstate self.uistate = uistate #self.db = CacheProxyDb(dbstate.db) self.db = dbstate.db top_dialog = Glade() top_dialog.connect_signals({ "destroy_passed_object" : self.close, "on_help_clicked" : self.on_help_clicked, "on_delete_event" : self.close, }) window = top_dialog.toplevel title = top_dialog.get_object("title") self.set_window(window, title, self.title) # start the progress indicator self.progress = ProgressMeter(self.title, _('Starting'), parent=uistate.window) self.progress.set_pass(_('Looking for possible loop for each person'), self.db.get_number_of_people()) self.model = Gtk.ListStore( GObject.TYPE_STRING, # 0==father id GObject.TYPE_STRING, # 1==father GObject.TYPE_STRING, # 2==son id GObject.TYPE_STRING, # 3==son GObject.TYPE_STRING, # 4==family gid GObject.TYPE_STRING) # 5==loop number self.model.set_sort_column_id( Gtk.TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, 0) self.treeview = top_dialog.get_object("treeview") self.treeview.set_model(self.model) col0 = Gtk.TreeViewColumn('', Gtk.CellRendererText(), text=5) col1 = Gtk.TreeViewColumn(_('Gramps ID'), Gtk.CellRendererText(), text=0) col2 = Gtk.TreeViewColumn(_('Parent'), Gtk.CellRendererText(), text=1) col3 = Gtk.TreeViewColumn(_('Gramps ID'), Gtk.CellRendererText(), text=2) col4 = Gtk.TreeViewColumn(_('Child'), Gtk.CellRendererText(), text=3) col5 = Gtk.TreeViewColumn(_('Family ID'), Gtk.CellRendererText(), text=4) col1.set_resizable(True) col2.set_resizable(True) col3.set_resizable(True) col4.set_resizable(True) col5.set_resizable(True) col1.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) col2.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) col3.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) col4.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) col5.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) self.treeview.append_column(col0) self.treeview.append_column(col1) self.treeview.append_column(col2) self.treeview.append_column(col3) self.treeview.append_column(col4) self.treeview.append_column(col5) self.treeselection = self.treeview.get_selection() self.treeview.connect('row-activated', self.rowactivated_cb) self.curr_fam = None people = self.db.get_person_handles() self.total = len(people) # total number of people to process. self.count = 0 # current number of people completely processed self.loop = 0 # Number of loops found for GUI pset = OrderedDict() # pset is the handle list of persons from the current start of # exploration path to the current limit. The use of OrderedDict # allows us to use it as a LIFO during recursion, as well as makes for # quick lookup. If we find a loop, pset provides a nice way to get # the loop path. self.done = set() # self.done is the handle set of people that have been fully explored # and do NOT have loops in the decendent tree. We use this to avoid # repeating work when we encounter one of these during the search. for person_handle in people: person = self.db.get_person_from_handle(person_handle) self.current = person self.parent = None self.descendants(person_handle, pset) # close the progress bar self.progress.close() self.show() def descendants(self, person_handle, pset): """ Find the descendants of a given person. Returns False if a loop for the person is NOT found, True if loop found We use the return value to ensure a person is not put on done list if part of a loop """ if person_handle in self.done: return False # We have already verified no loops for this one if person_handle in pset: # We found one loop. # person_handle is child, self.parent, self.curr_fam valid # see if it has already been put into display person = self.db.get_person_from_handle(person_handle) pers_id = person.get_gramps_id() pers_name = _nd.display(person) parent_id = self.parent.get_gramps_id() parent_name = _nd.display(self.parent) value = (parent_id, parent_name, pers_id, pers_name, self.curr_fam) found = False for pth in range(len(self.model)): path = Gtk.TreePath(pth) treeiter = self.model.get_iter(path) find = (self.model.get_value(treeiter, 0), self.model.get_value(treeiter, 1), self.model.get_value(treeiter, 2), self.model.get_value(treeiter, 3), self.model.get_value(treeiter, 4)) if find == value: found = True # This loop is in display model break if not found: # Need to put loop in display model. self.loop += 1 # place first node self.model.append(value + (str(self.loop),)) state = 0 # Now search for loop beginning. for hndl in pset.keys(): if hndl != person_handle and state == 0: continue # beginning not found if state == 0: state = 1 # found beginning, get first item to display continue # we have a good handle, now put item on display list self.parent = person person = self.db.get_person_from_handle(hndl) # Get the family that is both parent/person for fam_h in person.get_parent_family_handle_list(): if fam_h in self.parent.get_family_handle_list(): break family = self.db.get_family_from_handle(fam_h) fam_id = family.get_gramps_id() pers_id = person.get_gramps_id() pers_name = _nd.display(person) parent_id = self.parent.get_gramps_id() parent_name = _nd.display(self.parent) value = (parent_id, parent_name, pers_id, pers_name, fam_id, str(self.loop)) self.model.append(value) return True # We are not part of loop (yet) so search descendents person = self.db.get_person_from_handle(person_handle) # put in the pset path list for recursive calls to find pset[person_handle] = None loop = False for family_handle in person.get_family_handle_list(): family = self.db.get_family_from_handle(family_handle) if not family: # can happen with LivingProxyDb(PrivateProxyDb(db)) continue for child_ref in family.get_child_ref_list(): child_handle = child_ref.ref self.curr_fam = family.get_gramps_id() self.parent = person # if any descendants are part of loop, so is search person loop |= self.descendants(child_handle, pset) # we have completed search, we can pop the person off pset list person_handle, dummy = pset.popitem(last=True) if not loop: # person was not in loop, so add to done list and update progress self.done.add(person_handle) self.count += 1 self.progress.set_header("%d/%d" % (self.count, self.total)) self.progress.step() return False # person was in loop... return True def rowactivated_cb(self, treeview, path, column): """ Called when a row is activated. """ # first we need to check that the row corresponds to a person iter_ = self.model.get_iter(path) fam_id = self.model.get_value(iter_, 4) fam = self.dbstate.db.get_family_from_gramps_id(fam_id) if fam: try: EditFamily(self.dbstate, self.uistate, [], fam) except WindowActiveError: pass return True return False def on_help_clicked(self, obj): """ Display the relevant portion of Gramps manual. """ display_help(webpage=WIKI_HELP_PAGE, section=WIKI_HELP_SEC) def close(self, *obj): ManagedWindow.close(self, *obj)
class ChangeNames(tool.BatchTool, ManagedWindow): def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate self.label = _('Capitalization changes') self.cb = callback ManagedWindow.__init__(self,uistate,[],self.__class__) self.set_window(Gtk.Window(),Gtk.Label(),'') tool.BatchTool.__init__(self, dbstate, user, options_class, name) if self.fail: return self.progress = ProgressMeter(_('Checking Family Names'),'') self.progress.set_pass(_('Searching family names'), len(self.db.get_surname_list())) self.name_list = [] for name in self.db.get_surname_list(): name.strip() namesplitSP= name.split() lSP = len(namesplitSP) namesplitHY= name.split('-') lHY = len(namesplitHY) if lSP == lHY == 1: if name != name.capitalize(): # Single surname without hyphen(s) self.name_list.append(name) #if lSP == 1 and lHY > 1: #print "LSP==1", name, name.capitalize() #if name != name.capitalize(): # Single surname with hyphen(s) #self.name_list.append(name) if lSP>1 and lHY == 1: # more than one string in surname but no hyphen # check if first string is in prefix_list, if so test for cap in rest s1 = 0 if namesplitSP[0].lower() in prefix_list: s1 = 1 for x in range(len(namesplitSP)-s1): # check if any subsurname is not cap notcap = False if namesplitSP[s1+x] != namesplitSP[s1+x].capitalize(): notcap = True break if notcap: # Multiple surnames possibly after prefix self.name_list.append(name) if lHY > 1: # more than one string in surname but hyphen(s) exists # check if first string is in prefix_list, if so test for cap if namesplitSP[0].lower() in prefix_list: namesplitHY[0] = namesplitHY[0].replace(namesplitSP[0],'').strip() for x in range(len(namesplitHY)): # check if any subsurname is not cap notcap = False if namesplitHY[x] != namesplitHY[x].capitalize(): notcap = True break if notcap: # Multiple surnames possibly after frefix self.name_list.append(name) if uistate: self.progress.step() if self.name_list: self.display() else: self.progress.close() self.close() OkDialog(_('No modifications made'), _("No capitalization changes were detected."), parent=uistate.window) def name_cap(self, name): name.strip() namesplitSP = name.split() lSP = len(namesplitSP) lHY = len(name.split('-')) namesep = ' ' if lHY > 1: namesep = '-' namesplitSP = name.replace(namesep,' ').split() lSP= len(namesplitSP) if lSP == lHY == 1: #if name != name.capitalize(): # Single surname without space(s) or hyphen(s), normal case return name.capitalize() else: # more than one string in surname but no hyphen # check if first string is in prefix_list, if so CAP the rest # Names like (von) Kohl(-)Brandt result = "" s1 = 0 if namesplitSP[0].lower() in prefix_list: s1 = 1 result = namesplitSP[0].lower()+ ' ' for x in range(lSP-s1): # CAP all subsurnames result = result + namesplitSP[s1+x].capitalize() + namesep return result[:-1] def display(self): self.top = Glade() window = self.top.toplevel self.top.connect_signals({ "destroy_passed_object" : self.close, "on_ok_clicked" : self.on_ok_clicked, "on_help_clicked" : self.on_help_clicked, "on_delete_event" : self.close, }) self.list = self.top.get_object("list") self.set_window(window,self.top.get_object('title'),self.label) self.model = Gtk.ListStore(GObject.TYPE_BOOLEAN, GObject.TYPE_STRING, GObject.TYPE_STRING) r = Gtk.CellRendererToggle() r.connect('toggled',self.toggled) c = Gtk.TreeViewColumn(_('Select'),r,active=0) self.list.append_column(c) c = Gtk.TreeViewColumn(_('Original Name'), Gtk.CellRendererText(),text=1) self.list.append_column(c) c = Gtk.TreeViewColumn(_('Capitalization Change'), Gtk.CellRendererText(),text=2) self.list.append_column(c) self.list.set_model(self.model) self.iter_list = [] self.progress.set_pass(_('Building display'),len(self.name_list)) for name in self.name_list: handle = self.model.append() self.model.set_value(handle,0,True) self.model.set_value(handle,1, name) namecap = self.name_cap(name) self.model.set_value(handle,2, namecap) self.iter_list.append(handle) self.progress.step() self.progress.close() self.show() def toggled(self,cell,path_string): path = tuple(map(int, path_string.split(':'))) row = self.model[path] row[0] = not row[0] def build_menu_names(self, obj): return (self.label,None) def on_help_clicked(self, obj): """Display the relevant portion of GRAMPS manual""" display_help(WIKI_HELP_PAGE , WIKI_HELP_SEC) def on_ok_clicked(self, obj): with DbTxn(_("Capitalization changes"), self.db, batch=True ) as self.trans: self.db.disable_signals() changelist = set(self.model.get_value(node,1) for node in self.iter_list if self.model.get_value(node,0)) #with self.db.get_person_cursor(update=True, commit=True) as cursor: # for handle, data in cursor: for handle in self.db.get_person_handles(False): person = self.db.get_person_from_handle(handle) #person = Person(data) change = False for name in [person.get_primary_name()] + person.get_alternate_names(): sname = find_surname_name(handle, name.serialize()) if sname in changelist: change = True for surn in name.get_surname_list(): sname = self.name_cap(surn.get_surname()) surn.set_surname(sname) if change: #cursor.update(handle, person.serialize()) self.db.commit_person(person, transaction=self.trans) self.db.enable_signals() self.db.request_rebuild() # FIXME: this probably needs to be removed, and bookmarks # should always be rebuilt on a commit_person via signals # self.parent.bookmarks.redraw() self.close() self.cb()
def _createmap(self,place_x): """ Create all markers for each people's event in the database which has a lat/lon. """ dbstate = self.dbstate self.cal = config.get('preferences.calendar-format-report') self.place_list = [] self.places_found = [] self.place_without_coordinates = [] self.minlat = 0.0 self.maxlat = 0.0 self.minlon = 0.0 self.maxlon = 0.0 self.minyear = 9999 self.maxyear = 0 self.without = 0 latitude = "" longitude = "" self.nbmarkers = 0 self.nbplaces = 0 self.message_layer.clear_messages() self.message_layer.clear_font_attributes() self.no_show_places_in_status_bar = False # base "villes de france" : 38101 places : # createmap : 8'50"; create_markers : 1'23" # base "villes de france" : 38101 places : # createmap : 8'50"; create_markers : 0'07" with pixbuf optimization # base "villes de france" : 38101 places : # gramps 3.4 python 2.7 ( draw_markers are estimated when we move the map) # 38101 places : createmap : 04'32"; create_markers : 0'04"; draw markers : N/A :: 0'03" # 65598 places : createmap : 10'03"; create_markers : 0'07"; draw markers : N/A :: 0'05" # gramps 3.5 python 2.7 new marker layer # 38101 places : createmap : 03'09"; create_markers : 0'01"; draw markers : 0'04" # 65598 places : createmap : 08'48"; create_markers : 0'01"; draw markers : 0'07" _LOG.debug("%s" % time.strftime("start createmap : " "%a %d %b %Y %H:%M:%S", time.gmtime())) if self.show_all: self.show_all = False try: places_handle = dbstate.db.get_place_handles() except: return progress = ProgressMeter(self.window_name, can_cancel=False, parent=self.uistate.window) length = len(places_handle) progress.set_pass(_('Selecting all places'), length) for place_hdl in places_handle: place = dbstate.db.get_place_from_handle(place_hdl) self._create_one_place(place) progress.step() progress.close() elif self.generic_filter: place_list = self.generic_filter.apply(dbstate.db) progress = ProgressMeter(self.window_name, can_cancel=False, parent=self.uistate.window) length = len(place_list) progress.set_pass(_('Selecting all places'), length) for place_handle in place_list: place = dbstate.db.get_place_from_handle(place_handle) self._create_one_place(place) progress.step() progress.close() elif place_x: place = dbstate.db.get_place_from_handle(place_x) self._create_one_place(place) if ( place.get_latitude() != "" and place.get_longitude() != "" ): self.osm.set_center_and_zoom(float(place.get_latitude()), float(place.get_longitude()), int(config.get("geography.zoom"))) _LOG.debug(" stop createmap.") _LOG.debug("%s" % time.strftime("begin sort : " "%a %d %b %Y %H:%M:%S", time.gmtime())) self.sort = sorted(self.place_list, key=operator.itemgetter(0) ) _LOG.debug("%s" % time.strftime(" end sort : " "%a %d %b %Y %H:%M:%S", time.gmtime())) if self.nbmarkers > 500 : # performance issue. Is it the good value ? self.message_layer.add_message( _("The place name in the status bar is disabled.")) self.no_show_places_in_status_bar = True if self.nbplaces >= self._config.get("geography.max_places") : self.message_layer.set_font_attributes(None,None,"red") self.message_layer.add_message( _("The maximum number of places is reached (%d)." % self._config.get("geography.max_places"))) self.message_layer.add_message( _("Some information are missing.")) self.message_layer.add_message( _("Please, use filtering to reduce this number.")) self.message_layer.add_message( _("You can modify this value in the geography option.")) self.message_layer.add_message( _("In this case, it may take time to show all markers.")) self._create_markers()
class DisplayChart(ManagedWindow): def __init__(self, dbstate, uistate, people_list, track): self.dbstate = dbstate self.uistate = uistate ManagedWindow.__init__(self, uistate, track, self) self.db = dbstate.db self.my_list = people_list self.row_data = [] self.save_form = None self.topDialog = Glade() self.topDialog.connect_signals( { "on_write_table": self.on_write_table, "destroy_passed_object": self.close, "on_help_clicked": self.on_help_clicked, "on_apply_clicked": self.__dummy, "on_editor_clicked": self.__dummy, } ) window = self.topDialog.toplevel self.set_window(window, self.topDialog.get_object("title"), _("Event Comparison Results")) self.eventlist = self.topDialog.get_object("treeview") self.sort = Sort(self.db) self.my_list.sort(key=self.sort.by_last_name_key) self.event_titles = self.make_event_titles() self.table_titles = [_("Person"), _("ID")] for event_name in self.event_titles: self.table_titles.append(_("%(event_name)s Date") % {"event_name": event_name}) self.table_titles.append("sort") # This won't be shown in a tree self.table_titles.append(_("%(event_name)s Place") % {"event_name": event_name}) self.build_row_data() self.draw_display() self.show() def __dummy(self, obj): """dummy callback, needed because widget is in same glade file as another widget, so callbacks must be defined to avoid warnings. """ pass def on_help_clicked(self, obj): """Display the relevant portion of GRAMPS manual""" display_help(webpage=WIKI_HELP_PAGE, section=WIKI_HELP_SEC) def build_menu_names(self, obj): return (_("Event Comparison Results"), None) def draw_display(self): model_index = 0 tree_index = 0 mylist = [] renderer = Gtk.CellRendererText() for title in self.table_titles: mylist.append(str) if title == "sort": # This will override the previously defined column self.eventlist.get_column(tree_index - 1).set_sort_column_id(model_index) else: column = Gtk.TreeViewColumn(title, renderer, text=model_index) column.set_sort_column_id(model_index) self.eventlist.append_column(column) # This one numbers the tree columns: increment on new column tree_index += 1 # This one numbers the model columns: always increment model_index += 1 model = Gtk.ListStore(*mylist) self.eventlist.set_model(model) self.progress_bar.set_pass(_("Building display"), len(self.row_data)) for data in self.row_data: model.append(row=list(data)) self.progress_bar.step() self.progress_bar.close() def build_row_data(self): self.progress_bar = ProgressMeter(_("Comparing Events"), "", parent=self.window) self.progress_bar.set_pass(_("Building data"), len(self.my_list)) for individual_id in self.my_list: individual = self.db.get_person_from_handle(individual_id) name = individual.get_primary_name().get_name() gid = individual.get_gramps_id() the_map = defaultdict(list) for ievent_ref in individual.get_event_ref_list(): ievent = self.db.get_event_from_handle(ievent_ref.ref) event_name = str(ievent.get_type()) the_map[event_name].append(ievent_ref.ref) first = True done = False while not done: added = False tlist = [name, gid] if first else ["", ""] for ename in self.event_titles: if ename in the_map and len(the_map[ename]) > 0: event_handle = the_map[ename][0] del the_map[ename][0] date = place = "" if event_handle: event = self.db.get_event_from_handle(event_handle) date = get_date(event) sortdate = "%09d" % (event.get_date_object().get_sort_value()) place_handle = event.get_place_handle() if place_handle: place = self.db.get_place_from_handle(place_handle).get_title() tlist += [date, sortdate, place] added = True else: tlist += [""] * 3 if first: first = False self.row_data.append(tlist) elif not added: done = True else: self.row_data.append(tlist) self.progress_bar.step() def make_event_titles(self): """ Create the list of unique event types, along with the person's name, birth, and death. This should be the column titles of the report. """ the_map = defaultdict(int) for individual_id in self.my_list: individual = self.db.get_person_from_handle(individual_id) for event_ref in individual.get_event_ref_list(): event = self.db.get_event_from_handle(event_ref.ref) name = str(event.get_type()) if not name: break the_map[name] += 1 unsort_list = sorted([(d, k) for k, d in the_map.items()], key=lambda x: x[0], reverse=True) sort_list = [item[1] for item in unsort_list] ## Presently there's no Birth and Death. Instead there's Birth Date and ## Birth Place, as well as Death Date and Death Place. ## # Move birth and death to the begining of the list ## if _("Death") in the_map: ## sort_list.remove(_("Death")) ## sort_list = [_("Death")] + sort_list ## if _("Birth") in the_map: ## sort_list.remove(_("Birth")) ## sort_list = [_("Birth")] + sort_list return sort_list def on_write_table(self, obj): f = Gtk.FileChooserDialog( _("Select filename"), parent=self.window, action=Gtk.FileChooserAction.SAVE, buttons=(_("_Cancel"), Gtk.ResponseType.CANCEL, _("_Save"), Gtk.ResponseType.OK), ) f.set_current_folder(get_curr_dir()) status = f.run() f.hide() if status == Gtk.ResponseType.OK: name = conv_to_unicode(f.get_filename()) doc = ODSTab(len(self.row_data)) doc.creator(self.db.get_researcher().get_name()) spreadsheet = TableReport(name, doc) new_titles = [] skip_columns = [] index = 0 for title in self.table_titles: if title == "sort": skip_columns.append(index) else: new_titles.append(title) index += 1 spreadsheet.initialize(len(new_titles)) spreadsheet.write_table_head(new_titles) index = 0 for top in self.row_data: spreadsheet.set_row(index % 2) index += 1 spreadsheet.write_table_data(top, skip_columns) spreadsheet.finalize() f.destroy()
def find_potentials(self, thresh): self.progress = ProgressMeter(_('Find Duplicates'), _('Looking for duplicate people'), parent=self.window) index = 0 males = {} females = {} length = self.db.get_number_of_people() self.progress.set_pass(_('Pass 1: Building preliminary lists'), length) for p1_id in self.db.iter_person_handles(): self.progress.step() p1 = self.db.get_person_from_handle(p1_id) key = self.gen_key(get_surnames(p1.get_primary_name())) if p1.get_gender() == Person.MALE: if key in males: males[key].append(p1_id) else: males[key] = [p1_id] else: if key in females: females[key].append(p1_id) else: females[key] = [p1_id] self.progress.set_pass(_('Pass 2: Calculating potential matches'), length) for p1key in self.db.iter_person_handles(): self.progress.step() p1 = self.db.get_person_from_handle(p1key) key = self.gen_key(get_surnames(p1.get_primary_name())) if p1.get_gender() == Person.MALE: remaining = males[key] else: remaining = females[key] #index = 0 for p2key in remaining: #index += 1 if p1key == p2key: continue p2 = self.db.get_person_from_handle(p2key) if p2key in self.map: (v,c) = self.map[p2key] if v == p1key: continue chance = self.compare_people(p1,p2) if chance >= thresh: if p1key in self.map: val = self.map[p1key] if val[1] > chance: self.map[p1key] = (p2key,chance) else: self.map[p1key] = (p2key,chance) self.list = sorted(self.map) self.length = len(self.list) self.progress.close()
class Merge(tool.Tool,ManagedWindow): def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate tool.Tool.__init__(self, dbstate, options_class, name) ManagedWindow.__init__(self, uistate, [], self.__class__) self.dbstate = dbstate self.uistate = uistate self.map = {} self.list = [] self.index = 0 self.merger = None self.mergee = None self.removed = {} self.update = callback self.use_soundex = 1 top = Glade() # retrieve options threshold = self.options.handler.options_dict['threshold'] use_soundex = self.options.handler.options_dict['soundex'] my_menu = Gtk.ListStore(str, object) for val in sorted(_val2label): my_menu.append([_val2label[val], val]) self.soundex_obj = top.get_object("soundex") self.soundex_obj.set_active(use_soundex) self.soundex_obj.show() self.menu = top.get_object("menu") self.menu.set_model(my_menu) self.menu.set_active(0) window = top.toplevel self.set_window(window, top.get_object('title'), _('Find Possible Duplicate People')) top.connect_signals({ "on_do_merge_clicked" : self.__dummy, "on_help_show_clicked" : self.__dummy, "on_delete_show_event" : self.__dummy, "on_merge_ok_clicked" : self.on_merge_ok_clicked, "destroy_passed_object" : self.close, "on_help_clicked" : self.on_help_clicked, "on_delete_merge_event" : self.close, "on_delete_event" : self.close, }) self.show() def build_menu_names(self, obj): return (_("Tool settings"),_("Find Duplicates tool")) def on_help_clicked(self, obj): """Display the relevant portion of GRAMPS manual""" display_help(WIKI_HELP_PAGE , WIKI_HELP_SEC) def ancestors_of(self, p1_id, id_list): if (not p1_id) or (p1_id in id_list): return id_list.append(p1_id) p1 = self.db.get_person_from_handle(p1_id) f1_id = p1.get_main_parents_family_handle() if f1_id: f1 = self.db.get_family_from_handle(f1_id) self.ancestors_of(f1.get_father_handle(),id_list) self.ancestors_of(f1.get_mother_handle(),id_list) def on_merge_ok_clicked(self, obj): threshold = self.menu.get_model()[self.menu.get_active()][1] self.use_soundex = int(self.soundex_obj.get_active()) try: self.find_potentials(threshold) except AttributeError as msg: RunDatabaseRepair(str(msg), parent=self.window) return self.options.handler.options_dict['threshold'] = threshold self.options.handler.options_dict['soundex'] = self.use_soundex # Save options self.options.handler.save_options() if len(self.map) == 0: OkDialog( _("No matches found"), _("No potential duplicate people were found"), parent=self.window) else: try: ShowMatches(self.dbstate,self.uistate,self.track, self.list,self.map,self.update) except WindowActiveError: pass def find_potentials(self, thresh): self.progress = ProgressMeter(_('Find Duplicates'), _('Looking for duplicate people'), parent=self.window) index = 0 males = {} females = {} length = self.db.get_number_of_people() self.progress.set_pass(_('Pass 1: Building preliminary lists'), length) for p1_id in self.db.iter_person_handles(): self.progress.step() p1 = self.db.get_person_from_handle(p1_id) key = self.gen_key(get_surnames(p1.get_primary_name())) if p1.get_gender() == Person.MALE: if key in males: males[key].append(p1_id) else: males[key] = [p1_id] else: if key in females: females[key].append(p1_id) else: females[key] = [p1_id] self.progress.set_pass(_('Pass 2: Calculating potential matches'), length) for p1key in self.db.iter_person_handles(): self.progress.step() p1 = self.db.get_person_from_handle(p1key) key = self.gen_key(get_surnames(p1.get_primary_name())) if p1.get_gender() == Person.MALE: remaining = males[key] else: remaining = females[key] #index = 0 for p2key in remaining: #index += 1 if p1key == p2key: continue p2 = self.db.get_person_from_handle(p2key) if p2key in self.map: (v,c) = self.map[p2key] if v == p1key: continue chance = self.compare_people(p1,p2) if chance >= thresh: if p1key in self.map: val = self.map[p1key] if val[1] > chance: self.map[p1key] = (p2key,chance) else: self.map[p1key] = (p2key,chance) self.list = sorted(self.map) self.length = len(self.list) self.progress.close() def gen_key(self, val): if self.use_soundex: try: return soundex(val) except UnicodeEncodeError: return val else: return val def compare_people(self, p1, p2): name1 = p1.get_primary_name() name2 = p2.get_primary_name() chance = self.name_match(name1, name2) if chance == -1 : return -1 birth1_ref = p1.get_birth_ref() if birth1_ref: birth1 = self.db.get_event_from_handle(birth1_ref.ref) else: birth1 = Event() death1_ref = p1.get_death_ref() if death1_ref: death1 = self.db.get_event_from_handle(death1_ref.ref) else: death1 = Event() birth2_ref = p2.get_birth_ref() if birth2_ref: birth2 = self.db.get_event_from_handle(birth2_ref.ref) else: birth2 = Event() death2_ref = p2.get_death_ref() if death2_ref: death2 = self.db.get_event_from_handle(death2_ref.ref) else: death2 = Event() value = self.date_match(birth1.get_date_object(), birth2.get_date_object()) if value == -1 : return -1 chance += value value = self.date_match(death1.get_date_object(), death2.get_date_object()) if value == -1 : return -1 chance += value value = self.place_match(birth1.get_place_handle(), birth2.get_place_handle()) if value == -1 : return -1 chance += value value = self.place_match(death1.get_place_handle(), death2.get_place_handle()) if value == -1 : return -1 chance += value ancestors = [] self.ancestors_of(p1.get_handle(),ancestors) if p2.get_handle() in ancestors: return -1 ancestors = [] self.ancestors_of(p2.get_handle(),ancestors) if p1.get_handle() in ancestors: return -1 f1_id = p1.get_main_parents_family_handle() f2_id = p2.get_main_parents_family_handle() if f1_id and f2_id: f1 = self.db.get_family_from_handle(f1_id) f2 = self.db.get_family_from_handle(f2_id) dad1_id = f1.get_father_handle() if dad1_id: dad1 = get_name_obj(self.db.get_person_from_handle(dad1_id)) else: dad1 = None dad2_id = f2.get_father_handle() if dad2_id: dad2 = get_name_obj(self.db.get_person_from_handle(dad2_id)) else: dad2 = None value = self.name_match(dad1,dad2) if value == -1: return -1 chance += value mom1_id = f1.get_mother_handle() if mom1_id: mom1 = get_name_obj(self.db.get_person_from_handle(mom1_id)) else: mom1 = None mom2_id = f2.get_mother_handle() if mom2_id: mom2 = get_name_obj(self.db.get_person_from_handle(mom2_id)) else: mom2 = None value = self.name_match(mom1,mom2) if value == -1: return -1 chance += value for f1_id in p1.get_family_handle_list(): f1 = self.db.get_family_from_handle(f1_id) for f2_id in p2.get_family_handle_list(): f2 = self.db.get_family_from_handle(f2_id) if p1.get_gender() == Person.FEMALE: father1_id = f1.get_father_handle() father2_id = f2.get_father_handle() if father1_id and father2_id: if father1_id == father2_id: chance += 1 else: father1 = self.db.get_person_from_handle(father1_id) father2 = self.db.get_person_from_handle(father2_id) fname1 = get_name_obj(father1) fname2 = get_name_obj(father2) value = self.name_match(fname1,fname2) if value != -1: chance += value else: mother1_id = f1.get_mother_handle() mother2_id = f2.get_mother_handle() if mother1_id and mother2_id: if mother1_id == mother2_id: chance += 1 else: mother1 = self.db.get_person_from_handle(mother1_id) mother2 = self.db.get_person_from_handle(mother2_id) mname1 = get_name_obj(mother1) mname2 = get_name_obj(mother2) value = self.name_match(mname1,mname2) if value != -1: chance += value return chance def name_compare(self, s1, s2): if self.use_soundex: try: return compare(s1,s2) except UnicodeEncodeError: return s1 == s2 else: return s1 == s2 def date_match(self, date1, date2): if date1.is_empty() or date2.is_empty(): return 0 if date1.is_equal(date2): return 1 if date1.is_compound() or date2.is_compound(): return self.range_compare(date1,date2) if date1.get_year() == date2.get_year(): if date1.get_month() == date2.get_month(): return 0.75 if not date1.get_month_valid() or not date2.get_month_valid(): return 0.75 else: return -1 else: return -1 def range_compare(self, date1, date2): start_date_1 = date1.get_start_date()[0:3] start_date_2 = date2.get_start_date()[0:3] stop_date_1 = date1.get_stop_date()[0:3] stop_date_2 = date2.get_stop_date()[0:3] if date1.is_compound() and date2.is_compound(): if (start_date_2 <= start_date_1 <= stop_date_2 or start_date_1 <= start_date_2 <= stop_date_1 or start_date_2 <= stop_date_1 <= stop_date_2 or start_date_1 <= stop_date_2 <= stop_date_1): return 0.5 else: return -1 elif date2.is_compound(): if start_date_2 <= start_date_1 <= stop_date_2: return 0.5 else: return -1 else: if start_date_1 <= start_date_2 <= stop_date_1: return 0.5 else: return -1 def name_match(self, name, name1): if not name1 or not name: return 0 srn1 = get_surnames(name) sfx1 = name.get_suffix() srn2 = get_surnames(name1) sfx2 = name1.get_suffix() if not self.name_compare(srn1,srn2): return -1 if sfx1 != sfx2: if sfx1 != "" and sfx2 != "": return -1 if name.get_first_name() == name1.get_first_name(): return 1 else: list1 = name.get_first_name().split() list2 = name1.get_first_name().split() if len(list1) < len(list2): return self.list_reduce(list1,list2) else: return self.list_reduce(list2,list1) def place_match(self, p1_id, p2_id): if p1_id == p2_id: return 1 if not p1_id: name1 = "" else: p1 = self.db.get_place_from_handle(p1_id) name1 = p1.get_title() if not p2_id: name2 = "" else: p2 = self.db.get_place_from_handle(p2_id) name2 = p2.get_title() if not (name1 and name2): return 0 if name1 == name2: return 1 list1 = name1.replace(","," ").split() list2 = name2.replace(","," ").split() value = 0 for name in list1: for name2 in list2: if name == name2: value += 0.5 elif name[0] == name2[0] and self.name_compare(name, name2): value += 0.25 return min(value,1) if value else -1 def list_reduce(self, list1, list2): value = 0 for name in list1: for name2 in list2: if is_initial(name) and name[0] == name2[0]: value += 0.25 elif is_initial(name2) and name2[0] == name[0]: value += 0.25 elif name == name2: value += 0.5 elif name[0] == name2[0] and self.name_compare(name, name2): value += 0.25 return min(value,1) if value else -1 def __dummy(self, obj): """dummy callback, needed because a shared glade file is used for both toplevel windows and all signals must be handled. """ pass
def _createmap(self, place_x): """ Create all markers for each people's event in the database which has a lat/lon. """ dbstate = self.dbstate self.place_list = [] self.places_found = [] self.place_without_coordinates = [] self.minlat = 0.0 self.maxlat = 0.0 self.minlon = 0.0 self.maxlon = 0.0 self.minyear = 9999 self.maxyear = 0 self.without = 0 latitude = "" longitude = "" self.nbmarkers = 0 self.nbplaces = 0 self.remove_all_markers() self.message_layer.clear_messages() self.message_layer.clear_font_attributes() self.kml_layer.clear() self.no_show_places_in_status_bar = False _col = self._config.get self.plc_color = [ (PlaceType.UNKNOWN, _col('geography.color.unknown')), (PlaceType.CUSTOM, _col('geography.color.custom')), (PlaceType.COUNTRY, _col('geography.color.country')), (PlaceType.STATE, _col('geography.color.state')), (PlaceType.COUNTY, _col('geography.color.county')), (PlaceType.CITY, _col('geography.color.city')), (PlaceType.PARISH, _col('geography.color.parish')), (PlaceType.LOCALITY, _col('geography.color.locality')), (PlaceType.STREET, _col('geography.color.street')), (PlaceType.PROVINCE, _col('geography.color.province')), (PlaceType.REGION, _col('geography.color.region')), (PlaceType.DEPARTMENT, _col('geography.color.department')), (PlaceType.NEIGHBORHOOD, _col('geography.color.neighborhood')), (PlaceType.DISTRICT, _col('geography.color.district')), (PlaceType.BOROUGH, _col('geography.color.borough')), (PlaceType.MUNICIPALITY, _col('geography.color.municipality')), (PlaceType.TOWN, _col('geography.color.town')), (PlaceType.VILLAGE, _col('geography.color.village')), (PlaceType.HAMLET, _col('geography.color.hamlet')), (PlaceType.FARM, _col('geography.color.farm')), (PlaceType.BUILDING, _col('geography.color.building')), (PlaceType.NUMBER, _col('geography.color.number')) ] # base "villes de france" : 38101 places : # createmap : 8'50"; create_markers : 1'23" # base "villes de france" : 38101 places : # createmap : 8'50"; create_markers : 0'07" with pixbuf optimization # base "villes de france" : 38101 places : # gramps 3.4 python 2.7 (draw_markers are estimated when moving the map) # 38101 places: createmap: 04'32"; # create_markers: 0'04"; draw markers: N/A :: 0'03" # 65598 places: createmap: 10'03"; # create_markers: 0'07"; draw markers: N/A :: 0'05" # gramps 3.5 python 2.7 new marker layer # 38101 places: createmap: 03'09"; # create_markers: 0'01"; draw markers: 0'04" # 65598 places: createmap: 08'48"; # create_markers: 0'01"; draw markers: 0'07" _LOG.debug("%s", time.strftime("start createmap : " "%a %d %b %Y %H:%M:%S", time.gmtime())) if self.show_all: self.show_all = False try: places_handle = dbstate.db.get_place_handles() except: return progress = ProgressMeter(self.window_name, can_cancel=False, parent=self.uistate.window) length = len(places_handle) progress.set_pass(_('Selecting all places'), length) for place_hdl in places_handle: place = dbstate.db.get_place_from_handle(place_hdl) self._create_one_place(place) progress.step() progress.close() elif self.generic_filter: user=self.uistate.viewmanager.user place_list = self.generic_filter.apply(dbstate.db, user=user) progress = ProgressMeter(self.window_name, can_cancel=False, parent=self.uistate.window) length = len(place_list) progress.set_pass(_('Selecting all places'), length) for place_handle in place_list: place = dbstate.db.get_place_from_handle(place_handle) self._create_one_place(place) progress.step() progress.close() # reset completely the filter. It will be recreated next time. self.generic_filter = None elif place_x != None: place = dbstate.db.get_place_from_handle(place_x) self._create_one_place(place) self.message_layer.add_message( _("Right click on the map and select 'show all places'" " to show all known places with coordinates. " "You can change the markers color depending on place type. " "You can use filtering.")) if place.get_latitude() != "" and place.get_longitude() != "": latitude, longitude = conv_lat_lon(place.get_latitude(), place.get_longitude(), "D.D8") self.osm.set_center_and_zoom(float(latitude), float(longitude), int(config.get( "geography.zoom_when_center"))) else: self.message_layer.add_message( _("Right click on the map and select 'show all places'" " to show all known places with coordinates. " "You can use the history to navigate on the map. " "You can change the markers color depending on place type. " "You can use filtering.")) _LOG.debug(" stop createmap.") _LOG.debug("%s", time.strftime("begin sort : " "%a %d %b %Y %H:%M:%S", time.gmtime())) self.sort = sorted(self.place_list, key=operator.itemgetter(0) ) _LOG.debug("%s", time.strftime(" end sort : " "%a %d %b %Y %H:%M:%S", time.gmtime())) if self.nbmarkers > 500: # performance issue. Is it the good value ? self.message_layer.add_message( _("The place name in the status bar is disabled.")) self.no_show_places_in_status_bar = True if self.nbplaces >= self._config.get("geography.max_places"): self.message_layer.set_font_attributes(None, None, "red") self.message_layer.add_message( _("The maximum number of places is reached (%d).") % self._config.get("geography.max_places")) self.message_layer.add_message( _("Some information are missing.")) self.message_layer.add_message( _("Please, use filtering to reduce this number.")) self.message_layer.add_message( _("You can modify this value in the geography option.")) self.message_layer.add_message( _("In this case, it may take time to show all markers.")) self._create_markers()
def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate self.title = _('Find database loop') ManagedWindow.__init__(self, uistate, [], self.__class__) self.dbstate = dbstate self.uistate = uistate #self.db = CacheProxyDb(dbstate.db) self.db = dbstate.db top_dialog = Glade() top_dialog.connect_signals({ "destroy_passed_object" : self.close, "on_help_clicked" : self.on_help_clicked, "on_delete_event" : self.close, }) window = top_dialog.toplevel title = top_dialog.get_object("title") self.set_window(window, title, self.title) # start the progress indicator self.progress = ProgressMeter(self.title, _('Starting'), parent=uistate.window) self.progress.set_pass(_('Looking for possible loop for each person'), self.db.get_number_of_people()) self.model = Gtk.ListStore( GObject.TYPE_STRING, # 0==father id GObject.TYPE_STRING, # 1==father GObject.TYPE_STRING, # 2==son id GObject.TYPE_STRING, # 3==son GObject.TYPE_STRING, # 4==family gid GObject.TYPE_STRING) # 5==loop number self.model.set_sort_column_id( Gtk.TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, 0) self.treeview = top_dialog.get_object("treeview") self.treeview.set_model(self.model) col0 = Gtk.TreeViewColumn('', Gtk.CellRendererText(), text=5) col1 = Gtk.TreeViewColumn(_('Gramps ID'), Gtk.CellRendererText(), text=0) col2 = Gtk.TreeViewColumn(_('Parent'), Gtk.CellRendererText(), text=1) col3 = Gtk.TreeViewColumn(_('Gramps ID'), Gtk.CellRendererText(), text=2) col4 = Gtk.TreeViewColumn(_('Child'), Gtk.CellRendererText(), text=3) col5 = Gtk.TreeViewColumn(_('Family ID'), Gtk.CellRendererText(), text=4) col1.set_resizable(True) col2.set_resizable(True) col3.set_resizable(True) col4.set_resizable(True) col5.set_resizable(True) col1.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) col2.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) col3.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) col4.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) col5.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) self.treeview.append_column(col0) self.treeview.append_column(col1) self.treeview.append_column(col2) self.treeview.append_column(col3) self.treeview.append_column(col4) self.treeview.append_column(col5) self.treeselection = self.treeview.get_selection() self.treeview.connect('row-activated', self.rowactivated_cb) self.curr_fam = None people = self.db.get_person_handles() self.total = len(people) # total number of people to process. self.count = 0 # current number of people completely processed self.loop = 0 # Number of loops found for GUI pset = OrderedDict() # pset is the handle list of persons from the current start of # exploration path to the current limit. The use of OrderedDict # allows us to use it as a LIFO during recursion, as well as makes for # quick lookup. If we find a loop, pset provides a nice way to get # the loop path. self.done = set() # self.done is the handle set of people that have been fully explored # and do NOT have loops in the decendent tree. We use this to avoid # repeating work when we encounter one of these during the search. for person_handle in people: person = self.db.get_person_from_handle(person_handle) self.current = person self.parent = None self.descendants(person_handle, pset) # close the progress bar self.progress.close() self.show()
def _createmap(self, place_x): """ Create all markers for each people's event in the database which has a lat/lon. """ dbstate = self.dbstate self.place_list = [] self.places_found = [] self.place_without_coordinates = [] self.minlat = 0.0 self.maxlat = 0.0 self.minlon = 0.0 self.maxlon = 0.0 self.minyear = 9999 self.maxyear = 0 self.without = 0 latitude = "" longitude = "" self.nbmarkers = 0 self.nbplaces = 0 self.remove_all_markers() self.message_layer.clear_messages() self.message_layer.clear_font_attributes() self.kml_layer.clear() self.no_show_places_in_status_bar = False _col = self._config.get self.plc_color = [ (PlaceType.UNKNOWN, _col('geography.color.unknown')), (PlaceType.CUSTOM, _col('geography.color.custom')), (PlaceType.COUNTRY, _col('geography.color.country')), (PlaceType.STATE, _col('geography.color.state')), (PlaceType.COUNTY, _col('geography.color.county')), (PlaceType.CITY, _col('geography.color.city')), (PlaceType.PARISH, _col('geography.color.parish')), (PlaceType.LOCALITY, _col('geography.color.locality')), (PlaceType.STREET, _col('geography.color.street')), (PlaceType.PROVINCE, _col('geography.color.province')), (PlaceType.REGION, _col('geography.color.region')), (PlaceType.DEPARTMENT, _col('geography.color.department')), (PlaceType.NEIGHBORHOOD, _col('geography.color.neighborhood')), (PlaceType.DISTRICT, _col('geography.color.district')), (PlaceType.BOROUGH, _col('geography.color.borough')), (PlaceType.MUNICIPALITY, _col('geography.color.municipality')), (PlaceType.TOWN, _col('geography.color.town')), (PlaceType.VILLAGE, _col('geography.color.village')), (PlaceType.HAMLET, _col('geography.color.hamlet')), (PlaceType.FARM, _col('geography.color.farm')), (PlaceType.BUILDING, _col('geography.color.building')), (PlaceType.NUMBER, _col('geography.color.number')) ] # base "villes de france" : 38101 places : # createmap : 8'50"; create_markers : 1'23" # base "villes de france" : 38101 places : # createmap : 8'50"; create_markers : 0'07" with pixbuf optimization # base "villes de france" : 38101 places : # gramps 3.4 python 2.7 (draw_markers are estimated when moving the map) # 38101 places: createmap: 04'32"; # create_markers: 0'04"; draw markers: N/A :: 0'03" # 65598 places: createmap: 10'03"; # create_markers: 0'07"; draw markers: N/A :: 0'05" # gramps 3.5 python 2.7 new marker layer # 38101 places: createmap: 03'09"; # create_markers: 0'01"; draw markers: 0'04" # 65598 places: createmap: 08'48"; # create_markers: 0'01"; draw markers: 0'07" _LOG.debug( "%s", time.strftime("start createmap : " "%a %d %b %Y %H:%M:%S", time.gmtime())) self.custom_places() if self.show_all: self.show_all = False try: places_handle = dbstate.db.get_place_handles() except: return progress = ProgressMeter(self.window_name, can_cancel=False, parent=self.uistate.window) length = len(places_handle) progress.set_pass(_('Selecting all places'), length) for place_hdl in places_handle: place = dbstate.db.get_place_from_handle(place_hdl) self._create_one_place(place) progress.step() progress.close() elif self.generic_filter: user = self.uistate.viewmanager.user place_list = self.generic_filter.apply(dbstate.db, user=user) progress = ProgressMeter(self.window_name, can_cancel=False, parent=self.uistate.window) length = len(place_list) progress.set_pass(_('Selecting all places'), length) for place_handle in place_list: place = dbstate.db.get_place_from_handle(place_handle) self._create_one_place(place) progress.step() progress.close() # reset completely the filter. It will be recreated next time. self.generic_filter = None elif place_x != None: place = dbstate.db.get_place_from_handle(place_x) self._create_one_place(place) self.message_layer.add_message( _("Right click on the map and select 'show all places'" " to show all known places with coordinates. " "You can change the markers color depending on place type. " "You can use filtering.")) if place.get_latitude() != "" and place.get_longitude() != "": latitude, longitude = conv_lat_lon(place.get_latitude(), place.get_longitude(), "D.D8") if latitude and longitude: self.osm.set_center_and_zoom( float(latitude), float(longitude), int(config.get("geography.zoom_when_center"))) else: self.message_layer.add_message( _("Right click on the map and select 'show all places'" " to show all known places with coordinates. " "You can use the history to navigate on the map. " "You can change the markers color depending on place type. " "You can use filtering.")) _LOG.debug(" stop createmap.") _LOG.debug( "%s", time.strftime("begin sort : " "%a %d %b %Y %H:%M:%S", time.gmtime())) self.sort = sorted(self.place_list, key=operator.itemgetter(0)) _LOG.debug( "%s", time.strftime(" end sort : " "%a %d %b %Y %H:%M:%S", time.gmtime())) if self.nbmarkers > 500: # performance issue. Is it the good value ? self.message_layer.add_message( _("The place name in the status bar is disabled.")) self.no_show_places_in_status_bar = True if self.nbplaces >= self._config.get("geography.max_places"): self.message_layer.set_font_attributes(None, None, "red") self.message_layer.add_message( _("The maximum number of places is reached (%d).") % self._config.get("geography.max_places")) self.message_layer.add_message(_("Some information are missing.")) self.message_layer.add_message( _("Please, use filtering to reduce this number.")) self.message_layer.add_message( _("You can modify this value in the geography option.")) self.message_layer.add_message( _("In this case, it may take time to show all markers.")) self._create_markers()
class PopulateSources(tool.Tool, ManagedWindow): """ Gramplet that populates the database with sources and citations. """ def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate self.label = 'Populate sources and citations tool' ManagedWindow.__init__(self, uistate, [], self.__class__) self.set_window(Gtk.Window(), Gtk.Label(), '') tool.Tool.__init__(self, dbstate, options_class, name) dialog = self.display() response = dialog.run() dialog.destroy() if response == Gtk.ResponseType.ACCEPT: self.on_ok_clicked() OkDialog('Data generated', "The requested sources and citations were generated") self.close() def display(self): """ Constructs the GUI, consisting of a message, and fields to enter the required number of sources and citations """ # retrieve options num_sources = self.options.handler.options_dict['sources'] num_citations = self.options.handler.options_dict['citations'] # GUI setup: dialog = Gtk.Dialog( "Populate sources and citations tool", self.uistate.window, Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT, (Gtk.STOCK_CANCEL, Gtk.ResponseType.REJECT, Gtk.STOCK_OK, Gtk.ResponseType.ACCEPT)) label = Gtk.Label("Enter a valid number of sources and citations." " This will create the requested number of sources," " and for each source, will create the requested" " number of citations.") label.set_line_wrap(True) hbox1 = Gtk.HBox() label_sources = Gtk.Label(label="Number of sources" + ":") self.sources_entry = Gtk.Entry() self.sources_entry.set_text("%d" % num_sources) hbox1.pack_start(label_sources, False, True, 0) hbox1.pack_start(self.sources_entry, True, True, 0) hbox2 = Gtk.HBox() label_citations = Gtk.Label(label="Number of citations" + ":") self.citations_entry = Gtk.Entry() self.citations_entry.set_text("%d" % num_citations) hbox2.pack_start(label_citations, False, True, 0) hbox2.pack_start(self.citations_entry, True, True, 0) vbox = Gtk.VBox() vbox.pack_start(label, True, True, 0) vbox.pack_start(hbox1, False, True, 0) vbox.pack_start(hbox2, False, True, 0) dialog.vbox.set_spacing(10) dialog.vbox.pack_start(vbox, True, True, 0) dialog.show_all() return dialog def on_ok_clicked(self): """ Method that is run when you click the OK button. The numbers of sources and citations are retrieved from the entry box and used to govern the amount of data generated """ num_sources_text = self.sources_entry.get_text() try: num_sources = int(num_sources_text) except: return num_citations_text = self.citations_entry.get_text() num_citations = int(num_citations_text) self.progress = ProgressMeter('Generating data', '') self.progress.set_pass('Generating data', num_sources * num_citations) LOG.debug("sources %04d citations %04d" % (num_sources, num_citations)) source = Source() citation = Citation() self.db.disable_signals() with DbTxn('Populate sources and citations', self.db) as trans: for i in range(num_sources): source.gramps_id = None source.handle = None source.title = "Source %04d" % (i + 1) source_handle = self.db.add_source(source, trans) for j in range(num_citations): citation.gramps_id = None citation.handle = None citation.source_handle = source_handle citation.page = "Page %04d" % (j + 1) self.db.add_citation(citation, trans) self.progress.step() LOG.debug("sources and citations added") self.db.enable_signals() self.db.request_rebuild() self.progress.close() self.options.handler.options_dict['sources'] = num_sources self.options.handler.options_dict['citations'] = num_citations # Save options self.options.handler.save_options()
def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate tool.Tool.__init__(self, dbstate, options_class, name) self.db = dbstate.db progress = ProgressMeter(_('Thumbnail Generator'), can_cancel=True) length = self.db.get_number_of_media_objects() progress.set_pass(_('Generating media thumbnails'), length) for media in dbstate.db.iter_media_objects(): full_path = media_path_full(dbstate.db, media.get_path()) mime_type = media.get_mime_type() generate_thumbnail(full_path, mime_type) progress.step() if progress.get_cancelled(): break length = self.db.get_number_of_people() progress.set_pass(_('Generating thumbnails for person references'), length) for person in dbstate.db.iter_people(): self.generate_thumbnails(person) progress.step() if progress.get_cancelled(): break length = self.db.get_number_of_families() progress.set_pass(_('Generating thumbnails for family references'), length) for family in dbstate.db.iter_families(): self.generate_thumbnails(family) progress.step() if progress.get_cancelled(): break length = self.db.get_number_of_events() progress.set_pass(_('Generating thumbnails for event references'), length) for event in dbstate.db.iter_events(): self.generate_thumbnails(event) progress.step() if progress.get_cancelled(): break length = self.db.get_number_of_places() progress.set_pass(_('Generating thumbnails for place references'), length) for place in dbstate.db.iter_places(): self.generate_thumbnails(place) progress.step() if progress.get_cancelled(): break length = self.db.get_number_of_sources() progress.set_pass(_('Generating thumbnails for source references'), length) for source in dbstate.db.iter_sources(): self.generate_thumbnails(source) progress.step() if progress.get_cancelled(): break progress.close()
def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate self.label = _('Capitalization changes') self.cb = callback ManagedWindow.__init__(self,uistate,[],self.__class__) self.set_window(Gtk.Window(),Gtk.Label(),'') tool.BatchTool.__init__(self, dbstate, user, options_class, name) if self.fail: return self.progress = ProgressMeter(_('Checking Family Names'),'') self.progress.set_pass(_('Searching family names'), len(self.db.get_surname_list())) self.name_list = [] for name in self.db.get_surname_list(): name.strip() namesplitSP= name.split() lSP = len(namesplitSP) namesplitHY= name.split('-') lHY = len(namesplitHY) if lSP == lHY == 1: if name != name.capitalize(): # Single surname without hyphen(s) self.name_list.append(name) #if lSP == 1 and lHY > 1: #print "LSP==1", name, name.capitalize() #if name != name.capitalize(): # Single surname with hyphen(s) #self.name_list.append(name) if lSP>1 and lHY == 1: # more than one string in surname but no hyphen # check if first string is in prefix_list, if so test for cap in rest s1 = 0 if namesplitSP[0].lower() in prefix_list: s1 = 1 for x in range(len(namesplitSP)-s1): # check if any subsurname is not cap notcap = False if namesplitSP[s1+x] != namesplitSP[s1+x].capitalize(): notcap = True break if notcap: # Multiple surnames possibly after prefix self.name_list.append(name) if lHY > 1: # more than one string in surname but hyphen(s) exists # check if first string is in prefix_list, if so test for cap if namesplitSP[0].lower() in prefix_list: namesplitHY[0] = namesplitHY[0].replace(namesplitSP[0],'').strip() for x in range(len(namesplitHY)): # check if any subsurname is not cap notcap = False if namesplitHY[x] != namesplitHY[x].capitalize(): notcap = True break if notcap: # Multiple surnames possibly after frefix self.name_list.append(name) if uistate: self.progress.step() if self.name_list: self.display() else: self.progress.close() self.close() OkDialog(_('No modifications made'), _("No capitalization changes were detected."), parent=uistate.window)
def run_tool(self): self.progress = ProgressMeter(_('Running Date Test'),'', parent=self.parent_window) self.progress.set_pass(_('Generating dates'), 4) dates = [] # first some valid dates calendar = Date.CAL_GREGORIAN for quality in (Date.QUAL_NONE, Date.QUAL_ESTIMATED, Date.QUAL_CALCULATED): for modifier in (Date.MOD_NONE, Date.MOD_BEFORE, Date.MOD_AFTER, Date.MOD_ABOUT): for slash1 in (False,True): for month in range(0,13): for day in (0,5,27): if not month and day: continue d = Date() d.set(quality,modifier,calendar,(day,month,1789,slash1),"Text comment") dates.append( d) for modifier in (Date.MOD_RANGE, Date.MOD_SPAN): for slash1 in (False,True): for slash2 in (False,True): for month in range(0,13): for day in (0,5,27): if not month and day: continue d = Date() d.set(quality,modifier,calendar,(day,month,1789,slash1,day,month,1876,slash2),"Text comment") dates.append( d) if not month: continue d = Date() d.set(quality,modifier,calendar,(day,month,1789,slash1,day,13-month,1876,slash2),"Text comment") dates.append( d) if not day: continue d = Date() d.set(quality,modifier,calendar,(day,month,1789,slash1,32-day,month,1876,slash2),"Text comment") dates.append( d) d = Date() d.set(quality,modifier,calendar,(day,month,1789,slash1,32-day,13-month,1876,slash2),"Text comment") dates.append( d) modifier = Date.MOD_TEXTONLY d = Date() d.set(quality,modifier,calendar,Date.EMPTY, "This is a textual date") dates.append( d) self.progress.step() # test invalid dates #dateval = (4,7,1789,False,5,8,1876,False) #for l in range(1,len(dateval)): # d = Date() # try: # d.set(Date.QUAL_NONE,Date.MOD_NONE, # Date.CAL_GREGORIAN,dateval[:l],"Text comment") # dates.append( d) # except DateError, e: # d.set_as_text("Date identified value correctly as invalid.\n%s" % e) # dates.append( d) # except: # d = Date() # d.set_as_text("Date.set Exception %s" % ("".join(traceback.format_exception(*sys.exc_info())),)) # dates.append( d) #for l in range(1,len(dateval)): # d = Date() # try: # d.set(Date.QUAL_NONE,Date.MOD_SPAN,Date.CAL_GREGORIAN,dateval[:l],"Text comment") # dates.append( d) # except DateError, e: # d.set_as_text("Date identified value correctly as invalid.\n%s" % e) # dates.append( d) # except: # d = Date() # d.set_as_text("Date.set Exception %s" % ("".join(traceback.format_exception(*sys.exc_info())),)) # dates.append( d) #self.progress.step() #d = Date() #d.set(Date.QUAL_NONE,Date.MOD_NONE, # Date.CAL_GREGORIAN,(44,7,1789,False),"Text comment") #dates.append( d) #d = Date() #d.set(Date.QUAL_NONE,Date.MOD_NONE, # Date.CAL_GREGORIAN,(4,77,1789,False),"Text comment") #dates.append( d) #d = Date() #d.set(Date.QUAL_NONE,Date.MOD_SPAN, # Date.CAL_GREGORIAN, # (4,7,1789,False,55,8,1876,False),"Text comment") #dates.append( d) #d = Date() #d.set(Date.QUAL_NONE,Date.MOD_SPAN, # Date.CAL_GREGORIAN, # (4,7,1789,False,5,88,1876,False),"Text comment") #dates.append( d) with DbTxn(_("Date Test Plugin"), self.db, batch=True) as self.trans: self.db.disable_signals() self.progress.set_pass(_('Generating dates'), len(dates)) # create pass and fail tags pass_handle = self.create_tag(_('Pass'), '#0000FFFF0000') fail_handle = self.create_tag(_('Fail'), '#FFFF00000000') # now add them as birth to new persons i = 1 for dateval in dates: person = Person() surname = Surname() surname.set_surname("DateTest") name = Name() name.add_surname(surname) name.set_first_name("Test %d" % i) person.set_primary_name(name) self.db.add_person(person, self.trans) bevent = Event() bevent.set_type(EventType.BIRTH) bevent.set_date_object(dateval) bevent.set_description("Date Test %d (source)" % i) bevent_h = self.db.add_event(bevent, self.trans) bevent_ref = EventRef() bevent_ref.set_reference_handle(bevent_h) # for the death event display the date as text and parse it back to a new date ndate = None try: datestr = _dd.display( dateval) try: ndate = _dp.parse( datestr) if not ndate: ndate = Date() ndate.set_as_text("DateParser None") person.add_tag(fail_handle) else: person.add_tag(pass_handle) except: ndate = Date() ndate.set_as_text("DateParser Exception %s" % ("".join(traceback.format_exception(*sys.exc_info())),)) person.add_tag(fail_handle) else: person.add_tag(pass_handle) except: ndate = Date() ndate.set_as_text("DateDisplay Exception: %s" % ("".join(traceback.format_exception(*sys.exc_info())),)) person.add_tag(fail_handle) if dateval.get_modifier() != Date.MOD_TEXTONLY \ and ndate.get_modifier() == Date.MOD_TEXTONLY: # parser was unable to correctly parse the string ndate.set_as_text( "TEXTONLY: "+ndate.get_text()) person.add_tag(fail_handle) if dateval.get_modifier() == Date.MOD_TEXTONLY \ and dateval.get_text().count("Traceback") \ and pass_handle in person.get_tag_list(): person.add_tag(fail_handle) devent = Event() devent.set_type(EventType.DEATH) devent.set_date_object(ndate) devent.set_description("Date Test %d (result)" % i) devent_h = self.db.add_event(devent, self.trans) devent_ref = EventRef() devent_ref.set_reference_handle(devent_h) person.set_birth_ref(bevent_ref) person.set_death_ref(devent_ref) self.db.commit_person(person, self.trans) i = i + 1 self.progress.step() self.db.enable_signals() self.db.request_rebuild() self.progress.close()