PageRenderTime 52ms CodeModel.GetById 38ms app.highlight 12ms RepoModel.GetById 1ms app.codeStats 0ms

/Lib/idlelib/ClassBrowser.py

http://unladen-swallow.googlecode.com/
Python | 221 lines | 183 code | 12 blank | 26 comment | 15 complexity | 5fb8da23ad9a843cf649c8ebc2e8215e MD5 | raw file
  1"""Class browser.
  2
  3XXX TO DO:
  4
  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"""
 12
 13import os
 14import sys
 15import pyclbr
 16
 17import PyShell
 18from WindowList import ListedToplevel
 19from TreeWidget import TreeNode, TreeItem, ScrolledCanvas
 20from configHandler import idleConf
 21
 22class ClassBrowser:
 23
 24    def __init__(self, flist, name, path):
 25        # XXX This API should change, if the file doesn't end in ".py"
 26        # XXX the code here is bogus!
 27        self.name = name
 28        self.file = os.path.join(path[0], self.name + ".py")
 29        self.init(flist)
 30
 31    def close(self, event=None):
 32        self.top.destroy()
 33        self.node.destroy()
 34
 35    def init(self, flist):
 36        self.flist = flist
 37        # reset pyclbr
 38        pyclbr._modules.clear()
 39        # create top
 40        self.top = top = ListedToplevel(flist.root)
 41        top.protocol("WM_DELETE_WINDOW", self.close)
 42        top.bind("<Escape>", self.close)
 43        self.settitle()
 44        top.focus_set()
 45        # create scrolled canvas
 46        theme = idleConf.GetOption('main','Theme','name')
 47        background = idleConf.GetHighlight(theme, 'normal')['background']
 48        sc = ScrolledCanvas(top, bg=background, highlightthickness=0, takefocus=1)
 49        sc.frame.pack(expand=1, fill="both")
 50        item = self.rootnode()
 51        self.node = node = TreeNode(sc.canvas, None, item)
 52        node.update()
 53        node.expand()
 54
 55    def settitle(self):
 56        self.top.wm_title("Class Browser - " + self.name)
 57        self.top.wm_iconname("Class Browser")
 58
 59    def rootnode(self):
 60        return ModuleBrowserTreeItem(self.file)
 61
 62class ModuleBrowserTreeItem(TreeItem):
 63
 64    def __init__(self, file):
 65        self.file = file
 66
 67    def GetText(self):
 68        return os.path.basename(self.file)
 69
 70    def GetIconName(self):
 71        return "python"
 72
 73    def GetSubList(self):
 74        sublist = []
 75        for name in self.listclasses():
 76            item = ClassBrowserTreeItem(name, self.classes, self.file)
 77            sublist.append(item)
 78        return sublist
 79
 80    def OnDoubleClick(self):
 81        if os.path.normcase(self.file[-3:]) != ".py":
 82            return
 83        if not os.path.exists(self.file):
 84            return
 85        PyShell.flist.open(self.file)
 86
 87    def IsExpandable(self):
 88        return os.path.normcase(self.file[-3:]) == ".py"
 89
 90    def listclasses(self):
 91        dir, file = os.path.split(self.file)
 92        name, ext = os.path.splitext(file)
 93        if os.path.normcase(ext) != ".py":
 94            return []
 95        try:
 96            dict = pyclbr.readmodule_ex(name, [dir] + sys.path)
 97        except ImportError, msg:
 98            return []
 99        items = []
100        self.classes = {}
101        for key, cl in dict.items():
102            if cl.module == name:
103                s = key
104                if hasattr(cl, 'super') and cl.super:
105                    supers = []
106                    for sup in cl.super:
107                        if type(sup) is type(''):
108                            sname = sup
109                        else:
110                            sname = sup.name
111                            if sup.module != cl.module:
112                                sname = "%s.%s" % (sup.module, sname)
113                        supers.append(sname)
114                    s = s + "(%s)" % ", ".join(supers)
115                items.append((cl.lineno, s))
116                self.classes[s] = cl
117        items.sort()
118        list = []
119        for item, s in items:
120            list.append(s)
121        return list
122
123class ClassBrowserTreeItem(TreeItem):
124
125    def __init__(self, name, classes, file):
126        self.name = name
127        self.classes = classes
128        self.file = file
129        try:
130            self.cl = self.classes[self.name]
131        except (IndexError, KeyError):
132            self.cl = None
133        self.isfunction = isinstance(self.cl, pyclbr.Function)
134
135    def GetText(self):
136        if self.isfunction:
137            return "def " + self.name + "(...)"
138        else:
139            return "class " + self.name
140
141    def GetIconName(self):
142        if self.isfunction:
143            return "python"
144        else:
145            return "folder"
146
147    def IsExpandable(self):
148        if self.cl:
149            try:
150                return not not self.cl.methods
151            except AttributeError:
152                return False
153
154    def GetSubList(self):
155        if not self.cl:
156            return []
157        sublist = []
158        for name in self.listmethods():
159            item = MethodBrowserTreeItem(name, self.cl, self.file)
160            sublist.append(item)
161        return sublist
162
163    def OnDoubleClick(self):
164        if not os.path.exists(self.file):
165            return
166        edit = PyShell.flist.open(self.file)
167        if hasattr(self.cl, 'lineno'):
168            lineno = self.cl.lineno
169            edit.gotoline(lineno)
170
171    def listmethods(self):
172        if not self.cl:
173            return []
174        items = []
175        for name, lineno in self.cl.methods.items():
176            items.append((lineno, name))
177        items.sort()
178        list = []
179        for item, name in items:
180            list.append(name)
181        return list
182
183class MethodBrowserTreeItem(TreeItem):
184
185    def __init__(self, name, cl, file):
186        self.name = name
187        self.cl = cl
188        self.file = file
189
190    def GetText(self):
191        return "def " + self.name + "(...)"
192
193    def GetIconName(self):
194        return "python" # XXX
195
196    def IsExpandable(self):
197        return 0
198
199    def OnDoubleClick(self):
200        if not os.path.exists(self.file):
201            return
202        edit = PyShell.flist.open(self.file)
203        edit.gotoline(self.cl.methods[self.name])
204
205def main():
206    try:
207        file = __file__
208    except NameError:
209        file = sys.argv[0]
210        if sys.argv[1:]:
211            file = sys.argv[1]
212        else:
213            file = sys.argv[0]
214    dir, file = os.path.split(file)
215    name = os.path.splitext(file)[0]
216    ClassBrowser(PyShell.flist, name, [dir])
217    if sys.stdin is sys.__stdin__:
218        mainloop()
219
220if __name__ == "__main__":
221    main()