Guido van Rossum | 7f5c9ef | 1998-10-13 16:31:03 +0000 | [diff] [blame] | 1 | """Primitive class browser. |
| 2 | |
| 3 | XXX TO DO: |
| 4 | |
| 5 | - generalize the scrolling listbox with some behavior into a base class |
| 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 | 439c467 | 1998-10-13 03:59:57 +0000 | [diff] [blame] | 17 | |
Guido van Rossum | e6fae1c | 1998-10-15 23:27:08 +0000 | [diff] [blame] | 18 | from ScrolledList import ScrolledList |
| 19 | |
| 20 | |
Guido van Rossum | 439c467 | 1998-10-13 03:59:57 +0000 | [diff] [blame] | 21 | class ClassBrowser: |
| 22 | |
Guido van Rossum | 7f5c9ef | 1998-10-13 16:31:03 +0000 | [diff] [blame] | 23 | def __init__(self, flist, name): |
| 24 | root = flist.root |
Guido van Rossum | 439c467 | 1998-10-13 03:59:57 +0000 | [diff] [blame] | 25 | try: |
| 26 | dict = pyclbr.readmodule(name) |
| 27 | except ImportError, msg: |
| 28 | tkMessageBox.showerror("Import error", str(msg), parent=root) |
| 29 | return |
| 30 | if not dict: |
| 31 | tkMessageBox.showerror("Nothing to browse", |
| 32 | "Module %s defines no classes" % name, parent=root) |
| 33 | return |
Guido van Rossum | 7f5c9ef | 1998-10-13 16:31:03 +0000 | [diff] [blame] | 34 | self.flist = flist |
| 35 | self.dict = dict |
Guido van Rossum | 439c467 | 1998-10-13 03:59:57 +0000 | [diff] [blame] | 36 | self.root = root |
| 37 | self.top = top = Toplevel(root) |
Guido van Rossum | 7f5c9ef | 1998-10-13 16:31:03 +0000 | [diff] [blame] | 38 | self.top.protocol("WM_DELETE_WINDOW", self.close) |
Guido van Rossum | e6fae1c | 1998-10-15 23:27:08 +0000 | [diff] [blame] | 39 | top.wm_title("Class browser") |
Guido van Rossum | 7f5c9ef | 1998-10-13 16:31:03 +0000 | [diff] [blame] | 40 | self.leftframe = leftframe = Frame(top) |
| 41 | self.leftframe.pack(side="left", fill="both", expand=1) |
Guido van Rossum | 439c467 | 1998-10-13 03:59:57 +0000 | [diff] [blame] | 42 | # Create help label |
Guido van Rossum | e6fae1c | 1998-10-15 23:27:08 +0000 | [diff] [blame] | 43 | self.helplabel = Label(leftframe, text="Module %s" % name, |
| 44 | relief="groove", borderwidth=2) |
Guido van Rossum | 439c467 | 1998-10-13 03:59:57 +0000 | [diff] [blame] | 45 | self.helplabel.pack(fill="x") |
| 46 | # Create top frame, with scrollbar and listbox |
Guido van Rossum | e6fae1c | 1998-10-15 23:27:08 +0000 | [diff] [blame] | 47 | self.classviewer = ClassViewer( |
| 48 | self.leftframe, self.flist, self) |
Guido van Rossum | 439c467 | 1998-10-13 03:59:57 +0000 | [diff] [blame] | 49 | # Load the classes |
Guido van Rossum | e6fae1c | 1998-10-15 23:27:08 +0000 | [diff] [blame] | 50 | self.load_classes(dict, name) |
Guido van Rossum | 7f5c9ef | 1998-10-13 16:31:03 +0000 | [diff] [blame] | 51 | |
| 52 | def close(self): |
Guido van Rossum | e6fae1c | 1998-10-15 23:27:08 +0000 | [diff] [blame] | 53 | self.classviewer = None |
| 54 | self.methodviewer = None |
Guido van Rossum | 7f5c9ef | 1998-10-13 16:31:03 +0000 | [diff] [blame] | 55 | self.top.destroy() |
Guido van Rossum | 439c467 | 1998-10-13 03:59:57 +0000 | [diff] [blame] | 56 | |
Guido van Rossum | e6fae1c | 1998-10-15 23:27:08 +0000 | [diff] [blame] | 57 | def load_classes(self, dict, module): |
| 58 | self.classviewer.load_classes(dict, module) |
| 59 | if self.botframe: |
| 60 | self.botframe.destroy() |
| 61 | self.botframe = None |
| 62 | self.methodviewer = None |
| 63 | |
| 64 | botframe = None |
| 65 | methodhelplabel = None |
| 66 | methodviewer = None |
| 67 | |
| 68 | def show_methods(self, cl): |
| 69 | if not self.botframe: |
| 70 | self.botframe = Frame(self.top) |
| 71 | self.botframe.pack(side="right", expand=1, fill="both") |
| 72 | self.methodhelplabel = Label(self.botframe, |
| 73 | relief="groove", borderwidth=2) |
| 74 | self.methodhelplabel.pack(fill="x") |
| 75 | self.methodviewer = MethodViewer(self.botframe, self.flist) |
| 76 | self.methodhelplabel.config(text="Class %s" % cl.name) |
| 77 | self.methodviewer.load_methods(cl) |
| 78 | |
| 79 | |
| 80 | class ClassViewer(ScrolledList): |
| 81 | |
| 82 | def __init__(self, master, flist, browser): |
| 83 | ScrolledList.__init__(self, master) |
| 84 | self.flist = flist |
| 85 | self.browser = browser |
| 86 | |
| 87 | def load_classes(self, dict, module): |
| 88 | self.clear() |
| 89 | self.dict = dict |
Guido van Rossum | 7f5c9ef | 1998-10-13 16:31:03 +0000 | [diff] [blame] | 90 | items = [] |
| 91 | for key, value in dict.items(): |
| 92 | if value.module == module: |
| 93 | items.append((value.lineno, key, value)) |
Guido van Rossum | 439c467 | 1998-10-13 03:59:57 +0000 | [diff] [blame] | 94 | items.sort() |
Guido van Rossum | 7f5c9ef | 1998-10-13 16:31:03 +0000 | [diff] [blame] | 95 | for lineno, key, value in items: |
Guido van Rossum | 439c467 | 1998-10-13 03:59:57 +0000 | [diff] [blame] | 96 | s = key |
| 97 | if value.super: |
| 98 | super = [] |
| 99 | for sup in value.super: |
| 100 | name = sup.name |
| 101 | if sup.module != value.module: |
| 102 | name = "%s.%s" % (sup.module, name) |
| 103 | super.append(name) |
| 104 | s = s + "(%s)" % string.join(super, ", ") |
Guido van Rossum | e6fae1c | 1998-10-15 23:27:08 +0000 | [diff] [blame] | 105 | self.append(s) |
| 106 | |
| 107 | def getname(self, index): |
| 108 | name = self.listbox.get(index) |
| 109 | i = string.find(name, '(') |
| 110 | if i >= 0: |
| 111 | name = name[:i] |
| 112 | return name |
Guido van Rossum | 7f5c9ef | 1998-10-13 16:31:03 +0000 | [diff] [blame] | 113 | |
Guido van Rossum | e6fae1c | 1998-10-15 23:27:08 +0000 | [diff] [blame] | 114 | def getclass(self, index): |
| 115 | return self.dict[self.getname(index)] |
| 116 | |
| 117 | def on_select(self, index): |
Guido van Rossum | 7f5c9ef | 1998-10-13 16:31:03 +0000 | [diff] [blame] | 118 | self.show_methods(index) |
| 119 | |
Guido van Rossum | e6fae1c | 1998-10-15 23:27:08 +0000 | [diff] [blame] | 120 | def on_double(self, index): |
Guido van Rossum | 7f5c9ef | 1998-10-13 16:31:03 +0000 | [diff] [blame] | 121 | self.show_source(index) |
| 122 | |
Guido van Rossum | 7f5c9ef | 1998-10-13 16:31:03 +0000 | [diff] [blame] | 123 | def show_methods(self, index): |
Guido van Rossum | e6fae1c | 1998-10-15 23:27:08 +0000 | [diff] [blame] | 124 | cl = self.getclass(index) |
| 125 | self.browser.show_methods(cl) |
Guido van Rossum | 7f5c9ef | 1998-10-13 16:31:03 +0000 | [diff] [blame] | 126 | |
Guido van Rossum | e6fae1c | 1998-10-15 23:27:08 +0000 | [diff] [blame] | 127 | def show_source(self, index): |
| 128 | cl = self.getclass(index) |
| 129 | if os.path.isfile(cl.file): |
| 130 | edit = self.flist.open(cl.file) |
| 131 | edit.gotoline(cl.lineno) |
| 132 | |
| 133 | |
| 134 | class MethodViewer(ScrolledList): |
Guido van Rossum | 7f5c9ef | 1998-10-13 16:31:03 +0000 | [diff] [blame] | 135 | |
Guido van Rossum | e6fae1c | 1998-10-15 23:27:08 +0000 | [diff] [blame] | 136 | def __init__(self, master, flist): |
| 137 | ScrolledList.__init__(self, master) |
Guido van Rossum | 7f5c9ef | 1998-10-13 16:31:03 +0000 | [diff] [blame] | 138 | self.flist = flist |
Guido van Rossum | 7f5c9ef | 1998-10-13 16:31:03 +0000 | [diff] [blame] | 139 | |
| 140 | classinfo = None |
| 141 | |
Guido van Rossum | e6fae1c | 1998-10-15 23:27:08 +0000 | [diff] [blame] | 142 | def load_methods(self, cl): |
Guido van Rossum | 7f5c9ef | 1998-10-13 16:31:03 +0000 | [diff] [blame] | 143 | self.classinfo = cl |
Guido van Rossum | e6fae1c | 1998-10-15 23:27:08 +0000 | [diff] [blame] | 144 | self.clear() |
Guido van Rossum | 7f5c9ef | 1998-10-13 16:31:03 +0000 | [diff] [blame] | 145 | items = [] |
| 146 | for name, lineno in cl.methods.items(): |
| 147 | items.append((lineno, name)) |
| 148 | items.sort() |
| 149 | for item, name in items: |
Guido van Rossum | e6fae1c | 1998-10-15 23:27:08 +0000 | [diff] [blame] | 150 | self.append(name) |
Guido van Rossum | 439c467 | 1998-10-13 03:59:57 +0000 | [diff] [blame] | 151 | |
| 152 | def click_event(self, event): |
| 153 | pass |
| 154 | |
Guido van Rossum | e6fae1c | 1998-10-15 23:27:08 +0000 | [diff] [blame] | 155 | def on_double(self, index): |
| 156 | self.show_source(self.get(index)) |
Guido van Rossum | 439c467 | 1998-10-13 03:59:57 +0000 | [diff] [blame] | 157 | |
Guido van Rossum | e6fae1c | 1998-10-15 23:27:08 +0000 | [diff] [blame] | 158 | def show_source(self, name): |
| 159 | if os.path.isfile(self.classinfo.file): |
| 160 | edit = self.flist.open(self.classinfo.file) |
| 161 | edit.gotoline(self.classinfo.methods[name]) |