Generalized the scrolled list which is the base for the class and
method browser into a separate class in its own module.
This commit is contained in:
parent
341d1fe18e
commit
e6fae1cbca
|
@ -9,11 +9,15 @@ XXX TO DO:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
import string
|
import string
|
||||||
import pyclbr
|
import pyclbr
|
||||||
from Tkinter import *
|
from Tkinter import *
|
||||||
import tkMessageBox
|
import tkMessageBox
|
||||||
|
|
||||||
|
from ScrolledList import ScrolledList
|
||||||
|
|
||||||
|
|
||||||
class ClassBrowser:
|
class ClassBrowser:
|
||||||
|
|
||||||
def __init__(self, flist, name):
|
def __init__(self, flist, name):
|
||||||
|
@ -32,44 +36,62 @@ class ClassBrowser:
|
||||||
self.root = root
|
self.root = root
|
||||||
self.top = top = Toplevel(root)
|
self.top = top = Toplevel(root)
|
||||||
self.top.protocol("WM_DELETE_WINDOW", self.close)
|
self.top.protocol("WM_DELETE_WINDOW", self.close)
|
||||||
|
top.wm_title("Class browser")
|
||||||
self.leftframe = leftframe = Frame(top)
|
self.leftframe = leftframe = Frame(top)
|
||||||
self.leftframe.pack(side="left", fill="both", expand=1)
|
self.leftframe.pack(side="left", fill="both", expand=1)
|
||||||
top.wm_title("Class browser")
|
|
||||||
# Create help label
|
# Create help label
|
||||||
self.helplabel = Label(leftframe,
|
self.helplabel = Label(leftframe, text="Module %s" % name,
|
||||||
text="Classes in module %s" % name,
|
relief="groove", borderwidth=2)
|
||||||
borderwidth=2, relief="groove")
|
|
||||||
self.helplabel.pack(fill="x")
|
self.helplabel.pack(fill="x")
|
||||||
# Create top frame, with scrollbar and listbox
|
# Create top frame, with scrollbar and listbox
|
||||||
self.topframe = Frame(leftframe)
|
self.classviewer = ClassViewer(
|
||||||
self.topframe.pack(fill="both", expand=1)
|
self.leftframe, self.flist, self)
|
||||||
self.vbar = Scrollbar(self.topframe, name="vbar")
|
|
||||||
self.vbar.pack(side="right", fill="y")
|
|
||||||
self.listbox = Listbox(self.topframe, exportselection=0,
|
|
||||||
takefocus=1, width=30)
|
|
||||||
self.listbox.pack(expand=1, fill="both")
|
|
||||||
# Tie listbox and scrollbar together
|
|
||||||
self.vbar["command"] = self.listbox.yview
|
|
||||||
self.listbox["yscrollcommand"] = self.vbar.set
|
|
||||||
# Bind events to the list box
|
|
||||||
self.listbox.bind("<ButtonRelease-1>", self.click_event)
|
|
||||||
self.listbox.bind("<Double-ButtonRelease-1>", self.double_click_event)
|
|
||||||
##self.listbox.bind("<ButtonPress-3>", self.popup_event)
|
|
||||||
self.listbox.bind("<Key-Up>", self.up_event)
|
|
||||||
self.listbox.bind("<Key-Down>", self.down_event)
|
|
||||||
# Load the classes
|
# Load the classes
|
||||||
self.loadclasses(dict, name)
|
self.load_classes(dict, name)
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
|
self.classviewer = None
|
||||||
|
self.methodviewer = None
|
||||||
self.top.destroy()
|
self.top.destroy()
|
||||||
|
|
||||||
def loadclasses(self, dict, module):
|
def load_classes(self, dict, module):
|
||||||
|
self.classviewer.load_classes(dict, module)
|
||||||
|
if self.botframe:
|
||||||
|
self.botframe.destroy()
|
||||||
|
self.botframe = None
|
||||||
|
self.methodviewer = None
|
||||||
|
|
||||||
|
botframe = None
|
||||||
|
methodhelplabel = None
|
||||||
|
methodviewer = None
|
||||||
|
|
||||||
|
def show_methods(self, cl):
|
||||||
|
if not self.botframe:
|
||||||
|
self.botframe = Frame(self.top)
|
||||||
|
self.botframe.pack(side="right", expand=1, fill="both")
|
||||||
|
self.methodhelplabel = Label(self.botframe,
|
||||||
|
relief="groove", borderwidth=2)
|
||||||
|
self.methodhelplabel.pack(fill="x")
|
||||||
|
self.methodviewer = MethodViewer(self.botframe, self.flist)
|
||||||
|
self.methodhelplabel.config(text="Class %s" % cl.name)
|
||||||
|
self.methodviewer.load_methods(cl)
|
||||||
|
|
||||||
|
|
||||||
|
class ClassViewer(ScrolledList):
|
||||||
|
|
||||||
|
def __init__(self, master, flist, browser):
|
||||||
|
ScrolledList.__init__(self, master)
|
||||||
|
self.flist = flist
|
||||||
|
self.browser = browser
|
||||||
|
|
||||||
|
def load_classes(self, dict, module):
|
||||||
|
self.clear()
|
||||||
|
self.dict = dict
|
||||||
items = []
|
items = []
|
||||||
for key, value in dict.items():
|
for key, value in dict.items():
|
||||||
if value.module == module:
|
if value.module == module:
|
||||||
items.append((value.lineno, key, value))
|
items.append((value.lineno, key, value))
|
||||||
items.sort()
|
items.sort()
|
||||||
l = self.listbox
|
|
||||||
for lineno, key, value in items:
|
for lineno, key, value in items:
|
||||||
s = key
|
s = key
|
||||||
if value.super:
|
if value.super:
|
||||||
|
@ -80,133 +102,60 @@ class ClassBrowser:
|
||||||
name = "%s.%s" % (sup.module, name)
|
name = "%s.%s" % (sup.module, name)
|
||||||
super.append(name)
|
super.append(name)
|
||||||
s = s + "(%s)" % string.join(super, ", ")
|
s = s + "(%s)" % string.join(super, ", ")
|
||||||
l.insert("end", s)
|
self.append(s)
|
||||||
l.focus_set()
|
|
||||||
l.selection_clear(0, "end")
|
def getname(self, index):
|
||||||
if self.botframe:
|
name = self.listbox.get(index)
|
||||||
self.botframe.destroy()
|
i = string.find(name, '(')
|
||||||
self.botframe = None
|
if i >= 0:
|
||||||
self.methodviewer = None
|
name = name[:i]
|
||||||
|
return name
|
||||||
|
|
||||||
def click_event(self, event):
|
def getclass(self, index):
|
||||||
self.listbox.activate("@%d,%d" % (event.x, event.y))
|
return self.dict[self.getname(index)]
|
||||||
index = self.listbox.index("active")
|
|
||||||
|
def on_select(self, index):
|
||||||
self.show_methods(index)
|
self.show_methods(index)
|
||||||
|
|
||||||
def double_click_event(self, event):
|
def on_double(self, index):
|
||||||
self.listbox.activate("@%d,%d" % (event.x, event.y))
|
|
||||||
index = self.listbox.index("active")
|
|
||||||
self.show_source(index)
|
self.show_source(index)
|
||||||
|
|
||||||
def up_event(self, event):
|
|
||||||
index = self.listbox.index("active") - 1
|
|
||||||
if index < 0:
|
|
||||||
self.top.bell()
|
|
||||||
return "break"
|
|
||||||
self.show_methods(index)
|
|
||||||
return "break"
|
|
||||||
|
|
||||||
def down_event(self, event):
|
|
||||||
index = self.listbox.index("active") + 1
|
|
||||||
if index >= self.listbox.index("end"):
|
|
||||||
self.top.bell()
|
|
||||||
return "break"
|
|
||||||
self.show_methods(index)
|
|
||||||
return "break"
|
|
||||||
|
|
||||||
def show_source(self, index):
|
|
||||||
name = self.listbox.get(index)
|
|
||||||
i = string.find(name, '(')
|
|
||||||
if i >= 0:
|
|
||||||
name = name[:i]
|
|
||||||
cl = self.dict[name]
|
|
||||||
edit = self.flist.open(cl.file)
|
|
||||||
edit.gotoline(cl.lineno)
|
|
||||||
|
|
||||||
botframe = None
|
|
||||||
methodviewer = None
|
|
||||||
|
|
||||||
def show_methods(self, index):
|
def show_methods(self, index):
|
||||||
self.listbox.selection_clear(0, "end")
|
cl = self.getclass(index)
|
||||||
self.listbox.selection_set(index)
|
self.browser.show_methods(cl)
|
||||||
self.listbox.activate(index)
|
|
||||||
self.listbox.see(index)
|
|
||||||
self.listbox.focus_set()
|
|
||||||
name = self.listbox.get(index)
|
|
||||||
i = string.find(name, '(')
|
|
||||||
if i >= 0:
|
|
||||||
name = name[:i]
|
|
||||||
cl = self.dict[name]
|
|
||||||
if not self.botframe:
|
|
||||||
self.botframe = Frame(self.top)
|
|
||||||
self.botframe.pack(expand=1, fill="both")
|
|
||||||
if not self.methodviewer:
|
|
||||||
self.methodviewer = MethodViewer(self.botframe, self.flist)
|
|
||||||
self.methodviewer.loadmethods(cl)
|
|
||||||
|
|
||||||
class MethodViewer:
|
def show_source(self, index):
|
||||||
|
cl = self.getclass(index)
|
||||||
|
if os.path.isfile(cl.file):
|
||||||
|
edit = self.flist.open(cl.file)
|
||||||
|
edit.gotoline(cl.lineno)
|
||||||
|
|
||||||
|
|
||||||
|
class MethodViewer(ScrolledList):
|
||||||
|
|
||||||
# XXX There's a pattern emerging here...
|
def __init__(self, master, flist):
|
||||||
|
ScrolledList.__init__(self, master)
|
||||||
def __init__(self, frame, flist):
|
|
||||||
self.frame = frame
|
|
||||||
self.flist = flist
|
self.flist = flist
|
||||||
# Create help label
|
|
||||||
self.helplabel = Label(frame,
|
|
||||||
text="Methods", borderwidth=2, relief="groove")
|
|
||||||
self.helplabel.pack(fill="x")
|
|
||||||
# Create top frame, with scrollbar and listbox
|
|
||||||
self.topframe = Frame(frame)
|
|
||||||
self.topframe.pack(fill="both", expand=1)
|
|
||||||
self.vbar = Scrollbar(self.topframe, name="vbar")
|
|
||||||
self.vbar.pack(side="right", fill="y")
|
|
||||||
self.listbox = Listbox(self.topframe, exportselection=0,
|
|
||||||
takefocus=1, width=30)
|
|
||||||
self.listbox.pack(expand=1, fill="both")
|
|
||||||
# Tie listbox and scrollbar together
|
|
||||||
self.vbar["command"] = self.listbox.yview
|
|
||||||
self.listbox["yscrollcommand"] = self.vbar.set
|
|
||||||
# Bind events to the list box
|
|
||||||
self.listbox.bind("<ButtonRelease-1>", self.click_event)
|
|
||||||
self.listbox.bind("<Double-ButtonRelease-1>", self.double_click_event)
|
|
||||||
##self.listbox.bind("<ButtonPress-3>", self.popup_event)
|
|
||||||
self.listbox.bind("<Key-Up>", self.up_event)
|
|
||||||
self.listbox.bind("<Key-Down>", self.down_event)
|
|
||||||
|
|
||||||
classinfo = None
|
classinfo = None
|
||||||
|
|
||||||
def loadmethods(self, cl):
|
def load_methods(self, cl):
|
||||||
self.classinfo = cl
|
self.classinfo = cl
|
||||||
self.helplabel.config(text="Methods of class %s" % cl.name)
|
self.clear()
|
||||||
l = self.listbox
|
|
||||||
l.delete(0, "end")
|
|
||||||
l.selection_clear(0, "end")
|
|
||||||
items = []
|
items = []
|
||||||
for name, lineno in cl.methods.items():
|
for name, lineno in cl.methods.items():
|
||||||
items.append((lineno, name))
|
items.append((lineno, name))
|
||||||
items.sort()
|
items.sort()
|
||||||
for item, name in items:
|
for item, name in items:
|
||||||
l.insert("end", name)
|
self.append(name)
|
||||||
|
|
||||||
def click_event(self, event):
|
def click_event(self, event):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def double_click_event(self, event):
|
def on_double(self, index):
|
||||||
self.listbox.activate("@%d,%d" % (event.x, event.y))
|
self.show_source(self.get(index))
|
||||||
index = self.listbox.index("active")
|
|
||||||
self.show_source(index)
|
|
||||||
|
|
||||||
def up_event(self, event):
|
def show_source(self, name):
|
||||||
pass
|
if os.path.isfile(self.classinfo.file):
|
||||||
|
edit = self.flist.open(self.classinfo.file)
|
||||||
def down_event(self, event):
|
edit.gotoline(self.classinfo.methods[name])
|
||||||
pass
|
|
||||||
|
|
||||||
def show_source(self, index):
|
|
||||||
name = self.listbox.get(index)
|
|
||||||
i = string.find(name, '(')
|
|
||||||
if i >= 0:
|
|
||||||
name = name[:i]
|
|
||||||
edit = self.flist.open(self.classinfo.file)
|
|
||||||
edit.gotoline(self.classinfo.methods[name])
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,128 @@
|
||||||
|
from Tkinter import *
|
||||||
|
|
||||||
|
class ScrolledList:
|
||||||
|
|
||||||
|
def __init__(self, master, **options):
|
||||||
|
# Create top frame, with scrollbar and listbox
|
||||||
|
self.master = master
|
||||||
|
self.frame = frame = Frame(master)
|
||||||
|
self.frame.pack(fill="both", expand=1)
|
||||||
|
self.vbar = vbar = Scrollbar(frame, name="vbar")
|
||||||
|
self.vbar.pack(side="right", fill="y")
|
||||||
|
self.listbox = listbox = Listbox(frame, exportselection=0)
|
||||||
|
if options:
|
||||||
|
listbox.configure(options)
|
||||||
|
listbox.pack(expand=1, fill="both")
|
||||||
|
# Tie listbox and scrollbar together
|
||||||
|
vbar["command"] = listbox.yview
|
||||||
|
listbox["yscrollcommand"] = vbar.set
|
||||||
|
# Bind events to the list box
|
||||||
|
listbox.bind("<ButtonRelease-1>", self.click_event)
|
||||||
|
listbox.bind("<Double-ButtonRelease-1>", self.double_click_event)
|
||||||
|
listbox.bind("<ButtonPress-3>", self.popup_event)
|
||||||
|
listbox.bind("<Key-Up>", self.up_event)
|
||||||
|
listbox.bind("<Key-Down>", self.down_event)
|
||||||
|
# Set the focus
|
||||||
|
listbox.focus_set()
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
self.listbox.delete(0, "end")
|
||||||
|
|
||||||
|
def append(self, item):
|
||||||
|
self.listbox.insert("end", str(item))
|
||||||
|
|
||||||
|
def get(self, index):
|
||||||
|
return self.listbox.get(index)
|
||||||
|
|
||||||
|
def click_event(self, event):
|
||||||
|
self.listbox.activate("@%d,%d" % (event.x, event.y))
|
||||||
|
index = self.listbox.index("active")
|
||||||
|
self.select(index)
|
||||||
|
self.on_select(index)
|
||||||
|
return "break"
|
||||||
|
|
||||||
|
def double_click_event(self, event):
|
||||||
|
index = self.listbox.index("active")
|
||||||
|
self.select(index)
|
||||||
|
self.on_double(index)
|
||||||
|
return "break"
|
||||||
|
|
||||||
|
menu = None
|
||||||
|
|
||||||
|
def popup_event(self, event):
|
||||||
|
if not self.menu:
|
||||||
|
self.make_menu()
|
||||||
|
menu = self.menu
|
||||||
|
self.listbox.activate("@%d,%d" % (event.x, event.y))
|
||||||
|
index = self.listbox.index("active")
|
||||||
|
self.select(index)
|
||||||
|
menu.tk_popup(event.x_root, event.y_root)
|
||||||
|
|
||||||
|
def make_menu(self):
|
||||||
|
menu = Menu(self.listbox, tearoff=0)
|
||||||
|
self.menu = menu
|
||||||
|
self.fill_menu()
|
||||||
|
|
||||||
|
def up_event(self, event):
|
||||||
|
index = self.listbox.index("active")
|
||||||
|
if self.listbox.selection_includes(index):
|
||||||
|
index = index - 1
|
||||||
|
else:
|
||||||
|
index = self.listbox.size() - 1
|
||||||
|
if index < 0:
|
||||||
|
self.listbox.bell()
|
||||||
|
else:
|
||||||
|
self.select(index)
|
||||||
|
self.on_select(index)
|
||||||
|
return "break"
|
||||||
|
|
||||||
|
def down_event(self, event):
|
||||||
|
index = self.listbox.index("active")
|
||||||
|
if self.listbox.selection_includes(index):
|
||||||
|
index = index + 1
|
||||||
|
else:
|
||||||
|
index = 0
|
||||||
|
if index >= self.listbox.size():
|
||||||
|
self.listbox.bell()
|
||||||
|
else:
|
||||||
|
self.select(index)
|
||||||
|
self.on_select(index)
|
||||||
|
return "break"
|
||||||
|
|
||||||
|
def select(self, index):
|
||||||
|
self.listbox.focus_set()
|
||||||
|
self.listbox.activate(index)
|
||||||
|
self.listbox.selection_clear(0, "end")
|
||||||
|
self.listbox.selection_set(index)
|
||||||
|
self.listbox.see(index)
|
||||||
|
|
||||||
|
# Methods to override for specific actions
|
||||||
|
|
||||||
|
def fill_menu(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def on_select(self, index):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def on_double(self, index):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def test():
|
||||||
|
root = Tk()
|
||||||
|
root.protocol("WM_DELETE_WINDOW", root.destroy)
|
||||||
|
class MyScrolledList(ScrolledList):
|
||||||
|
def fill_menu(self): self.menu.add_command(label="pass")
|
||||||
|
def on_select(self, index): print "select", self.get(index)
|
||||||
|
def on_double(self, index): print "double", self.get(index)
|
||||||
|
s = MyScrolledList(root)
|
||||||
|
for i in range(30):
|
||||||
|
s.append("item %02d" % i)
|
||||||
|
return root
|
||||||
|
|
||||||
|
def main():
|
||||||
|
root = test()
|
||||||
|
root.mainloop()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
Loading…
Reference in New Issue