221 lines · 6.2 KB · Python
RawDownload
"""Class browser. XXX TO DO: - 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)- should the classes and methods lists also be in the module's menu bar?- add base classes to class browser tree""" import osimport sysimport pyclbr import PyShellfrom WindowList import ListedToplevelfrom TreeWidget import TreeNode, TreeItem, ScrolledCanvasfrom configHandler import idleConf class ClassBrowser:     def __init__(self, flist, name, path):        # XXX This API should change, if the file doesn't end in ".py"        # XXX the code here is bogus!        self.name = name        self.file = os.path.join(path[0], self.name + ".py")        self.init(flist)     def close(self, event=None):        self.top.destroy()        self.node.destroy()     def init(self, flist):        self.flist = flist        # 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        theme = idleConf.GetOption('main','Theme','name')        background = idleConf.GetHighlight(theme, 'normal')['background']        sc = ScrolledCanvas(top, bg=background, highlightthickness=0, takefocus=1)        sc.frame.pack(expand=1, fill="both")        item = self.rootnode()        self.node = 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_ex(name, [dir] + sys.path)        except ImportError, msg:            return []        items = []        self.classes = {}        for key, cl in dict.items():            if cl.module == name:                s = key                if hasattr(cl, 'super') and 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)" % ", ".join(supers)                items.append((cl.lineno, s))                self.classes[s] = cl        items.sort()        list = []        for item, s in items:            list.append(s)        return list class ClassBrowserTreeItem(TreeItem):     def __init__(self, name, classes, file):        self.name = name        self.classes = classes        self.file = file        try:            self.cl = self.classes[self.name]        except (IndexError, KeyError):            self.cl = None        self.isfunction = isinstance(self.cl, pyclbr.Function)     def GetText(self):        if self.isfunction:            return "def " + self.name + "(...)"        else:            return "class " + self.name     def GetIconName(self):        if self.isfunction:            return "python"        else:            return "folder"     def IsExpandable(self):        if self.cl:            try:                return not not self.cl.methods            except AttributeError:                return False     def GetSubList(self):        if not self.cl:            return []        sublist = []        for name in self.listmethods():            item = MethodBrowserTreeItem(name, self.cl, 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 hasattr(self.cl, 'lineno'):            lineno = self.cl.lineno            edit.gotoline(lineno)     def listmethods(self):        if not self.cl:            return []        items = []        for name, lineno in self.cl.methods.items():            items.append((lineno, name))        items.sort()        list = []        for item, name in items:            list.append(name)        return list class MethodBrowserTreeItem(TreeItem):     def __init__(self, name, cl, file):        self.name = name        self.cl = cl        self.file = file     def GetText(self):        return "def " + self.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()