]> git.saurik.com Git - wxWidgets.git/blob - wxPython/wxPython/lib/PyCrust/filling.py
call wxApp::OnExit() when wxExit() is called and don't do wxLogError from it (replace...
[wxWidgets.git] / wxPython / wxPython / lib / PyCrust / filling.py
1 """PyCrust 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 from wxPython.wx import *
9 from wxPython.stc import *
10 from version import VERSION
11 import inspect
12 import introspect
13 import keyword
14 import sys
15 import types
16
17 COMMONTYPES = [getattr(types, t) for t in dir(types) \
18 if not t.startswith('_') \
19 and t not in ('ClassType', 'InstanceType', 'ModuleType')]
20 try:
21 COMMONTYPES.append(type(''.__repr__)) # Method-wrapper in version 2.2.x.
22 except AttributeError:
23 pass
24
25
26 class FillingTree(wxTreeCtrl):
27 """PyCrust FillingTree based on wxTreeCtrl."""
28
29 name = 'PyCrust Filling Tree'
30 revision = __revision__
31
32 def __init__(self, parent, id=-1, pos=wxDefaultPosition, \
33 size=wxDefaultSize, style=wxTR_HAS_BUTTONS, \
34 rootObject=None, rootLabel=None, rootIsNamespace=0):
35 """Create a PyCrust FillingTree instance."""
36 wxTreeCtrl.__init__(self, parent, id, pos, size)
37 self.rootIsNamespace = rootIsNamespace
38 if not rootObject:
39 import __main__
40 rootObject = __main__
41 self.rootIsNamespace = 1
42 if not rootLabel: rootLabel = 'Ingredients'
43 rootData = wxTreeItemData(rootObject)
44 self.root = self.AddRoot(rootLabel, -1, -1, rootData)
45 self.SetItemHasChildren(self.root, self.hasChildren(self.root))
46 EVT_TREE_ITEM_EXPANDING(self, self.GetId(), self.OnItemExpanding)
47 EVT_TREE_ITEM_COLLAPSED(self, self.GetId(), self.OnItemCollapsed)
48 EVT_TREE_SEL_CHANGED(self, self.GetId(), self.OnSelChanged)
49
50 def hasChildren(self, o):
51 """Return true if object has children."""
52 if self.getChildren(o):
53 return true
54 else:
55 return false
56
57 def getChildren(self, o):
58 """Return a dictionary with the attributes or contents of object."""
59 busy = wxBusyCursor()
60 otype = type(o)
61 if (otype is types.DictType) \
62 or str(otype)[17:23] == 'BTrees' and hasattr(o, 'keys'):
63 return o
64 d = {}
65 if otype is types.ListType:
66 for n in range(len(o)):
67 key = '[' + str(n) + ']'
68 d[key] = o[n]
69 if otype not in COMMONTYPES:
70 for key in introspect.getAttributeNames(o):
71 # Believe it or not, some attributes can disappear, such as
72 # the exc_traceback attribute of the sys module. So this is
73 # nested in a try block.
74 try:
75 d[key] = getattr(o, key)
76 except:
77 pass
78 return d
79
80 def OnItemExpanding(self, event):
81 busy = wxBusyCursor()
82 selection = event.GetItem()
83 if self.IsExpanded(selection):
84 return
85 o = self.GetPyData(selection)
86 children = self.getChildren(o)
87 if not children:
88 return
89 list = children.keys()
90 try:
91 list.sort(lambda x, y: cmp(x.lower(), y.lower()))
92 except:
93 pass
94 for item in list:
95 itemtext = str(item)
96 # Show string dictionary items with single quotes, except for
97 # the first level of items, if they represent a namespace.
98 if type(o) is types.DictType \
99 and type(item) is types.StringType \
100 and (selection != self.root \
101 or (selection == self.root and not self.rootIsNamespace)):
102 itemtext = repr(item)
103 child = self.AppendItem(selection, itemtext, -1, -1, \
104 wxTreeItemData(children[item]))
105 self.SetItemHasChildren(child, self.hasChildren(children[item]))
106
107 def OnItemCollapsed(self, event):
108 """Remove all children from the item."""
109 busy = wxBusyCursor()
110 item = event.GetItem()
111 self.DeleteChildren(item)
112
113 def OnSelChanged(self, event):
114 busy = wxBusyCursor()
115 item = event.GetItem()
116 if item == self.root:
117 self.setText('')
118 return
119 o = self.GetPyData(item)
120 otype = type(o)
121 text = ''
122 text += self.getFullName(item)
123 text += '\n\nType: ' + str(otype)
124 try:
125 value = str(o)
126 except:
127 value = ''
128 if otype is types.StringType or otype is types.UnicodeType:
129 value = repr(o)
130 text += '\n\nValue: ' + value
131 if otype is types.InstanceType:
132 try:
133 text += '\n\nClass Definition:\n\n' + \
134 inspect.getsource(o.__class__)
135 except:
136 try:
137 text += '\n\n"""' + inspect.getdoc(o).strip() + '"""'
138 except:
139 pass
140 else:
141 try:
142 text += '\n\nSource Code:\n\n' + \
143 inspect.getsource(o)
144 except:
145 try:
146 text += '\n\n"""' + inspect.getdoc(o).strip() + '"""'
147 except:
148 pass
149 self.setText(text)
150
151 def getFullName(self, item, partial=''):
152 """Return a syntactically proper name for item."""
153 parent = self.GetItemParent(item)
154 parento = self.GetPyData(parent)
155 name = self.GetItemText(item)
156 # Apply dictionary syntax to dictionary items, except the root
157 # and first level children of a namepace.
158 if (type(parento) is types.DictType \
159 or str(type(parento))[17:23] == 'BTrees' \
160 and hasattr(parento, 'keys')) \
161 and ((item != self.root and parent != self.root) \
162 or (parent == self.root and not self.rootIsNamespace)):
163 name = '[' + name + ']'
164 # Apply dot syntax to multipart names.
165 if partial:
166 if partial[0] == '[':
167 name += partial
168 else:
169 name += '.' + partial
170 # Repeat for everything but the root item
171 # and first level children of a namespace.
172 if (item != self.root and parent != self.root) \
173 or (parent == self.root and not self.rootIsNamespace):
174 name = self.getFullName(parent, partial=name)
175 return name
176
177 def setText(self, text):
178 """Display information about the current selection."""
179
180 # This method will most likely be replaced by the enclosing app
181 # to do something more interesting, like write to a text control.
182 print text
183
184 def setStatusText(self, text):
185 """Display status information."""
186
187 # This method will most likely be replaced by the enclosing app
188 # to do something more interesting, like write to a status bar.
189 print text
190
191
192 if wxPlatform == '__WXMSW__':
193 faces = { 'times' : 'Times New Roman',
194 'mono' : 'Courier New',
195 'helv' : 'Lucida Console',
196 'lucida' : 'Lucida Console',
197 'other' : 'Comic Sans MS',
198 'size' : 10,
199 'lnsize' : 9,
200 'backcol': '#FFFFFF',
201 }
202 # Versions of wxPython prior to 2.3.2 had a sizing bug on Win platform.
203 # The font was 2 points too large. So we need to reduce the font size.
204 if ((wxMAJOR_VERSION, wxMINOR_VERSION) == (2, 3) and wxRELEASE_NUMBER < 2) \
205 or (wxMAJOR_VERSION <= 2 and wxMINOR_VERSION <= 2):
206 faces['size'] -= 2
207 faces['lnsize'] -= 2
208 else: # GTK
209 faces = { 'times' : 'Times',
210 'mono' : 'Courier',
211 'helv' : 'Helvetica',
212 'other' : 'new century schoolbook',
213 'size' : 12,
214 'lnsize' : 10,
215 'backcol': '#FFFFFF',
216 }
217
218
219 class FillingText(wxStyledTextCtrl):
220 """PyCrust FillingText based on wxStyledTextCtrl."""
221
222 name = 'PyCrust Filling Text'
223 revision = __revision__
224
225 def __init__(self, parent, id=-1, pos=wxDefaultPosition, \
226 size=wxDefaultSize, style=wxCLIP_CHILDREN):
227 """Create a PyCrust FillingText instance."""
228 wxStyledTextCtrl.__init__(self, parent, id, pos, size, style)
229 # Configure various defaults and user preferences.
230 self.config()
231
232 def config(self):
233 """Configure shell based on user preferences."""
234 self.SetMarginWidth(1, 0)
235
236 self.SetLexer(wxSTC_LEX_PYTHON)
237 self.SetKeyWords(0, ' '.join(keyword.kwlist))
238
239 self.setStyles(faces)
240 self.SetViewWhiteSpace(0)
241 self.SetTabWidth(4)
242 self.SetUseTabs(0)
243 self.SetReadOnly(1)
244 try:
245 self.SetWrapMode(1)
246 except AttributeError:
247 pass
248
249 def setStyles(self, faces):
250 """Configure font size, typeface and color for lexer."""
251
252 # Default style
253 self.StyleSetSpec(wxSTC_STYLE_DEFAULT, "face:%(mono)s,size:%(size)d" % faces)
254
255 self.StyleClearAll()
256
257 # Built in styles
258 self.StyleSetSpec(wxSTC_STYLE_LINENUMBER, "back:#C0C0C0,face:%(mono)s,size:%(lnsize)d" % faces)
259 self.StyleSetSpec(wxSTC_STYLE_CONTROLCHAR, "face:%(mono)s" % faces)
260 self.StyleSetSpec(wxSTC_STYLE_BRACELIGHT, "fore:#0000FF,back:#FFFF88")
261 self.StyleSetSpec(wxSTC_STYLE_BRACEBAD, "fore:#FF0000,back:#FFFF88")
262
263 # Python styles
264 self.StyleSetSpec(wxSTC_P_DEFAULT, "face:%(mono)s" % faces)
265 self.StyleSetSpec(wxSTC_P_COMMENTLINE, "fore:#007F00,face:%(mono)s" % faces)
266 self.StyleSetSpec(wxSTC_P_NUMBER, "")
267 self.StyleSetSpec(wxSTC_P_STRING, "fore:#7F007F,face:%(mono)s" % faces)
268 self.StyleSetSpec(wxSTC_P_CHARACTER, "fore:#7F007F,face:%(mono)s" % faces)
269 self.StyleSetSpec(wxSTC_P_WORD, "fore:#00007F,bold")
270 self.StyleSetSpec(wxSTC_P_TRIPLE, "fore:#7F0000")
271 self.StyleSetSpec(wxSTC_P_TRIPLEDOUBLE, "fore:#000033,back:#FFFFE8")
272 self.StyleSetSpec(wxSTC_P_CLASSNAME, "fore:#0000FF,bold")
273 self.StyleSetSpec(wxSTC_P_DEFNAME, "fore:#007F7F,bold")
274 self.StyleSetSpec(wxSTC_P_OPERATOR, "")
275 self.StyleSetSpec(wxSTC_P_IDENTIFIER, "")
276 self.StyleSetSpec(wxSTC_P_COMMENTBLOCK, "fore:#7F7F7F")
277 self.StyleSetSpec(wxSTC_P_STRINGEOL, "fore:#000000,face:%(mono)s,back:#E0C0E0,eolfilled" % faces)
278
279 def SetText(self, *args, **kwds):
280 self.SetReadOnly(0)
281 wxStyledTextCtrl.SetText(self, *args, **kwds)
282 self.SetReadOnly(1)
283
284
285 class Filling(wxSplitterWindow):
286 """PyCrust Filling based on wxSplitterWindow."""
287
288 name = 'PyCrust Filling'
289 revision = __revision__
290
291 def __init__(self, parent, id=-1, pos=wxDefaultPosition, \
292 size=wxDefaultSize, style=wxSP_3D, name='Filling Window', \
293 rootObject=None, rootLabel=None, rootIsNamespace=0):
294 """Create a PyCrust Filling instance."""
295 wxSplitterWindow.__init__(self, parent, id, pos, size, style, name)
296 self.fillingTree = FillingTree(parent=self, rootObject=rootObject, \
297 rootLabel=rootLabel, \
298 rootIsNamespace=rootIsNamespace)
299 self.fillingText = FillingText(parent=self)
300 self.SplitVertically(self.fillingTree, self.fillingText, 200)
301 self.SetMinimumPaneSize(1)
302 # Override the filling so that descriptions go to fillingText.
303 self.fillingTree.setText = self.fillingText.SetText
304 # Select the root item.
305 self.fillingTree.SelectItem(self.fillingTree.root)
306
307
308 class FillingFrame(wxFrame):
309 """Frame containing the PyCrust filling, or namespace tree component."""
310
311 name = 'PyCrust Filling Frame'
312 revision = __revision__
313
314 def __init__(self, parent=None, id=-1, title='PyFilling', \
315 pos=wxDefaultPosition, size=wxDefaultSize, \
316 style=wxDEFAULT_FRAME_STYLE, rootObject=None, \
317 rootLabel=None, rootIsNamespace=0):
318 """Create a PyCrust FillingFrame instance."""
319 wxFrame.__init__(self, parent, id, title, pos, size, style)
320 intro = 'Welcome To PyFilling - The Tastiest Namespace Inspector'
321 self.CreateStatusBar()
322 self.SetStatusText(intro)
323 if wxPlatform == '__WXMSW__':
324 import os
325 filename = os.path.join(os.path.dirname(__file__), 'PyCrust.ico')
326 icon = wxIcon(filename, wxBITMAP_TYPE_ICO)
327 self.SetIcon(icon)
328 self.filling = Filling(parent=self, rootObject=rootObject, \
329 rootLabel=rootLabel, \
330 rootIsNamespace=rootIsNamespace)
331 # Override the filling so that status messages go to the status bar.
332 self.filling.fillingTree.setStatusText = self.SetStatusText
333
334
335 class App(wxApp):
336 """PyFilling standalone application."""
337
338 def OnInit(self):
339 self.fillingFrame = FillingFrame()
340 self.fillingFrame.Show(true)
341 self.SetTopWindow(self.fillingFrame)
342 return true
343
344
345
346