* Fixes bug with reloading filters after they get edited.

* Adds logical operations XOR and 'Exactly one rule must match'
* XOR has no GUI yet, pending 'basic/advanced' preference
* Ability to invert the sense of the filter.
* What should be speed improvements by passing bound methods to the
  builtin filter function
* Changes to the XML input/output to support new functonality
* Changes to UI to support new functionality


svn: r919
This commit is contained in:
Jeffrey C. Ollie 2002-04-13 03:53:20 +00:00
parent 2ce94ad6fb
commit 69eb80544f
4 changed files with 178 additions and 36 deletions

View File

@ -494,6 +494,7 @@ class HasNameOf(Rule):
return 1 return 1
return 0 return 0
class MatchesFilter(Rule): class MatchesFilter(Rule):
"""Rule that checks against another filter""" """Rule that checks against another filter"""
@ -505,10 +506,10 @@ class MatchesFilter(Rule):
def apply(self, p): def apply(self, p):
for filter in SystemFilters.get_filters(): for filter in SystemFilters.get_filters():
if filter.get_name() == self.list[0]: if filter.get_name() == self.list[0]:
return len(filter.apply([p])) > 0 return filter.check(p)
for filter in CustomFilters.get_filters(): for filter in CustomFilters.get_filters():
if filter.get_name() == self.list[0]: if filter.get_name() == self.list[0]:
return len(filter.apply([p])) > 0 return filter.check(p)
return 0 return 0
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
@ -524,18 +525,35 @@ class GenericFilter:
self.flist = source.flist[:] self.flist = source.flist[:]
self.name = source.name self.name = source.name
self.comment = source.comment self.comment = source.comment
self.logical_or = source.logical_or self.logical_op = source.logical_op
self.invert = source.invert
else: else:
self.flist = [] self.flist = []
self.name = '' self.name = ''
self.comment = '' self.comment = ''
self.logical_or = 0 self.logical_op = 'and'
self.invert = 0
def set_logical_or(self,val): def set_logical_or(self,val):
self.logical_or = val self.logical_op = 'or'
def get_logical_or(self): def get_logical_or(self):
return self.logical_or return self.logical_op == 'or'
def set_logical_op(self,val):
if val in const.logical_functions:
self.logical_op = val
else:
self.logical_op = 'and'
def get_logical_op(self):
return self.logical_op
def set_invert(self, val):
self.invert = not not val
def get_invert(self):
return self.invert
def get_name(self): def get_name(self):
return self.name return self.name
@ -558,22 +576,65 @@ class GenericFilter:
def get_rules(self): def get_rules(self):
return self.flist return self.flist
def apply(self,list): def check_or(self,p):
result = [] test = 0
if self.logical_or: for rule in self.flist:
for p in list: test = test or rule.apply(p)
for rule in self.flist: if test:
if rule.apply(p): break
result.append(p) if self.invert:
break return not test
else: else:
for p in list: return test
for rule in self.flist:
if rule.apply(p) == 0: def check_xor(self,p):
break test = 0
else: for rule in self.flist:
result.append(p) temp = rule.apply(p)
return result test = ((not test) and temp) or (test and (not temp))
if self.invert:
return not test
else:
return test
def check_one(self,p):
count = 0
for rule in self.flist:
if rule.apply(p):
count = count + 1
if count > 1:
break
if self.invert:
return count != 1
else:
return count == 1
def check_and(self,p):
test = 1
for rule in self.flist:
test = test and rule.apply(p)
if not test:
break
if self.invert:
return not test
else:
return test
def check(self,p):
try:
m = getattr(self, 'check_' + self.logical_op)
except AttributeError:
m = self.check_and
return m(p)
def apply(self,list):
try:
m = getattr(self, 'check_' + self.logical_op)
except AttributeError:
m = self.check_and
return filter(m, list)
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# #
@ -642,8 +703,9 @@ class GenericFilterList:
f.write('<filters>\n') f.write('<filters>\n')
for i in self.filter_list: for i in self.filter_list:
f.write(' <filter name="%s"' % self.fix(i.get_name())) f.write(' <filter name="%s"' % self.fix(i.get_name()))
if i.get_logical_or(): if i.get_invert():
f.write(' function="1"') f.write(' invert="1"')
f.write(' function="%s"' % i.get_logical_op())
comment = i.get_comment() comment = i.get_comment()
if comment: if comment:
f.write(' comment="%s"' % self.fix(comment)) f.write(' comment="%s"' % self.fix(comment))
@ -681,9 +743,21 @@ class FilterParser(handler.ContentHandler):
self.f = GenericFilter() self.f = GenericFilter()
self.f.set_name(attrs['name']) self.f.set_name(attrs['name'])
if attrs.has_key('function'): if attrs.has_key('function'):
self.f.set_logical_or(int(attrs['function'])) try:
if int(attrs['function']):
op = 'or'
else:
op = 'and'
except ValueError:
op = attrs['function']
self.f.set_logical_op(op)
if attrs.has_key('comment'): if attrs.has_key('comment'):
self.f.set_comment(attrs['comment']) self.f.set_comment(attrs['comment'])
if attrs.has_key('invert'):
try:
self.f.set_invert(int(attrs['invert']))
except ValueError:
pass
self.gfilter_list.add(self.f) self.gfilter_list.add(self.f)
elif tag == "rule": elif tag == "rule":
name = attrs['class'] name = attrs['class']
@ -706,10 +780,12 @@ CustomFilters = None
def reload_system_filters(): def reload_system_filters():
global SystemFilters global SystemFilters
SystemFilters = GenericFilterList(const.system_filters) SystemFilters = GenericFilterList(const.system_filters)
SystemFilters.load()
def reload_custom_filters(): def reload_custom_filters():
global CustomFilters global CustomFilters
CustomFilters = GenericFilterList(const.custom_filters) CustomFilters = GenericFilterList(const.custom_filters)
CustomFilters.load()
if not SystemFilters: if not SystemFilters:
reload_system_filters() reload_system_filters()

