More installation info. Bump alpha version.
[python/dscho.git] / Tools / idle / ClassBrowser.py
blob338836a9fa332f573250f3a42809e420efbe3481
1 """Class browser.
3 XXX TO DO:
5 - reparse when source changed (maybe just a button would be OK?)
6 (or recheck on window popup)
7 - add popup menu with more options (e.g. doc strings, base classes, imports)
8 - show function argument list? (have to do pattern matching on source)
9 - should the classes and methods lists also be in the module's menu bar?
10 - add base classes to class browser tree
11 """
13 import os
14 import sys
15 import pyclbr
17 import PyShell
18 from WindowList import ListedToplevel
19 from TreeWidget import TreeNode, TreeItem, ScrolledCanvas
21 class ClassBrowser:
23 def __init__(self, flist, name, path):
24 # XXX This API should change, if the file doesn't end in ".py"
25 # XXX the code here is bogus!
26 self.name = name
27 self.file = os.path.join(path[0], self.name + ".py")
28 self.init(flist)
30 def close(self, event=None):
31 self.top.destroy()
32 self.node.destroy()
34 def init(self, flist):
35 self.flist = flist
36 # reset pyclbr
37 pyclbr._modules.clear()
38 # create top
39 self.top = top = ListedToplevel(flist.root)
40 top.protocol("WM_DELETE_WINDOW", self.close)
41 top.bind("<Escape>", self.close)
42 self.settitle()
43 top.focus_set()
44 # create scrolled canvas
45 sc = ScrolledCanvas(top, bg="white", highlightthickness=0, takefocus=1)
46 sc.frame.pack(expand=1, fill="both")
47 item = self.rootnode()
48 self.node = node = TreeNode(sc.canvas, None, item)
49 node.update()
50 node.expand()
52 def settitle(self):
53 self.top.wm_title("Class Browser - " + self.name)
54 self.top.wm_iconname("Class Browser")
56 def rootnode(self):
57 return ModuleBrowserTreeItem(self.file)
59 class ModuleBrowserTreeItem(TreeItem):
61 def __init__(self, file):
62 self.file = file
64 def GetText(self):
65 return os.path.basename(self.file)
67 def GetIconName(self):
68 return "python"
70 def GetSubList(self):
71 sublist = []
72 for name in self.listclasses():
73 item = ClassBrowserTreeItem(name, self.classes, self.file)
74 sublist.append(item)
75 return sublist
77 def OnDoubleClick(self):
78 if os.path.normcase(self.file[-3:]) != ".py":
79 return
80 if not os.path.exists(self.file):
81 return
82 PyShell.flist.open(self.file)
84 def IsExpandable(self):
85 return os.path.normcase(self.file[-3:]) == ".py"
87 def listclasses(self):
88 dir, file = os.path.split(self.file)
89 name, ext = os.path.splitext(file)
90 if os.path.normcase(ext) != ".py":
91 return []
92 try:
93 dict = pyclbr.readmodule_ex(name, [dir] + sys.path)
94 except ImportError, msg:
95 return []
96 items = []
97 self.classes = {}
98 for key, cl in dict.items():
99 if cl.module == name:
100 s = key
101 if cl.super:
102 supers = []
103 for sup in cl.super:
104 if type(sup) is type(''):
105 sname = sup
106 else:
107 sname = sup.name
108 if sup.module != cl.module:
109 sname = "%s.%s" % (sup.module, sname)
110 supers.append(sname)
111 s = s + "(%s)" % ", ".join(supers)
112 items.append((cl.lineno, s))
113 self.classes[s] = cl
114 items.sort()
115 list = []
116 for item, s in items:
117 list.append(s)
118 return list
120 class ClassBrowserTreeItem(TreeItem):
122 def __init__(self, name, classes, file):
123 self.name = name
124 self.classes = classes
125 self.file = file
126 try:
127 self.cl = self.classes[self.name]
128 except (IndexError, KeyError):
129 self.cl = None
130 self.isfunction = isinstance(self.cl, pyclbr.Function)
132 def GetText(self):
133 if self.isfunction:
134 return "def " + self.name + "(...)"
135 else:
136 return "class " + self.name
138 def GetIconName(self):
139 if self.isfunction:
140 return "python"
141 else:
142 return "folder"
144 def IsExpandable(self):
145 if self.cl:
146 return not not self.cl.methods
148 def GetSubList(self):
149 if not self.cl:
150 return []
151 sublist = []
152 for name in self.listmethods():
153 item = MethodBrowserTreeItem(name, self.cl, self.file)
154 sublist.append(item)
155 return sublist
157 def OnDoubleClick(self):
158 if not os.path.exists(self.file):
159 return
160 edit = PyShell.flist.open(self.file)
161 if hasattr(self.cl, 'lineno'):
162 lineno = self.cl.lineno
163 edit.gotoline(lineno)
165 def listmethods(self):
166 if not self.cl:
167 return []
168 items = []
169 for name, lineno in self.cl.methods.items():
170 items.append((lineno, name))
171 items.sort()
172 list = []
173 for item, name in items:
174 list.append(name)
175 return list
177 class MethodBrowserTreeItem(TreeItem):
179 def __init__(self, name, cl, file):
180 self.name = name
181 self.cl = cl
182 self.file = file
184 def GetText(self):
185 return "def " + self.name + "(...)"
187 def GetIconName(self):
188 return "python" # XXX
190 def IsExpandable(self):
191 return 0
193 def OnDoubleClick(self):
194 if not os.path.exists(self.file):
195 return
196 edit = PyShell.flist.open(self.file)
197 edit.gotoline(self.cl.methods[self.name])
199 def main():
200 try:
201 file = __file__
202 except NameError:
203 file = sys.argv[0]
204 if sys.argv[1:]:
205 file = sys.argv[1]
206 else:
207 file = sys.argv[0]
208 dir, file = os.path.split(file)
209 name = os.path.splitext(file)[0]
210 ClassBrowser(PyShell.flist, name, [dir])
211 if sys.stdin is sys.__stdin__:
212 mainloop()
214 if __name__ == "__main__":
215 main()