blob: 4093079bd3aafc7d3f922cbe59be77ca89dee612 [file] [log] [blame]
Guido van Rossum7f5c9ef1998-10-13 16:31:03 +00001"""Primitive class browser.
2
3XXX TO DO:
Guido van Rossum504b0bf1999-01-02 21:28:54 +00004
Guido van Rossum7f5c9ef1998-10-13 16:31:03 +00005- 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 Rossume6fae1c1998-10-15 23:27:08 +000012import os
Guido van Rossum439c4671998-10-13 03:59:57 +000013import string
14import pyclbr
Guido van Rossum7f5c9ef1998-10-13 16:31:03 +000015from Tkinter import *
16import tkMessageBox
Guido van Rossum504b0bf1999-01-02 21:28:54 +000017from WindowList import ListedToplevel
Guido van Rossumdc5066e1999-01-11 14:46:06 +000018from Separator import HSeparator
Guido van Rossum439c4671998-10-13 03:59:57 +000019
Guido van Rossume6fae1c1998-10-15 23:27:08 +000020from ScrolledList import ScrolledList
21
22
Guido van Rossum439c4671998-10-13 03:59:57 +000023class ClassBrowser:
Guido van Rossum504b0bf1999-01-02 21:28:54 +000024
Guido van Rossum654387e1998-12-18 15:52:54 +000025 def __init__(self, flist, name, path=[]):
Guido van Rossum7f5c9ef1998-10-13 16:31:03 +000026 root = flist.root
Guido van Rossum439c4671998-10-13 03:59:57 +000027 try:
Guido van Rossum654387e1998-12-18 15:52:54 +000028 dict = pyclbr.readmodule(name, path)
Guido van Rossum439c4671998-10-13 03:59:57 +000029 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 Rossum7f5c9ef1998-10-13 16:31:03 +000036 self.flist = flist
37 self.dict = dict
Guido van Rossum439c4671998-10-13 03:59:57 +000038 self.root = root
Guido van Rossum504b0bf1999-01-02 21:28:54 +000039 self.top = top = ListedToplevel(root)
Guido van Rossum7f5c9ef1998-10-13 16:31:03 +000040 self.top.protocol("WM_DELETE_WINDOW", self.close)
Guido van Rossumdc5066e1999-01-11 14:46:06 +000041 self.top.bind("<Escape>", self.close)
Guido van Rossum504b0bf1999-01-02 21:28:54 +000042 top.wm_title("Class Browser - " + name)
43 top.wm_iconname("ClBrowser")
Guido van Rossumdc5066e1999-01-11 14:46:06 +000044 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 Rossum439c4671998-10-13 03:59:57 +000049 # Create help label
Guido van Rossume6fae1c1998-10-15 23:27:08 +000050 self.helplabel = Label(leftframe, text="Module %s" % name,
51 relief="groove", borderwidth=2)
Guido van Rossum439c4671998-10-13 03:59:57 +000052 self.helplabel.pack(fill="x")
53 # Create top frame, with scrollbar and listbox
Guido van Rossume6fae1c1998-10-15 23:27:08 +000054 self.classviewer = ClassViewer(
55 self.leftframe, self.flist, self)
Guido van Rossum439c4671998-10-13 03:59:57 +000056 # Load the classes
Guido van Rossume6fae1c1998-10-15 23:27:08 +000057 self.load_classes(dict, name)
Guido van Rossum504b0bf1999-01-02 21:28:54 +000058
Guido van Rossumdc5066e1999-01-11 14:46:06 +000059 def close(self, event=None):
Guido van Rossume6fae1c1998-10-15 23:27:08 +000060 self.classviewer = None
61 self.methodviewer = None
Guido van Rossum7f5c9ef1998-10-13 16:31:03 +000062 self.top.destroy()
Guido van Rossum504b0bf1999-01-02 21:28:54 +000063
Guido van Rossume6fae1c1998-10-15 23:27:08 +000064 def load_classes(self, dict, module):
65 self.classviewer.load_classes(dict, module)
Guido van Rossumdc5066e1999-01-11 14:46:06 +000066 if self.methodframe:
67 self.methodframe.destroy()
68 self.methodframe = None
Guido van Rossume6fae1c1998-10-15 23:27:08 +000069 self.methodviewer = None
70
Guido van Rossumdc5066e1999-01-11 14:46:06 +000071 methodframe = None
Guido van Rossume6fae1c1998-10-15 23:27:08 +000072 methodhelplabel = None
73 methodviewer = None
Guido van Rossum504b0bf1999-01-02 21:28:54 +000074
Guido van Rossume6fae1c1998-10-15 23:27:08 +000075 def show_methods(self, cl):
Guido van Rossumdc5066e1999-01-11 14:46:06 +000076 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 Rossume6fae1c1998-10-15 23:27:08 +000080 relief="groove", borderwidth=2)
81 self.methodhelplabel.pack(fill="x")
Guido van Rossumdc5066e1999-01-11 14:46:06 +000082 self.methodviewer = MethodViewer(self.methodframe, self.flist)
Guido van Rossume6fae1c1998-10-15 23:27:08 +000083 self.methodhelplabel.config(text="Class %s" % cl.name)
84 self.methodviewer.load_methods(cl)
85
86
87class ClassViewer(ScrolledList):
Guido van Rossum504b0bf1999-01-02 21:28:54 +000088
Guido van Rossume6fae1c1998-10-15 23:27:08 +000089 def __init__(self, master, flist, browser):
Guido van Rossumdc5066e1999-01-11 14:46:06 +000090 ScrolledList.__init__(self, master, width=40)
Guido van Rossume6fae1c1998-10-15 23:27:08 +000091 self.flist = flist
92 self.browser = browser
Guido van Rossum504b0bf1999-01-02 21:28:54 +000093
Guido van Rossume6fae1c1998-10-15 23:27:08 +000094 def load_classes(self, dict, module):
95 self.clear()
96 self.dict = dict
Guido van Rossum7f5c9ef1998-10-13 16:31:03 +000097 items = []
98 for key, value in dict.items():
99 if value.module == module:
100 items.append((value.lineno, key, value))
Guido van Rossum439c4671998-10-13 03:59:57 +0000101 items.sort()
Guido van Rossum7f5c9ef1998-10-13 16:31:03 +0000102 for lineno, key, value in items:
Guido van Rossum439c4671998-10-13 03:59:57 +0000103 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 Rossume6fae1c1998-10-15 23:27:08 +0000112 self.append(s)
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000113
Guido van Rossume6fae1c1998-10-15 23:27:08 +0000114 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 Rossum7f5c9ef1998-10-13 16:31:03 +0000120
Guido van Rossume6fae1c1998-10-15 23:27:08 +0000121 def getclass(self, index):
122 return self.dict[self.getname(index)]
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000123
Guido van Rossume6fae1c1998-10-15 23:27:08 +0000124 def on_select(self, index):
Guido van Rossum7f5c9ef1998-10-13 16:31:03 +0000125 self.show_methods(index)
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000126
Guido van Rossume6fae1c1998-10-15 23:27:08 +0000127 def on_double(self, index):
Guido van Rossum7f5c9ef1998-10-13 16:31:03 +0000128 self.show_source(index)
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000129
Guido van Rossum7f5c9ef1998-10-13 16:31:03 +0000130 def show_methods(self, index):
Guido van Rossume6fae1c1998-10-15 23:27:08 +0000131 cl = self.getclass(index)
132 self.browser.show_methods(cl)
Guido van Rossum7f5c9ef1998-10-13 16:31:03 +0000133
Guido van Rossume6fae1c1998-10-15 23:27:08 +0000134 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
141class MethodViewer(ScrolledList):
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000142
Guido van Rossume6fae1c1998-10-15 23:27:08 +0000143 def __init__(self, master, flist):
144 ScrolledList.__init__(self, master)
Guido van Rossum7f5c9ef1998-10-13 16:31:03 +0000145 self.flist = flist
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000146
Guido van Rossum7f5c9ef1998-10-13 16:31:03 +0000147 classinfo = None
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000148
Guido van Rossume6fae1c1998-10-15 23:27:08 +0000149 def load_methods(self, cl):
Guido van Rossum7f5c9ef1998-10-13 16:31:03 +0000150 self.classinfo = cl
Guido van Rossume6fae1c1998-10-15 23:27:08 +0000151 self.clear()
Guido van Rossum7f5c9ef1998-10-13 16:31:03 +0000152 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 Rossume6fae1c1998-10-15 23:27:08 +0000157 self.append(name)
Guido van Rossum439c4671998-10-13 03:59:57 +0000158
159 def click_event(self, event):
160 pass
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000161
Guido van Rossume6fae1c1998-10-15 23:27:08 +0000162 def on_double(self, index):
163 self.show_source(self.get(index))
Guido van Rossum504b0bf1999-01-02 21:28:54 +0000164
Guido van Rossume6fae1c1998-10-15 23:27:08 +0000165 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])