View File

@ -869,3 +869,5 @@ NameTypesMap = {
_("Married Name") : "Married Name", _("Married Name") : "Married Name",
_("Other Name") : "Other Name", _("Other Name") : "Other Name",
} }
logical_functions = ['or', 'and', 'xor', 'one']

View File

@ -128,7 +128,10 @@ class FilterEditor:
self.top = self.glade.get_widget('define_filter') self.top = self.glade.get_widget('define_filter')
self.rule_list = self.glade.get_widget('rule_list') self.rule_list = self.glade.get_widget('rule_list')
self.fname = self.glade.get_widget('filter_name') self.fname = self.glade.get_widget('filter_name')
self.logor = self.glade.get_widget('logical_or') self.log_not = self.glade.get_widget('logical_not')
self.log_and = self.glade.get_widget('logical_and')
self.log_or = self.glade.get_widget('logical_or')
self.log_one = self.glade.get_widget('logical_one')
self.comment = self.glade.get_widget('comment') self.comment = self.glade.get_widget('comment')
self.ok = self.glade.get_widget('ok') self.ok = self.glade.get_widget('ok')
self.edit_btn = self.glade.get_widget('edit') self.edit_btn = self.glade.get_widget('edit')
@ -144,7 +147,14 @@ class FilterEditor:
'on_edit_clicked' : self.on_edit_clicked, 'on_edit_clicked' : self.on_edit_clicked,
'on_cancel_clicked' : self.on_cancel_clicked, 'on_cancel_clicked' : self.on_cancel_clicked,
}) })
self.logor.set_active(self.filter.get_logical_or()) if self.filter.get_invert():
self.log_not.set_active(1)
if self.filter.get_logical_op() == 'or':
self.log_or.set_active(1)
elif self.filter.get_logical_op() == 'one':
self.log_one.set_active(1)
else:
self.log_and.set_active(1)
if self.filter.get_name(): if self.filter.get_name():
self.fname.set_text(self.filter.get_name()) self.fname.set_text(self.filter.get_name())
self.comment.set_text(self.filter.get_comment()) self.comment.set_text(self.filter.get_comment())
@ -184,7 +194,14 @@ class FilterEditor:
if n == f.get_name(): if n == f.get_name():
self.filterdb.get_filters().remove(f) self.filterdb.get_filters().remove(f)
break break
self.filter.set_logical_or(self.logor.get_active()) self.filter.set_invert(self.log_not.get_active())
if self.log_or.get_active():
op = 'or'
elif self.log_one.get_active():
op = 'one'
else:
op = 'and'
self.filter.set_logical_op(op)
self.filterdb.add(self.filter) self.filterdb.add(self.filter)
self.draw_filters() self.draw_filters()
self.top.destroy() self.top.destroy()

