class FilterEditor(ManagedWindow): def __init__(self, namespace, filterdb, dbstate, uistate): ManagedWindow.__init__(self, uistate, [], FilterEditor) self.dbstate = dbstate self.db = dbstate.db self.filterdb = FilterList(filterdb) self.filterdb.load() self.width_key = "interface.filter-editor-width" self.height_key = "interface.filter-editor-height" self.namespace = namespace self.define_glade('filter_list', RULE_GLADE) self.filter_list = self.get_widget('filters') self.edit = self.get_widget('filter_list_edit') self.clone = self.get_widget('filter_list_clone') self.delete = self.get_widget('filter_list_delete') self.test = self.get_widget('filter_list_test') self.edit.set_sensitive(False) self.clone.set_sensitive(False) self.delete.set_sensitive(False) self.test.set_sensitive(False) self.set_window(self.get_widget('filter_list'), self.get_widget('filter_list_title'), _TITLES[self.namespace]) self.edit.connect('clicked', self.edit_filter) self.clone.connect('clicked', self.clone_filter) self.test.connect('clicked', self.test_clicked) self.delete.connect('clicked', self.delete_filter) self.connect_button('filter_list_help', self.help_clicked) self.connect_button('filter_list_close', self.close) self.connect_button('filter_list_add', self.add_new_filter) self.uistate.connect('filter-name-changed', self.clean_after_rename) self.clist = ListModel(self.filter_list, [(_('Filter'), 0, 150), (_('Comment'), 1, 150)], self.filter_select_row, self.edit_filter) self.draw_filters() self._set_size() self.show() def build_menu_names(self, obj): return (_("Custom Filter Editor"), _("Custom Filter Editor")) def help_clicked(self, obj): """Display the relevant portion of Gramps manual""" display_help(webpage=WIKI_HELP_PAGE, section=WIKI_HELP_SEC3) def filter_select_row(self, obj): store, node = self.clist.get_selected() if node: self.edit.set_sensitive(True) self.clone.set_sensitive(True) self.delete.set_sensitive(True) self.test.set_sensitive(True) else: self.edit.set_sensitive(False) self.clone.set_sensitive(False) self.delete.set_sensitive(False) self.test.set_sensitive(False) def close(self, *obj): self.filterdb.save() reload_custom_filters() #reload_system_filters() self.uistate.emit('filters-changed', (self.namespace, )) ManagedWindow.close(self, *obj) def draw_filters(self): self.clist.clear() for f in self.filterdb.get_filters(self.namespace): self.clist.add([f.get_name(), f.get_comment()], f) def add_new_filter(self, obj): the_filter = GenericFilterFactory(self.namespace)() EditFilter(self.namespace, self.dbstate, self.uistate, self.track, the_filter, self.filterdb, self.draw_filters) def edit_filter(self, obj): store, node = self.clist.get_selected() if node: gfilter = self.clist.get_object(node) EditFilter(self.namespace, self.dbstate, self.uistate, self.track, gfilter, self.filterdb, self.draw_filters) def clone_filter(self, obj): store, node = self.clist.get_selected() if node: old_filter = self.clist.get_object(node) the_filter = GenericFilterFactory(self.namespace)(old_filter) the_filter.set_name('') EditFilter(self.namespace, self.dbstate, self.uistate, self.track, the_filter, self.filterdb, self.draw_filters) def test_clicked(self, obj): store, node = self.clist.get_selected() if node: filt = self.clist.get_object(node) handle_list = filt.apply(self.db, self.get_all_handles()) ShowResults(self.db, self.uistate, self.track, handle_list, filt.get_name(), self.namespace) def delete_filter(self, obj): store, node = self.clist.get_selected() if node: gfilter = self.clist.get_object(node) name = gfilter.get_name() if self.check_recursive_filters(self.namespace, name): QuestionDialog( _('Delete Filter?'), _('This filter is currently being used ' 'as the base for other filters. Deleting' 'this filter will result in removing all ' 'other filters that depend on it.'), _('Delete Filter'), self._do_delete_selected_filter, self.window) else: self._do_delete_selected_filter() def _do_delete_selected_filter(self): store, node = self.clist.get_selected() if node: gfilter = self.clist.get_object(node) self._do_delete_filter(self.namespace, gfilter) self.draw_filters() def _do_delete_filter(self, space, gfilter): # Find everything we need to remove filter_set = set() self._find_dependent_filters(space, gfilter, filter_set) # Remove what we found filters = self.filterdb.get_filters(space) list(map(filters.remove, filter_set)) def _find_dependent_filters(self, space, gfilter, filter_set): """ This method recursively calls itself to find all filters that depend on the given filter, either directly through one of the rules, or through the chain of dependencies. The filter_set is amended with the found filters. """ filters = self.filterdb.get_filters(space) name = gfilter.get_name() for the_filter in filters: if the_filter.get_name() == name: continue for rule in the_filter.get_rules(): values = list(rule.values()) if issubclass(rule.__class__, MatchesFilterBase) \ and (name in values): self._find_dependent_filters(space, the_filter, filter_set) break # Add itself to the filter_set filter_set.add(gfilter) def get_all_handles(self): # Why use iter for some and get for others? if self.namespace == 'Person': return self.db.iter_person_handles() elif self.namespace == 'Family': return self.db.iter_family_handles() elif self.namespace == 'Event': return self.db.get_event_handles() elif self.namespace == 'Source': return self.db.get_source_handles() elif self.namespace == 'Citation': return self.db.get_citation_handles() elif self.namespace == 'Place': return self.db.iter_place_handles() elif self.namespace == 'Media': return self.db.get_media_object_handles() elif self.namespace == 'Repository': return self.db.get_repository_handles() elif self.namespace == 'Note': return self.db.get_note_handles() def clean_after_rename(self, space, old_name, new_name): if old_name == "": return if old_name == new_name: return for the_filter in self.filterdb.get_filters(space): for rule in the_filter.get_rules(): values = list(rule.values()) if issubclass(rule.__class__, MatchesFilterBase) \ and (old_name in values): ind = values.index(old_name) values[ind] = new_name def check_recursive_filters(self, space, name): for the_filter in self.filterdb.get_filters(space): for rule in the_filter.get_rules(): values = list(rule.values()) if issubclass(rule.__class__, MatchesFilterBase) \ and (name in values): return True return False
class FilterEditor(ManagedWindow): def __init__(self, namespace, filterdb, dbstate, uistate): ManagedWindow.__init__(self, uistate, [], FilterEditor) self.dbstate = dbstate self.db = dbstate.db self.filterdb = FilterList(filterdb) self.filterdb.load() self.namespace = namespace self.define_glade('filter_list', RULE_GLADE) self.filter_list = self.get_widget('filters') self.edit = self.get_widget('filter_list_edit') self.clone = self.get_widget('filter_list_clone') self.delete = self.get_widget('filter_list_delete') self.test = self.get_widget('filter_list_test') self.edit.set_sensitive(False) self.clone.set_sensitive(False) self.delete.set_sensitive(False) self.test.set_sensitive(False) self.set_window(self.get_widget('filter_list'), self.get_widget('filter_list_title'), _TITLES[self.namespace]) self.setup_configs('interface.filter-editor', 400, 350) self.edit.connect('clicked', self.edit_filter) self.clone.connect('clicked', self.clone_filter) self.test.connect('clicked', self.test_clicked) self.delete.connect('clicked', self.delete_filter) self.connect_button('filter_list_help', self.help_clicked) self.connect_button('filter_list_close', self.close) self.connect_button('filter_list_add', self.add_new_filter) self.uistate.connect('filter-name-changed', self.clean_after_rename) self.clist = ListModel( self.filter_list, [(_('Filter'), 0, 150), (_('Comment'), 1, 150)], self.filter_select_row, self.edit_filter) self.draw_filters() self._set_size() self.show() def build_menu_names(self, obj): return (_("Custom Filter Editor"), _("Custom Filter Editor")) def help_clicked(self, obj): """Display the relevant portion of Gramps manual""" display_help(webpage=WIKI_HELP_PAGE, section=WIKI_HELP_SEC3) def filter_select_row(self, obj): store, node = self.clist.get_selected() if node: self.edit.set_sensitive(True) self.clone.set_sensitive(True) self.delete.set_sensitive(True) self.test.set_sensitive(True) else: self.edit.set_sensitive(False) self.clone.set_sensitive(False) self.delete.set_sensitive(False) self.test.set_sensitive(False) def close(self, *obj): self.filterdb.save() reload_custom_filters() #reload_system_filters() self.uistate.emit('filters-changed', (self.namespace,)) ManagedWindow.close(self, *obj) def draw_filters(self): self.clist.clear() for f in self.filterdb.get_filters(self.namespace): self.clist.add([f.get_name(), f.get_comment()], f) def add_new_filter(self, obj): the_filter = GenericFilterFactory(self.namespace)() EditFilter(self.namespace, self.dbstate, self.uistate, self.track, the_filter, self.filterdb, self.draw_filters) def edit_filter(self, obj): store, node = self.clist.get_selected() if node: gfilter = self.clist.get_object(node) EditFilter(self.namespace, self.dbstate, self.uistate, self.track, gfilter, self.filterdb, self.draw_filters) def clone_filter(self, obj): store, node = self.clist.get_selected() if node: old_filter = self.clist.get_object(node) the_filter = GenericFilterFactory(self.namespace)(old_filter) the_filter.set_name('') EditFilter(self.namespace, self.dbstate, self.uistate, self.track, the_filter, self.filterdb, self.draw_filters) def test_clicked(self, obj): store, node = self.clist.get_selected() if node: filt = self.clist.get_object(node) try: handle_list = filt.apply(self.db, self.get_all_handles()) except FilterError as msg: (msg1, msg2) = msg.messages() ErrorDialog(msg1, msg2, parent=self.window) return ShowResults(self.db, self.uistate, self.track, handle_list, filt.get_name(),self.namespace) def delete_filter(self, obj): store, node = self.clist.get_selected() if node: gfilter = self.clist.get_object(node) name = gfilter.get_name() if self.check_recursive_filters(self.namespace, name): QuestionDialog( _('Delete Filter?'), _('This filter is currently being used ' 'as the base for other filters. Deleting' 'this filter will result in removing all ' 'other filters that depend on it.'), _('Delete Filter'), self._do_delete_selected_filter, parent=self.window) else: self._do_delete_selected_filter() def _do_delete_selected_filter(self): store, node = self.clist.get_selected() if node: gfilter = self.clist.get_object(node) self._do_delete_filter(self.namespace, gfilter) self.draw_filters() def _do_delete_filter(self, space, gfilter): # Find everything we need to remove filter_set = set() self._find_dependent_filters(space, gfilter, filter_set) # Remove what we found filters = self.filterdb.get_filters(space) list(map(filters.remove, filter_set)) def _find_dependent_filters(self, space, gfilter, filter_set): """ This method recursively calls itself to find all filters that depend on the given filter, either directly through one of the rules, or through the chain of dependencies. The filter_set is amended with the found filters. """ filters = self.filterdb.get_filters(space) name = gfilter.get_name() for the_filter in filters: if the_filter.get_name() == name: continue for rule in the_filter.get_rules(): values = list(rule.values()) if issubclass(rule.__class__, MatchesFilterBase) \ and (name in values): self._find_dependent_filters(space, the_filter, filter_set) break # Add itself to the filter_set filter_set.add(gfilter) def get_all_handles(self): # Why use iter for some and get for others? if self.namespace == 'Person': return self.db.iter_person_handles() elif self.namespace == 'Family': return self.db.iter_family_handles() elif self.namespace == 'Event': return self.db.get_event_handles() elif self.namespace == 'Source': return self.db.get_source_handles() elif self.namespace == 'Citation': return self.db.get_citation_handles() elif self.namespace == 'Place': return self.db.iter_place_handles() elif self.namespace == 'Media': return self.db.get_media_handles() elif self.namespace == 'Repository': return self.db.get_repository_handles() elif self.namespace == 'Note': return self.db.get_note_handles() def clean_after_rename(self, space, old_name, new_name): if old_name == "": return if old_name == new_name: return for the_filter in self.filterdb.get_filters(space): for rule in the_filter.get_rules(): values = list(rule.values()) if issubclass(rule.__class__, MatchesFilterBase) \ and (old_name in values): ind = values.index(old_name) values[ind] = new_name def check_recursive_filters(self, space, name): for the_filter in self.filterdb.get_filters(space): for rule in the_filter.get_rules(): values = list(rule.values()) if issubclass(rule.__class__, MatchesFilterBase) \ and (name in values): return True return False