diff options
author | Guido van Rossum <guido@python.org> | 1999-06-01 18:21:31 (GMT) |
---|---|---|
committer | Guido van Rossum <guido@python.org> | 1999-06-01 18:21:31 (GMT) |
commit | ec9cca776ae4330711b66a83c8177e899945e4e8 (patch) | |
tree | 7c4130f8a3d008efc3bed0cc89297b68c03f7049 /Tools/idle/ClassBrowser.py | |
parent | 1ff48ec85252ca799b5a3da833f69c7716c4afe0 (diff) | |
download | cpython-ec9cca776ae4330711b66a83c8177e899945e4e8.zip cpython-ec9cca776ae4330711b66a83c8177e899945e4e8.tar.gz cpython-ec9cca776ae4330711b66a83c8177e899945e4e8.tar.bz2 |
Rewritten based on TreeWidget.py
Diffstat (limited to 'Tools/idle/ClassBrowser.py')
-rw-r--r-- | Tools/idle/ClassBrowser.py | 318 |
1 files changed, 185 insertions, 133 deletions
diff --git a/Tools/idle/ClassBrowser.py b/Tools/idle/ClassBrowser.py index f9b1655..0cf978e 100644 --- a/Tools/idle/ClassBrowser.py +++ b/Tools/idle/ClassBrowser.py @@ -1,168 +1,220 @@ -"""Primitive class browser. +"""Class browser. XXX TO DO: -- reparse when source changed +- reparse when source changed (maybe just a button would be OK?) + (or recheck on window popup) - add popup menu with more options (e.g. doc strings, base classes, imports) -- show function argument list (have to do pattern matching on source) +- show function argument list? (have to do pattern matching on source) - should the classes and methods lists also be in the module's menu bar? +- add base classes to class browser tree +- make methodless classes inexpandable +- make classless modules inexpandable + """ import os +import sys import string import pyclbr -from Tkinter import * -import tkMessageBox -from WindowList import ListedToplevel -from Separator import HSeparator - -from ScrolledList import ScrolledList +import PyShell +from WindowList import ListedToplevel +from TreeWidget import TreeNode, TreeItem, ScrolledCanvas class ClassBrowser: - def __init__(self, flist, name, path=[]): - root = flist.root - try: - dict = pyclbr.readmodule(name, path) - except ImportError, msg: - tkMessageBox.showerror("Import error", str(msg), parent=root) - return - if not dict: - tkMessageBox.showerror("Nothing to browse", - "Module %s defines no classes" % name, parent=root) - return - self.flist = flist - self.dict = dict - self.root = root - self.top = top = ListedToplevel(root) - self.top.protocol("WM_DELETE_WINDOW", self.close) - self.top.bind("<Escape>", self.close) - top.wm_title("Class Browser - " + name) - top.wm_iconname("ClBrowser") - self.sepa = HSeparator(top) - leftframe, rightframe = self.sepa.parts() - self.leftframe = leftframe - self.rightframe = rightframe - leftframe.pack(side="left", fill="both", expand=1) - # Create help label - self.helplabel = Label(leftframe, text="Module %s" % name, - relief="groove", borderwidth=2) - self.helplabel.pack(fill="x") - # Create top frame, with scrollbar and listbox - self.classviewer = ClassViewer( - self.leftframe, self.flist, self) - # Load the classes - self.load_classes(dict, name) + def __init__(self, flist, name, path): + self.name = name + self.file = os.path.join(path[0], self.name + ".py") + self.init(flist) def close(self, event=None): - self.classviewer = None - self.methodviewer = None self.top.destroy() - def load_classes(self, dict, module): - self.classviewer.load_classes(dict, module) - if self.methodframe: - self.methodframe.destroy() - self.methodframe = None - self.methodviewer = None - - methodframe = None - methodhelplabel = None - methodviewer = None - - def show_methods(self, cl): - if not self.methodframe: - self.methodframe = Frame(self.rightframe) - self.methodframe.pack(side="right", expand=1, fill="both") - self.methodhelplabel = Label(self.methodframe, - relief="groove", borderwidth=2) - self.methodhelplabel.pack(fill="x") - self.methodviewer = MethodViewer(self.methodframe, 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, width=40) + def init(self, flist): self.flist = flist - self.browser = browser - - def load_classes(self, dict, module): - self.clear() - self.dict = dict + # reset pyclbr + pyclbr._modules.clear() + # create top + self.top = top = ListedToplevel(flist.root) + top.protocol("WM_DELETE_WINDOW", self.close) + top.bind("<Escape>", self.close) + self.settitle() + top.focus_set() + # create scrolled canvas + sc = ScrolledCanvas(top, bg="white", highlightthickness=0, takefocus=1) + sc.frame.pack(expand=1, fill="both") + item = self.rootnode() + node = TreeNode(sc.canvas, None, item) + node.update() + node.expand() + + def settitle(self): + self.top.wm_title("Class Browser - " + self.name) + self.top.wm_iconname("Class Browser") + + def rootnode(self): + return ModuleBrowserTreeItem(self.file) + +class ModuleBrowserTreeItem(TreeItem): + + def __init__(self, file): + self.file = file + + def GetText(self): + return os.path.basename(self.file) + + def GetIconName(self): + return "python" + + def GetSubList(self): + sublist = [] + for name in self.listclasses(): + item = ClassBrowserTreeItem(name, self.classes, self.file) + sublist.append(item) + return sublist + + def OnDoubleClick(self): + if os.path.normcase(self.file[-3:]) != ".py": + return + if not os.path.exists(self.file): + return + PyShell.flist.open(self.file) + + def IsExpandable(self): + return os.path.normcase(self.file[-3:]) == ".py" + + def listclasses(self): + dir, file = os.path.split(self.file) + name, ext = os.path.splitext(file) + if os.path.normcase(ext) != ".py": + return [] + try: + dict = pyclbr.readmodule(name, [dir] + sys.path) + except ImportError, msg: + return [] items = [] - for key, value in dict.items(): - if value.module == module: - items.append((value.lineno, key, value)) + self.classes = {} + for key, cl in dict.items(): + if cl.module == name: + s = key + if cl.super: + supers = [] + for sup in cl.super: + if type(sup) is type(''): + sname = sup + else: + sname = sup.name + if sup.module != cl.module: + sname = "%s.%s" % (sup.module, sname) + supers.append(sname) + s = s + "(%s)" % string.join(supers, ", ") + items.append((cl.lineno, s)) + self.classes[s] = cl items.sort() - for lineno, key, value in items: - s = key - if value.super: - super = [] - for sup in value.super: - name = sup.name - if sup.module != value.module: - name = "%s.%s" % (sup.module, name) - super.append(name) - s = s + "(%s)" % string.join(super, ", ") - self.append(s) - - def getname(self, index): - name = self.listbox.get(index) - i = string.find(name, '(') - if i >= 0: - name = name[:i] - return name + list = [] + for item, s in items: + list.append(s) + return list - def getclass(self, index): - return self.dict[self.getname(index)] +class ClassBrowserTreeItem(TreeItem): - def on_select(self, index): - self.show_methods(index) + def __init__(self, name, classes, file): + self.name = name + self.classes = classes + self.file = file - def on_double(self, index): - self.show_source(index) + def GetText(self): + return "class " + self.name - def show_methods(self, index): - cl = self.getclass(index) - self.browser.show_methods(cl) - - 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): - - def __init__(self, master, flist): - ScrolledList.__init__(self, master) - self.flist = flist - - classinfo = None + def IsExpandable(self): + try: + cl = self.classes[self.name] + except (IndexError, KeyError): + return 0 + else: + return not not cl.methods + + def GetSubList(self): + sublist = [] + for name in self.listmethods(): + item = MethodBrowserTreeItem( + name, self.classes[self.name], self.file) + sublist.append(item) + return sublist + + def OnDoubleClick(self): + if not os.path.exists(self.file): + return + edit = PyShell.flist.open(self.file) + if self.classes.has_key(self.name): + cl = self.classes[self.name] + else: + name = self.name + i = string.find(name, '(') + if i < 0: + return + name = name[:i] + if not self.classes.has_key(name): + return + cl = self.classes[name] + if not hasattr(cl, 'lineno'): + return + lineno = cl.lineno + edit.gotoline(lineno) - def load_methods(self, cl): - self.classinfo = cl - self.clear() + def listmethods(self): + try: + cl = self.classes[self.name] + except (IndexError, KeyError): + return [] items = [] for name, lineno in cl.methods.items(): items.append((lineno, name)) items.sort() + list = [] for item, name in items: - self.append(name) + list.append(name) + return list + +class MethodBrowserTreeItem(TreeItem): - def click_event(self, event): - pass + def __init__(self, name, cl, file): + self.name = name + self.cl = cl + self.file = file - def on_double(self, index): - self.show_source(self.get(index)) + def GetText(self): + return "def " + self.name + "(...)" - def show_source(self, name): - if os.path.isfile(self.classinfo.file): - edit = self.flist.open(self.classinfo.file) - edit.gotoline(self.classinfo.methods[name]) + def GetIconName(self): + return "python" # XXX + + def IsExpandable(self): + return 0 + + def OnDoubleClick(self): + if not os.path.exists(self.file): + return + edit = PyShell.flist.open(self.file) + edit.gotoline(self.cl.methods[self.name]) + +def main(): + try: + file = __file__ + except NameError: + file = sys.argv[0] + if sys.argv[1:]: + file = sys.argv[1] + else: + file = sys.argv[0] + dir, file = os.path.split(file) + name = os.path.splitext(file)[0] + ClassBrowser(PyShell.flist, name, [dir]) + if sys.stdin is sys.__stdin__: + mainloop() + +if __name__ == "__main__": + main() |