From 28d4740d3c0f358f87174c111d482b6abca6b049 Mon Sep 17 00:00:00 2001 From: Don Allingham Date: Fri, 2 Jun 2006 03:21:52 +0000 Subject: [PATCH] 2006-06-01 Don Allingham * src/DataViews/_PersonView.py: FilterEditor call sequence * src/FilterEditor/_EditFilter.py: added * src/FilterEditor/_FilterEditor.py: Break out other classes * src/FilterEditor/_EditRule.py: added * src/FilterEditor/_ShowResults.py: added * src/FilterEditor/Makefile.am: Add new files svn: r6843 --- ChangeLog | 8 + po/POTFILES.in | 5 +- src/DataViews/_PersonView.py | 2 +- src/FilterEditor/Makefile.am | 5 +- src/FilterEditor/_EditFilter.py | 201 ++++++++ src/FilterEditor/_EditRule.py | 524 +++++++++++++++++++++ src/FilterEditor/_FilterEditor.py | 744 +----------------------------- src/FilterEditor/_ShowResults.py | 100 ++++ 8 files changed, 866 insertions(+), 723 deletions(-) create mode 100644 src/FilterEditor/_EditFilter.py create mode 100644 src/FilterEditor/_EditRule.py create mode 100644 src/FilterEditor/_ShowResults.py diff --git a/ChangeLog b/ChangeLog index 636238076..6536c0f29 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2006-06-01 Don Allingham + * src/DataViews/_PersonView.py: FilterEditor call sequence + * src/FilterEditor/_EditFilter.py: added + * src/FilterEditor/_FilterEditor.py: Break out other classes + * src/FilterEditor/_EditRule.py: added + * src/FilterEditor/_ShowResults.py: added + * src/FilterEditor/Makefile.am: Add new files + 2006-06-01 Alex Roitman * src/ReportBase/_ReportDialog.py (report): Use new report modules for oddball reports. diff --git a/po/POTFILES.in b/po/POTFILES.in index fa8d5a83c..d6c9a7551 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -248,7 +248,6 @@ src/plugins/ExportVCalendar.py src/plugins/ExportVCard.py src/plugins/FamilyGroup.py src/plugins/FanChart.py -src/plugins/FilterEditor.py src/plugins/FtmStyleAncestors.py src/plugins/FtmStyleDescendants.py src/plugins/GraphViz.py @@ -470,6 +469,10 @@ src/plugins/vcalendarexport.glade src/plugins/vcardexport.glade src/plugins/verify.glade src/plugins/writeftree.glade +src/FilterEditor/_FilterEditor.py +src/FilterEditor/_EditFilter.py +src/FilterEditor/_EditRule.py +src/FilterEditor/_ShowResults.py # # Files to extract from and then merge into # diff --git a/src/DataViews/_PersonView.py b/src/DataViews/_PersonView.py index 1c7c9ed39..164cb69a4 100644 --- a/src/DataViews/_PersonView.py +++ b/src/DataViews/_PersonView.py @@ -208,7 +208,7 @@ class PersonView(PageView.PersonNavView): FilterEditor( 'Person', const.custom_filters, - self.dbstate.db, + self.dbstate, self.uistate) def set_column_order(self, column_list): diff --git a/src/FilterEditor/Makefile.am b/src/FilterEditor/Makefile.am index 66c530c7a..cf03200d5 100644 --- a/src/FilterEditor/Makefile.am +++ b/src/FilterEditor/Makefile.am @@ -4,7 +4,10 @@ pkgdatadir = $(datadir)/@PACKAGE@/FilterEditor pkgdata_PYTHON = \ __init__.py \ - _FilterEditor.py + _FilterEditor.py \ + _EditFilter.py \ + _EditRule.py \ + _ShowResults.py pkgpyexecdir = @pkgpyexecdir@/FilterEditor pkgpythondir = @pkgpythondir@/FilterEditor diff --git a/src/FilterEditor/_EditFilter.py b/src/FilterEditor/_EditFilter.py new file mode 100644 index 000000000..47641fd69 --- /dev/null +++ b/src/FilterEditor/_EditFilter.py @@ -0,0 +1,201 @@ +# +# 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: _FilterEditor.py 6840 2006-06-01 22:37:13Z dallingham $ + +""" +Custom Filter Editor tool. +""" + +__author__ = "Don Allingham" + +#------------------------------------------------------------------------- +# +# Python modules +# +#------------------------------------------------------------------------- +import os +from gettext import gettext as _ + +#------------------------------------------------------------------------ +# +# Set up logging +# +#------------------------------------------------------------------------ +import logging +log = logging.getLogger(".FilterEdit") + +#------------------------------------------------------------------------- +# +# GTK/GNOME +# +#------------------------------------------------------------------------- +import gtk +import gtk.glade +import GrampsDisplay + +#------------------------------------------------------------------------- +# +# GRAMPS modules +# +#------------------------------------------------------------------------- +import const +import RelLib +from Filters import GenericFilter, FilterList, Rules, \ + reload_custom_filters, reload_system_filters +import ListModel +import ManagedWindow + +#------------------------------------------------------------------------- +# +# +# +#------------------------------------------------------------------------- +class EditFilter(ManagedWindow.ManagedWindow): + + def __init__(self, space, dbstate, uistate, track, gfilter, filterdb, update): + + ManagedWindow.ManagedWindow.__init__(self, uistate, track, self) + + self.space = space + self.update = update + self.dbstate = dbstate + self.db = dbstate.db + self.filter = gfilter + self.filterdb = filterdb + + self.glade = gtk.glade.XML(const.rule_glade,'define_filter',"gramps") + self.define_title = self.glade.get_widget('title') + + self.set_window( + self.glade.get_widget('define_filter'), + self.define_title, + _('Define filter')) + + self.rule_list = self.glade.get_widget('rule_list') + self.rlist = ListModel.ListModel( + self.rule_list, + [(_('Name'),-1,150),(_('Value'),-1,150)], + self.select_row, + self.on_edit_clicked) + + self.fname = self.glade.get_widget('filter_name') + self.logical = self.glade.get_widget('rule_apply') + self.comment = self.glade.get_widget('comment') + self.ok = self.glade.get_widget('ok') + self.edit_btn = self.glade.get_widget('edit') + self.del_btn = self.glade.get_widget('delete') + self.glade.signal_autoconnect({ + 'on_ok_clicked' : self.on_ok_clicked, + 'on_cancel_clicked' : self.close_window, + 'on_filter_name_changed' : self.filter_name_changed, + 'on_add_clicked' : self.on_add_clicked, + "on_help_filtdef_clicked" : self.on_help_clicked, + 'on_edit_clicked' : self.on_edit_clicked, + }) + + 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) + 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('tools-util-cfe') + + def close_window(self,obj): + self.close() + + def filter_name_changed(self,obj): + name = unicode(self.fname.get_text()) + self.ok.set_sensitive(len(name) != 0) + + 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 + self.filter.set_name(n) + self.filter.set_comment(unicode(self.comment.get_text()).strip()) + for f in self.filterdb.get_filters(self.space)[:]: + if n == f.get_name(): + self.filterdb.get_filters(self.space).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.filterdb.add(self.space,self.filter) + self.update() + self.close() + + def on_add_clicked(self,obj): + from _EditRule import EditRule + + EditRule(self.space, self.dbstate, self.uistate, self.track, + self.filterdb, None, _('Add Rule'), self.update_rule) + + def on_edit_clicked(self,obj): + store,node = self.rlist.get_selected() + if node: + from _EditRule import EditRule + + d = self.rlist.get_object(node) + EditRule(self.space, self.dbstate, self.uistate, self.track, + self.filterdb, d, _('Edit Rule'), self.update_rule) + + def update_rule(self, old_rule, new_rule): + if old_rule: + 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() + diff --git a/src/FilterEditor/_EditRule.py b/src/FilterEditor/_EditRule.py new file mode 100644 index 000000000..de8a0e21d --- /dev/null +++ b/src/FilterEditor/_EditRule.py @@ -0,0 +1,524 @@ +# +# 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: _FilterEditor.py 6840 2006-06-01 22:37:13Z dallingham $ + +""" +Custom Filter Editor tool. +""" + +__author__ = "Don Allingham" + +#------------------------------------------------------------------------- +# +# Python modules +# +#------------------------------------------------------------------------- +import os +from gettext import gettext as _ + +#------------------------------------------------------------------------ +# +# Set up logging +# +#------------------------------------------------------------------------ +import logging +log = logging.getLogger(".FilterEdit") + +#------------------------------------------------------------------------- +# +# GTK/GNOME +# +#------------------------------------------------------------------------- +import gtk +import gtk.glade +import gobject +import GrampsDisplay + +#------------------------------------------------------------------------- +# +# GRAMPS modules +# +#------------------------------------------------------------------------- +import const +import RelLib +from Filters import GenericFilter, FilterList, Rules, \ + reload_custom_filters, reload_system_filters +import AutoComp +from Selectors import selector_factory +SelectPerson = selector_factory('Person') +import ManagedWindow + +#------------------------------------------------------------------------- +# +# Sorting function for the filter rules +# +#------------------------------------------------------------------------- +def by_rule_name(f,s): + return cmp(f.name,s.name) + +#------------------------------------------------------------------------- +# +# Constants +# +#------------------------------------------------------------------------- +_name2list = { + _('Personal event:') : RelLib.EventType().get_map(), + _('Family event:') : RelLib.EventType().get_map(), + _('Personal attribute:') : RelLib.AttributeType().get_map(), + _('Family attribute:') : RelLib.AttributeType().get_map(), +} + +_menulist = { + _('Relationship type:') : RelLib.FamilyRelType().get_map(), + } + +#------------------------------------------------------------------------- +# +# MyBoolean - check button with standard interface +# +#------------------------------------------------------------------------- +class MyBoolean(gtk.CheckButton): + + def __init__(self,label=None): + gtk.CheckButton.__init__(self,label) + self.show() + + def get_text(self): + return str(int(self.get_active())) + + def set_text(self,val): + is_active = not not int(val) + self.set_active(is_active) + +#------------------------------------------------------------------------- +# +# MyInteger - spin button with standard interface +# +#------------------------------------------------------------------------- +class MyInteger(gtk.SpinButton): + + def __init__(self,min,max): + gtk.SpinButton.__init__(self) + self.set_adjustment(gtk.Adjustment(min,min,max,1)) + self.show() + + def get_text(self): + return str(self.get_value_as_int()) + + def set_text(self,val): + self.set_value(int(val)) + +#------------------------------------------------------------------------- +# +# MyFilters - Combo box with list of filters with a standard interface +# +#------------------------------------------------------------------------- +class MyFilters(gtk.ComboBox): + + def __init__(self,filters): + gtk.ComboBox.__init__(self) + store = gtk.ListStore(str) + self.set_model(store) + cell = gtk.CellRendererText() + self.pack_start(cell,True) + self.add_attribute(cell,'text',0) + self.flist = [ f.get_name() for f in filters ] + self.flist.sort() + + for fname in self.flist: + store.append(row=[fname]) + self.set_active(0) + self.show() + + def get_text(self): + active = self.get_active() + if active < 0: + return "" + return self.flist[active] + + def set_text(self,val): + if val in self.flist: + self.set_active(self.flist.index(val)) + +#------------------------------------------------------------------------- +# +# MySource - Combo box with list of sources with a standard interface +# +#------------------------------------------------------------------------- +class MySource(gtk.ComboBox): + + def __init__(self, db): + gtk.ComboBox.__init__(self) + self.db = db + store = gtk.ListStore(str) + self.set_model(store) + cell = gtk.CellRendererText() + self.pack_start(cell,True) + self.add_attribute(cell,'text',0) + + self.slist = [] + for src_handle in self.db.get_source_handles(sort_handles=True): + src = self.db.get_source_from_handle(src_handle) + self.slist.append(src.get_gramps_id()) + store.append(row=["%s [%s]" % (src.get_title(),src.get_gramps_id())]) + + self.set_active(0) + self.show() + + def get_text(self): + active = self.get_active() + if active < 0: + return "" + return self.slist[active] + + def set_text(self,val): + if val in self.slist: + self.set_active(self.slist.index(val)) + +#------------------------------------------------------------------------- +# +# MyPlaces - AutoCombo text entry with list of places attached. Provides +# a standard interface +# +#------------------------------------------------------------------------- +class MyPlaces(gtk.Entry): + + def __init__(self,places): + gtk.Entry.__init__(self) + + AutoComp.fill_entry(self,places) + self.show() + +#------------------------------------------------------------------------- +# +# MyID - Person/GRAMPS ID selection box with a standard interface +# +#------------------------------------------------------------------------- +class MyID(gtk.HBox): + + def __init__(self, dbstate, uistate, track): + gtk.HBox.__init__(self,False,6) + self.dbstate = dbstate + self.db = dbstate.db + self.uistate = uistate + self.track = track + + self.entry = gtk.Entry() + self.entry.show() + self.button = gtk.Button() + self.button.set_label(_('Select...')) + self.button.connect('clicked',self.button_press) + self.button.show() + self.pack_start(self.entry) + self.add(self.button) + self.tooltips = gtk.Tooltips() + self.tooltips.set_tip(self.button,_('Select person from a list')) + self.tooltips.enable() + self.show() + self.set_text('') + + def button_press(self,obj): + inst = SelectPerson(self.dbstate, self.uistate, self.track, + _('Select Person')) + val = inst.run() + if val == None: + self.set_text('') + else: + self.set_text(val.get_gramps_id()) + + def get_text(self): + return unicode(self.entry.get_text()) + + def set_text(self,val): + try: + p = self.db.get_person_from_handle(val) + n = p.get_primary_name().get_name() + self.tooltips.set_tip(self.entry,n) + except: + self.tooltips.set_tip(self.entry,_('Not a valid person')) + self.entry.set_text(val) + +#------------------------------------------------------------------------- +# +# +# +#------------------------------------------------------------------------- +class MySelect(gtk.ComboBoxEntry): + + def __init__(self, values): + gtk.ComboBoxEntry.__init__(self) + AutoComp.fill_combo(self, values) + self.show() + + def get_text(self): + return self.transtable.find_key(unicode(self.child.get_text())) + + def set_text(self,val): + self.child.set_text(_(val)) + +#------------------------------------------------------------------------- +# +# +# +#------------------------------------------------------------------------- +class MyListSelect(gtk.ComboBox): + + def __init__(self,data_list): + gtk.ComboBox.__init__(self) + store = gtk.ListStore(str) + self.set_model(store) + cell = gtk.CellRendererText() + self.pack_start(cell,True) + self.add_attribute(cell,'text',0) + self.data_list = data_list + + for item in data_list: + store.append(row=[item]) + self.set_active(0) + self.show() + + def get_text(self): + active = self.get_active() + if active < 0: + return str(-1) + return str(active) + + def set_text(self,val): + active = int(val) + if active >=0: + self.set_active(active) + +#------------------------------------------------------------------------- +# +# +# +#------------------------------------------------------------------------- +class MyEntry(gtk.Entry): + + def __init__(self): + gtk.Entry.__init__(self) + self.show() + +#------------------------------------------------------------------------- +# +# +# +#------------------------------------------------------------------------- +class EditRule(ManagedWindow.ManagedWindow): + def __init__(self, space, dbstate, uistate, track, filterdb, val, + label, update): + + ManagedWindow.ManagedWindow.__init__(self, uistate, track, EditRule) + + self.space = space + self.dbstate = dbstate + self.db = dbstate.db + self.filterdb = filterdb + self.update_rule = update + + self.active_rule = val + self.rule = gtk.glade.XML(const.rule_glade,'rule_editor',"gramps") + self.set_window(self.rule.get_widget('rule_editor'), + self.rule.get_widget('title'),label) + self.window.hide() + self.valuebox = self.rule.get_widget('valuebox') + self.rname = self.rule.get_widget('ruletree') + self.rule_name = self.rule.get_widget('rulename') + + self.notebook = gtk.Notebook() + self.notebook.set_show_tabs(0) + self.notebook.set_show_border(0) + self.notebook.show() + self.valuebox.add(self.notebook) + self.page_num = 0 + self.page = [] + self.class2page = {} + the_map = {} + for class_obj in Rules.Person.editor_rule_list: + arglist = class_obj.labels + vallist = [] + tlist = [] + self.page.append((class_obj,vallist,tlist)) + pos = 0 + l2 = gtk.Label(class_obj.name) + l2.set_alignment(0,0.5) + l2.show() + c = gtk.TreeView() + c.set_data('d',pos) + c.show() + the_map[class_obj] = c + # Only add a table with parameters if there are any parameters + if arglist: + table = gtk.Table(3,len(arglist)) + else: + table = gtk.Table(1,1) + table.set_border_width(6) + table.set_col_spacings(6) + table.set_row_spacings(6) + table.show() + for v in arglist: + v1 = _(v) + l = gtk.Label(v1) + l.set_alignment(1,0.5) + l.show() + if v == _('Place:'): + t = MyPlaces([]) + elif v == _('Number of generations:'): + t = MyInteger(1,32) + elif v == _('ID:'): + t = MyID(self.dbstate, self.uistate, self.track) + elif v == _('Source ID:'): + t = MySource(self.db) + elif v == _('Filter name:'): + t = MyFilters(self.filterdb.get_filters(self.space)) + elif _name2list.has_key(v1): + data =_name2list[v1] + t = MySelect(data.values()) + elif _menulist.has_key(v1): + data =_menulist[v1] + t = MyListSelect(data.values()) + elif v == _('Inclusive:'): + t = MyBoolean(_('Include original person')) + elif v == _('Case sensitive:'): + t = MyBoolean(_('Use exact case of letters')) + elif v == _('Regular-Expression matching:'): + t = MyBoolean(_('Use regular expression')) + else: + t = MyEntry() + tlist.append(t) + table.attach(l,1,2,pos,pos+1,gtk.FILL,0,5,5) + table.attach(t,2,3,pos,pos+1,gtk.EXPAND|gtk.FILL,0,5,5) + pos = pos + 1 + self.notebook.append_page(table,gtk.Label(class_obj.name)) + self.class2page[class_obj] = self.page_num + self.page_num = self.page_num + 1 + self.page_num = 0 + self.store = gtk.TreeStore(gobject.TYPE_STRING,gobject.TYPE_PYOBJECT) + self.selection = self.rname.get_selection() + col = gtk.TreeViewColumn(_('Rule Name'),gtk.CellRendererText(),text=0) + self.rname.append_column(col) + self.rname.set_model(self.store) + + prev = None + last_top = None + + top_level = {} + top_node = {} + + # + # If editing a rule, get the name so that we can select it later + # + sel_node = None + if self.active_rule: + self.sel_class = self.active_rule.__class__ + else: + self.sel_class = None + + keys = the_map.keys() + keys.sort(by_rule_name) + keys.reverse() + catlist = [] + for class_obj in keys: + category = class_obj.category + if category not in catlist: + catlist.append(category) + catlist.sort() + + for category in catlist: + top_node[category] = self.store.insert_after(None,last_top) + top_level[category] = [] + last_top = top_node[category] + self.store.set(last_top,0,category,1,None) + + for class_obj in keys: + category = class_obj.category + top_level[category].append(class_obj.name) + node = self.store.insert_after(top_node[category],prev) + self.store.set(node,0,class_obj.name,1,class_obj) + + # + # if this is an edit rule, save the node + if class_obj == self.sel_class: + sel_node = node + + if sel_node: + self.selection.select_iter(sel_node) + page = self.class2page[self.active_rule.__class__] + self.notebook.set_current_page(page) + self.display_values(self.active_rule.__class__) + (class_obj,vallist,tlist) = self.page[page] + r = self.active_rule.values() + for i in range(0,len(tlist)): + tlist[i].set_text(r[i]) + + self.selection.connect('changed', self.on_node_selected) + self.rule.signal_autoconnect({ + 'rule_ok_clicked' : self.rule_ok, + "on_help_rule_clicked" : self.on_help_clicked, + 'rule_cancel_clicked' : self.close_window, + }) + + self.show() + + def on_help_clicked(self,obj): + """Display the relevant portion of GRAMPS manual""" + GrampsDisplay.help('append-filtref') + + def close_window(self,obj): + self.close() + + def on_node_selected(self,obj): + """Updates the informational display on the right hand side of + the dialog box with the description of the selected report""" + + store,node = self.selection.get_selected() + if node: + try: + class_obj = store.get_value(node,1) + self.display_values(class_obj) + except: + self.valuebox.set_sensitive(0) + self.rule_name.set_text(_('No rule selected')) + self.rule.get_widget('description').set_text('') + + def display_values(self,class_obj): + page = self.class2page[class_obj] + self.notebook.set_current_page(page) + self.valuebox.set_sensitive(1) + self.rule_name.set_text(class_obj.name) + self.rule.get_widget('description').set_text(class_obj.description) + + def rule_ok(self,obj): + if self.rule_name.get_text() == _('No rule selected'): + return + + try: + page = self.notebook.get_current_page() + (class_obj,vallist,tlist) = self.page[page] + value_list = [] + for x in tlist: + value_list.append(unicode(x.get_text())) + new_rule = class_obj(value_list) + + self.update_rule(self.active_rule, new_rule) + self.close() + except KeyError: + pass diff --git a/src/FilterEditor/_FilterEditor.py b/src/FilterEditor/_FilterEditor.py index 13dc53042..b815764c4 100644 --- a/src/FilterEditor/_FilterEditor.py +++ b/src/FilterEditor/_FilterEditor.py @@ -49,7 +49,6 @@ log = logging.getLogger(".FilterEdit") #------------------------------------------------------------------------- import gtk import gtk.glade -import gobject import GrampsDisplay #------------------------------------------------------------------------- @@ -61,273 +60,21 @@ import const import RelLib from Filters import GenericFilter, FilterList, Rules, \ reload_custom_filters, reload_system_filters -import AutoComp import ListModel -import Utils -from Selectors import selector_factory -SelectPerson = selector_factory('Person') import ManagedWindow -from PluginUtils import Tool, register_tool - -#------------------------------------------------------------------------- -# -# Constants -# -#------------------------------------------------------------------------- -_name2list = { - _('Personal event:') : RelLib.EventType().get_map(), - _('Family event:') : RelLib.EventType().get_map(), - _('Personal attribute:') : RelLib.AttributeType().get_map(), - _('Family attribute:') : RelLib.AttributeType().get_map(), -} - -_menulist = { - _('Relationship type:') : RelLib.FamilyRelType().get_map(), - } - -#------------------------------------------------------------------------- -# -# Sorting function for the filter rules -# -#------------------------------------------------------------------------- -def by_rule_name(f,s): - return cmp(f.name,s.name) - -#------------------------------------------------------------------------- -# -# MyBoolean - check button with standard interface -# -#------------------------------------------------------------------------- -class MyBoolean(gtk.CheckButton): - - def __init__(self,label=None): - gtk.CheckButton.__init__(self,label) - self.show() - - def get_text(self): - return str(int(self.get_active())) - - def set_text(self,val): - is_active = not not int(val) - self.set_active(is_active) - -#------------------------------------------------------------------------- -# -# MyInteger - spin button with standard interface -# -#------------------------------------------------------------------------- -class MyInteger(gtk.SpinButton): - - def __init__(self,min,max): - gtk.SpinButton.__init__(self) - self.set_adjustment(gtk.Adjustment(min,min,max,1)) - self.show() - - def get_text(self): - return str(self.get_value_as_int()) - - def set_text(self,val): - self.set_value(int(val)) - -#------------------------------------------------------------------------- -# -# MyFilters - Combo box with list of filters with a standard interface -# -#------------------------------------------------------------------------- -class MyFilters(gtk.ComboBox): - - def __init__(self,filters): - gtk.ComboBox.__init__(self) - store = gtk.ListStore(str) - self.set_model(store) - cell = gtk.CellRendererText() - self.pack_start(cell,True) - self.add_attribute(cell,'text',0) - self.flist = [ f.get_name() for f in filters ] - self.flist.sort() - - for fname in self.flist: - store.append(row=[fname]) - self.set_active(0) - self.show() - - def get_text(self): - active = self.get_active() - if active < 0: - return "" - return self.flist[active] - - def set_text(self,val): - if val in self.flist: - self.set_active(self.flist.index(val)) - -#------------------------------------------------------------------------- -# -# MySource - Combo box with list of sources with a standard interface -# -#------------------------------------------------------------------------- -class MySource(gtk.ComboBox): - - def __init__(self,db): - gtk.ComboBox.__init__(self) - self.db = db - store = gtk.ListStore(str) - self.set_model(store) - cell = gtk.CellRendererText() - self.pack_start(cell,True) - self.add_attribute(cell,'text',0) - - self.slist = [] - for src_handle in self.db.get_source_handles(sort_handles=True): - src = self.db.get_source_from_handle(src_handle) - self.slist.append(src.get_gramps_id()) - store.append(row=["%s [%s]" % (src.get_title(),src.get_gramps_id())]) - - self.set_active(0) - self.show() - - def get_text(self): - active = self.get_active() - if active < 0: - return "" - return self.slist[active] - - def set_text(self,val): - if val in self.slist: - self.set_active(self.slist.index(val)) - -#------------------------------------------------------------------------- -# -# MyPlaces - AutoCombo text entry with list of places attached. Provides -# a standard interface -# -#------------------------------------------------------------------------- -class MyPlaces(gtk.Entry): - - def __init__(self,places): - gtk.Entry.__init__(self) - - AutoComp.fill_entry(self,places) - self.show() - -#------------------------------------------------------------------------- -# -# MyID - Person/GRAMPS ID selection box with a standard interface -# -#------------------------------------------------------------------------- -class MyID(gtk.HBox): - - def __init__(self,db): - gtk.HBox.__init__(self,False,6) - self.db = db - - self.entry = gtk.Entry() - self.entry.show() - self.button = gtk.Button() - self.button.set_label(_('Select...')) - self.button.connect('clicked',self.button_press) - self.button.show() - self.pack_start(self.entry) - self.add(self.button) - self.tooltips = gtk.Tooltips() - self.tooltips.set_tip(self.button,_('Select person from a list')) - self.tooltips.enable() - self.show() - self.set_text('') - - def button_press(self,obj): - inst = SelectPerson.SelectPerson(self.db,_('Select Person')) - val = inst.run() - if val == None: - self.set_text('') - else: - self.set_text(val.get_gramps_id()) - - def get_text(self): - return unicode(self.entry.get_text()) - - def set_text(self,val): - try: - p = self.db.get_person_from_handle(val) - n = p.get_primary_name().get_name() - self.tooltips.set_tip(self.entry,n) - except: - self.tooltips.set_tip(self.entry,_('Not a valid person')) - self.entry.set_text(val) - -#------------------------------------------------------------------------- -# -# -# -#------------------------------------------------------------------------- -class MySelect(gtk.ComboBoxEntry): - - def __init__(self, values): - gtk.ComboBoxEntry.__init__(self) - AutoComp.fill_combo(self, values) - self.show() - - def get_text(self): - return self.transtable.find_key(unicode(self.child.get_text())) - - def set_text(self,val): - self.child.set_text(_(val)) - -#------------------------------------------------------------------------- -# -# -# -#------------------------------------------------------------------------- -class MyListSelect(gtk.ComboBox): - - def __init__(self,data_list): - gtk.ComboBox.__init__(self) - store = gtk.ListStore(str) - self.set_model(store) - cell = gtk.CellRendererText() - self.pack_start(cell,True) - self.add_attribute(cell,'text',0) - self.data_list = data_list - - for item in data_list: - store.append(row=[item]) - self.set_active(0) - self.show() - - def get_text(self): - active = self.get_active() - if active < 0: - return str(-1) - return str(active) - - def set_text(self,val): - active = int(val) - if active >=0: - self.set_active(active) - -#------------------------------------------------------------------------- -# -# -# -#------------------------------------------------------------------------- -class MyEntry(gtk.Entry): - - def __init__(self): - gtk.Entry.__init__(self) - self.show() - #------------------------------------------------------------------------- # # # #------------------------------------------------------------------------- class FilterEditor(ManagedWindow.ManagedWindow): - def __init__(self, space, filterdb, db, uistate): + def __init__(self, space, filterdb, dbstate, uistate): ManagedWindow.ManagedWindow.__init__(self, uistate, [], FilterEditor) - self.db = db + self.dbstate = dbstate + self.db = dbstate.db self.filterdb = FilterList(filterdb) self.filterdb.load() self.space = space @@ -373,14 +120,13 @@ class FilterEditor(ManagedWindow.ManagedWindow): def on_delete_event(self,obj,b): self.filterdb.save() - self.remove_itself_from_menu() reload_custom_filters() reload_system_filters() self.close() def filter_select_row(self,obj): - store,iter = self.clist.get_selected() - if iter: + store,node = self.clist.get_selected() + if node: self.edit.set_sensitive(True) self.delete.set_sensitive(True) self.test.set_sensitive(True) @@ -401,477 +147,35 @@ class FilterEditor(ManagedWindow.ManagedWindow): self.clist.add([f.get_name(),f.get_comment()],f) def add_new_filter(self,obj): + from _EditFilter import EditFilter + the_filter = GenericFilter() - EditFilter(self.space, self.db, self.uistate, self.track, + EditFilter(self.space, self.dbstate, self.uistate, self.track, the_filter, self.filterdb, self.draw_filters) def edit_filter(self,obj): - store,iter = self.clist.get_selected() - if iter: - filter = self.clist.get_object(iter) - EditFilter(self.space, self.db, self.uistate, self.track, - filter, self.filterdb, self.draw_filters) + store,node = self.clist.get_selected() + if node: + from _EditFilter import EditFilter + + gfilter = self.clist.get_object(node) + EditFilter(self.space, self.dbstate, self.uistate, self.track, + gfilter, self.filterdb, self.draw_filters) def test_clicked(self,obj): - store,iter = self.clist.get_selected() - if iter: - filt = self.clist.get_object(iter) + store,node = self.clist.get_selected() + if node: + from _ShowResults import ShowResults + + filt = self.clist.get_object(node) handle_list = filt.apply(self.db,self.db.get_person_handles(sort_handles=False)) ShowResults(self.db, self.uistate, self.track, handle_list, filt.get_name()) def delete_filter(self,obj): - store,iter = self.clist.get_selected() - if iter: - filter = self.clist.get_object(iter) - self.filterdb.get_filters(self.space).remove(filter) + store,node = self.clist.get_selected() + if node: + gfilter = self.clist.get_object(node) + self.filterdb.get_filters(self.space).remove(gfilter) self.draw_filters() -#------------------------------------------------------------------------- -# -# -# -#------------------------------------------------------------------------- -class EditFilter(ManagedWindow.ManagedWindow): - - def __init__(self, space, db, uistate, track, filter, filterdb, update): - - ManagedWindow.ManagedWindow.__init__(self, uistate, [], self) - - self.space = space - self.update = update - self.db = db - self.filter = filter - self.filterdb = filterdb - - self.glade = gtk.glade.XML(const.rule_glade,'define_filter',"gramps") - self.define_title = self.glade.get_widget('title') - - self.set_window( - self.glade.get_widget('define_filter'), - self.define_title, - _('Define filter')) - - self.rule_list = self.glade.get_widget('rule_list') - self.rlist = ListModel.ListModel( - self.rule_list, - [(_('Name'),-1,150),(_('Value'),-1,150)], - self.select_row, - self.on_edit_clicked) - - self.fname = self.glade.get_widget('filter_name') - self.logical = self.glade.get_widget('rule_apply') - self.comment = self.glade.get_widget('comment') - self.ok = self.glade.get_widget('ok') - self.edit_btn = self.glade.get_widget('edit') - self.del_btn = self.glade.get_widget('delete') - self.glade.signal_autoconnect({ - 'on_ok_clicked' : self.on_ok_clicked, - 'on_cancel_clicked' : self.close_window, - 'on_filter_name_changed' : self.filter_name_changed, - 'on_add_clicked' : self.on_add_clicked, - "on_help_filtdef_clicked" : self.on_help_clicked, - 'on_edit_clicked' : self.on_edit_clicked, - }) - - 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) - 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('tools-util-cfe') - - def close_window(self,obj): - self.close() - - def filter_name_changed(self,obj): - name = unicode(self.fname.get_text()) - self.ok.set_sensitive(len(name) != 0) - - def select_row(self,obj): - store,iter = self.rlist.get_selected() - if iter: - 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 - self.filter.set_name(n) - self.filter.set_comment(unicode(self.comment.get_text()).strip()) - for f in self.filterdb.get_filters(self.space)[:]: - if n == f.get_name(): - self.filterdb.get_filters(self.space).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.filterdb.add(self.space,self.filter) - self.update() - self.close() - - def on_add_clicked(self,obj): - EditRule(self.db, self.uistate, self.track, self.filterdb, - None, _('Add Rule'), self.update_rule) - - def on_edit_clicked(self,obj): - store,iter = self.rlist.get_selected() - if iter: - d = self.rlist.get_object(iter) - EditRule(self.db, self.uistate, self.track, self.filterdb, - d, _('Edit Rule'), self.update_rule) - - def update_rule(self, old_rule, new_rule): - if old_rule: - self.filter.delete_rule(old_rule) - self.filter.add_rule(new_rule) - self.draw_rules() - - def on_delete_clicked(self,obj): - store,iter = self.rlist.get_selected() - if iter: - filter = self.rlist.get_object(iter) - self.filter.delete_rule(filter) - self.draw_rules() - -#------------------------------------------------------------------------- -# -# -# -#------------------------------------------------------------------------- -class EditRule(ManagedWindow.ManagedWindow): - def __init__(self, db, uistate, track, filterdb, val, label, update): - - ManagedWindow.ManagedWindow.__init__(self, uistate, track, EditRule) - - self.db = db - self.filterdb = filterdb - self.update_rule = update - - self.active_rule = val - self.rule = gtk.glade.XML(const.rule_glade,'rule_editor',"gramps") - self.set_window(self.rule.get_widget('rule_editor'), - self.rule.get_widget('title'),label) - self.window.hide() - self.valuebox = self.rule.get_widget('valuebox') - self.rname = self.rule.get_widget('ruletree') - self.rule_name = self.rule.get_widget('rulename') - - self.notebook = gtk.Notebook() - self.notebook.set_show_tabs(0) - self.notebook.set_show_border(0) - self.notebook.show() - self.valuebox.add(self.notebook) - self.page_num = 0 - self.page = [] - self.class2page = {} - the_map = {} - for class_obj in Rules.Person.editor_rule_list: - arglist = class_obj.labels - vallist = [] - tlist = [] - self.page.append((class_obj,vallist,tlist)) - pos = 0 - l2 = gtk.Label(class_obj.name) - l2.set_alignment(0,0.5) - l2.show() - c = gtk.TreeView() - c.set_data('d',pos) - c.show() - the_map[class_obj] = c - # Only add a table with parameters if there are any parameters - if arglist: - table = gtk.Table(3,len(arglist)) - else: - table = gtk.Table(1,1) - table.set_border_width(6) - table.set_col_spacings(6) - table.set_row_spacings(6) - table.show() - for v in arglist: - v1 = _(v) - l = gtk.Label(v1) - l.set_alignment(1,0.5) - l.show() - if v == _('Place:'): - t = MyPlaces([]) - elif v == _('Number of generations:'): - t = MyInteger(1,32) - elif v == _('ID:'): - t = MyID(self.db) - elif v == _('Source ID:'): - t = MySource(self.db) - elif v == _('Filter name:'): - t = MyFilters(self.filterdb.get_filters(self.space)) - elif _name2list.has_key(v1): - data =_name2list[v1] - t = MySelect(data.values()) - elif _menulist.has_key(v1): - data =_menulist[v1] - t = MyListSelect(data.values()) - elif v == _('Inclusive:'): - t = MyBoolean(_('Include original person')) - elif v == _('Case sensitive:'): - t = MyBoolean(_('Use exact case of letters')) - elif v == _('Regular-Expression matching:'): - t = MyBoolean(_('Use regular expression')) - else: - t = MyEntry() - tlist.append(t) - table.attach(l,1,2,pos,pos+1,gtk.FILL,0,5,5) - table.attach(t,2,3,pos,pos+1,gtk.EXPAND|gtk.FILL,0,5,5) - pos = pos + 1 - self.notebook.append_page(table,gtk.Label(class_obj.name)) - self.class2page[class_obj] = self.page_num - self.page_num = self.page_num + 1 - self.page_num = 0 - self.store = gtk.TreeStore(gobject.TYPE_STRING,gobject.TYPE_PYOBJECT) - self.selection = self.rname.get_selection() - col = gtk.TreeViewColumn(_('Rule Name'),gtk.CellRendererText(),text=0) - self.rname.append_column(col) - self.rname.set_model(self.store) - - prev = None - last_top = None - - top_level = {} - top_node = {} - - # - # If editing a rule, get the name so that we can select it later - # - sel_node = None - if self.active_rule: - self.sel_class = self.active_rule.__class__ - else: - self.sel_class = None - - keys = the_map.keys() - keys.sort(by_rule_name) - keys.reverse() - catlist = [] - for class_obj in keys: - category = class_obj.category - if category not in catlist: - catlist.append(category) - catlist.sort() - - for category in catlist: - top_node[category] = self.store.insert_after(None,last_top) - top_level[category] = [] - last_top = top_node[category] - self.store.set(last_top,0,category,1,None) - - for class_obj in keys: - category = class_obj.category - top_level[category].append(class_obj.name) - node = self.store.insert_after(top_node[category],prev) - self.store.set(node,0,class_obj.name,1,class_obj) - - # - # if this is an edit rule, save the node - if class_obj == self.sel_class: - sel_node = node - - if sel_node: - self.selection.select_iter(sel_node) - page = self.class2page[self.active_rule.__class__] - self.notebook.set_current_page(page) - self.display_values(self.active_rule.__class__) - (class_obj,vallist,tlist) = self.page[page] - r = self.active_rule.values() - for i in range(0,len(tlist)): - tlist[i].set_text(r[i]) - - self.selection.connect('changed', self.on_node_selected) - self.rule.signal_autoconnect({ - 'rule_ok_clicked' : self.rule_ok, - "on_help_rule_clicked" : self.on_help_clicked, - 'rule_cancel_clicked' : self.close_window, - }) - - self.show() - - def on_help_clicked(self,obj): - """Display the relevant portion of GRAMPS manual""" - GrampsDisplay.help('append-filtref') - - def close_window(self,obj): - self.close() - - def on_node_selected(self,obj): - """Updates the informational display on the right hand side of - the dialog box with the description of the selected report""" - - store,iter = self.selection.get_selected() - if iter: - try: - class_obj = store.get_value(iter,1) - self.display_values(class_obj) - except: - self.valuebox.set_sensitive(0) - self.rule_name.set_text(_('No rule selected')) - self.rule.get_widget('description').set_text('') - - def display_values(self,class_obj): - page = self.class2page[class_obj] - self.notebook.set_current_page(page) - self.valuebox.set_sensitive(1) - self.rule_name.set_text(class_obj.name) - self.rule.get_widget('description').set_text(class_obj.description) - - def rule_ok(self,obj): - if self.rule_name.get_text() == _('No rule selected'): - return - - try: - page = self.notebook.get_current_page() - (class_obj,vallist,tlist) = self.page[page] - value_list = [] - for x in tlist: - value_list.append(unicode(x.get_text())) - new_rule = class_obj(value_list) - - self.update_rule(self.active_rule, new_rule) - self.close() - except KeyError: - pass - -#------------------------------------------------------------------------- -# -# -# -#------------------------------------------------------------------------- -class ShowResults(ManagedWindow.ManagedWindow): - def __init__(self, db, uistate, track, handle_list, filtname): - - ManagedWindow.ManagedWindow.__init__(self, uistate, track, self) - - self.filtname = filtname - self.glade = gtk.glade.XML(const.rule_glade,'test',"gramps") - - self.set_window( - self.glade.get_widget('test'), - self.glade.get_widget('title'), - _('Filter Test')) - - text = self.glade.get_widget('text') - - self.glade.signal_autoconnect({ - 'on_close_clicked' : self.close_window, - }) - - n = [] - for p_handle in handle_list: - p = db.get_person_from_handle(p_handle) - n.append ("%s [%s]\n" % - (p.get_primary_name().get_name(),p.get_gramps_id())) - - n.sort () - text.get_buffer().set_text(''.join(n)) - - self.show() - - def close_window(self,obj): - self.close() - -#------------------------------------------------------------------------- -# -# -# -#------------------------------------------------------------------------- -class CustomFilterEditor(Tool.Tool): - def __init__(self, dbstate, uistate, options_class, name, callback=None): - - Tool.Tool.__init__(self, dbstate, options_class, name) - - FilterEditor(const.custom_filters, dbstate.db, uistate) - -#------------------------------------------------------------------------- -# -# -# -#------------------------------------------------------------------------- -class SystemFilterEditor(Tool.Tool): - def __init__(self, dbstate, uistate, options_class, name,callback=None): - - Tool.Tool.__init__(self, dbstate, options_class, name) - - FilterEditor(const.system_filters, dbstate.db, uistate) - -#------------------------------------------------------------------------ -# -# -# -#------------------------------------------------------------------------ -class FilterEditorOptions(Tool.ToolOptions): - """ - Defines options and provides handling interface. - """ - - def __init__(self,name,person_id=None): - Tool.ToolOptions.__init__(self, name, person_id) - -#------------------------------------------------------------------------- -# -# -# -#------------------------------------------------------------------------- -register_tool( - name = 'cfilted', - category = Tool.TOOL_UTILS, - tool_class = CustomFilterEditor, - options_class = FilterEditorOptions, - modes = Tool.MODE_GUI, - translated_name = _("Custom Filter Editor"), - status = _("Stable"), - author_name = "Donald N. Allingham", - author_email = "don@gramps-project.org", - description=_("The Custom Filter Editor builds custom " - "filters that can be used to select people " - "included in reports, exports, and other utilities.") - ) - -if ((os.path.exists(const.system_filters) and - os.access(const.system_filters, os.W_OK)) or - (os.path.exists(os.path.dirname(const.system_filters)) and - os.access(os.path.dirname(const.system_filters), os.W_OK))): - register_tool( - name = 'sfilted', - category = Tool.TOOL_UTILS, - tool_class = SystemFilterEditor, - options_class = FilterEditorOptions, - modes = Tool.MODE_GUI, - translated_name = _("System Filter Editor"), - status = _("Stable"), - author_name = "Donald N. Allingham", - author_email = "don@gramps-project.org", - description=_("The System Filter Editor builds custom " - "filters that can be used by anyone on the system " - "to select people included in reports, exports, " - "and other utilities.") - ) diff --git a/src/FilterEditor/_ShowResults.py b/src/FilterEditor/_ShowResults.py new file mode 100644 index 000000000..5a28129e5 --- /dev/null +++ b/src/FilterEditor/_ShowResults.py @@ -0,0 +1,100 @@ +# +# 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: _FilterEditor.py 6840 2006-06-01 22:37:13Z dallingham $ + +""" +Custom Filter Editor tool. +""" + +__author__ = "Don Allingham" + +#------------------------------------------------------------------------- +# +# Python modules +# +#------------------------------------------------------------------------- +import os +from gettext import gettext as _ + +#------------------------------------------------------------------------ +# +# Set up logging +# +#------------------------------------------------------------------------ +import logging +log = logging.getLogger(".FilterEdit") + +#------------------------------------------------------------------------- +# +# GTK/GNOME +# +#------------------------------------------------------------------------- +import gtk +import gtk.glade +import gobject +import GrampsDisplay + +#------------------------------------------------------------------------- +# +# GRAMPS modules +# +#------------------------------------------------------------------------- +import const +import ManagedWindow + +#------------------------------------------------------------------------- +# +# +# +#------------------------------------------------------------------------- +class ShowResults(ManagedWindow.ManagedWindow): + def __init__(self, db, uistate, track, handle_list, filtname): + + ManagedWindow.ManagedWindow.__init__(self, uistate, track, self) + + self.filtname = filtname + self.glade = gtk.glade.XML(const.rule_glade,'test',"gramps") + + self.set_window( + self.glade.get_widget('test'), + self.glade.get_widget('title'), + _('Filter Test')) + + text = self.glade.get_widget('text') + + self.glade.signal_autoconnect({ + 'on_close_clicked' : self.close_window, + }) + + n = [] + for p_handle in handle_list: + p = db.get_person_from_handle(p_handle) + n.append ("%s [%s]\n" % + (p.get_primary_name().get_name(),p.get_gramps_id())) + + n.sort () + text.get_buffer().set_text(''.join(n)) + + self.show() + + def close_window(self,obj): + self.close() +