View File

@ -123,7 +123,7 @@
<widget> <widget>
<class>GtkTable</class> <class>GtkTable</class>
<name>table1</name> <name>table1</name>
<rows>4</rows> <rows>6</rows>
<columns>2</columns> <columns>2</columns>
<homogeneous>False</homogeneous> <homogeneous>False</homogeneous>
<row_spacing>0</row_spacing> <row_spacing>0</row_spacing>
@ -241,17 +241,17 @@
<widget> <widget>
<class>GtkRadioButton</class> <class>GtkRadioButton</class>
<name>logical_and</name> <name>logical_one</name>
<can_focus>True</can_focus> <can_focus>True</can_focus>
<label>All rules must apply</label> <label>Exactly one rule must apply</label>
<active>True</active> <active>False</active>
<draw_indicator>True</draw_indicator> <draw_indicator>True</draw_indicator>
<group>logic</group> <group>logic</group>
<child> <child>
<left_attach>1</left_attach> <left_attach>1</left_attach>
<right_attach>2</right_attach> <right_attach>2</right_attach>
<top_attach>2</top_attach> <top_attach>5</top_attach>
<bottom_attach>3</bottom_attach> <bottom_attach>6</bottom_attach>
<xpad>0</xpad> <xpad>0</xpad>
<ypad>0</ypad> <ypad>0</ypad>
<xexpand>False</xexpand> <xexpand>False</xexpand>
@ -271,6 +271,30 @@
<active>False</active> <active>False</active>
<draw_indicator>True</draw_indicator> <draw_indicator>True</draw_indicator>
<group>logic</group> <group>logic</group>
<child>
<left_attach>1</left_attach>
<right_attach>2</right_attach>
<top_attach>4</top_attach>
<bottom_attach>5</bottom_attach>
<xpad>0</xpad>
<ypad>0</ypad>
<xexpand>False</xexpand>
<yexpand>False</yexpand>
<xshrink>False</xshrink>
<yshrink>False</yshrink>
<xfill>True</xfill>
<yfill>False</yfill>
</child>
</widget>
<widget>
<class>GtkRadioButton</class>
<name>logical_and</name>
<can_focus>True</can_focus>
<label>All rules must apply</label>
<active>True</active>
<draw_indicator>True</draw_indicator>
<group>logic</group>
<child> <child>
<left_attach>1</left_attach> <left_attach>1</left_attach>
<right_attach>2</right_attach> <right_attach>2</right_attach>
@ -286,6 +310,29 @@
<yfill>False</yfill> <yfill>False</yfill>
</child> </child>
</widget> </widget>
<widget>
<class>GtkCheckButton</class>
<name>logical_not</name>
<can_focus>True</can_focus>
<label>Invert</label>
<active>False</active>
<draw_indicator>True</draw_indicator>
<child>
<left_attach>1</left_attach>
<right_attach>2</right_attach>
<top_attach>2</top_attach>
<bottom_attach>3</bottom_attach>
<xpad>0</xpad>
<ypad>0</ypad>
<xexpand>False</xexpand>
<yexpand>False</yexpand>
<xshrink>False</xshrink>
<yshrink>False</yshrink>
<xfill>True</xfill>
<yfill>False</yfill>
</child>
</widget>
</widget> </widget>
<widget> <widget>