Continued work on GEP008: Consolidate src/FilterEditor files into one file and move it to gui/filtereditor.py.
svn: r14074
This commit is contained in:
@@ -184,6 +184,7 @@ src/gui/__init__.py
|
|||||||
src/gui/dbguielement.py
|
src/gui/dbguielement.py
|
||||||
src/gui/dbloader.py
|
src/gui/dbloader.py
|
||||||
src/gui/dbman.py
|
src/gui/dbman.py
|
||||||
|
src/gui/filtereditor.py
|
||||||
src/gui/grampsgui.py
|
src/gui/grampsgui.py
|
||||||
src/gui/pluginmanager.py
|
src/gui/pluginmanager.py
|
||||||
src/gui/utils.py
|
src/gui/utils.py
|
||||||
@@ -826,12 +827,6 @@ src/Filters/SideBar/_MediaSidebarFilter.py
|
|||||||
src/Filters/SideBar/_RepoSidebarFilter.py
|
src/Filters/SideBar/_RepoSidebarFilter.py
|
||||||
src/Filters/SideBar/_NoteSidebarFilter.py
|
src/Filters/SideBar/_NoteSidebarFilter.py
|
||||||
|
|
||||||
# FilterEditor package
|
|
||||||
src/FilterEditor/_FilterEditor.py
|
|
||||||
src/FilterEditor/_EditFilter.py
|
|
||||||
src/FilterEditor/_EditRule.py
|
|
||||||
src/FilterEditor/_ShowResults.py
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Glade files
|
# Glade files
|
||||||
#
|
#
|
||||||
|
@@ -1,22 +0,0 @@
|
|||||||
# This is the src/FilterEditor level Makefile for Gramps
|
|
||||||
|
|
||||||
pkgdatadir = $(datadir)/@PACKAGE@/FilterEditor
|
|
||||||
|
|
||||||
pkgdata_PYTHON = \
|
|
||||||
__init__.py \
|
|
||||||
_FilterEditor.py \
|
|
||||||
_EditFilter.py \
|
|
||||||
_EditRule.py \
|
|
||||||
_ShowResults.py
|
|
||||||
|
|
||||||
pkgpyexecdir = @pkgpyexecdir@/FilterEditor
|
|
||||||
pkgpythondir = @pkgpythondir@/FilterEditor
|
|
||||||
|
|
||||||
# Clean up all the byte-compiled files
|
|
||||||
MOSTLYCLEANFILES = *pyc *pyo
|
|
||||||
|
|
||||||
GRAMPS_PY_MODPATH = "../"
|
|
||||||
|
|
||||||
pycheck:
|
|
||||||
(export PYTHONPATH=$(GRAMPS_PY_MODPATH); \
|
|
||||||
pychecker $(pkgdata_PYTHON));
|
|
@@ -1,218 +0,0 @@
|
|||||||
#
|
|
||||||
# Gramps - a GTK+/GNOME based genealogy program
|
|
||||||
#
|
|
||||||
# Copyright (C) 2000-2007 Donald N. Allingham
|
|
||||||
#
|
|
||||||
# This program is free software; you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation; either version 2 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with this program; if not, write to the Free Software
|
|
||||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
#
|
|
||||||
|
|
||||||
# $Id:_EditFilter.py 9912 2008-01-22 09:17:46Z acraphae $
|
|
||||||
|
|
||||||
"""
|
|
||||||
Custom Filter Editor tool.
|
|
||||||
"""
|
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
|
||||||
#
|
|
||||||
# Python modules
|
|
||||||
#
|
|
||||||
#-------------------------------------------------------------------------
|
|
||||||
|
|
||||||
#------------------------------------------------------------------------
|
|
||||||
#
|
|
||||||
# Set up logging
|
|
||||||
#
|
|
||||||
#------------------------------------------------------------------------
|
|
||||||
import logging
|
|
||||||
log = logging.getLogger(".FilterEdit")
|
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
|
||||||
#
|
|
||||||
# GRAMPS modules
|
|
||||||
#
|
|
||||||
#-------------------------------------------------------------------------
|
|
||||||
import const
|
|
||||||
import ListModel
|
|
||||||
import ManagedWindow
|
|
||||||
import GrampsDisplay
|
|
||||||
import Errors
|
|
||||||
from TransUtils import sgettext as _
|
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
|
||||||
#
|
|
||||||
# Constants
|
|
||||||
#
|
|
||||||
#-------------------------------------------------------------------------
|
|
||||||
WIKI_HELP_PAGE = WIKI_HELP_PAGE = '%s_-_Filters' % const.URL_MANUAL_PAGE
|
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
|
||||||
#
|
|
||||||
#
|
|
||||||
#
|
|
||||||
#-------------------------------------------------------------------------
|
|
||||||
class EditFilter(ManagedWindow.ManagedWindow):
|
|
||||||
|
|
||||||
def __init__(self, namespace, dbstate, uistate, track, gfilter,
|
|
||||||
filterdb, update):
|
|
||||||
|
|
||||||
ManagedWindow.ManagedWindow.__init__(self, uistate, track, self)
|
|
||||||
|
|
||||||
self.namespace = namespace
|
|
||||||
self.update = update
|
|
||||||
self.dbstate = dbstate
|
|
||||||
self.db = dbstate.db
|
|
||||||
self.filter = gfilter
|
|
||||||
self.filterdb = filterdb
|
|
||||||
|
|
||||||
self.define_glade('define_filter', const.RULE_GLADE)
|
|
||||||
|
|
||||||
self.set_window(
|
|
||||||
self.get_widget('define_filter'),
|
|
||||||
self.get_widget('definition_title'),
|
|
||||||
_('Define filter'))
|
|
||||||
|
|
||||||
self.rlist = ListModel.ListModel(
|
|
||||||
self.get_widget('rule_list'),
|
|
||||||
[(_('Name'),-1,150),(_('Values'),-1,150)],
|
|
||||||
self.select_row,
|
|
||||||
self.on_edit_clicked)
|
|
||||||
|
|
||||||
self.fname = self.get_widget('filter_name')
|
|
||||||
self.logical = self.get_widget('rule_apply')
|
|
||||||
self.logical_not = self.get_widget('logical_not')
|
|
||||||
self.comment = self.get_widget('comment')
|
|
||||||
self.ok_btn = self.get_widget('definition_ok')
|
|
||||||
self.edit_btn = self.get_widget('definition_edit')
|
|
||||||
self.del_btn = self.get_widget('definition_delete')
|
|
||||||
self.add_btn = self.get_widget('definition_add')
|
|
||||||
|
|
||||||
self.ok_btn.connect('clicked', self.on_ok_clicked)
|
|
||||||
self.edit_btn.connect('clicked', self.on_edit_clicked)
|
|
||||||
self.del_btn.connect('clicked', self.on_delete_clicked)
|
|
||||||
self.add_btn.connect('clicked', self.on_add_clicked)
|
|
||||||
|
|
||||||
self.get_widget('definition_help').connect('clicked',
|
|
||||||
self.on_help_clicked)
|
|
||||||
self.get_widget('definition_cancel').connect('clicked',
|
|
||||||
self.close_window)
|
|
||||||
self.fname.connect('changed', self.filter_name_changed)
|
|
||||||
|
|
||||||
if self.filter.get_logical_op() == 'or':
|
|
||||||
self.logical.set_active(1)
|
|
||||||
elif self.filter.get_logical_op() == 'one':
|
|
||||||
self.logical.set_active(2)
|
|
||||||
else:
|
|
||||||
self.logical.set_active(0)
|
|
||||||
self.logical_not.set_active(self.filter.get_invert())
|
|
||||||
if self.filter.get_name():
|
|
||||||
self.fname.set_text(self.filter.get_name())
|
|
||||||
self.comment.set_text(self.filter.get_comment())
|
|
||||||
self.draw_rules()
|
|
||||||
|
|
||||||
self.show()
|
|
||||||
|
|
||||||
def on_help_clicked(self, obj):
|
|
||||||
"""Display the relevant portion of GRAMPS manual"""
|
|
||||||
GrampsDisplay.help(webpage=WIKI_HELP_PAGE)
|
|
||||||
|
|
||||||
def close_window(self, obj):
|
|
||||||
self.close()
|
|
||||||
|
|
||||||
def filter_name_changed(self, obj):
|
|
||||||
name = unicode(self.fname.get_text())
|
|
||||||
# Make sure that the name is not empty
|
|
||||||
# and not in the list of existing filters (excluding this one)
|
|
||||||
names = [filt.get_name()
|
|
||||||
for filt in self.filterdb.get_filters(self.namespace)
|
|
||||||
if filt != self.filter]
|
|
||||||
self.ok_btn.set_sensitive((len(name) != 0) and (name not in names))
|
|
||||||
|
|
||||||
def select_row(self, obj):
|
|
||||||
store, node = self.rlist.get_selected()
|
|
||||||
if node:
|
|
||||||
self.edit_btn.set_sensitive(True)
|
|
||||||
self.del_btn.set_sensitive(True)
|
|
||||||
else:
|
|
||||||
self.edit_btn.set_sensitive(False)
|
|
||||||
self.del_btn.set_sensitive(False)
|
|
||||||
|
|
||||||
def draw_rules(self):
|
|
||||||
self.rlist.clear()
|
|
||||||
for r in self.filter.get_rules():
|
|
||||||
self.rlist.add([r.name,r.display_values()],r)
|
|
||||||
|
|
||||||
def on_ok_clicked(self, obj):
|
|
||||||
n = unicode(self.fname.get_text()).strip()
|
|
||||||
if n == '':
|
|
||||||
return
|
|
||||||
if n != self.filter.get_name():
|
|
||||||
self.uistate.emit('filter-name-changed',
|
|
||||||
(self.namespace,unicode(self.filter.get_name()), n))
|
|
||||||
self.filter.set_name(n)
|
|
||||||
self.filter.set_comment(unicode(self.comment.get_text()).strip())
|
|
||||||
for f in self.filterdb.get_filters(self.namespace)[:]:
|
|
||||||
if n == f.get_name():
|
|
||||||
self.filterdb.get_filters(self.namespace).remove(f)
|
|
||||||
break
|
|
||||||
val = self.logical.get_active()
|
|
||||||
if val == 1:
|
|
||||||
op = 'or'
|
|
||||||
elif val == 2:
|
|
||||||
op = 'one'
|
|
||||||
else:
|
|
||||||
op = 'and'
|
|
||||||
self.filter.set_logical_op(op)
|
|
||||||
self.filter.set_invert(self.logical_not.get_active())
|
|
||||||
self.filterdb.add(self.namespace,self.filter)
|
|
||||||
self.update()
|
|
||||||
self.close()
|
|
||||||
|
|
||||||
def on_add_clicked(self, obj):
|
|
||||||
from _EditRule import EditRule
|
|
||||||
|
|
||||||
try:
|
|
||||||
EditRule(self.namespace, self.dbstate, self.uistate, self.track,
|
|
||||||
self.filterdb, None, _('Add Rule'), self.update_rule,
|
|
||||||
self.filter.get_name())
|
|
||||||
except Errors.WindowActiveError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def on_edit_clicked(self, obj):
|
|
||||||
store, node = self.rlist.get_selected()
|
|
||||||
if node:
|
|
||||||
from _EditRule import EditRule
|
|
||||||
|
|
||||||
d = self.rlist.get_object(node)
|
|
||||||
|
|
||||||
try:
|
|
||||||
EditRule(self.namespace, self.dbstate, self.uistate, self.track,
|
|
||||||
self.filterdb, d, _('Edit Rule'), self.update_rule,
|
|
||||||
self.filter.get_name())
|
|
||||||
except Errors.WindowActiveError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def update_rule(self, old_rule, new_rule):
|
|
||||||
if old_rule is not None:
|
|
||||||
self.filter.delete_rule(old_rule)
|
|
||||||
self.filter.add_rule(new_rule)
|
|
||||||
self.draw_rules()
|
|
||||||
|
|
||||||
def on_delete_clicked(self, obj):
|
|
||||||
store, node = self.rlist.get_selected()
|
|
||||||
if node:
|
|
||||||
gfilter = self.rlist.get_object(node)
|
|
||||||
self.filter.delete_rule(gfilter)
|
|
||||||
self.draw_rules()
|
|
||||||
|
|
@@ -1,276 +0,0 @@
|
|||||||
#
|
|
||||||
# Gramps - a GTK+/GNOME based genealogy program
|
|
||||||
#
|
|
||||||
# Copyright (C) 2000-2007 Donald N. Allingham
|
|
||||||
#
|
|
||||||
# This program is free software; you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation; either version 2 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with this program; if not, write to the Free Software
|
|
||||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
#
|
|
||||||
|
|
||||||
# $Id:_FilterEditor.py 9912 2008-01-22 09:17:46Z acraphae $
|
|
||||||
|
|
||||||
"""
|
|
||||||
Custom Filter Editor tool.
|
|
||||||
"""
|
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
|
||||||
#
|
|
||||||
# Python modules
|
|
||||||
#
|
|
||||||
#-------------------------------------------------------------------------
|
|
||||||
from gettext import gettext as _
|
|
||||||
|
|
||||||
#------------------------------------------------------------------------
|
|
||||||
#
|
|
||||||
# Set up logging
|
|
||||||
#
|
|
||||||
#------------------------------------------------------------------------
|
|
||||||
import logging
|
|
||||||
log = logging.getLogger(".FilterEdit")
|
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
|
||||||
#
|
|
||||||
# GTK/GNOME
|
|
||||||
#
|
|
||||||
#-------------------------------------------------------------------------
|
|
||||||
import GrampsDisplay
|
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
|
||||||
#
|
|
||||||
# GRAMPS modules
|
|
||||||
#
|
|
||||||
#-------------------------------------------------------------------------
|
|
||||||
import const
|
|
||||||
from Filters import (GenericFilterFactory, FilterList, reload_custom_filters)
|
|
||||||
from Filters.Rules._MatchesFilterBase import MatchesFilterBase
|
|
||||||
import ListModel
|
|
||||||
import ManagedWindow
|
|
||||||
from QuestionDialog import QuestionDialog
|
|
||||||
from FilterEditor._EditFilter import EditFilter
|
|
||||||
|
|
||||||
# dictionary mapping FILTER_TYPE of views to Filter window name
|
|
||||||
_TITLES = {
|
|
||||||
'Person' : _("Person Filters"),
|
|
||||||
'Family' : _('Family Filters'),
|
|
||||||
'Event' : _('Event Filters'),
|
|
||||||
'Place' : _('Place Filters'),
|
|
||||||
'Source' : _('Source Filters'),
|
|
||||||
'MediaObject' : _('Media Object Filters'),
|
|
||||||
'Repository' : _('Repository Filters'),
|
|
||||||
'Note' : _('Note Filters'),
|
|
||||||
}
|
|
||||||
|
|
||||||
class FilterEditor(ManagedWindow.ManagedWindow):
|
|
||||||
def __init__(self, namespace, filterdb, dbstate, uistate):
|
|
||||||
|
|
||||||
ManagedWindow.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', const.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.ListModel(
|
|
||||||
self.filter_list,
|
|
||||||
[(_('Filter'), 0, 150), (_('Comment'), 1, 150)],
|
|
||||||
self.filter_select_row,
|
|
||||||
self.edit_filter)
|
|
||||||
self.draw_filters()
|
|
||||||
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"""
|
|
||||||
GrampsDisplay.help()
|
|
||||||
|
|
||||||
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.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:
|
|
||||||
from FilterEditor._ShowResults import ShowResults
|
|
||||||
|
|
||||||
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)
|
|
||||||
for the_filter in filter_set:
|
|
||||||
filters.remove(the_filter)
|
|
||||||
|
|
||||||
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:
|
|
||||||
for rule in the_filter.get_rules():
|
|
||||||
values = 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):
|
|
||||||
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 == 'Place':
|
|
||||||
return self.db.iter_place_handles()
|
|
||||||
elif self.namespace == 'MediaObject':
|
|
||||||
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 = 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 = rule.values()
|
|
||||||
if issubclass(rule.__class__, MatchesFilterBase) \
|
|
||||||
and (name in values):
|
|
||||||
return True
|
|
||||||
return False
|
|
@@ -1,164 +0,0 @@
|
|||||||
#
|
|
||||||
# Gramps - a GTK+/GNOME based genealogy program
|
|
||||||
#
|
|
||||||
# Copyright (C) 2000-2008 Donald N. Allingham
|
|
||||||
#
|
|
||||||
# This program is free software; you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation; either version 2 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with this program; if not, write to the Free Software
|
|
||||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
#
|
|
||||||
|
|
||||||
# $Id$
|
|
||||||
|
|
||||||
"""
|
|
||||||
Custom Filter Editor tool.
|
|
||||||
"""
|
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
|
||||||
#
|
|
||||||
# Python modules
|
|
||||||
#
|
|
||||||
#-------------------------------------------------------------------------
|
|
||||||
import locale
|
|
||||||
from gettext import gettext as _
|
|
||||||
|
|
||||||
#------------------------------------------------------------------------
|
|
||||||
#
|
|
||||||
# Set up logging
|
|
||||||
#
|
|
||||||
#------------------------------------------------------------------------
|
|
||||||
import logging
|
|
||||||
log = logging.getLogger(".FilterEdit")
|
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
|
||||||
#
|
|
||||||
# GTK/GNOME
|
|
||||||
#
|
|
||||||
#-------------------------------------------------------------------------
|
|
||||||
import gtk
|
|
||||||
import gobject
|
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
|
||||||
#
|
|
||||||
# GRAMPS modules
|
|
||||||
#
|
|
||||||
#-------------------------------------------------------------------------
|
|
||||||
import const
|
|
||||||
import ManagedWindow
|
|
||||||
from gen.display.name import displayer as _nd
|
|
||||||
import Utils
|
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
|
||||||
#
|
|
||||||
#
|
|
||||||
#
|
|
||||||
#-------------------------------------------------------------------------
|
|
||||||
class ShowResults(ManagedWindow.ManagedWindow):
|
|
||||||
def __init__(self, db, uistate, track, handle_list, filtname, namespace):
|
|
||||||
|
|
||||||
ManagedWindow.ManagedWindow.__init__(self, uistate, track, self)
|
|
||||||
|
|
||||||
self.db = db
|
|
||||||
self.filtname = filtname
|
|
||||||
self.namespace = namespace
|
|
||||||
self.define_glade('test', const.RULE_GLADE,)
|
|
||||||
self.set_window(
|
|
||||||
self.get_widget('test'),
|
|
||||||
self.get_widget('test_title'),
|
|
||||||
_('Filter Test'))
|
|
||||||
|
|
||||||
render = gtk.CellRendererText()
|
|
||||||
|
|
||||||
tree = self.get_widget('list')
|
|
||||||
model = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
|
|
||||||
tree.set_model(model)
|
|
||||||
|
|
||||||
column_n = gtk.TreeViewColumn(_('Name'), render, text=0)
|
|
||||||
tree.append_column(column_n)
|
|
||||||
|
|
||||||
column_n = gtk.TreeViewColumn(_('ID'), render, text=1)
|
|
||||||
tree.append_column(column_n)
|
|
||||||
|
|
||||||
self.get_widget('test_close').connect('clicked', self.close)
|
|
||||||
|
|
||||||
new_list = sorted(
|
|
||||||
(self.sort_val_from_handle(h) for h in handle_list),
|
|
||||||
key=lambda x: locale.strxfrm(x[0])
|
|
||||||
)
|
|
||||||
|
|
||||||
for s_, handle in new_list:
|
|
||||||
name, gid = self.get_name_id(handle)
|
|
||||||
model.append(row=[name, gid])
|
|
||||||
|
|
||||||
self.show()
|
|
||||||
|
|
||||||
def get_name_id(self, handle):
|
|
||||||
if self.namespace == 'Person':
|
|
||||||
person = self.db.get_person_from_handle(handle)
|
|
||||||
name = _nd.sorted(person)
|
|
||||||
gid = person.get_gramps_id()
|
|
||||||
elif self.namespace == 'Family':
|
|
||||||
family = self.db.get_family_from_handle(handle)
|
|
||||||
name = Utils.family_name(family, self.db)
|
|
||||||
gid = family.get_gramps_id()
|
|
||||||
elif self.namespace == 'Event':
|
|
||||||
event = self.db.get_event_from_handle(handle)
|
|
||||||
name = event.get_description()
|
|
||||||
gid = event.get_gramps_id()
|
|
||||||
elif self.namespace == 'Source':
|
|
||||||
source = self.db.get_source_from_handle(handle)
|
|
||||||
name = source.get_title()
|
|
||||||
gid = source.get_gramps_id()
|
|
||||||
elif self.namespace == 'Place':
|
|
||||||
place = self.db.get_place_from_handle(handle)
|
|
||||||
name = place.get_title()
|
|
||||||
gid = place.get_gramps_id()
|
|
||||||
elif self.namespace == 'MediaObject':
|
|
||||||
obj = self.db.get_object_from_handle(handle)
|
|
||||||
name = obj.get_description()
|
|
||||||
gid = obj.get_gramps_id()
|
|
||||||
elif self.namespace == 'Repository':
|
|
||||||
repo = self.db.get_repository_from_handle(handle)
|
|
||||||
name = repo.get_name()
|
|
||||||
gid = repo.get_gramps_id()
|
|
||||||
elif self.namespace == 'Note':
|
|
||||||
note = self.db.get_note_from_handle(handle)
|
|
||||||
name = note.get().replace('\n', ' ')
|
|
||||||
#String must be unicode for truncation to work for non ascii characters
|
|
||||||
name = unicode(name)
|
|
||||||
if len(name) > 80:
|
|
||||||
name = name[:80]+"..."
|
|
||||||
gid = note.get_gramps_id()
|
|
||||||
return (name, gid)
|
|
||||||
|
|
||||||
def sort_val_from_handle(self, handle):
|
|
||||||
if self.namespace == 'Person':
|
|
||||||
name = self.db.get_person_from_handle(handle).get_primary_name()
|
|
||||||
sortname = _nd.sort_string(name)
|
|
||||||
elif self.namespace == 'Family':
|
|
||||||
sortname = Utils.family_name(
|
|
||||||
self.db.get_family_from_handle(handle),self.db)
|
|
||||||
elif self.namespace == 'Event':
|
|
||||||
sortname = self.db.get_event_from_handle(handle).get_description()
|
|
||||||
elif self.namespace == 'Source':
|
|
||||||
sortname = self.db.get_source_from_handle(handle).get_title()
|
|
||||||
elif self.namespace == 'Place':
|
|
||||||
sortname = self.db.get_place_from_handle(handle).get_title()
|
|
||||||
elif self.namespace == 'MediaObject':
|
|
||||||
sortname = self.db.get_object_from_handle(handle).get_description()
|
|
||||||
elif self.namespace == 'Repository':
|
|
||||||
sortname = self.db.get_repository_from_handle(handle).get_name()
|
|
||||||
elif self.namespace == 'Note':
|
|
||||||
gid = self.db.get_note_from_handle(handle).get_gramps_id()
|
|
||||||
sortname = gid
|
|
||||||
return (sortname, handle)
|
|
@@ -1,23 +0,0 @@
|
|||||||
#
|
|
||||||
# Gramps - a GTK+/GNOME based genealogy program
|
|
||||||
#
|
|
||||||
# Copyright (C) 2000-2006 Donald N. Allingham
|
|
||||||
#
|
|
||||||
# This program is free software; you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation; either version 2 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with this program; if not, write to the Free Software
|
|
||||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
#
|
|
||||||
|
|
||||||
# $Id$
|
|
||||||
|
|
||||||
from _FilterEditor import FilterEditor
|
|
@@ -2,13 +2,11 @@
|
|||||||
# $Id$
|
# $Id$
|
||||||
|
|
||||||
SUBDIRS = \
|
SUBDIRS = \
|
||||||
BasicUtils \
|
|
||||||
cli \
|
cli \
|
||||||
data \
|
data \
|
||||||
DateHandler \
|
DateHandler \
|
||||||
docgen \
|
docgen \
|
||||||
Filters \
|
Filters \
|
||||||
FilterEditor \
|
|
||||||
gen \
|
gen \
|
||||||
glade \
|
glade \
|
||||||
GrampsLocale \
|
GrampsLocale \
|
||||||
|
@@ -16,6 +16,7 @@ pkgdata_PYTHON = \
|
|||||||
dbguielement.py \
|
dbguielement.py \
|
||||||
dbloader.py \
|
dbloader.py \
|
||||||
dbman.py \
|
dbman.py \
|
||||||
|
filtereditor.py \
|
||||||
grampsgui.py \
|
grampsgui.py \
|
||||||
pluginmanager.py \
|
pluginmanager.py \
|
||||||
utils.py \
|
utils.py \
|
||||||
|
@@ -2,8 +2,6 @@
|
|||||||
# Gramps - a GTK+/GNOME based genealogy program
|
# Gramps - a GTK+/GNOME based genealogy program
|
||||||
#
|
#
|
||||||
# Copyright (C) 2000-2007 Donald N. Allingham
|
# Copyright (C) 2000-2007 Donald N. Allingham
|
||||||
# Copyright (C) 2007-2008 Brian G. Matherly
|
|
||||||
# Copyright (C) 2008 Benny Malengier
|
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify
|
# This program is free software; you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -20,7 +18,7 @@
|
|||||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
#
|
#
|
||||||
|
|
||||||
# $Id$
|
# $Id:_FilterEditor.py 9912 2008-01-22 09:17:46Z acraphae $
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Custom Filter Editor tool.
|
Custom Filter Editor tool.
|
||||||
@@ -31,7 +29,7 @@ Custom Filter Editor tool.
|
|||||||
# Python modules
|
# Python modules
|
||||||
#
|
#
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
from gettext import gettext as _
|
import locale
|
||||||
|
|
||||||
#------------------------------------------------------------------------
|
#------------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
@@ -39,7 +37,7 @@ from gettext import gettext as _
|
|||||||
#
|
#
|
||||||
#------------------------------------------------------------------------
|
#------------------------------------------------------------------------
|
||||||
import logging
|
import logging
|
||||||
log = logging.getLogger(".FilterEdit")
|
log = logging.getLogger(".filtereditor")
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
@@ -54,29 +52,41 @@ import gobject
|
|||||||
# GRAMPS modules
|
# GRAMPS modules
|
||||||
#
|
#
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
import GrampsDisplay
|
from Filters import (GenericFilterFactory, FilterList, reload_custom_filters)
|
||||||
|
from Filters.Rules._MatchesFilterBase import MatchesFilterBase
|
||||||
|
import ListModel
|
||||||
|
import ManagedWindow
|
||||||
|
from QuestionDialog import QuestionDialog
|
||||||
import const
|
import const
|
||||||
|
import GrampsDisplay
|
||||||
|
import Errors
|
||||||
|
from TransUtils import sgettext as _
|
||||||
import gen.lib
|
import gen.lib
|
||||||
from Filters import Rules
|
from Filters import Rules
|
||||||
import AutoComp
|
import AutoComp
|
||||||
from gui.selectors import SelectorFactory
|
from gui.selectors import SelectorFactory
|
||||||
from gen.display.name import displayer as _nd
|
from gen.display.name import displayer as _nd
|
||||||
import Utils
|
import Utils
|
||||||
import ManagedWindow
|
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
|
||||||
#
|
|
||||||
# Sorting function for the filter rules
|
|
||||||
#
|
|
||||||
#-------------------------------------------------------------------------
|
|
||||||
def by_rule_name(f, s):
|
|
||||||
return cmp(f.name, s.name)
|
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
# Constants
|
# Constants
|
||||||
#
|
#
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
|
WIKI_HELP_PAGE = WIKI_HELP_PAGE = '%s_-_Filters' % const.URL_MANUAL_PAGE
|
||||||
|
|
||||||
|
# dictionary mapping FILTER_TYPE of views to Filter window name
|
||||||
|
_TITLES = {
|
||||||
|
'Person' : _("Person Filters"),
|
||||||
|
'Family' : _('Family Filters'),
|
||||||
|
'Event' : _('Event Filters'),
|
||||||
|
'Place' : _('Place Filters'),
|
||||||
|
'Source' : _('Source Filters'),
|
||||||
|
'MediaObject' : _('Media Object Filters'),
|
||||||
|
'Repository' : _('Repository Filters'),
|
||||||
|
'Note' : _('Note Filters'),
|
||||||
|
}
|
||||||
|
|
||||||
_name2typeclass = {
|
_name2typeclass = {
|
||||||
_('Personal event:') : gen.lib.EventType,
|
_('Personal event:') : gen.lib.EventType,
|
||||||
_('Family event:') : gen.lib.EventType,
|
_('Family event:') : gen.lib.EventType,
|
||||||
@@ -90,6 +100,14 @@ _name2typeclass = {
|
|||||||
_('Note type:') : gen.lib.NoteType,
|
_('Note type:') : gen.lib.NoteType,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# Sorting function for the filter rules
|
||||||
|
#
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
def by_rule_name(f, s):
|
||||||
|
return cmp(f.name, s.name)
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
# MyBoolean - check button with standard interface
|
# MyBoolean - check button with standard interface
|
||||||
@@ -336,7 +354,7 @@ class MySource(MyID):
|
|||||||
|
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
#
|
# MySelect
|
||||||
#
|
#
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
class MySelect(gtk.ComboBoxEntry):
|
class MySelect(gtk.ComboBoxEntry):
|
||||||
@@ -359,7 +377,7 @@ class MySelect(gtk.ComboBoxEntry):
|
|||||||
|
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
#
|
# MyEntry
|
||||||
#
|
#
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
class MyEntry(gtk.Entry):
|
class MyEntry(gtk.Entry):
|
||||||
@@ -370,7 +388,7 @@ class MyEntry(gtk.Entry):
|
|||||||
|
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
#
|
# EditRule
|
||||||
#
|
#
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
class EditRule(ManagedWindow.ManagedWindow):
|
class EditRule(ManagedWindow.ManagedWindow):
|
||||||
@@ -635,3 +653,470 @@ class EditRule(ManagedWindow.ManagedWindow):
|
|||||||
self.close()
|
self.close()
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# EditFilter
|
||||||
|
#
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
class EditFilter(ManagedWindow.ManagedWindow):
|
||||||
|
|
||||||
|
def __init__(self, namespace, dbstate, uistate, track, gfilter,
|
||||||
|
filterdb, update):
|
||||||
|
|
||||||
|
ManagedWindow.ManagedWindow.__init__(self, uistate, track, self)
|
||||||
|
|
||||||
|
self.namespace = namespace
|
||||||
|
self.update = update
|
||||||
|
self.dbstate = dbstate
|
||||||
|
self.db = dbstate.db
|
||||||
|
self.filter = gfilter
|
||||||
|
self.filterdb = filterdb
|
||||||
|
|
||||||
|
self.define_glade('define_filter', const.RULE_GLADE)
|
||||||
|
|
||||||
|
self.set_window(
|
||||||
|
self.get_widget('define_filter'),
|
||||||
|
self.get_widget('definition_title'),
|
||||||
|
_('Define filter'))
|
||||||
|
|
||||||
|
self.rlist = ListModel.ListModel(
|
||||||
|
self.get_widget('rule_list'),
|
||||||
|
[(_('Name'),-1,150),(_('Values'),-1,150)],
|
||||||
|
self.select_row,
|
||||||
|
self.on_edit_clicked)
|
||||||
|
|
||||||
|
self.fname = self.get_widget('filter_name')
|
||||||
|
self.logical = self.get_widget('rule_apply')
|
||||||
|
self.logical_not = self.get_widget('logical_not')
|
||||||
|
self.comment = self.get_widget('comment')
|
||||||
|
self.ok_btn = self.get_widget('definition_ok')
|
||||||
|
self.edit_btn = self.get_widget('definition_edit')
|
||||||
|
self.del_btn = self.get_widget('definition_delete')
|
||||||
|
self.add_btn = self.get_widget('definition_add')
|
||||||
|
|
||||||
|
self.ok_btn.connect('clicked', self.on_ok_clicked)
|
||||||
|
self.edit_btn.connect('clicked', self.on_edit_clicked)
|
||||||
|
self.del_btn.connect('clicked', self.on_delete_clicked)
|
||||||
|
self.add_btn.connect('clicked', self.on_add_clicked)
|
||||||
|
|
||||||
|
self.get_widget('definition_help').connect('clicked',
|
||||||
|
self.on_help_clicked)
|
||||||
|
self.get_widget('definition_cancel').connect('clicked',
|
||||||
|
self.close_window)
|
||||||
|
self.fname.connect('changed', self.filter_name_changed)
|
||||||
|
|
||||||
|
if self.filter.get_logical_op() == 'or':
|
||||||
|
self.logical.set_active(1)
|
||||||
|
elif self.filter.get_logical_op() == 'one':
|
||||||
|
self.logical.set_active(2)
|
||||||
|
else:
|
||||||
|
self.logical.set_active(0)
|
||||||
|
self.logical_not.set_active(self.filter.get_invert())
|
||||||
|
if self.filter.get_name():
|
||||||
|
self.fname.set_text(self.filter.get_name())
|
||||||
|
self.comment.set_text(self.filter.get_comment())
|
||||||
|
self.draw_rules()
|
||||||
|
|
||||||
|
self.show()
|
||||||
|
|
||||||
|
def on_help_clicked(self, obj):
|
||||||
|
"""Display the relevant portion of GRAMPS manual"""
|
||||||
|
GrampsDisplay.help(webpage=WIKI_HELP_PAGE)
|
||||||
|
|
||||||
|
def close_window(self, obj):
|
||||||
|
self.close()
|
||||||
|
|
||||||
|
def filter_name_changed(self, obj):
|
||||||
|
name = unicode(self.fname.get_text())
|
||||||
|
# Make sure that the name is not empty
|
||||||
|
# and not in the list of existing filters (excluding this one)
|
||||||
|
names = [filt.get_name()
|
||||||
|
for filt in self.filterdb.get_filters(self.namespace)
|
||||||
|
if filt != self.filter]
|
||||||
|
self.ok_btn.set_sensitive((len(name) != 0) and (name not in names))
|
||||||
|
|
||||||
|
def select_row(self, obj):
|
||||||
|
store, node = self.rlist.get_selected()
|
||||||
|
if node:
|
||||||
|
self.edit_btn.set_sensitive(True)
|
||||||
|
self.del_btn.set_sensitive(True)
|
||||||
|
else:
|
||||||
|
self.edit_btn.set_sensitive(False)
|
||||||
|
self.del_btn.set_sensitive(False)
|
||||||
|
|
||||||
|
def draw_rules(self):
|
||||||
|
self.rlist.clear()
|
||||||
|
for r in self.filter.get_rules():
|
||||||
|
self.rlist.add([r.name,r.display_values()],r)
|
||||||
|
|
||||||
|
def on_ok_clicked(self, obj):
|
||||||
|
n = unicode(self.fname.get_text()).strip()
|
||||||
|
if n == '':
|
||||||
|
return
|
||||||
|
if n != self.filter.get_name():
|
||||||
|
self.uistate.emit('filter-name-changed',
|
||||||
|
(self.namespace,unicode(self.filter.get_name()), n))
|
||||||
|
self.filter.set_name(n)
|
||||||
|
self.filter.set_comment(unicode(self.comment.get_text()).strip())
|
||||||
|
for f in self.filterdb.get_filters(self.namespace)[:]:
|
||||||
|
if n == f.get_name():
|
||||||
|
self.filterdb.get_filters(self.namespace).remove(f)
|
||||||
|
break
|
||||||
|
val = self.logical.get_active()
|
||||||
|
if val == 1:
|
||||||
|
op = 'or'
|
||||||
|
elif val == 2:
|
||||||
|
op = 'one'
|
||||||
|
else:
|
||||||
|
op = 'and'
|
||||||
|
self.filter.set_logical_op(op)
|
||||||
|
self.filter.set_invert(self.logical_not.get_active())
|
||||||
|
self.filterdb.add(self.namespace,self.filter)
|
||||||
|
self.update()
|
||||||
|
self.close()
|
||||||
|
|
||||||
|
def on_add_clicked(self, obj):
|
||||||
|
try:
|
||||||
|
EditRule(self.namespace, self.dbstate, self.uistate, self.track,
|
||||||
|
self.filterdb, None, _('Add Rule'), self.update_rule,
|
||||||
|
self.filter.get_name())
|
||||||
|
except Errors.WindowActiveError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def on_edit_clicked(self, obj):
|
||||||
|
store, node = self.rlist.get_selected()
|
||||||
|
if node:
|
||||||
|
d = self.rlist.get_object(node)
|
||||||
|
|
||||||
|
try:
|
||||||
|
EditRule(self.namespace, self.dbstate, self.uistate, self.track,
|
||||||
|
self.filterdb, d, _('Edit Rule'), self.update_rule,
|
||||||
|
self.filter.get_name())
|
||||||
|
except Errors.WindowActiveError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def update_rule(self, old_rule, new_rule):
|
||||||
|
if old_rule is not None:
|
||||||
|
self.filter.delete_rule(old_rule)
|
||||||
|
self.filter.add_rule(new_rule)
|
||||||
|
self.draw_rules()
|
||||||
|
|
||||||
|
def on_delete_clicked(self, obj):
|
||||||
|
store, node = self.rlist.get_selected()
|
||||||
|
if node:
|
||||||
|
gfilter = self.rlist.get_object(node)
|
||||||
|
self.filter.delete_rule(gfilter)
|
||||||
|
self.draw_rules()
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# ShowResults
|
||||||
|
#
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
class ShowResults(ManagedWindow.ManagedWindow):
|
||||||
|
def __init__(self, db, uistate, track, handle_list, filtname, namespace):
|
||||||
|
|
||||||
|
ManagedWindow.ManagedWindow.__init__(self, uistate, track, self)
|
||||||
|
|
||||||
|
self.db = db
|
||||||
|
self.filtname = filtname
|
||||||
|
self.namespace = namespace
|
||||||
|
self.define_glade('test', const.RULE_GLADE,)
|
||||||
|
self.set_window(
|
||||||
|
self.get_widget('test'),
|
||||||
|
self.get_widget('test_title'),
|
||||||
|
_('Filter Test'))
|
||||||
|
|
||||||
|
render = gtk.CellRendererText()
|
||||||
|
|
||||||
|
tree = self.get_widget('list')
|
||||||
|
model = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
|
||||||
|
tree.set_model(model)
|
||||||
|
|
||||||
|
column_n = gtk.TreeViewColumn(_('Name'), render, text=0)
|
||||||
|
tree.append_column(column_n)
|
||||||
|
|
||||||
|
column_n = gtk.TreeViewColumn(_('ID'), render, text=1)
|
||||||
|
tree.append_column(column_n)
|
||||||
|
|
||||||
|
self.get_widget('test_close').connect('clicked', self.close)
|
||||||
|
|
||||||
|
new_list = sorted(
|
||||||
|
(self.sort_val_from_handle(h) for h in handle_list),
|
||||||
|
key=lambda x: locale.strxfrm(x[0])
|
||||||
|
)
|
||||||
|
|
||||||
|
for s_, handle in new_list:
|
||||||
|
name, gid = self.get_name_id(handle)
|
||||||
|
model.append(row=[name, gid])
|
||||||
|
|
||||||
|
self.show()
|
||||||
|
|
||||||
|
def get_name_id(self, handle):
|
||||||
|
if self.namespace == 'Person':
|
||||||
|
person = self.db.get_person_from_handle(handle)
|
||||||
|
name = _nd.sorted(person)
|
||||||
|
gid = person.get_gramps_id()
|
||||||
|
elif self.namespace == 'Family':
|
||||||
|
family = self.db.get_family_from_handle(handle)
|
||||||
|
name = Utils.family_name(family, self.db)
|
||||||
|
gid = family.get_gramps_id()
|
||||||
|
elif self.namespace == 'Event':
|
||||||
|
event = self.db.get_event_from_handle(handle)
|
||||||
|
name = event.get_description()
|
||||||
|
gid = event.get_gramps_id()
|
||||||
|
elif self.namespace == 'Source':
|
||||||
|
source = self.db.get_source_from_handle(handle)
|
||||||
|
name = source.get_title()
|
||||||
|
gid = source.get_gramps_id()
|
||||||
|
elif self.namespace == 'Place':
|
||||||
|
place = self.db.get_place_from_handle(handle)
|
||||||
|
name = place.get_title()
|
||||||
|
gid = place.get_gramps_id()
|
||||||
|
elif self.namespace == 'MediaObject':
|
||||||
|
obj = self.db.get_object_from_handle(handle)
|
||||||
|
name = obj.get_description()
|
||||||
|
gid = obj.get_gramps_id()
|
||||||
|
elif self.namespace == 'Repository':
|
||||||
|
repo = self.db.get_repository_from_handle(handle)
|
||||||
|
name = repo.get_name()
|
||||||
|
gid = repo.get_gramps_id()
|
||||||
|
elif self.namespace == 'Note':
|
||||||
|
note = self.db.get_note_from_handle(handle)
|
||||||
|
name = note.get().replace('\n', ' ')
|
||||||
|
#String must be unicode for truncation to work for non ascii characters
|
||||||
|
name = unicode(name)
|
||||||
|
if len(name) > 80:
|
||||||
|
name = name[:80]+"..."
|
||||||
|
gid = note.get_gramps_id()
|
||||||
|
return (name, gid)
|
||||||
|
|
||||||
|
def sort_val_from_handle(self, handle):
|
||||||
|
if self.namespace == 'Person':
|
||||||
|
name = self.db.get_person_from_handle(handle).get_primary_name()
|
||||||
|
sortname = _nd.sort_string(name)
|
||||||
|
elif self.namespace == 'Family':
|
||||||
|
sortname = Utils.family_name(
|
||||||
|
self.db.get_family_from_handle(handle),self.db)
|
||||||
|
elif self.namespace == 'Event':
|
||||||
|
sortname = self.db.get_event_from_handle(handle).get_description()
|
||||||
|
elif self.namespace == 'Source':
|
||||||
|
sortname = self.db.get_source_from_handle(handle).get_title()
|
||||||
|
elif self.namespace == 'Place':
|
||||||
|
sortname = self.db.get_place_from_handle(handle).get_title()
|
||||||
|
elif self.namespace == 'MediaObject':
|
||||||
|
sortname = self.db.get_object_from_handle(handle).get_description()
|
||||||
|
elif self.namespace == 'Repository':
|
||||||
|
sortname = self.db.get_repository_from_handle(handle).get_name()
|
||||||
|
elif self.namespace == 'Note':
|
||||||
|
gid = self.db.get_note_from_handle(handle).get_gramps_id()
|
||||||
|
sortname = gid
|
||||||
|
return (sortname, handle)
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# FilterEditor
|
||||||
|
#
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
class FilterEditor(ManagedWindow.ManagedWindow):
|
||||||
|
def __init__(self, namespace, filterdb, dbstate, uistate):
|
||||||
|
|
||||||
|
ManagedWindow.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', const.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.ListModel(
|
||||||
|
self.filter_list,
|
||||||
|
[(_('Filter'), 0, 150), (_('Comment'), 1, 150)],
|
||||||
|
self.filter_select_row,
|
||||||
|
self.edit_filter)
|
||||||
|
self.draw_filters()
|
||||||
|
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"""
|
||||||
|
GrampsDisplay.help()
|
||||||
|
|
||||||
|
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.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)
|
||||||
|
for the_filter in filter_set:
|
||||||
|
filters.remove(the_filter)
|
||||||
|
|
||||||
|
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:
|
||||||
|
for rule in the_filter.get_rules():
|
||||||
|
values = 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):
|
||||||
|
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 == 'Place':
|
||||||
|
return self.db.iter_place_handles()
|
||||||
|
elif self.namespace == 'MediaObject':
|
||||||
|
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 = 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 = rule.values()
|
||||||
|
if issubclass(rule.__class__, MatchesFilterBase) \
|
||||||
|
and (name in values):
|
||||||
|
return True
|
||||||
|
return False
|
@@ -59,6 +59,7 @@ from gui.utils import add_menuitem
|
|||||||
import const
|
import const
|
||||||
import Utils
|
import Utils
|
||||||
from QuestionDialog import QuestionDialog, QuestionDialog2
|
from QuestionDialog import QuestionDialog, QuestionDialog2
|
||||||
|
from gui.filtereditor import FilterEditor
|
||||||
from TransUtils import sgettext as _
|
from TransUtils import sgettext as _
|
||||||
|
|
||||||
#----------------------------------------------------------------
|
#----------------------------------------------------------------
|
||||||
@@ -354,8 +355,6 @@ class ListView(NavigationView):
|
|||||||
self.build_tree()
|
self.build_tree()
|
||||||
|
|
||||||
def filter_editor(self, obj):
|
def filter_editor(self, obj):
|
||||||
from FilterEditor import FilterEditor
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
FilterEditor(self.FILTER_TYPE , const.CUSTOM_FILTERS,
|
FilterEditor(self.FILTER_TYPE , const.CUSTOM_FILTERS,
|
||||||
self.dbstate, self.uistate)
|
self.dbstate, self.uistate)
|
||||||
|
@@ -58,7 +58,7 @@ import GrampsDisplay
|
|||||||
import ManagedWindow
|
import ManagedWindow
|
||||||
from TransUtils import sgettext as _
|
from TransUtils import sgettext as _
|
||||||
from glade import Glade
|
from glade import Glade
|
||||||
|
from gui.filtereditor import FilterEditor
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
@@ -163,9 +163,8 @@ class EventComparison(Tool.Tool,ManagedWindow.ManagedWindow):
|
|||||||
return (_("Filter selection"),_("Event Comparison tool"))
|
return (_("Filter selection"),_("Event Comparison tool"))
|
||||||
|
|
||||||
def filter_editor_clicked(self, obj):
|
def filter_editor_clicked(self, obj):
|
||||||
import FilterEditor
|
|
||||||
try:
|
try:
|
||||||
FilterEditor.FilterEditor('Person',const.CUSTOM_FILTERS,
|
FilterEditor('Person',const.CUSTOM_FILTERS,
|
||||||
self.dbstate,self.uistate)
|
self.dbstate,self.uistate)
|
||||||
except Errors.WindowActiveError:
|
except Errors.WindowActiveError:
|
||||||
pass
|
pass
|
||||||
|
@@ -65,6 +65,7 @@ import config
|
|||||||
from QuestionDialog import RunDatabaseRepair, ErrorDialog
|
from QuestionDialog import RunDatabaseRepair, ErrorDialog
|
||||||
import Bookmarks
|
import Bookmarks
|
||||||
import const
|
import const
|
||||||
|
from gui.filtereditor import FilterEditor
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
@@ -505,8 +506,6 @@ class PedigreeView(NavigationView):
|
|||||||
callback=self.filter_editor)
|
callback=self.filter_editor)
|
||||||
|
|
||||||
def filter_editor(self, obj):
|
def filter_editor(self, obj):
|
||||||
from FilterEditor import FilterEditor
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
FilterEditor('Person', const.CUSTOM_FILTERS,
|
FilterEditor('Person', const.CUSTOM_FILTERS,
|
||||||
self.dbstate, self.uistate)
|
self.dbstate, self.uistate)
|
||||||
|
@@ -53,6 +53,7 @@ except:
|
|||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
import gen.lib
|
import gen.lib
|
||||||
from gui.views.navigationview import NavigationView
|
from gui.views.navigationview import NavigationView
|
||||||
|
from gui.filtereditor import FilterEditor
|
||||||
from gen.display.name import displayer as name_displayer
|
from gen.display.name import displayer as name_displayer
|
||||||
from Utils import (media_path_full, probably_alive, find_children,
|
from Utils import (media_path_full, probably_alive, find_children,
|
||||||
find_parents, find_witnessed_people)
|
find_parents, find_witnessed_people)
|
||||||
@@ -632,8 +633,6 @@ class PedigreeViewExt(NavigationView):
|
|||||||
callback=self.filter_editor)
|
callback=self.filter_editor)
|
||||||
|
|
||||||
def filter_editor(self, obj):
|
def filter_editor(self, obj):
|
||||||
from FilterEditor import FilterEditor
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
FilterEditor('Person', const.CUSTOM_FILTERS,
|
FilterEditor('Person', const.CUSTOM_FILTERS,
|
||||||
self.dbstate, self.uistate)
|
self.dbstate, self.uistate)
|
||||||
|
@@ -49,6 +49,7 @@ import pango
|
|||||||
import gen.lib
|
import gen.lib
|
||||||
from gui.views.navigationview import NavigationView
|
from gui.views.navigationview import NavigationView
|
||||||
from gui.editors import EditPerson, EditFamily
|
from gui.editors import EditPerson, EditFamily
|
||||||
|
from gui.filtereditor import FilterEditor
|
||||||
from gen.display.name import displayer as name_displayer
|
from gen.display.name import displayer as name_displayer
|
||||||
from Utils import media_path_full, probably_alive
|
from Utils import media_path_full, probably_alive
|
||||||
import DateHandler
|
import DateHandler
|
||||||
@@ -384,8 +385,6 @@ class RelationshipView(NavigationView):
|
|||||||
self.family_action.set_sensitive(False)
|
self.family_action.set_sensitive(False)
|
||||||
|
|
||||||
def filter_editor(self, obj):
|
def filter_editor(self, obj):
|
||||||
from FilterEditor import FilterEditor
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
FilterEditor('Person', const.CUSTOM_FILTERS,
|
FilterEditor('Person', const.CUSTOM_FILTERS,
|
||||||
self.dbstate, self.uistate)
|
self.dbstate, self.uistate)
|
||||||
|
Reference in New Issue
Block a user