I took the time to clean up the implementation of Percolator and add
some comments and doc-strings. I plan to do the same for Delegator
soon. I have found these to be very confusing and hard to understand,
although they could be a good piece of code to learn from. I hope I've
made the code more Pythonic :)
This version of Percolator inherits from Delegator (since a Percolator
"is a" Delegator, after all). I've also refactored the
Tk-Text-widget-specific stuff into a subclass, TkTextPercolator, which
is functionally equivalent to the original Percolator.
To use this in IDLE, use this file instead of Percolator.py (either
replace it or import this file instead of the original), and use the
TkTextPercolator class instead of Percolator (in EditorWindow.py).
I'm willing to post this as a patch on SF if there is any interest.
Comments are most welcome :)
- Tal
from WidgetRedirector import WidgetRedirector
from Delegator import Delegator
class Percolator(Delegator):
"""A linked list of Delegator objects, each delegating to the next.
A Percolator is a Delegator, and therefore inherits from Delegator.
Use 'insertfilter' to add a Delegator to the beginning of the list,
and 'removefilter' to remove a Delegator from (anywhere in) the list.
'setdelegate' and 'getdelegate' refer to the original delegate, to which
the last delegator in the list delegates.
"""
def __init__(self, delegate):
Delegator.__init__(self)
self.top = self.bottom = Delegator(delegate)
# Always actually delegate to self.top
top = property(lambda self: Delegator.getdelegate(self),
lambda self, top: Delegator.setdelegate(self, top))
# setdelegate and getdelegate refer to the original delegate
def setdelegate(self, delegate):
self.bottom.setdelegate(delegate)
def getdelegate(self):
return self.bottom.getdelegate()
def close(self):
while self.top is not self.bottom:
self.removefilter(top)
self.top = None
self.setdelegate(None)
def insertfilter(self, filter):
# Perhaps rename to pushfilter()?
assert isinstance(filter, Delegator)
assert filter.delegate is None
filter.setdelegate(self.top)
self.top = filter
def removefilter(self, filter):
# XXX Perhaps should only support popfilter()?
assert isinstance(filter, Delegator)
assert filter.delegate is not None
f = self.top
if f is filter:
self.top = filter.getdelegate()
filter.setdelegate(None)
else:
while f.delegate is not filter:
assert f is not self.bottom
f.resetcache()
f = f.delegate
f.setdelegate(filter.getdelegate())
class TkTextPercolator(Percolator):
"""A specialized Percolator used to wrap a Tk Text widget.
The Text widget's insert and delete methods are redirected to the top of
the Percolator. The bottom-most Delegator has the original insert and
delete methods.
This uses the WidgetRedirector class which allows redirecting Tcl/Tk calls
to Python functions/methods.
"""
def __init__(self, text):
Percolator.__init__(self, text)
self.redir = WidgetRedirector(text)
# Register functions which dynamically retrieve the methods (see below)
self.bottom.insert = self.redir.register("insert", self.insert)
self.bottom.delete = self.redir.register("delete", self.delete)
def close(self):
self.redir.close(); self.redir = None
Percolator.close(self)
# The 'insert' and 'delete' methods ensure dynamic resolution of
# 'self.top.insert'. Without this, the widget's 'insert' method would be
# redirected to whatever self.insert is delegated to during construction,
# since self.insert is evaluated when __init__ is run. (likewise for
# 'delete')
def insert(self, index, chars, tags=None):
self.top.insert(index, chars, tags)
def delete(self, index1, index2=None):
self.top.delete(index1, index2)
def main():
class Tracer(Delegator):
def __init__(self, name):
self.name = name
Delegator.__init__(self, None)
def insert(self, *args):
print self.name, ": insert", args
self.delegate.insert(*args)
def delete(self, *args):
print self.name, ": delete", args
self.delegate.delete(*args)
from Tkinter import Tk, Text
root = Tk()
root.wm_protocol("WM_DELETE_WINDOW", root.quit)
text = Text()
text.pack()
text.focus_set()
p = TkTextPercolator(text)
t1 = Tracer("t1")
t2 = Tracer("t2")
p.insertfilter(t1)
p.insertfilter(t2)
root.mainloop()
p.removefilter(t2)
root.mainloop()
p.insertfilter(t2)
p.removefilter(t1)
root.mainloop()
root.destroy()
if __name__ == "__main__":
main()
_______________________________________________
IDLE-dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/idle-dev