Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ec9cca7

Browse files
committed
Rewritten based on TreeWidget.py
1 parent 1ff48ec commit ec9cca7

2 files changed

Lines changed: 252 additions & 265 deletions

File tree

Tools/idle/ClassBrowser.py

Lines changed: 185 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -1,168 +1,220 @@
1-
"""Primitive class browser.
1+
"""Class browser.
22
33
XXX TO DO:
44
5-
- reparse when source changed
5+
- reparse when source changed (maybe just a button would be OK?)
6+
(or recheck on window popup)
67
- add popup menu with more options (e.g. doc strings, base classes, imports)
7-
- show function argument list (have to do pattern matching on source)
8+
- show function argument list? (have to do pattern matching on source)
89
- should the classes and methods lists also be in the module's menu bar?
10+
- add base classes to class browser tree
11+
- make methodless classes inexpandable
12+
- make classless modules inexpandable
13+
914
1015
"""
1116

1217
import os
18+
import sys
1319
import string
1420
import pyclbr
15-
from Tkinter import *
16-
import tkMessageBox
17-
from WindowList import ListedToplevel
18-
from Separator import HSeparator
19-
20-
from ScrolledList import ScrolledList
2121

22+
import PyShell
23+
from WindowList import ListedToplevel
24+
from TreeWidget import TreeNode, TreeItem, ScrolledCanvas
2225

2326
class ClassBrowser:
2427

25-
def __init__(self, flist, name, path=[]):
26-
root = flist.root
27-
try:
28-
dict = pyclbr.readmodule(name, path)
29-
except ImportError, msg:
30-
tkMessageBox.showerror("Import error", str(msg), parent=root)
31-
return
32-
if not dict:
33-
tkMessageBox.showerror("Nothing to browse",
34-
"Module %s defines no classes" % name, parent=root)
35-
return
36-
self.flist = flist
37-
self.dict = dict
38-
self.root = root
39-
self.top = top = ListedToplevel(root)
40-
self.top.protocol("WM_DELETE_WINDOW", self.close)
41-
self.top.bind("<Escape>", self.close)
42-
top.wm_title("Class Browser - " + name)
43-
top.wm_iconname("ClBrowser")
44-
self.sepa = HSeparator(top)
45-
leftframe, rightframe = self.sepa.parts()
46-
self.leftframe = leftframe
47-
self.rightframe = rightframe
48-
leftframe.pack(side="left", fill="both", expand=1)
49-
# Create help label
50-
self.helplabel = Label(leftframe, text="Module %s" % name,
51-
relief="groove", borderwidth=2)
52-
self.helplabel.pack(fill="x")
53-
# Create top frame, with scrollbar and listbox
54-
self.classviewer = ClassViewer(
55-
self.leftframe, self.flist, self)
56-
# Load the classes
57-
self.load_classes(dict, name)
28+
def __init__(self, flist, name, path):
29+
self.name = name
30+
self.file = os.path.join(path[0], self.name + ".py")
31+
self.init(flist)
5832

5933
def close(self, event=None):
60-
self.classviewer = None
61-
self.methodviewer = None
6234
self.top.destroy()
6335

64-
def load_classes(self, dict, module):
65-
self.classviewer.load_classes(dict, module)
66-
if self.methodframe:
67-
self.methodframe.destroy()
68-
self.methodframe = None
69-
self.methodviewer = None
70-
71-
methodframe = None
72-
methodhelplabel = None
73-
methodviewer = None
74-
75-
def show_methods(self, cl):
76-
if not self.methodframe:
77-
self.methodframe = Frame(self.rightframe)
78-
self.methodframe.pack(side="right", expand=1, fill="both")
79-
self.methodhelplabel = Label(self.methodframe,
80-
relief="groove", borderwidth=2)
81-
self.methodhelplabel.pack(fill="x")
82-
self.methodviewer = MethodViewer(self.methodframe, self.flist)
83-
self.methodhelplabel.config(text="Class %s" % cl.name)
84-
self.methodviewer.load_methods(cl)
85-
86-
87-
class ClassViewer(ScrolledList):
88-
89-
def __init__(self, master, flist, browser):
90-
ScrolledList.__init__(self, master, width=40)
36+
def init(self, flist):
9137
self.flist = flist
92-
self.browser = browser
93-
94-
def load_classes(self, dict, module):
95-
self.clear()
96-
self.dict = dict
38+
# reset pyclbr
39+
pyclbr._modules.clear()
40+
# create top
41+
self.top = top = ListedToplevel(flist.root)
42+
top.protocol("WM_DELETE_WINDOW", self.close)
43+
top.bind("<Escape>", self.close)
44+
self.settitle()
45+
top.focus_set()
46+
# create scrolled canvas
47+
sc = ScrolledCanvas(top, bg="white", highlightthickness=0, takefocus=1)
48+
sc.frame.pack(expand=1, fill="both")
49+
item = self.rootnode()
50+
node = TreeNode(sc.canvas, None, item)
51+
node.update()
52+
node.expand()
53+
54+
def settitle(self):
55+
self.top.wm_title("Class Browser - " + self.name)
56+
self.top.wm_iconname("Class Browser")
57+
58+
def rootnode(self):
59+
return ModuleBrowserTreeItem(self.file)
60+
61+
class ModuleBrowserTreeItem(TreeItem):
62+
63+
def __init__(self, file):
64+
self.file = file
65+
66+
def GetText(self):
67+
return os.path.basename(self.file)
68+
69+
def GetIconName(self):
70+
return "python"
71+
72+
def GetSubList(self):
73+
sublist = []
74+
for name in self.listclasses():
75+
item = ClassBrowserTreeItem(name, self.classes, self.file)
76+
sublist.append(item)
77+
return sublist
78+
79+
def OnDoubleClick(self):
80+
if os.path.normcase(self.file[-3:]) != ".py":
81+
return
82+
if not os.path.exists(self.file):
83+
return
84+
PyShell.flist.open(self.file)
85+
86+
def IsExpandable(self):
87+
return os.path.normcase(self.file[-3:]) == ".py"
88+
89+
def listclasses(self):
90+
dir, file = os.path.split(self.file)
91+
name, ext = os.path.splitext(file)
92+
if os.path.normcase(ext) != ".py":
93+
return []
94+
try:
95+
dict = pyclbr.readmodule(name, [dir] + sys.path)
96+
except ImportError, msg:
97+
return []
9798
items = []
98-
for key, value in dict.items():
99-
if value.module == module:
100-
items.append((value.lineno, key, value))
99+
self.classes = {}
100+
for key, cl in dict.items():
101+
if cl.module == name:
102+
s = key
103+
if cl.super:
104+
supers = []
105+
for sup in cl.super:
106+
if type(sup) is type(''):
107+
sname = sup
108+
else:
109+
sname = sup.name
110+
if sup.module != cl.module:
111+
sname = "%s.%s" % (sup.module, sname)
112+
supers.append(sname)
113+
s = s + "(%s)" % string.join(supers, ", ")
114+
items.append((cl.lineno, s))
115+
self.classes[s] = cl
101116
items.sort()
102-
for lineno, key, value in items:
103-
s = key
104-
if value.super:
105-
super = []
106-
for sup in value.super:
107-
name = sup.name
108-
if sup.module != value.module:
109-
name = "%s.%s" % (sup.module, name)
110-
super.append(name)
111-
s = s + "(%s)" % string.join(super, ", ")
112-
self.append(s)
113-
114-
def getname(self, index):
115-
name = self.listbox.get(index)
116-
i = string.find(name, '(')
117-
if i >= 0:
118-
name = name[:i]
119-
return name
117+
list = []
118+
for item, s in items:
119+
list.append(s)
120+
return list
120121

121-
def getclass(self, index):
122-
return self.dict[self.getname(index)]
122+
class ClassBrowserTreeItem(TreeItem):
123123

124-
def on_select(self, index):
125-
self.show_methods(index)
124+
def __init__(self, name, classes, file):
125+
self.name = name
126+
self.classes = classes
127+
self.file = file
126128

127-
def on_double(self, index):
128-
self.show_source(index)
129+
def GetText(self):
130+
return "class " + self.name
129131

130-
def show_methods(self, index):
131-
cl = self.getclass(index)
132-
self.browser.show_methods(cl)
133-
134-
def show_source(self, index):
135-
cl = self.getclass(index)
136-
if os.path.isfile(cl.file):
137-
edit = self.flist.open(cl.file)
138-
edit.gotoline(cl.lineno)
139-
140-
141-
class MethodViewer(ScrolledList):
142-
143-
def __init__(self, master, flist):
144-
ScrolledList.__init__(self, master)
145-
self.flist = flist
146-
147-
classinfo = None
132+
def IsExpandable(self):
133+
try:
134+
cl = self.classes[self.name]
135+
except (IndexError, KeyError):
136+
return 0
137+
else:
138+
return not not cl.methods
139+
140+
def GetSubList(self):
141+
sublist = []
142+
for name in self.listmethods():
143+
item = MethodBrowserTreeItem(
144+
name, self.classes[self.name], self.file)
145+
sublist.append(item)
146+
return sublist
147+
148+
def OnDoubleClick(self):
149+
if not os.path.exists(self.file):
150+
return
151+
edit = PyShell.flist.open(self.file)
152+
if self.classes.has_key(self.name):
153+
cl = self.classes[self.name]
154+
else:
155+
name = self.name
156+
i = string.find(name, '(')
157+
if i < 0:
158+
return
159+
name = name[:i]
160+
if not self.classes.has_key(name):
161+
return
162+
cl = self.classes[name]
163+
if not hasattr(cl, 'lineno'):
164+
return
165+
lineno = cl.lineno
166+
edit.gotoline(lineno)
148167

149-
def load_methods(self, cl):
150-
self.classinfo = cl
151-
self.clear()
168+
def listmethods(self):
169+
try:
170+
cl = self.classes[self.name]
171+
except (IndexError, KeyError):
172+
return []
152173
items = []
153174
for name, lineno in cl.methods.items():
154175
items.append((lineno, name))
155176
items.sort()
177+
list = []
156178
for item, name in items:
157-
self.append(name)
179+
list.append(name)
180+
return list
181+
182+
class MethodBrowserTreeItem(TreeItem):
158183

159-
def click_event(self, event):
160-
pass
184+
def __init__(self, name, cl, file):
185+
self.name = name
186+
self.cl = cl
187+
self.file = file
161188

162-
def on_double(self, index):
163-
self.show_source(self.get(index))
189+
def GetText(self):
190+
return "def " + self.name + "(...)"
164191

165-
def show_source(self, name):
166-
if os.path.isfile(self.classinfo.file):
167-
edit = self.flist.open(self.classinfo.file)
168-
edit.gotoline(self.classinfo.methods[name])
192+
def GetIconName(self):
193+
return "python" # XXX
194+
195+
def IsExpandable(self):
196+
return 0
197+
198+
def OnDoubleClick(self):
199+
if not os.path.exists(self.file):
200+
return
201+
edit = PyShell.flist.open(self.file)
202+
edit.gotoline(self.cl.methods[self.name])
203+
204+
def main():
205+
try:
206+
file = __file__
207+
except NameError:
208+
file = sys.argv[0]
209+
if sys.argv[1:]:
210+
file = sys.argv[1]
211+
else:
212+
file = sys.argv[0]
213+
dir, file = os.path.split(file)
214+
name = os.path.splitext(file)[0]
215+
ClassBrowser(PyShell.flist, name, [dir])
216+
if sys.stdin is sys.__stdin__:
217+
mainloop()
218+
219+
if __name__ == "__main__":
220+
main()

0 commit comments

Comments
 (0)