* 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:
parent
2ce94ad6fb
commit
69eb80544f
@ -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()
|
||||||
|
@ -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']
|
||||||
|
@ -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()
|
||||||
|
@ -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>
|
||||||
|
Loading…
Reference in New Issue
Block a user