]> git.saurik.com Git - wxWidgets.git/blob - wxPython/wx/py/filling.py
Take advantage of the new ctors accepting a wxArrayString
[wxWidgets.git] / wxPython / wx / py / filling.py
1 """Filling is the gui tree control through which a user can navigate
2 the local namespace or any object."""
3
4 __author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
5 __cvsid__ = "$Id$"
6 __revision__ = "$Revision$"[11:-2]
7
8 import wx
9
10 import dispatcher
11 import editwindow
12 import inspect
13 import introspect
14 import keyword
15 import sys
16 import types
17 from version import VERSION
18
19 try:
20 True
21 except NameError:
22 True = 1==1
23 False = 1==0
24
25 COMMONTYPES = [getattr(types, t) for t in dir(types) \
26 if not t.startswith('_') \
27 and t not in ('ClassType', 'InstanceType', 'ModuleType')]
28
29 DOCTYPES = ('BuiltinFunctionType', 'BuiltinMethodType', 'ClassType',
30 'FunctionType', 'GeneratorType', 'InstanceType',
31 'LambdaType', 'MethodType', 'ModuleType',
32 'UnboundMethodType', 'method-wrapper')
33
34 SIMPLETYPES = [getattr(types, t) for t in dir(types) \
35 if not t.startswith('_') and t not in DOCTYPES]
36
37 del t
38
39 try:
40 COMMONTYPES.append(type(''.__repr__)) # Method-wrapper in version 2.2.x.
41 except AttributeError:
42 pass
43
44
45 class FillingTree(wx.TreeCtrl):
46 """FillingTree based on TreeCtrl."""
47
48 name = 'Filling Tree'
49 revision = __revision__
50
51 def __init__(self, parent, id=-1, pos=wx.DefaultPosition,
52 size=wx.DefaultSize, style=wx.TR_DEFAULT_STYLE,
53 rootObject=None, rootLabel=None, rootIsNamespace=False,
54 static=False):
55 """Create FillingTree instance."""
56 wx.TreeCtrl.__init__(self, parent, id, pos, size, style)
57 self.rootIsNamespace = rootIsNamespace
58 import __main__
59 if rootObject is None:
60 rootObject = __main__.__dict__
61 self.rootIsNamespace = True
62 if rootObject is __main__.__dict__ and rootLabel is None:
63 rootLabel = 'locals()'
64 if not rootLabel:
65 rootLabel = 'Ingredients'
66 rootData = wx.TreeItemData(rootObject)
67 self.item = self.root = self.AddRoot(rootLabel, -1, -1, rootData)
68 self.SetItemHasChildren(self.root, self.objHasChildren(rootObject))
69 wx.EVT_TREE_ITEM_EXPANDING(self, self.GetId(), self.OnItemExpanding)
70 wx.EVT_TREE_ITEM_COLLAPSED(self, self.GetId(), self.OnItemCollapsed)
71 wx.EVT_TREE_SEL_CHANGED(self, self.GetId(), self.OnSelChanged)
72 wx.EVT_TREE_ITEM_ACTIVATED(self, self.GetId(), self.OnItemActivated)
73 if not static:
74 dispatcher.connect(receiver=self.push, signal='Interpreter.push')
75
76 def push(self, command, more):
77 """Receiver for Interpreter.push signal."""
78 self.display()
79
80 def OnItemExpanding(self, event):
81 """Add children to the item."""
82 busy = wx.BusyCursor()
83 item = event.GetItem()
84 if self.IsExpanded(item):
85 return
86 self.addChildren(item)
87 # self.SelectItem(item)
88
89 def OnItemCollapsed(self, event):
90 """Remove all children from the item."""
91 busy = wx.BusyCursor()
92 item = event.GetItem()
93 # self.CollapseAndReset(item)
94 # self.DeleteChildren(item)
95 # self.SelectItem(item)
96
97 def OnSelChanged(self, event):
98 """Display information about the item."""
99 busy = wx.BusyCursor()
100 self.item = event.GetItem()
101 self.display()
102
103 def OnItemActivated(self, event):
104 """Launch a DirFrame."""
105 item = event.GetItem()
106 text = self.getFullName(item)
107 obj = self.GetPyData(item)
108 frame = FillingFrame(parent=self, size=(600, 100), rootObject=obj,
109 rootLabel=text, rootIsNamespace=False)
110 frame.Show()
111
112 def objHasChildren(self, obj):
113 """Return true if object has children."""
114 if self.objGetChildren(obj):
115 return True
116 else:
117 return False
118
119 def objGetChildren(self, obj):
120 """Return dictionary with attributes or contents of object."""
121 busy = wx.BusyCursor()
122 otype = type(obj)
123 if otype is types.DictType \
124 or str(otype)[17:23] == 'BTrees' and hasattr(obj, 'keys'):
125 return obj
126 d = {}
127 if otype is types.ListType or otype is types.TupleType:
128 for n in range(len(obj)):
129 key = '[' + str(n) + ']'
130 d[key] = obj[n]
131 if otype not in COMMONTYPES:
132 for key in introspect.getAttributeNames(obj):
133 # Believe it or not, some attributes can disappear,
134 # such as the exc_traceback attribute of the sys
135 # module. So this is nested in a try block.
136 try:
137 d[key] = getattr(obj, key)
138 except:
139 pass
140 return d
141
142 def addChildren(self, item):
143 self.DeleteChildren(item)
144 obj = self.GetPyData(item)
145 children = self.objGetChildren(obj)
146 if not children:
147 return
148 keys = children.keys()
149 keys.sort(lambda x, y: cmp(str(x).lower(), str(y).lower()))
150 for key in keys:
151 itemtext = str(key)
152 # Show string dictionary items with single quotes, except
153 # for the first level of items, if they represent a
154 # namespace.
155 if type(obj) is types.DictType \
156 and type(key) is types.StringType \
157 and (item != self.root \
158 or (item == self.root and not self.rootIsNamespace)):
159 itemtext = repr(key)
160 child = children[key]
161 data = wx.TreeItemData(child)
162 branch = self.AppendItem(parent=item, text=itemtext, data=data)
163 self.SetItemHasChildren(branch, self.objHasChildren(child))
164
165 def display(self):
166 item = self.item
167 if self.IsExpanded(item):
168 self.addChildren(item)
169 self.setText('')
170 obj = self.GetPyData(item)
171 if wx.Platform == '__WXMSW__':
172 if obj is None: # Windows bug fix.
173 return
174 self.SetItemHasChildren(item, self.objHasChildren(obj))
175 otype = type(obj)
176 text = ''
177 text += self.getFullName(item)
178 text += '\n\nType: ' + str(otype)
179 try:
180 value = str(obj)
181 except:
182 value = ''
183 if otype is types.StringType or otype is types.UnicodeType:
184 value = repr(obj)
185 text += '\n\nValue: ' + value
186 if otype not in SIMPLETYPES:
187 try:
188 text += '\n\nDocstring:\n\n"""' + \
189 inspect.getdoc(obj).strip() + '"""'
190 except:
191 pass
192 if otype is types.InstanceType:
193 try:
194 text += '\n\nClass Definition:\n\n' + \
195 inspect.getsource(obj.__class__)
196 except:
197 pass
198 else:
199 try:
200 text += '\n\nSource Code:\n\n' + \
201 inspect.getsource(obj)
202 except:
203 pass
204 self.setText(text)
205
206 def getFullName(self, item, partial=''):
207 """Return a syntactically proper name for item."""
208 name = self.GetItemText(item)
209 parent = None
210 obj = None
211 if item != self.root:
212 parent = self.GetItemParent(item)
213 obj = self.GetPyData(parent)
214 # Apply dictionary syntax to dictionary items, except the root
215 # and first level children of a namepace.
216 if (type(obj) is types.DictType \
217 or str(type(obj))[17:23] == 'BTrees' \
218 and hasattr(obj, 'keys')) \
219 and ((item != self.root and parent != self.root) \
220 or (parent == self.root and not self.rootIsNamespace)):
221 name = '[' + name + ']'
222 # Apply dot syntax to multipart names.
223 if partial:
224 if partial[0] == '[':
225 name += partial
226 else:
227 name += '.' + partial
228 # Repeat for everything but the root item
229 # and first level children of a namespace.
230 if (item != self.root and parent != self.root) \
231 or (parent == self.root and not self.rootIsNamespace):
232 name = self.getFullName(parent, partial=name)
233 return name
234
235 def setText(self, text):
236 """Display information about the current selection."""
237
238 # This method will likely be replaced by the enclosing app to
239 # do something more interesting, like write to a text control.
240 print text
241
242 def setStatusText(self, text):
243 """Display status information."""
244
245 # This method will likely be replaced by the enclosing app to
246 # do something more interesting, like write to a status bar.
247 print text
248
249
250 class FillingText(editwindow.EditWindow):
251 """FillingText based on StyledTextCtrl."""
252
253 name = 'Filling Text'
254 revision = __revision__
255
256 def __init__(self, parent, id=-1, pos=wx.DefaultPosition,
257 size=wx.DefaultSize, style=wx.CLIP_CHILDREN,
258 static=False):
259 """Create FillingText instance."""
260 editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
261 # Configure various defaults and user preferences.
262 self.SetReadOnly(True)
263 self.SetWrapMode(True)
264 self.SetMarginWidth(1, 0)
265 if not static:
266 dispatcher.connect(receiver=self.push, signal='Interpreter.push')
267
268 def push(self, command, more):
269 """Receiver for Interpreter.push signal."""
270 self.Refresh()
271
272 def SetText(self, *args, **kwds):
273 self.SetReadOnly(False)
274 editwindow.EditWindow.SetText(self, *args, **kwds)
275 self.SetReadOnly(True)
276
277
278 class Filling(wx.SplitterWindow):
279 """Filling based on wxSplitterWindow."""
280
281 name = 'Filling'
282 revision = __revision__
283
284 def __init__(self, parent, id=-1, pos=wx.DefaultPosition,
285 size=wx.DefaultSize, style=wx.SP_3D,
286 name='Filling Window', rootObject=None,
287 rootLabel=None, rootIsNamespace=False, static=False):
288 """Create a Filling instance."""
289 wx.SplitterWindow.__init__(self, parent, id, pos, size, style, name)
290 self.tree = FillingTree(parent=self, rootObject=rootObject,
291 rootLabel=rootLabel,
292 rootIsNamespace=rootIsNamespace,
293 static=static)
294 self.text = FillingText(parent=self, static=static)
295 self.SplitVertically(self.tree, self.text, 130)
296 self.SetMinimumPaneSize(1)
297 # Override the filling so that descriptions go to FillingText.
298 self.tree.setText = self.text.SetText
299 # Display the root item.
300 ## self.tree.SelectItem(self.tree.root)
301 self.tree.display()
302
303
304 class FillingFrame(wx.Frame):
305 """Frame containing the namespace tree component."""
306
307 name = 'Filling Frame'
308 revision = __revision__
309
310 def __init__(self, parent=None, id=-1, title='PyFilling',
311 pos=wx.DefaultPosition, size=(600, 400),
312 style=wx.DEFAULT_FRAME_STYLE, rootObject=None,
313 rootLabel=None, rootIsNamespace=False, static=False):
314 """Create FillingFrame instance."""
315 wx.Frame.__init__(self, parent, id, title, pos, size, style)
316 intro = 'PyFilling - The Tastiest Namespace Inspector'
317 self.CreateStatusBar()
318 self.SetStatusText(intro)
319 import images
320 self.SetIcon(images.getPyIcon())
321 self.filling = Filling(parent=self, rootObject=rootObject,
322 rootLabel=rootLabel,
323 rootIsNamespace=rootIsNamespace,
324 static=static)
325 # Override so that status messages go to the status bar.
326 self.filling.tree.setStatusText = self.SetStatusText
327
328
329 class App(wx.App):
330 """PyFilling standalone application."""
331
332 def OnInit(self):
333 wx.InitAllImageHandlers()
334 self.fillingFrame = FillingFrame()
335 self.fillingFrame.Show(True)
336 self.SetTopWindow(self.fillingFrame)
337 return True