* 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:
		| @@ -494,6 +494,7 @@ class HasNameOf(Rule): | ||||
|                 return 1 | ||||
|         return 0 | ||||
|  | ||||
|      | ||||
| class MatchesFilter(Rule): | ||||
|     """Rule that checks against another filter""" | ||||
|  | ||||
| @@ -505,10 +506,10 @@ class MatchesFilter(Rule): | ||||
|     def apply(self, p): | ||||
|         for filter in SystemFilters.get_filters(): | ||||
|             if filter.get_name() == self.list[0]: | ||||
|                 return len(filter.apply([p])) > 0 | ||||
|                 return filter.check(p) | ||||
|         for filter in CustomFilters.get_filters(): | ||||
|             if filter.get_name() == self.list[0]: | ||||
|                 return len(filter.apply([p])) > 0 | ||||
|                 return filter.check(p) | ||||
|         return 0 | ||||
|      | ||||
| #------------------------------------------------------------------------- | ||||
| @@ -524,18 +525,35 @@ class GenericFilter: | ||||
|             self.flist = source.flist[:] | ||||
|             self.name = source.name | ||||
|             self.comment = source.comment | ||||
|             self.logical_or = source.logical_or | ||||
|             self.logical_op = source.logical_op | ||||
|             self.invert = source.invert | ||||
|         else: | ||||
|             self.flist = [] | ||||
|             self.name = '' | ||||
|             self.comment = '' | ||||
|             self.logical_or = 0 | ||||
|             self.logical_op = 'and' | ||||
|             self.invert = 0 | ||||
|  | ||||
|     def set_logical_or(self,val): | ||||
|         self.logical_or = val | ||||
|         self.logical_op = 'or' | ||||
|  | ||||
|     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): | ||||
|         return self.name | ||||
| @@ -557,23 +575,66 @@ class GenericFilter: | ||||
|  | ||||
|     def get_rules(self): | ||||
|         return self.flist | ||||
|      | ||||
|     def apply(self,list): | ||||
|         result = [] | ||||
|         if self.logical_or: | ||||
|             for p in list: | ||||
|                 for rule in self.flist: | ||||
|                     if rule.apply(p): | ||||
|                         result.append(p) | ||||
|                         break | ||||
|  | ||||
|     def check_or(self,p): | ||||
|         test = 0 | ||||
|         for rule in self.flist: | ||||
|             test = test or rule.apply(p) | ||||
|             if test: | ||||
|                 break | ||||
|         if self.invert: | ||||
|             return not test | ||||
|         else: | ||||
|             for p in list: | ||||
|                 for rule in self.flist: | ||||
|                     if rule.apply(p) == 0: | ||||
|                         break | ||||
|                 else: | ||||
|                     result.append(p) | ||||
|         return result | ||||
|             return test | ||||
|  | ||||
|     def check_xor(self,p): | ||||
|         test = 0 | ||||
|         for rule in self.flist: | ||||
|             temp = rule.apply(p) | ||||
|             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') | ||||
|         for i in self.filter_list: | ||||
|             f.write('  <filter name="%s"' % self.fix(i.get_name())) | ||||
|             if i.get_logical_or(): | ||||
|                 f.write(' function="1"') | ||||
|             if i.get_invert(): | ||||
|                 f.write(' invert="1"') | ||||
|             f.write(' function="%s"' % i.get_logical_op()) | ||||
|             comment = i.get_comment() | ||||
|             if comment: | ||||
|                 f.write(' comment="%s"' % self.fix(comment)) | ||||
| @@ -681,9 +743,21 @@ class FilterParser(handler.ContentHandler): | ||||
|             self.f = GenericFilter() | ||||
|             self.f.set_name(attrs['name']) | ||||
|             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'): | ||||
|                 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) | ||||
|         elif tag == "rule": | ||||
|             name = attrs['class'] | ||||
| @@ -706,11 +780,13 @@ CustomFilters = None | ||||
| def reload_system_filters(): | ||||
|     global SystemFilters | ||||
|     SystemFilters = GenericFilterList(const.system_filters) | ||||
|  | ||||
|     SystemFilters.load() | ||||
|      | ||||
| def reload_custom_filters(): | ||||
|     global CustomFilters | ||||
|     CustomFilters = GenericFilterList(const.custom_filters) | ||||
|  | ||||
|     CustomFilters.load() | ||||
|      | ||||
| if not SystemFilters: | ||||
|     reload_system_filters() | ||||
|  | ||||
|   | ||||
| @@ -869,3 +869,5 @@ NameTypesMap = { | ||||
|     _("Married Name")  : "Married 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.rule_list = self.glade.get_widget('rule_list') | ||||
|         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.ok = self.glade.get_widget('ok') | ||||
|         self.edit_btn = self.glade.get_widget('edit') | ||||
| @@ -144,7 +147,14 @@ class FilterEditor: | ||||
|             'on_edit_clicked' : self.on_edit_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(): | ||||
|             self.fname.set_text(self.filter.get_name()) | ||||
|         self.comment.set_text(self.filter.get_comment()) | ||||
| @@ -184,7 +194,14 @@ class FilterEditor: | ||||
|             if n == f.get_name(): | ||||
|                 self.filterdb.get_filters().remove(f) | ||||
|                 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.draw_filters() | ||||
|         self.top.destroy() | ||||
|   | ||||
| @@ -123,7 +123,7 @@ | ||||
|       <widget> | ||||
| 	<class>GtkTable</class> | ||||
| 	<name>table1</name> | ||||
| 	<rows>4</rows> | ||||
| 	<rows>6</rows> | ||||
| 	<columns>2</columns> | ||||
| 	<homogeneous>False</homogeneous> | ||||
| 	<row_spacing>0</row_spacing> | ||||
| @@ -241,17 +241,17 @@ | ||||
|  | ||||
| 	<widget> | ||||
| 	  <class>GtkRadioButton</class> | ||||
| 	  <name>logical_and</name> | ||||
| 	  <name>logical_one</name> | ||||
| 	  <can_focus>True</can_focus> | ||||
| 	  <label>All rules must apply</label> | ||||
| 	  <active>True</active> | ||||
| 	  <label>Exactly one rule must apply</label> | ||||
| 	  <active>False</active> | ||||
| 	  <draw_indicator>True</draw_indicator> | ||||
| 	  <group>logic</group> | ||||
| 	  <child> | ||||
| 	    <left_attach>1</left_attach> | ||||
| 	    <right_attach>2</right_attach> | ||||
| 	    <top_attach>2</top_attach> | ||||
| 	    <bottom_attach>3</bottom_attach> | ||||
| 	    <top_attach>5</top_attach> | ||||
| 	    <bottom_attach>6</bottom_attach> | ||||
| 	    <xpad>0</xpad> | ||||
| 	    <ypad>0</ypad> | ||||
| 	    <xexpand>False</xexpand> | ||||
| @@ -271,6 +271,30 @@ | ||||
| 	  <active>False</active> | ||||
| 	  <draw_indicator>True</draw_indicator> | ||||
| 	  <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> | ||||
| 	    <left_attach>1</left_attach> | ||||
| 	    <right_attach>2</right_attach> | ||||
| @@ -286,6 +310,29 @@ | ||||
| 	    <yfill>False</yfill> | ||||
| 	  </child> | ||||
| 	</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> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user