Kaydet (Commit) ec9cca77 authored tarafından Guido van Rossum's avatar Guido van Rossum

Rewritten based on TreeWidget.py

üst 1ff48ec8
"""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()
import os
import sys
import imp
import string
import tkMessageBox
from MultiScrolledLists import MultiScrolledLists
from TreeWidget import TreeItem
from ClassBrowser import ClassBrowser, ModuleBrowserTreeItem
class PathBrowser(MultiScrolledLists):
class PathBrowser(ClassBrowser):
def __init__(self, flist):
self.flist = flist
MultiScrolledLists.__init__(self, flist.root, 4)
def longtitle(self):
return "Path Browser"
def width(self, i):
return 30
def height(self, i):
return 20
def subtitle(self, i):
if i == 0:
return "Path Entries (sys.path)"
if i-1 >= len(self.path):
return ""
if i == 1:
return self.path[0]
if i == 2:
return "Classes in " + self.path[1]
if i == 3:
s = self.path[2]
i = string.find(s, "(")
if i > 0:
s = s[:i]
return "Methods of " + s
return ""
def items(self, i):
if i == 0:
return sys.path
if i == 1:
return self.listmodules()
if i == 2:
return self.listclasses()
if i == 3:
return self.listmethods()
def listmodules(self):
dir = self.path[0] or os.curdir
self.init(flist)
def settitle(self):
self.top.wm_title("Path Browser")
self.top.wm_iconname("Path Browser")
def rootnode(self):
return PathBrowserTreeItem()
class PathBrowserTreeItem(TreeItem):
def GetText(self):
return "sys.path"
def GetSubList(self):
sublist = []
for dir in sys.path:
item = DirBrowserTreeItem(dir)
sublist.append(item)
return sublist
class DirBrowserTreeItem(TreeItem):
def __init__(self, dir, packages=[]):
self.dir = dir
self.packages = packages
def GetText(self):
if not self.packages:
return self.dir
else:
return self.packages[-1] + ": package"
def GetSubList(self):
try:
names = os.listdir(self.dir or os.curdir)
except os.error:
return []
packages = []
for name in names:
file = os.path.join(self.dir, name)
if self.ispackagedir(file):
nn = os.path.normcase(name)
packages.append((nn, name, file))
packages.sort()
sublist = []
for nn, name, file in packages:
item = DirBrowserTreeItem(file, self.packages + [name])
sublist.append(item)
for nn, name in self.listmodules(names):
item = ModuleBrowserTreeItem(os.path.join(self.dir, name))
sublist.append(item)
return sublist
def ispackagedir(self, file):
if not os.path.isdir(file):
return 0
init = os.path.join(file, "__init__.py")
return os.path.exists(init)
def listmodules(self, allnames):
modules = {}
suffixes = imp.get_suffixes()
allnames = os.listdir(dir)
sorted = []
for suff, mode, flag in suffixes:
i = -len(suff)
......@@ -65,96 +83,13 @@ class PathBrowser(MultiScrolledLists):
sorted.append((normed_name, name))
allnames.remove(name)
sorted.sort()
names = []
for nn, name in sorted:
names.append(name)
return names
def listclasses(self):
import pyclbr
dir = self.path[0]
file = self.path[1]
name, ext = os.path.splitext(file)
if os.path.normcase(ext) != ".py":
self.top.bell()
return []
try:
self.top.configure(cursor="watch")
self.top.update_idletasks()
try:
dict = pyclbr.readmodule(name, [dir] + sys.path)
finally:
self.top.configure(cursor="")
except ImportError, msg:
tkMessageBox.showerror("Import error", str(msg), parent=root)
return []
items = []
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()
list = []
for item, s in items:
list.append(s)
return list
def listmethods(self):
try:
cl = self.classes[self.path[2]]
except (IndexError, KeyError):
return []
items = []
for name, lineno in cl.methods.items():
items.append((lineno, name))
items.sort()
list = []
for item, name in items:
list.append(name)
return list
def on_double(self, index, i):
if i == 0:
return
if i >= 1:
dir = self.path[0]
file = self.path[1]
name, ext = os.path.splitext(file)
if os.path.normcase(ext) != ".py":
self.top.bell()
return
fullname = os.path.join(dir, file)
edit = self.flist.open(fullname)
if i >= 2:
classname = self.path[2]
try:
cl = self.classes[classname]
except KeyError:
cl = None
else:
if i == 2:
edit.gotoline(cl.lineno)
else:
methodname = self.path[3]
edit.gotoline(cl.methods[methodname])
return sorted
def main():
import PyShell
PathBrowser(PyShell.flist)
if sys.stdin is sys.__stdin__:
mainloop()
if __name__ == "__main__":
main()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment