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:
Brian Matherly 2010-01-14 04:58:30 +00:00
parent e2f9eec6e9
commit d9a0ab8a90
14 changed files with 511 additions and 740 deletions

View File

@ -184,6 +184,7 @@ src/gui/__init__.py
src/gui/dbguielement.py
src/gui/dbloader.py
src/gui/dbman.py
src/gui/filtereditor.py
src/gui/grampsgui.py
src/gui/pluginmanager.py
src/gui/utils.py
@ -826,12 +827,6 @@ src/Filters/SideBar/_MediaSidebarFilter.py
src/Filters/SideBar/_RepoSidebarFilter.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
#

View File

@ -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));

View File

@ -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()

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -2,13 +2,11 @@
# $Id$
SUBDIRS = \
BasicUtils \
cli \
data \
DateHandler \
docgen \
Filters \
FilterEditor \
gen \
glade \
GrampsLocale \

View File

@ -16,6 +16,7 @@ pkgdata_PYTHON = \
dbguielement.py \
dbloader.py \
dbman.py \
filtereditor.py \
grampsgui.py \
pluginmanager.py \
utils.py \

View File

@ -2,8 +2,6 @@
# Gramps - a GTK+/GNOME based genealogy program
#
# 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
# 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
#
# $Id$
# $Id:_FilterEditor.py 9912 2008-01-22 09:17:46Z acraphae $
"""
Custom Filter Editor tool.
@ -31,7 +29,7 @@ Custom Filter Editor tool.
# Python modules
#
#-------------------------------------------------------------------------
from gettext import gettext as _
import locale
#------------------------------------------------------------------------
#
@ -39,7 +37,7 @@ from gettext import gettext as _
#
#------------------------------------------------------------------------
import logging
log = logging.getLogger(".FilterEdit")
log = logging.getLogger(".filtereditor")
#-------------------------------------------------------------------------
#
@ -54,29 +52,41 @@ import gobject
# 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 GrampsDisplay
import Errors
from TransUtils import sgettext as _
import gen.lib
from Filters import Rules
import AutoComp
from gui.selectors import SelectorFactory
from gen.display.name import displayer as _nd
import Utils
import ManagedWindow
#-------------------------------------------------------------------------
#
# Sorting function for the filter rules
#
#-------------------------------------------------------------------------
def by_rule_name(f, s):
return cmp(f.name, s.name)
#-------------------------------------------------------------------------
#
# 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 = {
_('Personal event:') : gen.lib.EventType,
_('Family event:') : gen.lib.EventType,
@ -90,6 +100,14 @@ _name2typeclass = {
_('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
@ -336,7 +354,7 @@ class MySource(MyID):
#-------------------------------------------------------------------------
#
#
# MySelect
#
#-------------------------------------------------------------------------
class MySelect(gtk.ComboBoxEntry):
@ -359,7 +377,7 @@ class MySelect(gtk.ComboBoxEntry):
#-------------------------------------------------------------------------
#
#
# MyEntry
#
#-------------------------------------------------------------------------
class MyEntry(gtk.Entry):
@ -370,7 +388,7 @@ class MyEntry(gtk.Entry):
#-------------------------------------------------------------------------
#
#
# EditRule
#
#-------------------------------------------------------------------------
class EditRule(ManagedWindow.ManagedWindow):
@ -635,3 +653,470 @@ class EditRule(ManagedWindow.ManagedWindow):
self.close()
except KeyError:
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

View File

@ -59,6 +59,7 @@ from gui.utils import add_menuitem
import const
import Utils
from QuestionDialog import QuestionDialog, QuestionDialog2
from gui.filtereditor import FilterEditor
from TransUtils import sgettext as _
#----------------------------------------------------------------
@ -354,8 +355,6 @@ class ListView(NavigationView):
self.build_tree()
def filter_editor(self, obj):
from FilterEditor import FilterEditor
try:
FilterEditor(self.FILTER_TYPE , const.CUSTOM_FILTERS,
self.dbstate, self.uistate)

View File

@ -58,7 +58,7 @@ import GrampsDisplay
import ManagedWindow
from TransUtils import sgettext as _
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"))
def filter_editor_clicked(self, obj):
import FilterEditor
try:
FilterEditor.FilterEditor('Person',const.CUSTOM_FILTERS,
FilterEditor('Person',const.CUSTOM_FILTERS,
self.dbstate,self.uistate)
except Errors.WindowActiveError:
pass

View File

@ -65,6 +65,7 @@ import config
from QuestionDialog import RunDatabaseRepair, ErrorDialog
import Bookmarks
import const
from gui.filtereditor import FilterEditor
#-------------------------------------------------------------------------
#
@ -505,8 +506,6 @@ class PedigreeView(NavigationView):
callback=self.filter_editor)
def filter_editor(self, obj):
from FilterEditor import FilterEditor
try:
FilterEditor('Person', const.CUSTOM_FILTERS,
self.dbstate, self.uistate)

View File

@ -53,6 +53,7 @@ except:
#-------------------------------------------------------------------------
import gen.lib
from gui.views.navigationview import NavigationView
from gui.filtereditor import FilterEditor
from gen.display.name import displayer as name_displayer
from Utils import (media_path_full, probably_alive, find_children,
find_parents, find_witnessed_people)
@ -632,8 +633,6 @@ class PedigreeViewExt(NavigationView):
callback=self.filter_editor)
def filter_editor(self, obj):
from FilterEditor import FilterEditor
try:
FilterEditor('Person', const.CUSTOM_FILTERS,
self.dbstate, self.uistate)

View File

@ -49,6 +49,7 @@ import pango
import gen.lib
from gui.views.navigationview import NavigationView
from gui.editors import EditPerson, EditFamily
from gui.filtereditor import FilterEditor
from gen.display.name import displayer as name_displayer
from Utils import media_path_full, probably_alive
import DateHandler
@ -384,8 +385,6 @@ class RelationshipView(NavigationView):
self.family_action.set_sensitive(False)
def filter_editor(self, obj):
from FilterEditor import FilterEditor
try:
FilterEditor('Person', const.CUSTOM_FILTERS,
self.dbstate, self.uistate)