home *** CD-ROM | disk | FTP | other *** search
/ PC World 2001 April / PCWorld_2001-04_cd.bin / Software / TemaCD / webclean / !!!python!!! / BeOpen-Python-2.0.exe / CLASSBROWSER.PY < prev    next >
Encoding:
Python Source  |  2000-09-28  |  6.4 KB  |  225 lines

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