1 """Filling is the gui tree control through which a user can navigate 
   2 the local namespace or any object.""" 
   4 __author__ 
= "Patrick K. O'Brien <pobrien@orbtech.com>" 
   6 __revision__ 
= "$Revision$"[11:-2] 
  17 from version 
import VERSION
 
  20 COMMONTYPES 
= [getattr(types
, t
) for t 
in dir(types
) \
 
  21                if not t
.startswith('_') \
 
  22                and t 
not in ('ClassType', 'InstanceType', 'ModuleType')] 
  24 DOCTYPES 
= ('BuiltinFunctionType', 'BuiltinMethodType', 'ClassType', 
  25             'FunctionType', 'GeneratorType', 'InstanceType', 
  26             'LambdaType', 'MethodType', 'ModuleType', 
  27             'UnboundMethodType', 'method-wrapper') 
  29 SIMPLETYPES 
= [getattr(types
, t
) for t 
in dir(types
) \
 
  30                if not t
.startswith('_') and t 
not in DOCTYPES
] 
  35     COMMONTYPES
.append(type(''.__repr
__))  # Method-wrapper in version 2.2.x. 
  36 except AttributeError: 
  40 class FillingTree(wx
.TreeCtrl
): 
  41     """FillingTree based on TreeCtrl.""" 
  44     revision 
= __revision__
 
  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, 
  50         """Create FillingTree instance.""" 
  51         wx
.TreeCtrl
.__init
__(self
, parent
, id, pos
, size
, style
) 
  52         self
.rootIsNamespace 
= rootIsNamespace
 
  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()' 
  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()) 
  69             dispatcher
.connect(receiver
=self
.push
, signal
='Interpreter.push') 
  71     def push(self
, command
, more
): 
  72         """Receiver for Interpreter.push signal.""" 
  75     def OnItemExpanding(self
, event
): 
  76         """Add children to the item.""" 
  77         busy 
= wx
.BusyCursor() 
  78         item 
= event
.GetItem() 
  79         if self
.IsExpanded(item
): 
  81         self
.addChildren(item
) 
  82 #        self.SelectItem(item) 
  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) 
  92     def OnSelChanged(self
, event
): 
  93         """Display information about the item.""" 
  94         busy 
= wx
.BusyCursor() 
  95         self
.item 
= event
.GetItem() 
  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) 
 107     def objHasChildren(self
, obj
): 
 108         """Return true if object has children.""" 
 109         if self
.objGetChildren(obj
): 
 114     def objGetChildren(self
, obj
): 
 115         """Return dictionary with attributes or contents of object.""" 
 116         busy 
= wx
.BusyCursor() 
 118         if otype 
is types
.DictType \
 
 119         or str(otype
)[17:23] == 'BTrees' and hasattr(obj
, 'keys'): 
 122         if otype 
is types
.ListType 
or otype 
is types
.TupleType
: 
 123             for n 
in range(len(obj
)): 
 124                 key 
= '[' + str(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. 
 132                     d
[key
] = getattr(obj
, key
) 
 137     def addChildren(self
, item
): 
 138         self
.DeleteChildren(item
) 
 139         obj 
= self
.GetPyData(item
) 
 140         children 
= self
.objGetChildren(obj
) 
 143         keys 
= children
.keys() 
 144         keys
.sort(lambda x
, y
: cmp(str(x
).lower(), str(y
).lower())) 
 147             # Show string dictionary items with single quotes, except 
 148             # for the first level of items, if they represent a 
 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
)): 
 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
)) 
 164         if self
.IsExpanded(item
): 
 165             self
.addChildren(item
) 
 167         obj 
= self
.GetPyData(item
) 
 168         if wx
.Platform 
== '__WXMSW__': 
 169             if obj 
is None: # Windows bug fix. 
 171         self
.SetItemHasChildren(item
, self
.objHasChildren(obj
)) 
 174         text 
+= self
.getFullName(item
) 
 175         text 
+= '\n\nType: ' + str(otype
) 
 180         if otype 
is types
.StringType 
or otype 
is types
.UnicodeType
: 
 182         text 
+= '\n\nValue: ' + value
 
 183         if otype 
