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