summaryrefslogtreecommitdiffstats
path: root/Tools/idle/ClassBrowser.py
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>1999-06-01 18:21:31 (GMT)
committerGuido van Rossum <guido@python.org>1999-06-01 18:21:31 (GMT)
commitec9cca776ae4330711b66a83c8177e899945e4e8 (patch)
tree7c4130f8a3d008efc3bed0cc89297b68c03f7049 /Tools/idle/ClassBrowser.py
parent1ff48ec85252ca799b5a3da833f69c7716c4afe0 (diff)
downloadcpython-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.py318
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()