diff --git a/ChangeLog b/ChangeLog index 8f0d59164..7545c2ee3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2006-01-17 Martin Hawlisch + * src/EventView.py (ui_definition): Add filter menu entry + * src/FamilyList.py (ui_definition): Add filter menu entry + * src/PlaceView.py (ui_definition): Add filter menu entry + * src/RepositoryView.py (ui_definition): Add filter menu entry + * src/SourceView.py (ui_definition): Add filter menu entry + * src/GenericFilter.py: Adding generic filter widget to be used in all + list views; Custom filter rules now get prefixed by primary object type + * src/PageView.py: Add filter control to all list views + * src/PersonView.py: Filter handling moved to GenericFiler + 2006-01-17 Richard Taylor * src/ObjectSelector/_FamilyFrame.py src/ObjectSelector/_FamilyPreviewFrame.py src/ObjectSelector/_FamilyTreeFrame.py src/ObjectSelector/_ObjectSelectorWindow.py diff --git a/src/EventView.py b/src/EventView.py index f428240d4..c644fff5e 100644 --- a/src/EventView.py +++ b/src/EventView.py @@ -86,6 +86,9 @@ class EventView(PageView.ListView): def ui_definition(self): return ''' + + + diff --git a/src/FamilyList.py b/src/FamilyList.py index 90eb1416e..2656da940 100644 --- a/src/FamilyList.py +++ b/src/FamilyList.py @@ -90,6 +90,9 @@ class FamilyListView(PageView.ListView): + + + @@ -123,4 +126,3 @@ class FamilyListView(PageView.ListView): import EditFamily family = self.dbstate.db.get_family_from_handle(handle) EditFamily.EditFamily(self.dbstate,self.uistate,[],family) - diff --git a/src/GenericFilter.py b/src/GenericFilter.py index 64a5187f8..792d7ad6b 100644 --- a/src/GenericFilter.py +++ b/src/GenericFilter.py @@ -2279,14 +2279,19 @@ class GenericFilterList: loads the filters.""" def __init__(self,file): - self.filter_list = [] + self.filter_list = {} self.file = os.path.expanduser(file) - def get_filters(self): - return self.filter_list + def get_filters(self,namespace): + try: + return self.filter_list[namespace] + except KeyError: + return [] - def add(self,filt): - self.filter_list.append(filt) + def add(self,namespace,filt): + if namespace not in self.filter_list: + self.filter_list[namespace] = [] + self.filter_list[namespace].append(filt) def load(self): try: @@ -2313,24 +2318,27 @@ class GenericFilterList: f.write("\n") f.write('\n') - for i in self.filter_list: - f.write(' \n') - for rule in i.get_rules(): - rule_module_name = rule.__module__ - rule_class_name = rule.__class__.__name__ - rule_save_name = "%s.%s" % (rule_module_name,rule_class_name) - f.write(' \n' % rule_save_name) - for v in rule.values(): - f.write(' \n' % self.fix(v)) - f.write(' \n') - f.write(' \n') + for namespace in self.filter_list: + f.write('\n' % "person") + for i in namespace: + f.write(' \n') + for rule in i.get_rules(): + rule_module_name = rule.__module__ + rule_class_name = rule.__class__.__name__ + rule_save_name = "%s.%s" % (rule_module_name,rule_class_name) + f.write(' \n' % rule_save_name) + for v in rule.values(): + f.write(' \n' % self.fix(v)) + f.write(' \n') + f.write(' \n') + f.write('\n') f.write('\n') f.close() @@ -2349,12 +2357,18 @@ class FilterParser(handler.ContentHandler): self.r = None self.a = [] self.cname = None + self.namespace = "person" def setDocumentLocator(self,locator): self.locator = locator def startElement(self,tag,attrs): - if tag == "filter": + if tag == "object": + if attrs.has_key('type'): + self.namespace = attrs['type'] + else: + self.namespace = "generic" + elif tag == "filter": self.f = GenericFilter() self.f.set_name(attrs['name']) if attrs.has_key('function'): @@ -2373,7 +2387,7 @@ class FilterParser(handler.ContentHandler): self.f.set_invert(int(attrs['invert'])) except ValueError: pass - self.gfilter_list.add(self.f) + self.gfilter_list.add(self.namespace,self.f) elif tag == "rule": save_name = attrs['class'] if save_name in old_names_2_class.keys(): @@ -2529,7 +2543,7 @@ class GrampsFilterComboBox(gtk.ComboBox): class FilterStore(gtk.ListStore): - def __init__(self,local_filters=[], default=""): + def __init__(self,local_filters=[], namespace="generic",default=""): gtk.ListStore.__init__(self,str) self.list_map = [] self.def_index = 0 @@ -2543,7 +2557,7 @@ class FilterStore(gtk.ListStore): self.def_index = cnt cnt += 1 - for filt in SystemFilters.get_filters() + CustomFilters.get_filters(): + for filt in SystemFilters.get_filters(namespace) + CustomFilters.get_filters(namespace): name = _(filt.get_name()) self.append(row=[name]) self.list_map.append(filt) @@ -2557,7 +2571,99 @@ class FilterStore(gtk.ListStore): def get_filter(self,index): return self.list_map[index] - +class FilterWidget: + def __init__( self, uistate, on_apply, apply_done = None): + self.on_apply_callback = on_apply + self.apply_done_callback = apply_done + self.uistate = uistate + + def build( self): + self.filterbar = gtk.HBox() + self.filterbar.set_spacing(4) + self.filter_text = gtk.Entry() + self.filter_label = gtk.Label('Label:') + self.filter_list = gtk.ComboBox() + self.filter_invert = gtk.CheckButton('Invert') + self.filter_button = gtk.Button('Apply') + self.filter_button.connect( 'clicked',self.apply_filter_clicked) + self.filterbar.pack_start(self.filter_list,False) + self.filterbar.pack_start(self.filter_label,False) + self.filterbar.pack_start(self.filter_text,True) + self.filterbar.pack_start(self.filter_invert,False) + self.filterbar.pack_end(self.filter_button,False) + + self.filter_text.set_sensitive(False) + + return self.filterbar + + def setup_filter( self, default_filters, namespace="generic"): + cell = gtk.CellRendererText() + self.filter_list.clear() + self.filter_list.pack_start(cell,True) + self.filter_list.add_attribute(cell,'text',0) + + filter_list = [] + + for f in default_filters: + all = GenericFilter() + rule = f[0](f[1]) + print rule + all.set_name( rule.name) + all.add_rule( rule) + filter_list.append(all) + + self.filter_model = FilterStore(filter_list, namespace) + self.filter_list.set_model(self.filter_model) + self.filter_list.set_active(self.filter_model.default_index()) + self.filter_list.connect('changed',self.on_filter_name_changed) + self.filter_text.set_sensitive(False) + self.DataFilter = filter_list[self.filter_model.default_index()] + + def apply_filter_clicked(self,ev=None): + print "apply_filter_clicked" + index = self.filter_list.get_active() + self.DataFilter = self.filter_model.get_filter(index) + if self.DataFilter.need_param: + qual = unicode(self.filter_text.get_text()) + self.DataFilter.set_parameter(qual) + self.apply_filter() + if self.apply_done_callback: + self.apply_done_callback() + + def on_filter_name_changed(self,obj): + print "on_filter_name_changed" + index = self.filter_list.get_active() + mime_filter = self.filter_model.get_filter(index) + qual = mime_filter.need_param + if qual: + self.filter_text.show() + self.filter_text.set_sensitive(True) + self.filter_label.show() + self.filter_label.set_text(mime_filter.get_rules()[0].labels[0]) + else: + self.filter_text.hide() + self.filter_text.set_sensitive(False) + self.filter_label.hide() + + def apply_filter(self,current_model=None): + self.uistate.status_text(_('Updating display...')) + self.on_apply_callback() + self.uistate.modify_statusbar() + + def get_filter( self): + print "get_filter" + print self.DataFilter.flist[0] + return self.DataFilter + + def inverted( self): + return self.filter_invert.get_active() + + def show( self): + self.filterbar.show() + + def hide( self): + self.filterbar.hide() + def build_filter_menu(local_filters = [], default=""): menu = gtk.Menu() diff --git a/src/PageView.py b/src/PageView.py index 698c15b2d..6b648f4f2 100644 --- a/src/PageView.py +++ b/src/PageView.py @@ -22,6 +22,7 @@ import gtk import TreeTips +import GenericFilter NAVIGATION_NONE = -1 NAVIGATION_PERSON = 0 @@ -316,6 +317,13 @@ class ListView(PageView): contains the interface. This containter will be inserted into a gtk.Notebook page. """ + self.vbox = gtk.VBox() + self.vbox.set_border_width(0) + self.vbox.set_spacing(4) + + self.generic_filter_widget = GenericFilter.FilterWidget( self.uistate, self.build_tree) + filter_box = self.generic_filter_widget.build() + self.list = gtk.TreeView() self.list.set_rules_hint(True) self.list.set_headers_visible(True) @@ -328,6 +336,9 @@ class ListView(PageView): scrollwindow.set_shadow_type(gtk.SHADOW_ETCHED_IN) scrollwindow.add(self.list) + self.vbox.pack_start(filter_box,False) + self.vbox.pack_start(scrollwindow,True) + self.renderer = gtk.CellRendererText() self.inactive = False @@ -336,8 +347,22 @@ class ListView(PageView): self.selection = self.list.get_selection() #self.selection.connect('changed',self.row_changed) - return scrollwindow + self.setup_filter() + + return self.vbox + def setup_filter(self): + """ + Builds the default filters and add them to the filter menu. + """ + default_filters = [ + [GenericFilter.Everyone, []], + [GenericFilter.HasTextMatchingSubstringOf, ['',0,0]], + [GenericFilter.HasTextMatchingRegexpOf, ['',0,1]], + [GenericFilter.PeoplePrivate, []], + ] + self.generic_filter_widget.setup_filter( default_filters) + def column_clicked(self,obj,data): if self.sort_col != data: order = gtk.SORT_ASCENDING @@ -419,6 +444,8 @@ class ListView(PageView): self.add_action('Add', gtk.STOCK_ADD, "_Add", callback=self.add) self.add_action('Edit', gtk.STOCK_EDIT, "_Edit", callback=self.edit) self.add_action('Remove',gtk.STOCK_REMOVE,"_Remove",callback=self.remove) + self.add_toggle_action('Filter', None, '_Filter', + callback=self.filter_toggle) def button_press(self,obj,event): if event.type == gtk.gdk._2BUTTON_PRESS and event.button == 1: @@ -440,3 +467,9 @@ class ListView(PageView): def double_click(self,obj,event): return False + + def filter_toggle(self,obj): + if obj.get_active(): + self.generic_filter_widget.show() + else: + self.generic_filter_widget.hide() diff --git a/src/PersonView.py b/src/PersonView.py index 212b82164..69dea5808 100644 --- a/src/PersonView.py +++ b/src/PersonView.py @@ -78,7 +78,7 @@ class PersonView(PageView.PersonNavView): self.handle_col = len(column_names)+2 def change_page(self): - self.on_filter_name_changed(None) + self.generic_filter_widget.on_filter_name_changed(None) def define_actions(self): """ @@ -126,20 +126,9 @@ class PersonView(PageView.PersonNavView): self.vbox.set_border_width(4) self.vbox.set_spacing(4) - self.filterbar = gtk.HBox() - self.filterbar.set_spacing(4) - self.filter_text = gtk.Entry() - self.filter_label = gtk.Label('Label:') - self.filter_list = gtk.ComboBox() - self.filter_invert = gtk.CheckButton('Invert') - self.filter_button = gtk.Button('Apply') - self.filterbar.pack_start(self.filter_list,False) - self.filterbar.pack_start(self.filter_label,False) - self.filterbar.pack_start(self.filter_text,True) - self.filterbar.pack_start(self.filter_invert,False) - self.filterbar.pack_end(self.filter_button,False) - - self.filter_text.set_sensitive(False) + self.generic_filter_widget = GenericFilter.FilterWidget( self.uistate, self.build_tree, self.goto_active_person) + filter_box = self.generic_filter_widget.build() + self.tree = gtk.TreeView() self.tree.set_rules_hint(True) @@ -152,7 +141,7 @@ class PersonView(PageView.PersonNavView): scrollwindow.add(self.tree) scrollwindow.show_all() - self.vbox.pack_start(self.filterbar,False) + self.vbox.pack_start(filter_box,False) self.vbox.pack_start(scrollwindow,True) self.renderer = gtk.CellRendererText() @@ -168,9 +157,9 @@ class PersonView(PageView.PersonNavView): self.selection.set_mode(gtk.SELECTION_MULTIPLE) self.selection.connect('changed',self.row_changed) - self.vbox.set_focus_chain([self.tree, self.filter_list, - self.filter_text, self.filter_invert, - self.filter_button]) + #self.vbox.set_focus_chain([self.tree, self.filter_list, + # self.filter_text, self.filter_invert, + # self.filter_button]) self.setup_filter() return self.vbox @@ -239,7 +228,7 @@ class PersonView(PageView.PersonNavView): db.connect('person-update', self.person_updated) db.connect('person-delete', self.person_removed) db.connect('person-rebuild', self.build_tree) - self.apply_filter() + self.generic_filter_widget.apply_filter() def goto_active_person(self,obj=None): """ @@ -298,135 +287,32 @@ class PersonView(PageView.PersonNavView): """ Builds the default filters and add them to the filter menu. """ - - cell = gtk.CellRendererText() - self.filter_list.clear() - self.filter_list.pack_start(cell,True) - self.filter_list.add_attribute(cell,'text',0) - - filter_list = [] - - self.DataFilter = None - - all = GenericFilter.GenericFilter() - all.set_name(_("Entire Database")) - all.add_rule(GenericFilter.Everyone([])) - - all = GenericFilter.GenericFilter() - all.set_name(_("Entire Database")) - all.add_rule(GenericFilter.Everyone([])) - filter_list.append(all) - - all = GenericFilter.GenericFilter() - all.set_name(_("Females")) - all.add_rule(GenericFilter.IsFemale([])) - filter_list.append(all) - - all = GenericFilter.GenericFilter() - all.set_name(_("Males")) - all.add_rule(GenericFilter.IsMale([])) - filter_list.append(all) - - all = GenericFilter.GenericFilter() - all.set_name(_("People with unknown gender")) - all.add_rule(GenericFilter.HasUnknownGender([])) - filter_list.append(all) - - all = GenericFilter.GenericFilter() - all.set_name(_("Disconnected individuals")) - all.add_rule(GenericFilter.Disconnected([])) - filter_list.append(all) - - all = GenericFilter.ParamFilter() - all.set_name(_("People with names containing...")) - all.add_rule(GenericFilter.SearchName([''])) - filter_list.append(all) - - all = GenericFilter.GenericFilter() - all.set_name(_("Adopted people")) - all.add_rule(GenericFilter.HaveAltFamilies([])) - filter_list.append(all) - - all = GenericFilter.GenericFilter() - all.set_name(_("People with images")) - all.add_rule(GenericFilter.HavePhotos([])) - filter_list.append(all) - - all = GenericFilter.GenericFilter() - all.set_name(_("People with incomplete names")) - all.add_rule(GenericFilter.IncompleteNames([])) - filter_list.append(all) - - all = GenericFilter.GenericFilter() - all.set_name(_("People with children")) - all.add_rule(GenericFilter.HaveChildren([])) - filter_list.append(all) - - all = GenericFilter.GenericFilter() - all.set_name(_("People with no marriage records")) - all.add_rule(GenericFilter.NeverMarried([])) - filter_list.append(all) - - all = GenericFilter.GenericFilter() - all.set_name(_("People with multiple marriage records")) - all.add_rule(GenericFilter.MultipleMarriages([])) - filter_list.append(all) - - all = GenericFilter.GenericFilter() - all.set_name(_("People without a known birth date")) - all.add_rule(GenericFilter.NoBirthdate([])) - filter_list.append(all) - - all = GenericFilter.GenericFilter() - all.set_name(_("People with incomplete events")) - all.add_rule(GenericFilter.PersonWithIncompleteEvent([])) - filter_list.append(all) - - all = GenericFilter.GenericFilter() - all.set_name(_("Families with incomplete events")) - all.add_rule(GenericFilter.FamilyWithIncompleteEvent([])) - filter_list.append(all) - - all = GenericFilter.ParamFilter() - all.set_name(_("People probably alive")) - all.add_rule(GenericFilter.ProbablyAlive([''])) - filter_list.append(all) - - all = GenericFilter.GenericFilter() - all.set_name(_("People marked private")) - all.add_rule(GenericFilter.PeoplePrivate([])) - filter_list.append(all) - - all = GenericFilter.GenericFilter() - all.set_name(_("Witnesses")) - all.add_rule(GenericFilter.IsWitness(['',''])) - filter_list.append(all) - - all = GenericFilter.ParamFilter() - all.set_name(_("People with records containing...")) - all.add_rule(GenericFilter.HasTextMatchingSubstringOf(['',0,0])) - filter_list.append(all) - - all = GenericFilter.ParamFilter() - all.set_name(_("People with records matching regular expression...")) - all.add_rule(GenericFilter.HasTextMatchingRegexpOf(['',0,1])) - filter_list.append(all) - - all = GenericFilter.GenericFilter() - all.set_name(_("People with notes")) - all.add_rule(GenericFilter.HasNote([])) - filter_list.append(all) - - all = GenericFilter.ParamFilter() - all.set_name(_("People with notes containing...")) - all.add_rule(GenericFilter.HasNoteMatchingSubstringOf([''])) - filter_list.append(all) - - self.filter_model = GenericFilter.FilterStore(filter_list) - self.filter_list.set_model(self.filter_model) - self.filter_list.set_active(self.filter_model.default_index()) - self.filter_list.connect('changed',self.on_filter_name_changed) - self.filter_text.set_sensitive(False) + default_filters = [ + [GenericFilter.Everyone, []], + [GenericFilter.IsFemale, []], + [GenericFilter.IsMale, []], + [GenericFilter.HasUnknownGender, []], + [GenericFilter.Disconnected, []], + [GenericFilter.SearchName, ['']], + [GenericFilter.HaveAltFamilies, []], + [GenericFilter.HavePhotos, []], + [GenericFilter.IncompleteNames, []], + [GenericFilter.HaveChildren, []], + [GenericFilter.NeverMarried, []], + [GenericFilter.MultipleMarriages, []], + [GenericFilter.NoBirthdate, []], + [GenericFilter.PersonWithIncompleteEvent, []], + [GenericFilter.FamilyWithIncompleteEvent, []], + [GenericFilter.ProbablyAlive, ['']], + [GenericFilter.PeoplePrivate, []], + [GenericFilter.IsWitness, ['','']], + [GenericFilter.HasTextMatchingSubstringOf, ['',0,0]], + [GenericFilter.HasTextMatchingRegexpOf, ['',0,1]], + [GenericFilter.HasNote, []], + [GenericFilter.HasNoteMatchingSubstringOf, ['']], + [GenericFilter.IsFemale, []], + ] + self.generic_filter_widget.setup_filter( default_filters, "person") def build_tree(self): """ @@ -434,7 +320,7 @@ class PersonView(PageView.PersonNavView): rebuild of the data. """ self.model = PeopleModel.PeopleModel( - self.dbstate.db, self.DataFilter, self.filter_invert.get_active()) + self.dbstate.db, self.generic_filter_widget.get_filter(), self.generic_filter_widget.inverted()) self.tree.set_model(self.model) if self.model.tooltip_column != None: @@ -444,9 +330,9 @@ class PersonView(PageView.PersonNavView): def filter_toggle(self,obj): if obj.get_active(): - self.filterbar.show() + self.generic_filter_widget.show() else: - self.filterbar.hide() + self.generic_filter_widget.hide() def add(self,obj): person = RelLib.Person() @@ -592,15 +478,6 @@ class PersonView(PageView.PersonNavView): sel_data.set(DdTargets.PERSON_LINK_LIST.drag_type,8, pickle.dumps(selected_ids)) - def apply_filter_clicked(self): - index = self.filter_list.get_active() - self.DataFilter = self.filter_model.get_filter(index) - if self.DataFilter.need_param: - qual = unicode(self.filter_text.get_text()) - self.DataFilter.set_parameter(qual) - self.apply_filter() - self.goto_active_person() - def person_added(self,handle_list): for node in handle_list: person = self.dbstate.db.get_person_from_handle(node) @@ -697,24 +574,6 @@ class PersonView(PageView.PersonNavView): self.goto_active_person() - def on_filter_name_changed(self,obj): - index = self.filter_list.get_active() - mime_filter = self.filter_model.get_filter(index) - qual = mime_filter.need_param - if qual: - self.filter_text.show() - self.filter_text.set_sensitive(True) - self.filter_label.show() - self.filter_label.set_text(mime_filter.get_rules()[0].labels[0]) - else: - self.filter_text.hide() - self.filter_text.set_sensitive(False) - self.filter_label.hide() - - def apply_filter(self,current_model=None): - self.uistate.status_text(_('Updating display...')) - self.build_tree() - self.uistate.modify_statusbar() def get_selected_objects(self): (mode,paths) = self.selection.get_selected_rows() diff --git a/src/PlaceView.py b/src/PlaceView.py index 5ed9509d6..57a973a10 100644 --- a/src/PlaceView.py +++ b/src/PlaceView.py @@ -90,6 +90,9 @@ class PlaceView(PageView.ListView): def ui_definition(self): return ''' + + + diff --git a/src/RepositoryView.py b/src/RepositoryView.py index 7d67b3c9f..44a4eec1f 100644 --- a/src/RepositoryView.py +++ b/src/RepositoryView.py @@ -93,6 +93,9 @@ class RepositoryView(PageView.ListView): def ui_definition(self): return ''' + + + diff --git a/src/SourceView.py b/src/SourceView.py index 91029969d..64065ef1c 100644 --- a/src/SourceView.py +++ b/src/SourceView.py @@ -85,6 +85,9 @@ class SourceView(PageView.ListView): def ui_definition(self): return ''' + + +