not in SIMPLETYPES
: 
 185                 text 
+= '\n\nDocstring:\n\n"""' + \
 
 186                         inspect
.getdoc(obj
).strip() + '"""' 
 189         if otype 
is types
.InstanceType
: 
 191                 text 
+= '\n\nClass Definition:\n\n' + \
 
 192                         inspect
.getsource(obj
.__class
__) 
 197                 text 
+= '\n\nSource Code:\n\n' + \
 
 198                         inspect
.getsource(obj
) 
 203     def getFullName(self
, item
, partial
=''): 
 204         """Return a syntactically proper name for item.""" 
 205         name 
= self
.GetItemText(item
) 
 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. 
 221             if partial
[0] == '[': 
 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
) 
 232     def setText(self
, text
): 
 233         """Display information about the current selection.""" 
 235         # This method will likely be replaced by the enclosing app to 
 236         # do something more interesting, like write to a text control. 
 239     def setStatusText(self
, text
): 
 240         """Display status information.""" 
 242         # This method will likely be replaced by the enclosing app to 
 243         # do something more interesting, like write to a status bar. 
 247 class FillingText(editwindow
.EditWindow
): 
 248     """FillingText based on StyledTextCtrl.""" 
 250     name 
= 'Filling Text' 
 251     revision 
= __revision__
 
 253     def __init__(self
, parent
, id=-1, pos
=wx
.DefaultPosition
, 
 254                  size
=wx
.DefaultSize
, style
=wx
.CLIP_CHILDREN
, 
 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) 
 263             dispatcher
.connect(receiver
=self
.push
, signal
='Interpreter.push') 
 265     def push(self
, command
, more
): 
 266         """Receiver for Interpreter.push signal.""" 
 269     def SetText(self
, *args
, **kwds
): 
 270         self
.SetReadOnly(False) 
 271         editwindow
.EditWindow
.SetText(self
, *args
, **kwds
) 
 272         self
.SetReadOnly(True) 
 275 class Filling(wx
.SplitterWindow
): 
 276     """Filling based on wxSplitterWindow.""" 
 279     revision 
= __revision__
 
 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
) 
 288         self
.tree 
= FillingTree(parent
=self
, rootObject
=rootObject
, 
 290                                 rootIsNamespace
=rootIsNamespace
, 
 292         self
.text 
= FillingText(parent
=self
, static
=static
) 
 294         wx
.FutureCall(1, self
.SplitVertically
, self
.tree
, self
.text
, 200) 
 296         self
.SetMinimumPaneSize(1) 
 298         # Override the filling so that descriptions go to FillingText. 
 299         self
.tree
.setText 
= self
.text
.SetText
 
 301         # Display the root item. 
 302         self
.tree
.SelectItem(self
.tree
.root
) 
 305         self
.Bind(wx
.EVT_SPLITTER_SASH_POS_CHANGED
, self
.OnChanged
) 
 307     def OnChanged(self
, event
): 
 308         #this is important: do not evaluate this event=> otherwise, splitterwindow behaves strange 
 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) 
 318             self
.text
.SetZoom(zoom
) 
 320     def SaveSettings(self
, config
): 
 321         config
.WriteInt('Sash/FillingPos', self
.GetSashPosition()) 
 322         config
.WriteInt('View/Zoom/Filling', self
.text
.GetZoom()) 
 326 class FillingFrame(wx
.Frame
): 
 327     """Frame containing the namespace tree component.""" 
 329     name 
= 'Filling Frame' 
 330     revision 
= __revision__
 
 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
) 
 342         self
.SetIcon(images
.getPyIcon()) 
 343         self
.filling 
= Filling(parent
=self
, rootObject
=rootObject
, 
 345                                rootIsNamespace
=rootIsNamespace
, 
 347         # Override so that status messages go to the status bar. 
 348         self
.filling
.tree
.setStatusText 
= self
.SetStatusText
 
 352     """PyFilling standalone application.""" 
 355         wx
.InitAllImageHandlers() 
 356         self
.fillingFrame 
= FillingFrame() 
 357         self
.fillingFrame
.Show(True) 
 358         self
.SetTopWindow(self
.fillingFrame
)