Guido van Rossum | 7f5c9ef | 1998-10-13 16:31:03 +0000 | [diff] [blame] | 1 | """Primitive class browser. |
| 2 | |
| 3 | XXX TO DO: |
Guido van Rossum | 504b0bf | 1999-01-02 21:28:54 +0000 | [diff] [blame] | 4 | |
Guido van Rossum | 21ad59f | 1999-04-08 20:28:42 +0000 | [diff] [blame] | 5 | - reparse when source changed |
Guido van Rossum | 7f5c9ef | 1998-10-13 16:31:03 +0000 | [diff] [blame] | 6 | - add popup menu with more options (e.g. doc strings, base classes, imports) |
| 7 | - show function argument list (have to do pattern matching on source) |
| 8 | - should the classes and methods lists also be in the module's menu bar? |
| 9 | |
| 10 | """ |
| 11 | |
Guido van Rossum | e6fae1c | 1998-10-15 23:27:08 +0000 | [diff] [blame] | 12 | import os |
Guido van Rossum | 439c467 | 1998-10-13 03:59:57 +0000 | [diff] [blame] | 13 | import string |
| 14 | import pyclbr |
Guido van Rossum | 7f5c9ef | 1998-10-13 16:31:03 +0000 | [diff] [blame] | 15 | from Tkinter import * |
| 16 | import tkMessageBox |
Guido van Rossum | 504b0bf | 1999-01-02 21:28:54 +0000 | [diff] [blame] | 17 | from WindowList import ListedToplevel |
Guido van Rossum | dc5066e | 1999-01-11 14:46:06 +0000 | [diff] [blame] | 18 | from Separator import HSeparator |
Guido van Rossum | 439c467 | 1998-10-13 03:59:57 +0000 | [diff] [blame] | 19 | |
Guido van Rossum | e6fae1c | 1998-10-15 23:27:08 +0000 | [diff] [blame] | 20 | from ScrolledList import ScrolledList |
| 21 | |
| 22 | |
Guido van Rossum | 439c467 | 1998-10-13 03:59:57 +0000 | [diff] [blame] | 23 | class ClassBrowser: |
Guido van Rossum | 504b0bf | 1999-01-02 21:28:54 +0000 | [diff] [blame] | 24 | |
Guido van Rossum | 654387e | 1998-12-18 15:52:54 +0000 | [diff] [blame] | 25 | def __init__(self, flist, name, path=[]): |
Guido van Rossum | 7f5c9ef | 1998-10-13 16:31:03 +0000 | [diff] [blame] | 26 | root = flist.root |
Guido van Rossum | 439c467 | 1998-10-13 03:59:57 +0000 | [diff] [blame] | 27 | try: |
Guido van Rossum | 654387e | 1998-12-18 15:52:54 +0000 | [diff] [blame] | 28 | dict = pyclbr.readmodule(name, path) |
Guido van Rossum | 439c467 | 1998-10-13 03:59:57 +0000 | [diff] [blame] | 29 | except ImportError, msg: |
| 30 | tkMessageBox.showerror("Import error", str(msg), parent=root) |
| 31 | return |
| 32 | if not dict: |
| 33 | tkMessageBox.showerror("Nothing to browse", |
| 34 | "Module %s defines no classes" % name, parent=root) |
| 35 | return |
Guido van Rossum | 7f5c9ef | 1998-10-13 16:31:03 +0000 | [diff] [blame] | 36 | self.flist = flist |
| 37 | self.dict = dict |
Guido van Rossum | 439c467 | 1998-10-13 03:59:57 +0000 | [diff] [blame] | 38 | self.root = root |
Guido van Rossum | 504b0bf | 1999-01-02 21:28:54 +0000 | [diff] [blame] | 39 | self.top = top = ListedToplevel(root) |
Guido van Rossum | 7f5c9ef | 1998-10-13 16:31:03 +0000 | [diff] [blame] | 40 | self.top.protocol("WM_DELETE_WINDOW", self.close) |
Guido van Rossum | dc5066e | 1999-01-11 14:46:06 +0000 | [diff] [blame] | 41 | self.top.bind("<Escape>", self.close) |
Guido van Rossum | 504b0bf | 1999-01-02 21:28:54 +0000 | [diff] [blame] | 42 | top.wm_title("Class Browser - " + name) |
| 43 | top.wm_iconname("ClBrowser") |
Guido van Rossum | dc5066e | 1999-01-11 14:46:06 +0000 | [diff] [blame] | 44 | self.sepa = HSeparator(top) |
| 45 | leftframe, rightframe = self.sepa.parts() |
| 46 | self.leftframe = leftframe |
| 47 | self.rightframe = rightframe |
| 48 | leftframe.pack(side="left", fill="both", expand=1) |
Guido van Rossum | 439c467 | 1998-10-13 03:59:57 +0000 | [diff] [blame] | 49 | # Create help label |
Guido van Rossum | e6fae1c | 1998-10-15 23:27:08 +0000 | [diff] [blame] | 50 | self.helplabel = Label(leftframe, text="Module %s" % name, |
| 51 | relief="groove", borderwidth=2) |
Guido van Rossum | 439c467 | 1998-10-13 03:59:57 +0000 | [diff] [blame] | 52 | self.helplabel.pack(fill="x") |
| 53 | # Create top frame, with scrollbar and listbox |
Guido van Rossum | e6fae1c | 1998-10-15 23:27:08 +0000 | [diff] [blame] | 54 | self.classviewer = ClassViewer( |
| 55 | self.leftframe, self.flist, self) |
Guido van Rossum | 439c467 | 1998-10-13 03:59:57 +0000 | [diff] [blame] | 56 | # Load the classes |
Guido van Rossum | e6fae1c | 1998-10-15 23:27:08 +0000 | [diff] [blame] | 57 | self.load_classes(dict, name) |
Guido van Rossum | 504b0bf | 1999-01-02 21:28:54 +0000 | [diff] [blame] | 58 | |
Guido van Rossum | dc5066e | 1999-01-11 14:46:06 +0000 | [diff] [blame] | 59 | def close(self, event=None): |
Guido van Rossum | e6fae1c | 1998-10-15 23:27:08 +0000 | [diff] [blame] | 60 | self.classviewer = None |
| 61 | self.methodviewer = None |
Guido van Rossum | 7f5c9ef | 1998-10-13 16:31:03 +0000 | [diff] [blame] | 62 | self.top.destroy() |
Guido van Rossum | 504b0bf | 1999-01-02 21:28:54 +0000 | [diff] [blame] | 63 | |
Guido van Rossum | e6fae1c | 1998-10-15 23:27:08 +0000 | [diff] [blame] | 64 | def load_classes(self, dict, module): |
| 65 | self.classviewer.load_classes(dict, module) |
Guido van Rossum | dc5066e | 1999-01-11 14:46:06 +0000 | [diff] [blame] | 66 | if self.methodframe: |
| 67 | self.methodframe.destroy() |
| 68 | self.methodframe = None |
Guido van Rossum | e6fae1c | 1998-10-15 23:27:08 +0000 | [diff] [blame] | 69 | self.methodviewer = None |
| 70 | |
Guido van Rossum | dc5066e | 1999-01-11 14:46:06 +0000 | [diff] [blame] | 71 | methodframe = None |
Guido van Rossum | e6fae1c | 1998-10-15 23:27:08 +0000 | [diff] [blame] | 72 | methodhelplabel = None |
| 73 | methodviewer = None |
Guido van Rossum | 504b0bf | 1999-01-02 21:28:54 +0000 | [diff] [blame] | 74 | |
Guido van Rossum | e6fae1c | 1998-10-15 23:27:08 +0000 | [diff] [blame] | 75 | def show_methods(self, cl): |
Guido van Rossum | dc5066e | 1999-01-11 14:46:06 +0000 | [diff] [blame] | 76 | if not self.methodframe: |
| 77 | self.methodframe = Frame(self.rightframe) |
| 78 | self.methodframe.pack(side="right", expand=1, fill="both") |
| 79 | self.methodhelplabel = Label(self.methodframe, |
Guido van Rossum | e6fae1c | 1998-10-15 23:27:08 +0000 | [diff] [blame] | 80 | relief="groove", borderwidth=2) |
| 81 | self.methodhelplabel.pack(fill="x") |
Guido van Rossum | dc5066e | 1999-01-11 14:46:06 +0000 | [diff] [blame] | 82 | self.methodviewer = MethodViewer(self.methodframe, self.flist) |
Guido van Rossum | e6fae1c | 1998-10-15 23:27:08 +0000 | [diff] [blame] | 83 | self.methodhelplabel.config(text="Class %s" % cl.name) |
| 84 | self.methodviewer.load_methods(cl) |
| 85 | |
| 86 | |
| 87 | class ClassViewer(ScrolledList): |
Guido van Rossum | 504b0bf | 1999-01-02 21:28:54 +0000 | [diff] [blame] | 88 | |
Guido van Rossum | e6fae1c | 1998-10-15 23:27:08 +0000 | [diff] [blame] | 89 | def __init__(self, master, flist, browser): |
Guido van Rossum | dc5066e | 1999-01-11 14:46:06 +0000 | [diff] [blame] | 90 | ScrolledList.__init__(self, master, width=40) |
Guido van Rossum | e6fae1c | 1998-10-15 23:27:08 +0000 | [diff] [blame] | 91 | self.flist = flist |
| 92 | self.browser = browser |
Guido van Rossum | 504b0bf | 1999-01-02 21:28:54 +0000 | [diff] [blame] | 93 | |
Guido van Rossum | e6fae1c | 1998-10-15 23:27:08 +0000 | [diff] [blame] | 94 | def load_classes(self, dict, module): |
| 95 | self.clear() |
| 96 | self.dict = dict |
Guido van Rossum | 7f5c9ef | 1998-10-13 16:31:03 +0000 | [diff] [blame] | 97 | items = [] |
| 98 | for key, value in dict.items(): |
| 99 | if value.module == module: |
| 100 | items.append((value.lineno, key, value)) |
Guido van Rossum | 439c467 | 1998-10-13 03:59:57 +0000 | [diff] [blame] | 101 | items.sort() |
Guido van Rossum | 7f5c9ef | 1998-10-13 16:31:03 +0000 | [diff] [blame] | 102 | for lineno, key, value in items: |
Guido van Rossum | 439c467 | 1998-10-13 03:59:57 +0000 | [diff] [blame] | 103 | s = key |
| 104 | if value.super: |
| 105 | super = [] |
| 106 | for sup in value.super: |
| 107 | name = sup.name |
| 108 | if sup.module != value.module: |
| 109 | name = "%s.%s" % (sup.module, name) |
| 110 | super.append(name) |
| 111 | s = s + "(%s)" % string.join(super, ", ") |
Guido van Rossum | e6fae1c | 1998-10-15 23:27:08 +0000 | [diff] [blame] | 112 | self.append(s) |
Guido van Rossum | 504b0bf | 1999-01-02 21:28:54 +0000 | [diff] [blame] | 113 | |
Guido van Rossum | e6fae1c | 1998-10-15 23:27:08 +0000 | [diff] [blame] | 114 | def getname(self, index): |
| 115 | name = self.listbox.get(index) |
| 116 | i = string.find(name, '(') |
| 117 | if i >= 0: |
| 118 | name = name[:i] |
| 119 | return name |
Guido van Rossum | 7f5c9ef | 1998-10-13 16:31:03 +0000 | [diff] [blame] | 120 | |
Guido van Rossum | e6fae1c | 1998-10-15 23:27:08 +0000 | [diff] [blame] | 121 | def getclass(self, index): |
| 122 | return self.dict[self.getname(index)] |
Guido van Rossum | 504b0bf | 1999-01-02 21:28:54 +0000 | [diff] [blame] | 123 | |
Guido van Rossum | e6fae1c | 1998-10-15 23:27:08 +0000 | [diff] [blame] | 124 | def on_select(self, index): |
Guido van Rossum | 7f5c9ef | 1998-10-13 16:31:03 +0000 | [diff] [blame] | 125 | self.show_methods(index) |
Guido van Rossum | 504b0bf | 1999-01-02 21:28:54 +0000 | [diff] [blame] | 126 | |
Guido van Rossum | e6fae1c | 1998-10-15 23:27:08 +0000 | [diff] [blame] | 127 | def on_double(self, index): |
Guido van Rossum | 7f5c9ef | 1998-10-13 16:31:03 +0000 | [diff] [blame] | 128 | self.show_source(index) |
Guido van Rossum | 504b0bf | 1999-01-02 21:28:54 +0000 | [diff] [blame] | 129 | |
Guido van Rossum | 7f5c9ef | 1998-10-13 16:31:03 +0000 | [diff] [blame] | 130 | def show_methods(self, index): |
Guido van Rossum | e6fae1c | 1998-10-15 23:27:08 +0000 | [diff] [blame] | 131 | cl = self.getclass(index) |
| 132 | self.browser.show_methods(cl) |
Guido van Rossum | 7f5c9ef | 1998-10-13 16:31:03 +0000 | [diff] [blame] | 133 | |
Guido van Rossum | e6fae1c | 1998-10-15 23:27:08 +0000 | [diff] [blame] | 134 | def show_source(self, index): |
| 135 | cl = self.getclass(index) |
| 136 | if os.path.isfile(cl.file): |
| 137 | edit = self.flist.open(cl.file) |
| 138 | edit.gotoline(cl.lineno) |
| 139 | |
| 140 | |
| 141 | class MethodViewer(ScrolledList): |
Guido van Rossum | 504b0bf | 1999-01-02 21:28:54 +0000 | [diff] [blame] | 142 | |
Guido van Rossum | e6fae1c | 1998-10-15 23:27:08 +0000 | [diff] [blame] | 143 | def __init__(self, master, flist): |
| 144 | ScrolledList.__init__(self, master) |
Guido van Rossum | 7f5c9ef | 1998-10-13 16:31:03 +0000 | [diff] [blame] | 145 | self.flist = flist |
Guido van Rossum | 504b0bf | 1999-01-02 21:28:54 +0000 | [diff] [blame] | 146 | |
Guido van Rossum | 7f5c9ef | 1998-10-13 16:31:03 +0000 | [diff] [blame] | 147 | classinfo = None |
Guido van Rossum | 504b0bf | 1999-01-02 21:28:54 +0000 | [diff] [blame] | 148 | |
Guido van Rossum | e6fae1c | 1998-10-15 23:27:08 +0000 | [diff] [blame] | 149 | def load_methods(self, cl): |
Guido van Rossum | 7f5c9ef | 1998-10-13 16:31:03 +0000 | [diff] [blame] | 150 | self.classinfo = cl |
Guido van Rossum | e6fae1c | 1998-10-15 23:27:08 +0000 | [diff] [blame] | 151 | self.clear() |
Guido van Rossum | 7f5c9ef | 1998-10-13 16:31:03 +0000 | [diff] [blame] | 152 | items = [] |
| 153 | for name, lineno in cl.methods.items(): |
| 154 | items.append((lineno, name)) |
| 155 | items.sort() |
| 156 | for item, name in items: |
Guido van Rossum | e6fae1c | 1998-10-15 23:27:08 +0000 | [diff] [blame] | 157 | self.append(name) |
Guido van Rossum | 439c467 | 1998-10-13 03:59:57 +0000 | [diff] [blame] | 158 | |
| 159 | def click_event(self, event): |
| 160 | pass |
Guido van Rossum | 504b0bf | 1999-01-02 21:28:54 +0000 | [diff] [blame] | 161 | |
Guido van Rossum | e6fae1c | 1998-10-15 23:27:08 +0000 | [diff] [blame] | 162 | def on_double(self, index): |
| 163 | self.show_source(self.get(index)) |
Guido van Rossum | 504b0bf | 1999-01-02 21:28:54 +0000 | [diff] [blame] | 164 | |
Guido van Rossum | e6fae1c | 1998-10-15 23:27:08 +0000 | [diff] [blame] | 165 | def show_source(self, name): |
| 166 | if os.path.isfile(self.classinfo.file): |
| 167 | edit = self.flist.open(self.classinfo.file) |
| 168 | edit.gotoline(self.classinfo.methods[name]) |