Package tkintertable :: Module Filtering
[hide private]
[frames] | no frames]

Source Code for Module tkintertable.Filtering

  1  #!/usr/bin/env python 
  2  """ 
  3      Module implements Table filtering and searching functionality. 
  4      Created Oct 2008 
  5      Copyright (C) Damien Farrell 
  6   
  7      This program is free software; you can redistribute it and/or 
  8      modify it under the terms of the GNU General Public License 
  9      as published by the Free Software Foundation; either version 2 
 10      of the License, or (at your option) any later version. 
 11   
 12      This program is distributed in the hope that it will be useful, 
 13      but WITHOUT ANY WARRANTY; without even the implied warranty of 
 14      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 15      GNU General Public License for more details. 
 16   
 17      You should have received a copy of the GNU General Public License 
 18      along with this program; if not, write to the Free Software 
 19      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
 20  """ 
 21   
 22  from Tkinter import * 
 23  import Pmw 
 24  from types import * 
 25  import re 
 26   
27 -def contains(v1,v2):
28 if v1 in v2: 29 return True
30
31 -def excludes(v1, v2):
32 if not v1 in v2: 33 return True
34
35 -def equals(v1,v2):
36 if v1==v2: 37 return True
38
39 -def notequals(v1,v2):
40 if v1!=v2: 41 return True
42
43 -def greaterthan(v1,v2):
44 if v2>v1: 45 return True 46 return False
47
48 -def lessthan(v1,v2):
49 if v2<v1: 50 return True 51 return False
52
53 -def startswith(v1,v2):
54 if v2.startswith(v1): 55 return True
56
57 -def endswith(v1,v2):
58 if v2.endswith(v1): 59 return True
60
61 -def haslength(v1,v2):
62 if len(v2)>v1: 63 return True
64
65 -def isnumber(v1,v2):
66 try: 67 float(v2) 68 return True 69 except: 70 return False
71
72 -def regex(v1,v2):
73 """Apply a regular expression""" 74 print re.findall(v1,v2) 75 return
76 77 operatornames = {'=':equals,'!=':notequals, 78 'contains':contains,'excludes':excludes, 79 '>':greaterthan,'<':lessthan, 80 'starts with':startswith, 81 'ends with':endswith, 82 'has length':haslength, 83 'is number':isnumber} 84
85 -def doFiltering(searchfunc, filters=None):
86 """Module level method. Filter recs by several filters using a user provided 87 search function. 88 filters is a list of tuples of the form (key,value,operator,bool) 89 returns: found record keys""" 90 91 if filters == None: 92 return 93 F = filters 94 sets = [] 95 for f in F: 96 col, val, op, boolean = f 97 names = searchfunc(col, val, op) 98 sets.append((set(names), boolean)) 99 names = sets[0][0] 100 for s in sets[1:]: 101 b=s[1] 102 if b == 'AND': 103 names = names & s[0] 104 elif b == 'OR': 105 names = names | s[0] 106 elif b == 'NOT': 107 names = names - s[0] 108 #print len(names) 109 names = list(names) 110 return names
111
112 -class FilterFrame(Frame):
113
114 - def __init__(self, parent, fields, callback=None, closecallback=None):
115 """Create a filtering gui frame. 116 Callback must be some method that can accept tuples of filter 117 parameters connected by boolean operators """ 118 Frame.__init__(self, parent) 119 self.parent = parent 120 self.callback = callback 121 self.closecallback = closecallback 122 self.fields = fields 123 self.filters = [] 124 self.addFilterBar() 125 addbutton=Button(self,text='Go', command=self.callback,bg='lightblue') 126 addbutton.grid(row=0,column=0,sticky='news',padx=2,pady=2) 127 addbutton=Button(self,text='+Add Filter', command=self.addFilterBar) 128 addbutton.grid(row=0,column=1,sticky='news',padx=2,pady=2) 129 cbutton=Button(self,text='Close', command=self.close) 130 cbutton.grid(row=0,column=2,sticky='news',padx=2,pady=2) 131 self.resultsvar=IntVar() 132 Label(self,text='found:').grid(row=0,column=3,sticky='nes') 133 Label(self,textvariable=self.resultsvar).grid(row=0,column=4,sticky='nws',padx=2,pady=2) 134 return
135
136 - def addFilterBar(self):
137 """Add filter""" 138 index = len(self.filters) 139 f = FilterBar(self, index, self.fields) 140 self.filters.append(f) 141 f.grid(row=index+1,column=0,columnspan=5,sticky='news',padx=2,pady=2) 142 return
143
144 - def close(self):
145 """Close frame and do stuff in parent app if needed""" 146 self.closecallback() 147 self.destroy() 148 return
149
150 - def doFiltering(self, searchfunc):
151 F=[] 152 for f in self.filters: 153 F.append(f.getFilter()) 154 names = doFiltering(searchfunc, F) 155 self.updateResults(len(names)) 156 return names
157
158 - def updateResults(self, i):
159 self.resultsvar.set(i) 160 return
161
162 -class FilterBar(Frame):
163 """Class providing filter widgets""" 164 operators = ['contains','excludes','=','!=','>','<','starts with', 165 'ends with','has length','is number'] 166 booleanops = ['AND','OR','NOT']
167 - def __init__(self, parent, index, fields):
168 Frame.__init__(self, parent) 169 self.parent=parent 170 self.index = index 171 self.filtercol=StringVar() 172 initial = fields[0] 173 filtercolmenu = Pmw.OptionMenu(self, 174 labelpos = 'w', 175 label_text = 'Column:', 176 menubutton_textvariable = self.filtercol, 177 items = fields, 178 initialitem = initial, 179 menubutton_width = 10) 180 filtercolmenu.grid(row=0,column=1,sticky='news',padx=2,pady=2) 181 self.operator=StringVar() 182 operatormenu = Pmw.OptionMenu(self, 183 menubutton_textvariable = self.operator, 184 items = self.operators, 185 initialitem = 'contains', 186 menubutton_width = 8) 187 operatormenu.grid(row=0,column=2,sticky='news',padx=2,pady=2) 188 self.filtercolvalue=StringVar() 189 valsbox=Entry(self,textvariable=self.filtercolvalue,width=20,bg='white') 190 valsbox.grid(row=0,column=3,sticky='news',padx=2,pady=2) 191 valsbox.bind("<Return>", self.parent.callback) 192 self.booleanop=StringVar() 193 booleanopmenu = Pmw.OptionMenu(self, 194 menubutton_textvariable = self.booleanop, 195 items = self.booleanops, 196 initialitem = 'AND', 197 menubutton_width = 6) 198 booleanopmenu.grid(row=0,column=0,sticky='news',padx=2,pady=2) 199 #disable the boolean operator if it's the first filter 200 if self.index == 0: 201 booleanopmenu.component('menubutton').configure(state=DISABLED) 202 cbutton=Button(self,text='-', command=self.close) 203 cbutton.grid(row=0,column=5,sticky='news',padx=2,pady=2) 204 return
205
206 - def close(self):
207 """Destroy and remove from parent""" 208 self.parent.filters.remove(self) 209 self.destroy() 210 return
211
212 - def getFilter(self):
213 """Get filter values for this instance""" 214 col = self.filtercol.get() 215 val = self.filtercolvalue.get() 216 op = self.operator.get() 217 booleanop = self.booleanop.get() 218 return col, val, op, booleanop
219