| 
									
										
										
										
											1999-06-01 18:21:31 +00:00
										 |  |  | """Class browser.
 | 
					
						
							| 
									
										
										
										
											1998-10-13 16:31:03 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | XXX TO DO: | 
					
						
							| 
									
										
										
										
											1999-01-02 21:28:54 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-06-01 18:21:31 +00:00
										 |  |  | - reparse when source changed (maybe just a button would be OK?) | 
					
						
							|  |  |  |     (or recheck on window popup) | 
					
						
							| 
									
										
										
										
											1998-10-13 16:31:03 +00:00
										 |  |  | - add popup menu with more options (e.g. doc strings, base classes, imports) | 
					
						
							| 
									
										
										
										
											1999-06-01 18:21:31 +00:00
										 |  |  | - show function argument list? (have to do pattern matching on source) | 
					
						
							| 
									
										
										
										
											1998-10-13 16:31:03 +00:00
										 |  |  | - should the classes and methods lists also be in the module's menu bar? | 
					
						
							| 
									
										
										
										
											1999-06-01 18:21:31 +00:00
										 |  |  | - add base classes to class browser tree | 
					
						
							| 
									
										
										
										
											1998-10-13 16:31:03 +00:00
										 |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-10-15 23:27:08 +00:00
										 |  |  | import os | 
					
						
							| 
									
										
										
										
											1999-06-01 18:21:31 +00:00
										 |  |  | import sys | 
					
						
							| 
									
										
										
										
											1998-10-13 03:59:57 +00:00
										 |  |  | import string | 
					
						
							|  |  |  | import pyclbr | 
					
						
							| 
									
										
										
										
											1998-10-15 23:27:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-06-10 15:19:14 +00:00
										 |  |  | # XXX Patch pyclbr with dummies if it's vintage Python 1.5.2: | 
					
						
							|  |  |  | if not hasattr(pyclbr, "readmodule_ex"): | 
					
						
							|  |  |  |     pyclbr.readmodule_ex = pyclbr.readmodule | 
					
						
							|  |  |  | if not hasattr(pyclbr, "Function"): | 
					
						
							|  |  |  |     class Function(pyclbr.Class): | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  |     pyclbr.Function = Function | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-06-01 18:21:31 +00:00
										 |  |  | import PyShell | 
					
						
							|  |  |  | from WindowList import ListedToplevel | 
					
						
							|  |  |  | from TreeWidget import TreeNode, TreeItem, ScrolledCanvas | 
					
						
							| 
									
										
										
										
											1998-10-15 23:27:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-10-13 03:59:57 +00:00
										 |  |  | class ClassBrowser: | 
					
						
							| 
									
										
										
										
											1999-01-02 21:28:54 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-06-01 18:21:31 +00:00
										 |  |  |     def __init__(self, flist, name, path): | 
					
						
							| 
									
										
										
										
											2000-02-15 18:02:11 +00:00
										 |  |  |         # XXX This API should change, if the file doesn't end in ".py" | 
					
						
							|  |  |  |         # XXX the code here is bogus! | 
					
						
							| 
									
										
										
										
											1999-06-01 18:21:31 +00:00
										 |  |  |         self.name = name | 
					
						
							|  |  |  |         self.file = os.path.join(path[0], self.name + ".py") | 
					
						
							|  |  |  |         self.init(flist) | 
					
						
							| 
									
										
										
										
											1999-01-02 21:28:54 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-01-11 14:46:06 +00:00
										 |  |  |     def close(self, event=None): | 
					
						
							| 
									
										
										
										
											1998-10-13 16:31:03 +00:00
										 |  |  |         self.top.destroy() | 
					
						
							| 
									
										
										
										
											1999-06-25 17:08:19 +00:00
										 |  |  |         self.node.destroy() | 
					
						
							| 
									
										
										
										
											1999-01-02 21:28:54 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-06-01 18:21:31 +00:00
										 |  |  |     def init(self, flist): | 
					
						
							| 
									
										
										
										
											1998-10-15 23:27:08 +00:00
										 |  |  |         self.flist = flist | 
					
						
							| 
									
										
										
										
											1999-06-01 18:21:31 +00:00
										 |  |  |         # 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() | 
					
						
							| 
									
										
										
										
											1999-06-25 17:08:19 +00:00
										 |  |  |         self.node = node = TreeNode(sc.canvas, None, item) | 
					
						
							| 
									
										
										
										
											1999-06-01 18:21:31 +00:00
										 |  |  |         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: | 
					
						
							| 
									
										
										
										
											1999-06-10 15:19:14 +00:00
										 |  |  |             dict = pyclbr.readmodule_ex(name, [dir] + sys.path) | 
					
						
							| 
									
										
										
										
											1999-06-01 18:21:31 +00:00
										 |  |  |         except ImportError, msg: | 
					
						
							|  |  |  |             return [] | 
					
						
							| 
									
										
										
										
											1998-10-13 16:31:03 +00:00
										 |  |  |         items = [] | 
					
						
							| 
									
										
										
										
											1999-06-01 18:21:31 +00:00
										 |  |  |         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 | 
					
						
							| 
									
										
										
										
											1998-10-13 03:59:57 +00:00
										 |  |  |         items.sort() | 
					
						
							| 
									
										
										
										
											1999-06-01 18:21:31 +00:00
										 |  |  |         list = [] | 
					
						
							|  |  |  |         for item, s in items: | 
					
						
							|  |  |  |             list.append(s) | 
					
						
							|  |  |  |         return list | 
					
						
							| 
									
										
										
										
											1998-10-13 16:31:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-06-01 18:21:31 +00:00
										 |  |  | class ClassBrowserTreeItem(TreeItem): | 
					
						
							| 
									
										
										
										
											1999-01-02 21:28:54 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-06-01 18:21:31 +00:00
										 |  |  |     def __init__(self, name, classes, file): | 
					
						
							|  |  |  |         self.name = name | 
					
						
							|  |  |  |         self.classes = classes | 
					
						
							|  |  |  |         self.file = file | 
					
						
							| 
									
										
										
										
											1999-06-10 15:19:14 +00:00
										 |  |  |         try: | 
					
						
							|  |  |  |             self.cl = self.classes[self.name] | 
					
						
							|  |  |  |         except (IndexError, KeyError): | 
					
						
							|  |  |  |             self.cl = None | 
					
						
							|  |  |  |         self.isfunction = isinstance(self.cl, pyclbr.Function) | 
					
						
							| 
									
										
										
										
											1999-01-02 21:28:54 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-06-01 18:21:31 +00:00
										 |  |  |     def GetText(self): | 
					
						
							| 
									
										
										
										
											1999-06-10 15:19:14 +00:00
										 |  |  |         if self.isfunction: | 
					
						
							|  |  |  |             return "def " + self.name + "(...)" | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             return "class " + self.name | 
					
						
							| 
									
										
										
										
											1999-01-02 21:28:54 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-06-10 15:19:14 +00:00
										 |  |  |     def GetIconName(self): | 
					
						
							|  |  |  |         if self.isfunction: | 
					
						
							|  |  |  |             return "python" | 
					
						
							| 
									
										
										
										
											1999-06-01 18:21:31 +00:00
										 |  |  |         else: | 
					
						
							| 
									
										
										
										
											1999-06-10 15:19:14 +00:00
										 |  |  |             return "folder" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def IsExpandable(self): | 
					
						
							|  |  |  |         if self.cl: | 
					
						
							|  |  |  |             return not not self.cl.methods | 
					
						
							| 
									
										
										
										
											1999-06-01 18:21:31 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def GetSubList(self): | 
					
						
							| 
									
										
										
										
											1999-06-10 15:19:14 +00:00
										 |  |  |         if not self.cl: | 
					
						
							|  |  |  |             return [] | 
					
						
							| 
									
										
										
										
											1999-06-01 18:21:31 +00:00
										 |  |  |         sublist = [] | 
					
						
							|  |  |  |         for name in self.listmethods(): | 
					
						
							| 
									
										
										
										
											1999-06-10 15:19:14 +00:00
										 |  |  |             item = MethodBrowserTreeItem(name, self.cl, self.file) | 
					
						
							| 
									
										
										
										
											1999-06-01 18:21:31 +00:00
										 |  |  |             sublist.append(item) | 
					
						
							|  |  |  |         return sublist | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def OnDoubleClick(self): | 
					
						
							|  |  |  |         if not os.path.exists(self.file): | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         edit = PyShell.flist.open(self.file) | 
					
						
							| 
									
										
										
										
											1999-06-10 15:19:14 +00:00
										 |  |  |         if hasattr(self.cl, 'lineno'): | 
					
						
							|  |  |  |             lineno = self.cl.lineno | 
					
						
							|  |  |  |             edit.gotoline(lineno) | 
					
						
							| 
									
										
										
										
											1999-01-02 21:28:54 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-06-01 18:21:31 +00:00
										 |  |  |     def listmethods(self): | 
					
						
							| 
									
										
										
										
											1999-06-10 15:19:14 +00:00
										 |  |  |         if not self.cl: | 
					
						
							| 
									
										
										
										
											1999-06-01 18:21:31 +00:00
										 |  |  |             return [] | 
					
						
							| 
									
										
										
										
											1998-10-13 16:31:03 +00:00
										 |  |  |         items = [] | 
					
						
							| 
									
										
										
										
											1999-06-10 15:19:14 +00:00
										 |  |  |         for name, lineno in self.cl.methods.items(): | 
					
						
							| 
									
										
										
										
											1998-10-13 16:31:03 +00:00
										 |  |  |             items.append((lineno, name)) | 
					
						
							|  |  |  |         items.sort() | 
					
						
							| 
									
										
										
										
											1999-06-01 18:21:31 +00:00
										 |  |  |         list = [] | 
					
						
							| 
									
										
										
										
											1998-10-13 16:31:03 +00:00
										 |  |  |         for item, name in items: | 
					
						
							| 
									
										
										
										
											1999-06-01 18:21:31 +00:00
										 |  |  |             list.append(name) | 
					
						
							|  |  |  |         return list | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class MethodBrowserTreeItem(TreeItem): | 
					
						
							| 
									
										
										
										
											1998-10-13 16:31:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-06-01 18:21:31 +00:00
										 |  |  |     def __init__(self, name, cl, file): | 
					
						
							|  |  |  |         self.name = name | 
					
						
							|  |  |  |         self.cl = cl | 
					
						
							|  |  |  |         self.file = file | 
					
						
							| 
									
										
										
										
											1999-01-02 21:28:54 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-06-01 18:21:31 +00:00
										 |  |  |     def GetText(self): | 
					
						
							|  |  |  |         return "def " + self.name + "(...)" | 
					
						
							| 
									
										
										
										
											1999-01-02 21:28:54 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-06-01 18:21:31 +00:00
										 |  |  |     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() |