~ubuntu-dev/wxwidgets2.6/upstream-debian

« back to all changes in this revision

Viewing changes to wxPython/wx/py/filling.py

  • Committer: Daniel T Chen
  • Date: 2006-06-26 10:15:11 UTC
  • Revision ID: crimsun@ubuntu.com-20060626101511-a4436cec4c6d9b35
ImportĀ DebianĀ 2.6.3.2.1

Show diffs side-by-side

added added

removed removed

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