001:
002:
003:
004:
005:
006:
007:
008:
009: reloadable=True
010: reloadables=[]
011:
012:
013:
014: import itertools
015: import gtk
016:
017:
018:
019: def canonical(s):
020: return s.lower().expandtabs(1)
021:
022:
023:
024: class FiltTable(gtk.ListStore):
025:
026:
027:
028:
029: def __init__(self,rows=[],ncols=None,wcols=None,xcols=[]):
030: if ncols==None and wcols==None:
031: ncols=1
032: wcols=[False]
033: elif ncols==None:
034: assert isinstance(wcols,list)
035: ncols=len(wcols)
036: elif wcols==None:
037: assert isinstance(ncols,int) and ncols>=1
038: wcols=[False]*ncols
039: else:
040: assert isinstance(ncols,int) and ncols>=1
041: assert isinstance(wcols,list) and len(wcols)==ncols
042: assert isinstance(xcols,list)
043: columns=(str,)*ncols+tuple([t for (n,t) in xcols])
044: gtk.ListStore.__init__(self,*columns)
045: self.ncols=ncols
046: self.wcols=wcols
047: self.xcolnil=tuple([n for (n,t) in xcols])
048: if rows:
049: assert isinstance(rows[0],tuple)
050: mcols=len(rows[0])
051: assert mcols==ncols+len(xcols)
052: else:
053: mcols=ncols+len(xcols)
054: self.clear()
055:
056: presorted=zip(itertools.count(),rows)
057: for s in presorted:
058: assert isinstance(s[1],tuple) and len(s[1])==mcols
059: self.append(s[1])
060: self.history=[(
061: "",
062: 0,
063: self.filtered_nil()+[
064: ((0,),(0,s[1][0]<>""),[],s,True,canonical(s[1][0]))
065: for s in presorted
066: ],
067: )]
068:
069:
070:
071:
072:
073:
074:
075:
076:
077:
078:
079:
080:
081:
082:
083: def filtered_nil(self):
084: return []
085:
086: def filter_next_column(self,char):
087: assert isinstance(char,str) and len(char)==1
088: (prev_filter,prev_column,prev_filtered)=self.history[-1]
089: (new_filter,new_column)=(prev_filter+char,prev_column+1)
090: if new_column<self.ncols:
091: new_filtered=[
092: (
093: c,(0,s[1][new_column]<>""),[x]+xs,
094: s,q and not x[1],canonical(s[1][new_column])
095: )
096: for (c,x,xs,s,q,y) in prev_filtered
097: ]
098: else:
099: self.clear()
100: new_filtered=self.filtered_nil()
101: self.history.append((new_filter,new_column,new_filtered))
102:
103: def filter_append(self,char):
104: assert isinstance(char,str) and len(char)==1
105: self.clear()
106: (prev_filter,column,prev_filtered)=self.history[-1]
107: (new_filter,new_filtered)=(prev_filter+char,self.filtered_nil())
108: for (c,x,xs,s,q,y) in prev_filtered:
109: i=y.find(char)+1
110: if i:
111: self.append(s[1])
112: new_y=y[i:]
113: if self.wcols[column]:
114: quality=(len(new_y)-new_y.rfind(char),new_y<>"",)
115: else:
116: quality=(x[0]+i,new_y<>"",)
117: new_filtered.append((c,quality,xs,s,q and i==1,new_y))
118: self.history.append((new_filter,column,new_filtered))
119:
120: def filter_comprehend(self,comp,inpt=None):
121: comp=canonical(comp)
122: (xfilter,xcolumn,xfiltered)=self.history[-1]
123: displayedfilter=xfilter
124: while not comp.startswith(xfilter):
125: self.history.pop()
126: (xfilter,xcolumn,xfiltered)=self.history[-1]
127: for char in comp[len(xfilter):]:
128:
129: if char in ".:;,":
130: self.filter_next_column(char)
131: (xfilter,xcolumn,xfiltered)=self.history[-1]
132: else:
133: self.filter_append(char)
134: (xfilter,xcolumn,xfiltered)=self.history[-1]
135: displayedfilter=xfilter
136: if displayedfilter<>xfilter:
137:
138: gtk.ListStore.clear(self)
139: for (c,x,xs,s,q,y) in xfiltered:
140: self.append(s[1])
141: if inpt<>None:
142: for i in range(len(self.history)-1,0,-1):
143: (xfilter,xcolumn,xfiltered)=self.history[i]
144: if len(xfilter)<=inpt:
145: break
146: return xcolumn
147:
148: def filter_nonempty(self):
149: return len(self.history[-1][2])
150:
151: def filtered_size(self):
152: return len(self.history[-1][2])
153:
154: def exact_fit(self,upto=0):
155: (xfilter,xcolumn,xfiltered)=self.history[-1]
156: mustbeblank=range(xcolumn+1,upto)
157: for (i,(c,x,xs,s,q,y)) in enumerate(xfiltered):
158: if q and not x[1]:
159: for b in mustbeblank:
160: if s[1][b]: break
161: else:
162: return (i,)
163:
164: def best_fit(self):
165: (xfilter,xcolumn,xfiltered)=self.history[-1]
166: xref=zip(xfiltered,itertools.count())
167: if xref:
168: return (min(xref)[1],)
169: else:
170: return None
171:
172: def get_row_selection(self,indexpath,selector):
173: if isinstance(indexpath,tuple) and len(indexpath)==1:
174: (index,)=indexpath
175: else:
176: index=indexpath
177: if isinstance(index,int) and 0<=index<self.filtered_size():
178: (xfilter,xcolumn,xfiltered)=self.history[-1]
179: (c,x,xs,s,q,y)=xfiltered[index]
180: return selector(c,x,xs,s,q,y)
181: else:
182: return None
183:
184: def get_row(self,indexpath):
185: return self.get_row_selection(indexpath,lambda c,x,xs,s,q,y: s[1])
186:
187: def get_zipped_row(self,indexpath):
188: return self.get_row_selection(indexpath,lambda c,x,xs,s,q,y: s)
189:
190: def find_exact_row(self,target):
191: (xfilter,xcolumn,xfiltered)=self.history[-1]
192: for (i,(c,x,xs,s,q,y)) in enumerate(xfiltered):
193: if s[1]==target:
194: return (i,)
195: else:
196: return None
197:
198: def find_match_row(self,target):
199: (xfilter,xcolumn,xfiltered)=self.history[-1]
200: for (i,(c,x,xs,s,q,y)) in enumerate(xfiltered):
201: if target(s[1]):
202: return (i,)
203: else:
204: return None
205:
206:
207:
208: class SplitColumns(object):
209:
210:
211: def __init__(self,*p,**pp):
212: if p:
213: self.cols=p
214: if "ncols" in pp:
215: self.ncols=pp["ncols"]
216: else:
217: self.ncols=len(self.cols)
218: else:
219: if "ncols" in pp:
220: self.ncols=pp["ncols"]
221: else:
222: self.ncols=1
223: self.cols = (1,)*self.ncols
224: assert len(self.cols)==self.ncols
225: self.history=[("",(),"",0,0)]
226:
227: def split_comprehend(self,comp,inpt=None):
228: (xcomp,cs,c,ls,l)=self.history[-1]
229: col=len(cs)
230: while not comp.startswith(xcomp):
231: self.history.pop()
232: (xcomp,cs,c,ls,l)=self.history[-1]
233: col=len(cs)
234: for char in comp[len(xcomp):]:
235: if char in ".:;," and col<self.ncols-1:
236: l+=1
237: ls+=1
238: if l==self.cols[col]:
239: self.history.append((xcomp+char,cs+(c,),"",ls,0))
240: else:
241: self.history.append((xcomp+char,cs,c+char,ls,l))
242: else:
243: self.history.append((xcomp+char,cs,c+char,ls,l))
244: (xcomp,cs,c,ls,l)=self.history[-1]
245: col=len(cs)
246: if inpt<>None:
247: for i in range(len(self.history)-1,0,-1):
248: (xcomp,cs,c,ls,l)=self.history[i]
249: col=len(cs)
250: if len(xcomp)<=inpt:
251: break
252: return (col,ls)
253:
254: def get_split_padded(self):
255: (xcomp,cs,c,ls,l)=self.history[-1]
256: cs+=(c,)
257: if self.ncols>len(cs):
258: return cs+("",)*(self.ncols-len(cs))
259: else:
260: return cs[:self.ncols]
261:
262: def get_split(self):
263: (xcomp,cs,c,ls,l)=self.history[-1]
264: cs+=(c,)
265: if self.ncols>len(cs):
266: return cs+("",)*(self.ncols-len(cs))
267: else:
268: return cs[:self.ncols]
269:
270: def get_split_chain(self):
271: (xcomp,cs,c,ls,l)=self.history[-1]
272: cs+=(c,)
273: return cs
274:
275:
276:
277:
278:
279: class FiltCombo(FiltTable):
280:
281:
282: def __init__(self,*p,**pp):
283: FiltTable.__init__(self,*p,**pp)
284: self.split_columns=SplitColumns(ncols=self.ncols)
285: (xfilter,xcolumn,xfiltered)=self.history[-1]
286:
287: (c,x,xs,s,q,y)=xfiltered[0]
288: xfiltered[0]=((-1,),x,xs,s,q,y)
289:
290: def clear(self):
291: gtk.ListStore.clear(self)
292: self.append(("",)*self.ncols+self.xcolnil)
293:
294: def filtered_nil(self):
295: return [((1,),(0,0),[],(-1,("",)*self.ncols+self.xcolnil),True,"")]
296:
297: def filter_comprehend(self,comp,inpt=None):
298: self.split_columns.split_comprehend(comp)
299: comp=canonical(comp)
300: (xfilter,xcolumn,xfiltered)=self.history[-1]
301: displayedfilter=xfilter
302: while not comp.startswith(xfilter):
303: self.history.pop()
304: (xfilter,xcolumn,xfiltered)=self.history[-1]
305: for char in comp[len(xfilter):]:
306: if char in ".:;,":
307: self.filter_next_column(char)
308: (xfilter,xcolumn,xfiltered)=self.history[-1]
309: else:
310: self.filter_append(char)
311: (xfilter,xcolumn,xfiltered)=self.history[-1]
312: displayedfilter=xfilter
313: if displayedfilter<>xfilter:
314:
315: gtk.ListStore.clear(self)
316: for (c,x,xs,s,q,y) in xfiltered:
317: self.append(s[1])
318: self.show_filter()
319: if inpt<>None:
320: for i in range(len(self.history)-1,0,-1):
321: (xfilter,xcolumn,xfiltered)=self.history[i]
322: if len(xfilter)<=inpt:
323: break
324: return xcolumn
325:
326: def show_filter(self):
327: row=self.split_columns.get_split_padded()
328: iter=self.get_iter_first()
329: for i in range(len(row)):
330: self.set_value(iter,i,row[i])
331: (xfilter,xcolumn,xfiltered)=self.history[-1]
332: (c,x,xs,s,q,y)=xfiltered[0]
333:
334: if xfilter=="":
335: xfiltered[0]=((-1,),x,xs,(-1,row+self.xcolnil),q,y)
336: else:
337: xfiltered[0]=((+1,),x,xs,(-1,row+self.xcolnil),q,y)
338:
339:
340:
341: class FiltChainTable(FiltTable):
342:
343:
344: def __init__(self,rows=[]):
345: FiltTable.__init__(self,[(s,) for s in rows])
346:
347: def filter_comprehend(self,comp,inpt=None):
348: comp=canonical(comp)
349: (xfilter,x,xfiltered)=self.history[-1]
350: assert x==0
351: displayedfilter=xfilter
352: while not comp.startswith(xfilter):
353: self.history.pop()
354: (xfilter,x,xfiltered)=self.history[-1]
355: assert x==0
356: for char in comp[len(xfilter):]:
357: if char in " .:;,":
358: xchain=(xfilter,comp[len(xfilter)+1:])
359: break
360: if char.isdigit():
361: xchain=(xfilter,comp[len(xfilter):])
362: break
363:
364: self.filter_append(char)
365: (xfilter,x,xfiltered)=self.history[-1]
366: assert x==0
367: displayedfilter=xfilter
368: else:
369: xchain=(xfilter,)
370: if displayedfilter<>xfilter:
371:
372: gtk.ListStore.clear(self)
373: for (c,x,xs,s,q,y) in xfiltered:
374: self.append(s[1])
375: return xchain
376:
377: