0001 """Class browser. 0002 0003 XXX TO DO: 0004 0005 - reparse when source changed (maybe just a button would be OK?) 0006 (or recheck on window popup) 0007 - add popup menu with more options (e.g. doc strings, base classes, imports) 0008 - show function argument list? (have to do pattern matching on source) 0009 - should the classes and methods lists also be in the module's menu bar? 0010 - add base classes to class browser tree 0011 """ 0012 0013 import os 0014 import sys 0015 import pyclbr 0016 0017 import PyShell 0018 from WindowList import ListedToplevel 0019 from TreeWidget import TreeNode, TreeItem, ScrolledCanvas 0020 from configHandler import idleConf 0021 0022 class ClassBrowser: 0023 0024 def __init__(self, flist, name, path): 0025 # XXX This API should change, if the file doesn't end in ".py" 0026 # XXX the code here is bogus! 0027 self.name = name 0028 self.file = os.path.join(path[0], self.name + ".py") 0029 self.init(flist) 0030 0031 def close(self, event=None): 0032 self.top.destroy() 0033 self.node.destroy() 0034 0035 def init(self, flist): 0036 self.flist = flist 0037 # reset pyclbr 0038 pyclbr._modules.clear() 0039 # create top 0040 self.top = top = ListedToplevel(flist.root) 0041 top.protocol("WM_DELETE_WINDOW", self.close) 0042 top.bind("<Escape>", self.close) 0043 self.settitle() 0044 top.focus_set() 0045 # create scrolled canvas 0046 theme = idleConf.GetOption('main','Theme','name') 0047 background = idleConf.GetHighlight(theme, 'normal')['background'] 0048 sc = ScrolledCanvas(top, bg=background, highlightthickness=0, takefocus=1) 0049 sc.frame.pack(expand=1, fill="both") 0050 item = self.rootnode() 0051 self.node = node = TreeNode(sc.canvas, None, item) 0052 node.update() 0053 node.expand() 0054 0055 def settitle(self): 0056 self.top.wm_title("Class Browser - " + self.name) 0057 self.top.wm_iconname("Class Browser") 0058 0059 def rootnode(self): 0060 return ModuleBrowserTreeItem(self.file) 0061 0062 class ModuleBrowserTreeItem(TreeItem): 0063 0064 def __init__(self, file): 0065 self.file = file 0066 0067 def GetText(self): 0068 return os.path.basename(self.file) 0069 0070 def GetIconName(self): 0071 return "python" 0072 0073 def GetSubList(self): 0074 sublist = [] 0075 for name in self.listclasses(): 0076 item = ClassBrowserTreeItem(name, self.classes, self.file) 0077 sublist.append(item) 0078 return sublist 0079 0080 def OnDoubleClick(self): 0081 if os.path.normcase(self.file[-3:]) != ".py": 0082 return 0083 if not os.path.exists(self.file): 0084 return 0085 PyShell.flist.open(self.file) 0086 0087 def IsExpandable(self): 0088 return os.path.normcase(self.file[-3:]) == ".py" 0089 0090 def listclasses(self): 0091 dir, file = os.path.split(self.file) 0092 name, ext = os.path.splitext(file) 0093 if os.path.normcase(ext) != ".py": 0094 return [] 0095 try: 0096 dict = pyclbr.readmodule_ex(name, [dir] + sys.path) 0097 except ImportError, msg: 0098 return [] 0099 items = [] 0100 self.classes = {} 0101 for key, cl in dict.items(): 0102 if cl.module == name: 0103 s = key 0104 if hasattr(cl, 'super') and cl.super: 0105 supers = [] 0106 for sup in cl.super: 0107 if type(sup) is type(''): 0108 sname = sup 0109 else: 0110 sname = sup.name 0111 if sup.module != cl.module: 0112 sname = "%s.%s" % (sup.module, sname) 0113 supers.append(sname) 0114 s = s + "(%s)" % ", ".join(supers) 0115 items.append((cl.lineno, s)) 0116 self.classes[s] = cl 0117 items.sort() 0118 list = [] 0119 for item, s in items: 0120 list.append(s) 0121 return list 0122 0123 class ClassBrowserTreeItem(TreeItem): 0124 0125 def __init__(self, name, classes, file): 0126 self.name = name 0127 self.classes = classes 0128 self.file = file 0129 try: 0130 self.cl = self.classes[self.name] 0131 except (IndexError, KeyError): 0132 self.cl = None 0133 self.isfunction = isinstance(self.cl, pyclbr.Function) 0134 0135 def GetText(self): 0136 if self.isfunction: 0137 return "def " + self.name + "(...)" 0138 else: 0139 return "class " + self.name 0140 0141 def GetIconName(self): 0142 if self.isfunction: 0143 return "python" 0144 else: 0145 return "folder" 0146 0147 def IsExpandable(self): 0148 if self.cl: 0149 try: 0150 return not not self.cl.methods 0151 except AttributeError: 0152 return False 0153 0154 def GetSubList(self): 0155 if not self.cl: 0156 return [] 0157 sublist = [] 0158 for name in self.listmethods(): 0159 item = MethodBrowserTreeItem(name, self.cl, self.file) 0160 sublist.append(item) 0161 return sublist 0162 0163 def OnDoubleClick(self): 0164 if not os.path.exists(self.file): 0165 return 0166 edit = PyShell.flist.open(self.file) 0167 if hasattr(self.cl, 'lineno'): 0168 lineno = self.cl.lineno 0169 edit.gotoline(lineno) 0170 0171 def listmethods(self): 0172 if not self.cl: 0173 return [] 0174 items = [] 0175 for name, lineno in self.cl.methods.items(): 0176 items.append((lineno, name)) 0177 items.sort() 0178 list = [] 0179 for item, name in items: 0180 list.append(name) 0181 return list 0182 0183 class MethodBrowserTreeItem(TreeItem): 0184 0185 def __init__(self, name, cl, file): 0186 self.name = name 0187 self.cl = cl 0188 self.file = file 0189 0190 def GetText(self): 0191 return "def " + self.name + "(...)" 0192 0193 def GetIconName(self): 0194 return "python" # XXX 0195 0196 def IsExpandable(self): 0197 return 0 0198 0199 def OnDoubleClick(self): 0200 if not os.path.exists(self.file): 0201 return 0202 edit = PyShell.flist.open(self.file) 0203 edit.gotoline(self.cl.methods[self.name]) 0204 0205 def main(): 0206 try: 0207 file = __file__ 0208 except NameError: 0209 file = sys.argv[0] 0210 if sys.argv[1:]: 0211 file = sys.argv[1] 0212 else: 0213 file = sys.argv[0] 0214 dir, file = os.path.split(file) 0215 name = os.path.splitext(file)[0] 0216 ClassBrowser(PyShell.flist, name, [dir]) 0217 if sys.stdin is sys.__stdin__: 0218 mainloop() 0219 0220 if __name__ == "__main__": 0221 main() 0222
Generated by PyXR 0.9.4