def makefilter( self, category, filtername, filtertext, initial_statements, statements ): the_filter = GenericFilterFactory(category.objclass)() rule = category.filterrule([filtertext, initial_statements, statements]) if not filtername: OkDialog( _("Error"), "Please supply a title/name", parent=self.uistate.window ) return if not filtertext: OkDialog( _("Error"), "Please supply a filtering condition", parent=self.uistate.window, ) return the_filter.add_rule(rule) the_filter.set_name(filtername) filterdb = FilterList(CUSTOM_FILTERS) filterdb.load() filters = filterdb.get_filters_dict(category.objclass) if filtername in filters: msg = "Filter '{}' already exists; choose another name".format(filtername) OkDialog(_("Error"), msg, parent=self.uistate.window) return filterdb.add(category.objclass, the_filter) print("added filter", the_filter) filterdb.save() reload_custom_filters() self.uistate.emit("filters-changed", (category.objclass,)) msg = "Created filter {0}".format(filtername) OkDialog(_("Done"), msg, parent=self.uistate.window)
def __search_ref_places(self, obj): self.store_button.hide() placehandle = self.uistate.get_active("Place") if not placehandle: OkDialog(_("No place selected"), "", parent=self.uistate.window) return place = self.dbstate.db.get_place_from_handle(placehandle) pname = place.get_name().get_value() ptype = place.get_type().value self.place = place if ptype not in {PlaceType.CITY,PlaceType.TOWN,PlaceType.MUNICIPALITY,PlaceType.PARISH}: OkDialog(_("Place type not supported"), _("The type must be a 'City', 'Town', 'Municipality' or 'Parish'."), parent=self.uistate.window) return places = self.__fetch_ref_places(pname) if places is None: return if places == []: OkDialog(_("Error retrieving reference data"), _("Place not found in reference data"), parent=self.uistate.window) return store = Gtk.TreeStore(str,str,int) for place in places: store.append(None,[place['name'],place["type"],place["id"]]) self.place_list.set_model(store) self.place_list.show() if self.tree: self.tree.hide()
def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate self.dbstate = dbstate self.db = dbstate.db count = 0 has_assoc = False for person_handle in self.db.get_person_handles(): person = self.db.get_person_from_handle(person_handle) for assoc in person.get_person_ref_list(): has_assoc = True oldRel = assoc.get_relation() if oldRel in ASSOC_LOOKUP: associate = self.db.get_person_from_handle(assoc.ref) update = True for assoc_rev in associate.get_person_ref_list(): if assoc_rev.get_relation() == ASSOC_LOOKUP.get( assoc.get_relation( )) and assoc_rev.ref == person_handle: update = False if update: newRel = ASSOC_LOOKUP.get(assoc.get_relation()) personRef = PersonRef() personRef.set_reference_handle(person_handle) personRef.set_relation(newRel) personRef.merge(assoc) with DbTxn( _('Add %s reciprocal association') % _nd.display(associate), self.db) as self.trans: associate.add_person_ref(personRef) self.db.commit_person(associate, self.trans) count += 1 if uistate: if count > 0: OkDialog(_("Sync Associations"), _("{} Reciprocal associations created".format(count)), parent=uistate.window) elif has_assoc: OkDialog(_("Sync Associations"), _("All reciprocal associations exist, none created"), parent=uistate.window) else: OkDialog( _("Sync Associations"), _("No existing associations, so no reciprocal ones needed" ), parent=uistate.window) else: print("{} Reciprocal associations created".format(count))
def __read_ref_places(self, id): watch_cursor = Gdk.Cursor(Gdk.CursorType.WATCH) self.root.get_window().set_cursor(watch_cursor) self.store_button.hide() data = self.__fetch_sub_places(id) if data is None: return if len(data) == 0: return subordinates = data['surrounds'] store = Gtk.TreeStore(str,str) self.__build_treestore(store,subordinates,None) self.tree.set_model(store) self.tree.show() self.subordinates = subordinates self.root.get_window().set_cursor(None) if len(subordinates) == 0: OkDialog(_("No subordinates"), "", parent=self.uistate.window) return self.store_button.show()
def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate tool.Tool.__init__(self, dbstate, options_class, name) if self.db.readonly: return self.db.disable_signals() if uistate: self.callback = uistate.pulse_progressbar uistate.set_busy_cursor(True) uistate.progress.show() uistate.push_message(dbstate, _("Rebuilding reference maps...")) else: self.callback = None print(_("Rebuilding reference maps...")) self.db.reindex_reference_map(self.callback) if uistate: uistate.set_busy_cursor(False) uistate.progress.hide() OkDialog(_("Reference maps rebuilt"), _('All reference maps have been rebuilt.'), parent=uistate.window) else: print(_("All reference maps have been rebuilt.")) self.db.enable_signals()
def __remove_from(self, objects, category): """Remove the tag from objects of a selected category.""" counter = [0, 0] num = len(objects) name = _("Add/Remove Tag Tool") with DbTxn(name, self.db, batch=True) as self.trans: self.db.disable_signals() self.progress.set_pass(_('Process tags...'), num) for handle in objects: Object = self.db.method("get_%s_from_handle", category)(handle) if self.remove and (self.tag_handle in Object.get_tag_list()): Object.remove_tag(self.tag_handle) self.db.method("commit_%s", category)(Object, self.trans) counter[0] += 1 elif not self.remove and (self.tag_handle not in Object.get_tag_list()): Object.add_tag(self.tag_handle) self.db.method("commit_%s", category)(Object, self.trans) counter[1] += 1 self.progress.step() self.db.enable_signals() self.db.request_rebuild() # Inform the user afterwards txt = (_("added"), str(counter[1])) if self.remove: txt = (_("removed"), str(counter[0])) text = _("Tag '{}' was {} to {} {} objects.\n") text_f = text.format(self.tag_name(), *txt, category) OkDialog(_("INFO"), text_f, parent=self.window)
def __init__(self, dbstate, user, options_class, name, callback=None): uistate = user.uistate tool.Tool.__init__(self, dbstate, options_class, name) if self.db.readonly: return self.db.disable_signals() if uistate: self.callback = uistate.pulse_progressbar uistate.set_busy_cursor(True) uistate.progress.show() uistate.push_message(dbstate, _("Rebuilding secondary indexes...")) self.db.rebuild_secondary(self.callback) uistate.set_busy_cursor(False) uistate.progress.hide() OkDialog(_("Secondary indexes rebuilt"), _('All secondary indexes have been rebuilt.'), parent=uistate.window) else: print("Rebuilding Secondary Indexes...") self.db.rebuild_secondary(None) print("All secondary indexes have been rebuilt.") self.db.enable_signals() self.db.request_rebuild()
def loadstate(self, filename, loadtitle=True): # type: (str) -> None scriptfile = ScriptFile() query = scriptfile.load(filename) if query.category and query.category != self.category_name: msg = "Warning: saved query is for category '{}'. Current category is '{}'." msg = msg.format(query.category, self.category_name) OkDialog( _("Warning"), msg, parent=self.uistate.window, ) if not query.title and loadtitle: name = os.path.split(filename)[1] query.title = name.replace(SCRIPTFILE_EXTENSION, "") self.title.set_text(query.title) set_text(self.expressions, query.expressions) set_text(self.filter, query.filter) set_text(self.statements, query.statements) set_text(self.initial_statements, query.initial_statements) scope = query.scope self.all_objects.set_active(scope == "all") self.filtered_objects.set_active(scope == "filtered_") self.selected_objects.set_active(scope == "selected") self.unwind_lists.set_active(query.unwind_lists) self.commit_checkbox.set_active(query.commit_changes) self.summary_checkbox.set_active(query.summary_only)
def __remove_from(self, objects, category): """ Remove the tag from objects of a selected category :param objects: object handles of a selected category :type objects: list :param category: name of a selected category :type category: string """ db = self.dbstate.db counter = 0 with DbTxn(_("Remove Tag Tool"), self.db, batch=True) as self.trans: self.db.disable_signals() num = len(objects) self.progress.set_pass(_('Removing tags...'), num) for handle in objects: Object = eval("db.get_{}_from_handle(handle)".format(category)) if self.tag_handle in Object.get_tag_list(): Object.remove_tag(self.tag_handle) eval("self.db.commit_{}(Object, self.trans)".format( category)) counter += 1 self.progress.step() self.db.enable_signals() self.db.request_rebuild() text = _("Tag '{}' removed from {} {}.\n") text_f = text.format(self.tag_name(), str(counter), category) OkDialog("INFO", text_f, parent=self.window)
def __install(self, _obj, _list_obj): """ Callback function from the "Install" button """ model, node = self._selection_reg.get_selected() if not node: return path = model.get_path(node) pid = model.get_value(node, R_ID) status = model.get_value(node, R_STAT) if (status & INSTALLED) and not (status & UPDATE): self.__uninstall(pid, path) return for addon in self.addons: if addon['i'] == pid: name = addon['n'] fname = addon['z'] url = "%s/download/%s" % (config.get("behavior.addons-url"), fname) load_ok = load_addon_file(url, callback=LOG.debug) if not load_ok: OkDialog(_("Installation Errors"), _("The following addons had errors: ") + name, parent=self.window) return self.__rebuild_reg_list(path) pdata = self._pmgr.get_plugin(pid) if pdata and (status & UPDATE) and (pdata.ptype == VIEW or pdata.ptype == GRAMPLET): self.restart_needed = True
def __apply(self,obj): if self.objname != "note": selected_prop = self._resolve_radio(self.group) propname = selected_prop.propname getpropfunc, setpropfunc = self.get_propfuncs(self.objname, propname) if getpropfunc is None: OkDialog("failed","") return if self.objname == "note" and self.use_regex.get_active(): getpropfunc, setpropfunc = self.get_propfuncs(self.objname, "text") with DbTxn(_("Setting properties"), self.dbstate.db) as self.trans: selected_handles = self.uistate.viewmanager.active_page.selected_handles() num_objects = len(selected_handles) for handle in selected_handles: obj = self.getfunc(handle) old_text = self.old_text.get_text() new_text = self.new_text.get_text() if self.objname == "note" and not self.use_regex.get_active(): next_text = obj.get_styledtext().replace(old_text, StyledText(new_text)) obj.set_styledtext(next_text) self.commitfunc(obj,self.trans) continue orig_text = getpropfunc(obj) if self.use_regex.get_active(): try: next_text = re.sub(old_text,new_text,orig_text) except Exception as e: traceback.print_exc() raise RuntimeError(_("Regex operation failed: {}").format(e)) else: next_text = orig_text.replace(old_text,new_text) setpropfunc(obj, next_text) self.commitfunc(obj,self.trans)
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 __remove_from_notes(self, notes, tag_name, tag_handle): """ This functions handles the tag removal and the progress window as well as informing the user about the amount of sources the tag was removed from. """ counter = 0 with DbTxn(_("Remove Tag Tool"), self.db, batch=True) as self.trans: self.db.disable_signals() num_notes = len(notes) self.progress.set_pass(_('Removing tags...'), num_notes) for note_handle in notes: note = self.dbstate.db.get_note_from_handle(note_handle) if tag_handle in note.get_tag_list(): note.remove_tag(tag_handle) self.db.commit_citation(note, self.trans) counter += 1 self.db.enable_signals() self.db.request_rebuild() text = _("Tag '{}' removed from {} notes.\n") text_f = text.format(tag_name, str(counter)) OkDialog("INFO", text_f, parent=self.window)
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 __fetch_sub_places(self, id): import urllib url = baseurl + "record_with_subs?" + urllib.parse.urlencode({"id":id}) json_data = urllib.request.urlopen(url).read() if not json_data: OkDialog(_("Error retrieving reference data"), "", parent=self.uistate.window) return None data = json.loads(json_data.decode("utf-8")) if data['status'] != "OK": OkDialog(_("Error retrieving reference data"), data['statusText'], parent=self.uistate.window) return None return data["record"]
def __store_ref_places(self,obj): self.placecount = 0 self.newplacecount = 0 self.duplicates = 0 self.__store_ref_places2(self.place,self.subordinates) OkDialog(_("Reference places added"), _("Added {} new places, {} places already existed").format(self.newplacecount, self.duplicates), parent=self.uistate.window)
def check_filechange(self): # type: () -> bool global lastmod modtime = os.stat(__file__).st_mtime if lastmod and lastmod < modtime: OkDialog("File changed", "Please reload") return False lastmod = modtime return True
def __check_media_list(self, media_list): """ Return 'True' if media list is valid and contains media handles only. """ if False in media_list: OkDialog("INFO", "Select images first.", parent=self.window) return False # Invalid, because user didn't selected a image else: return True # valid list of handles
def __remove_media_from_people(self, person_media_handles, people): """ Remove selected media from selected people when menu option "remove" was selected. """ count_media = 0 count_person = 0 handle_error = 0 with DbTxn(_("Avatar Generator"), self.db, batch=True) as self.trans: self.db.disable_signals() num_people = len(people) self.progress.set_pass(_('Remove avatar images...'), num_people) for person_handle in people: person = self.__db.get_person_from_handle(person_handle) media_removed = False for mediaRef_obj in person.get_media_list(): ref = mediaRef_obj.get_referenced_handles() try: media = self.__db.get_media_from_handle(ref[0][1]) media_handle = media.get_handle() if media_handle in person_media_handles: person.remove_media_references(media_handle) self.db.commit_person(person, self.trans) count_media += 1 media_removed = True except HandleError: handle_error += 1 if media_removed: count_person += 1 self.progress.step() self.db.enable_signals() self.db.request_rebuild() if count_media == 0 and count_person == 0: OkDialog(_("INFO"), _("No media was removed."), parent=self.window) else: info_text = _("{} media references were removed from {} persons.") info_text = info_text.format(count_media, count_person) if handle_error > 0: info_text2 = _("\n{} HandleError occured, but were ignored.") info_text2 = info_text2.format(handle_error) info_text = info_text + info_text2 OkDialog(_("INFO"), info_text, parent=self.window)
def _check_for_updates(self): """ handle the check for updates button """ try: available_updates() except: # pylint: disable=bare-except OkDialog(_("Checking Addons Failed"), _("The addon repository appears to be unavailable. " "Please try again later."), parent=self.window) self.__rebuild_reg_list()
def __select(self,obj): self.selected_handle = self.uistate.get_active('Place') if not self.selected_handle: OkDialog(_("Please select a place that will be set as an enclosing place"), "", parent=self.uistate.window) return selected_parent = self.dbstate.db.get_place_from_handle(self.selected_handle) self.selected_name = selected_parent.get_name().value self.enclosing_place.set_text(self.selected_name)
def run(self): """Run the tool.""" db = self.dbstate.get_database() menu = self.options.menu opt = self.options.options_dict sub_str = opt["find"] replace_str = opt["replace"] keep_old = opt["keep_old"] regex = opt["regex"] txt = _("Event Description Editor") iter_events = db.iter_event_handles() index = opt["events"] filter_ = menu.filter_list[index] events = filter_.apply(db, iter_events) with DbTxn(txt, db, batch=True) as self.trans: db.disable_signals() num = len(events) counter = 0 self.progress.set_pass(_('Search substring...'), num) for handle in events: Event = db.get_event_from_handle(handle) event_desc = Event.get_description() if sub_str == "": break elif not regex and sub_str in event_desc and not keep_old: Event.set_description(replace_str) counter += 1 elif not regex and sub_str in event_desc and keep_old: new_str = event_desc.replace(sub_str, replace_str) Event.set_description(new_str) counter += 1 elif regex and re.search(sub_str, event_desc) and not keep_old: Event.set_description(replace_str) counter += 1 elif regex and re.search(sub_str, event_desc) and keep_old: for string in re.findall(sub_str, event_desc): if string != "": new_str = event_desc.replace(string, replace_str) Event.set_description(new_str) counter += 1 db.commit_event(Event, self.trans) self.progress.step() db.enable_signals() db.request_rebuild() OkDialog(_("INFO"), _("%s event descriptions of %s events were changed.") % (str(counter), str(num)), parent=self.window)
def __check_menu_option(self): """ Checks if menu options are generated and the tool can execute. """ tag_category = self.__opt_by_name('category') if not tag_category: txt = ("The Remove Tag Tool requires at least one person, family " "and tag to execute.") OkDialog("ERROR", txt, parent=self.window) else: self.__get_menu_options()
def __valid_options(self): """Check if all menu options are valid for report generation.""" dct = self._opt mid = dct["mid"] is_img = self.__media_is_img(mid) # no media file selected if not mid or mid == "": OkDialog(_("INFO"), _("You have to select an image to generate " "this report."), parent=self.window) return False # 'include custom note' checked, but no custom note selected if dct["incl_note"] and dct["note"] == "": OkDialog(_("INFO"), _("You have to select a custom note or uncheck" " the option 'include custom note' to " "generate this report."), parent=self.window) return False # incorrect media file, not an image if not is_img: OkDialog(_("INFO"), _("You have to select an image to " "generate this report."), parent=self.window) return False # other file output than PDF (PDF is only one supported right now) if self.options.get_output()[-3:] != "pdf": OkDialog(_("INFO"), _("This report only supports PDF as output " "file format."), parent=self.window) return False # if everything is valid return True
def copy(self, obj): # type: (Gtk.Widget) -> None clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD) import io stringio = io.StringIO() writer = csv.writer(stringio) for row in self.store: writer.writerow(row) clipboard.set_text(stringio.getvalue(), -1) OkDialog("Info", "Result list copied to clipboard")
def run(self): self.db = self.dbstate.get_database() self.cnt = [] opt = [] for entry in ["years", "person", "event", "media", "no_date"]: opt.append(self.get_opt(entry)) # Check if the user has ticked at least on category if True in opt[1:4]: self.lock_function(opt) else: OkDialog("Information", "Choose at least one category e.g. " "'Persons' to progress", parent=self.window)
def __fetch_ref_places(self, name): url = baseurl + "search?" + urllib.parse.urlencode({"lookfor":name}) print(url) try: json_data = urllib.request.urlopen(url).read() except: OkDialog(_("Error retrieving reference data"), traceback.format_exc(), parent=self.uistate.window) return None print(json_data) if not json_data: OkDialog(_("Error retrieving reference data"), "", parent=self.uistate.window) return None data = json.loads(json_data.decode("utf-8")) if data['status'] != "OK": OkDialog(_("Error retrieving reference data"), data['statusText'], parent=self.uistate.window) return None return data['records']
def lock_function(self, opt): """Lock objects depending on user selection and timeframe.""" date = Today() - opt[0] lock_no_date = opt[4] if opt[1]: self.lock_persons(date, lock_no_date) if opt[2]: self.lock_events(date, lock_no_date) if opt[3]: self.lock_media(date, lock_no_date) txt = "" for entry in self.cnt: txt += _("Set private: %d %s\n") % (entry[1], entry[0]) for entry in self.cnt: txt += _("Not private: %d %s\n") % (entry[2], entry[0]) OkDialog(_("Set Privacy Tool"), txt, parent=self.window)
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 __uninstall(self, pid, path): """ Uninstall the plugin """ pdata = self._pmgr.get_plugin(pid) try: if os.path.islink(pdata.fpath): # linux link os.unlink(pdata.fpath) elif os.stat(pdata.fpath).st_ino != os.lstat(pdata.fpath).st_ino: # it's probably a Windows junction or softlink os.rmdir(pdata.fpath) else: # it's a real directory shutil.rmtree(pdata.fpath) except: # pylint: disable=bare-except OkDialog(_("Error"), _("Error removing the '%s' directory, The uninstall may " "have failed") % pdata.fpath, parent=self.window) self.__rebuild_reg_list(path) self.restart_needed = True