Module component
[hide private]
[frames] | no frames]

Source Code for Module component

  1  # Name:         component.py 
  2  # Purpose:      base component classes 
  3  # Author:       Roman Rolinsky <rolinsky@femagsoft.com> 
  4  # Created:      31.05.2007 
  5  # RCS-ID:       $Id: component.py 48572 2007-09-05 19:47:46Z ROL $ 
  6   
  7  """ 
  8  Component plugin classes. 
  9   
 10  This module defines base classes and for deriving component plugin 
 11  classes and contains some global variables used to register components 
 12  with XRCed. 
 13   
 14  Components are objects of Component class or one of the derived 
 15  classes used to define specialized components (such as sizers). After 
 16  a component object is constructed and configured it can be registered 
 17  using the Manager global object. 
 18   
 19  """ 
 20   
 21   
 22  import os,sys,bisect 
 23  import wx 
 24  from sets import Set 
 25  from globals import * 
 26  from model import Model 
 27  from attribute import * 
 28  import params 
 29  import view 
 30  import images 
 31   
 32  DEFAULT_POS = (1000,1000) 
 33   
 34  # Group compatibility specifications.  
 35  # Key is the parent group, value is the list of child groups. 
 36  # !value means named main group is excluded from possible children. 
 37  # "root" is a special group for the tree root 
 38  parentChildGroups = { 
 39      'root': ['top_level', 'component'],      # top-level objects 
 40      'frame': ['toolbar', 'menubar', 'statusbar'], 
 41      'wizard': ['wizard_page'], 
 42      'window': ['control', 'window', 'sizer', 'btnsizer', '!frame'], 
 43      'sizer': ['control', 'sizer', 'btnsizer', 'spacer'], 
 44      'book': ['control', 'window', '!sizer', '!btnsizer'], 
 45      'btnsizer': ['stdbtn'], 
 46      'menubar': ['menu'], 
 47      'toolbar': ['tool', 'separator'], 
 48      'menu': ['menu', 'menu_item', 'separator'], 
 49  } 
 50  ''' 
 51  Definition of compatibility of component groups as I{key}:I{group_list} pairs, where 
 52  I{key} is a parent group name and I{group_list} is a list of children group names or 
 53  group names prefixed with '!' character to exclude components having corresponding 
 54  primary group. This dictionary can be modified by component plugins directly 
 55  (some care must be taken not to redefine existing relations or breake them). 
 56  ''' 
 57   
 58   
59 -class Component(object):
60 '''Base class for component plugins.''' 61 # Common window attributes 62 windowAttributes = ['fg', 'bg', 'font', 'tooltip', 'help', 63 'enabled', 'focused', 'hidden'] 64 '''Default window attributes for window-like components.''' 65 genericStyles = [ 66 'wxSIMPLE_BORDER', 'wxSUNKEN_BORDER', 'wxDOUBLE_BORDER', 67 'wxRAISED_BORDER', 'wxSTATIC_BORDER', 'wxNO_BORDER', 68 'wxCLIP_CHILDREN', 'wxTRANSPARENT_WINDOW', 'wxWANTS_CHARS', 69 'wxNO_FULL_REPAINT_ON_RESIZE', 'wxFULL_REPAINT_ON_RESIZE' 70 ] 71 '''Default generic styles.''' 72 genericExStyles = [ 73 'wxWS_EX_VALIDATE_RECURSIVELY', 74 'wxWS_EX_BLOCK_EVENTS', 75 'wxWS_EX_TRANSIENT', 76 'wxFRAME_EX_CONTEXTHELP', 77 'wxWS_EX_PROCESS_IDLE', 78 'wxWS_EX_PROCESS_UI_UPDATES' 79 ] 80 '''Default generic extended styles.''' 81 genericEvents = [ 82 'EVT_WINDOW_CREATE', 'EVT_WINDOW_DESTROY', 83 'EVT_MOVE', 'EVT_SIZE', 84 'EVT_MOUSE_EVENTS', 'EVT_MOTION', 85 'EVT_LEFT_DOWN', 'EVT_LEFT_DCLICK', 86 'EVT_MIDDLE_DOWN', 'EVT_MIDDLE_DCLICK', 87 'EVT_RIGHT_DOWN', 'EVT_RIGHT_DCLICK', 'EVT_MOUSEWHEEL', 88 'EVT_ENTER_WINDOW', 'EVT_LEAVE_WINDOW', 89 'EVT_KEY_DOWN', 'EVT_KEY_UP', 'EVT_CHAR', 90 'EVT_PAINT', 'EVT_ERASE_BACKGROUND', 91 'EVT_CONTEXT_MENU', 'EVT_HELP', 92 'EVT_SET_FOCUS', 'EVT_KILL_FOCUS', 'EVT_CHILD_FOCUS', 93 'EVT_UPDATE_UI', 'EVT_IDLE', 94 ] 95 '''Default generic events.''' 96 hasName = True # most elements have XRC IDs 97 '''True if component has an XRC ID attribute.''' 98 isTopLevel = False # if can be created as top level window 99 '''True if component can be a top-level object in XML tree.''' 100 renameDict = {} 101 '''Dictionary of I{old_name}:I{new_name} for renaming some attributes 102 in the Attribute Panel.''' 103
104 - def __init__(self, klass, groups, attributes, **kargs):
105 ''' 106 Construct a new Component object. 107 108 @param klass: Interface element class name (e.g. C{'wxButton'}). 109 @param groups: List of group names to which this component belongs. 110 First group is considered to be the I{primary group}. 111 @param attributes: List of XRC attribute names. 112 113 B{Supported keyword parameters:} 114 115 @keyword defaults: Dictionary of default attribute values for creating 116 new items. 117 @keyword specials: Dictionary of I{attribute_name}:I{attribute_class} pairs 118 for specifying special attribute classes for some attributes, instead of 119 using default Attribute class. 120 @keyword params: Dictionary of pairs I{attribute_name}:I{param_class} where 121 I{param_class} is a attribute interface class (one of classes in 122 params.py or a custom class). If a param class is not specified, a default 123 value defined by C{paramDict} dictionary is used. 124 @keyword image,images: C{wx.Image} object or a list of C{wx.Image} objects 125 for tree icons. 126 @keyword events: List of event names for code genration panel. 127 ''' 128 self.klass = klass 129 self.groups = groups 130 self.attributes = attributes 131 self.styles = [] 132 self.exStyles = [] 133 self.defaults = kargs.get('defaults', {}) 134 # Special Attribute classes if required 135 self.specials = kargs.get('specials', {}) 136 # Some default special attributes 137 self.specials['font'] = FontAttribute 138 self.specials['XRCED'] = CodeAttribute 139 # Special Param classes if required 140 self.params = kargs.get('params', {}) 141 # Tree image 142 if 'images' in kargs: 143 self.images = kargs['images'] 144 elif 'image' in kargs: 145 self.images = [kargs['image']] 146 elif not 'image' in self.__dict__: 147 self.images = [] 148 # Code generation data 149 self.events = kargs.get('events', [])
150
151 - def addStyles(self, *styles):
152 '''Add more styles.''' 153 self.styles.extend(styles)
154
155 - def addExStyles(self, *styles):
156 '''Add more extra styles.''' 157 self.exStyles.extend(styles)
158
159 - def setSpecial(self, attrName, attrClass):
160 '''Set special attribute class for processing XML. 161 162 @param attrName: Attribute name. 163 @param attrClass: Attribute class. 164 ''' 165 self.specials[attrName] = attrClass
166
167 - def setParamClass(self, attrName, paramClass):
168 '''Set special attribute panel class for editing attribute value. 169 170 @param attrName: Attribute name. 171 @param paramClass: Param class. 172 ''' 173 self.params[attrName] = paramClass
174
175 - def getTreeImageId(self, node):
176 try: 177 return self.images[0].Id 178 except IndexError: 179 return 0
180
181 - def getTreeText(self, node):
182 label = node.getAttribute('subclass') 183 if not label: 184 label = node.getAttribute('class') 185 if self.hasName: 186 name = node.getAttribute('name') 187 if name: label += ' "%s"' % name 188 return label
189
190 - def addEvents(self, *events):
191 '''Add more events.''' 192 self.events.extend(events)
193 194 # Order components having same index by group and klass
195 - def __cmp__(self, other):
196 if self.groups < other.groups: return -1 197 elif self.groups == other.groups: 198 if self.klass < other.klass: return -1 199 elif self.klass == other.klass: return 0 200 else: return 1 201 else: return 1
202
203 - def __repr__(self):
204 return "Component('%s', %s)" % (self.klass, self.attributes)
205
206 - def canHaveChild(self, component):
207 '''True if the current component can have child of given type. 208 209 This function is redefined by container classes.''' 210 return False
211
212 - def canBeReplaced(self, component):
213 '''True if the current component can be replaced by component. 214 215 This function can be redefined by derived classes.''' 216 return component.groups == groups
217
218 - def isContainer(self):
219 '''True if component is a container (can have child nodes).''' 220 return isinstance(self, Container)
221
222 - def getAttribute(self, node, attribute):
223 attrClass = self.specials.get(attribute, Attribute) 224 # 'object' means attribute is a text node without element tag, 225 if attribute == 'object': 226 return attrClass.get(node) 227 elif issubclass(attrClass, AttributeAttribute): 228 return attrClass.getAA(node, attribute) 229 for n in node.childNodes: 230 if n.nodeType == node.ELEMENT_NODE and n.tagName == attribute: 231 return attrClass.get(n) 232 return attrClass.get(None)
233
234 - def addAttribute(self, node, attribute, value):
235 '''Add attribute element.''' 236 attrClass = self.specials.get(attribute, Attribute) 237 attrClass.add(node, attribute, value)
238
239 - def makeTestWin(self, res, name):
240 '''Method can be overrided by derived classes to create custom test view. 241 242 @param res: C{wx.xrc.XmlResource} object with current test resource. 243 @param name: XRC ID of tested object. 244 ''' 245 if not self.hasName: raise NotImplementedError 246 247 testWin = view.testWin 248 if self.isTopLevel: 249 # Top-level window creates frame itself 250 frame = None 251 object = res.LoadObject(view.frame, STD_NAME, self.klass) 252 object.Fit() 253 testWin.size = object.GetSize() 254 else: 255 # Create MiniFrame to hold selected subtree 256 frame = testWin.frame 257 if not frame: 258 frame = wx.MiniFrame(view.frame, -1, '%s: %s' % (self.klass, name), name=STD_NAME, 259 style=wx.CAPTION|wx.CLOSE_BOX|wx.RESIZE_BORDER) 260 frame.panel = wx.Panel(frame) 261 object = res.LoadObject(frame.panel, STD_NAME, self.klass) 262 if not object: raise NotImplementedError 263 object.SetPosition((20,20)) 264 object.Fit() 265 if not isinstance(object, wx.Window): raise NotImplementedError 266 if not testWin.frame: 267 frame.SetClientSize(object.GetSize()+(20,20)) 268 testWin.size = frame.GetSize() 269 return frame, object
270
271 - def getRect(self, obj):
272 '''Return bounding box coordinates for C{obj}.''' 273 # Object's rect must be relative to testWin.object 274 if isinstance(obj, wx.Window): 275 return [obj.GetRect()] 276 elif isinstance(obj, wx.Rect): # spacer 277 return [obj] 278 else: 279 return None
280
281 - def copyAttributes(self, srcNode, dstNode):
282 '''Copy relevant attribute nodes from srcNode to dstNode.''' 283 dstComp = Manager.getNodeComp(dstNode) 284 for n in srcNode.childNodes: 285 if n.nodeType == n.ELEMENT_NODE: 286 a = n.tagName 287 # Check if attributes are compatible 288 srcAttrClass = self.specials.get(a, Attribute) 289 dstAttrClass = dstComp.specials.get(a, Attribute) 290 if srcAttrClass is not dstAttrClass: continue 291 srcParamClass = self.params.get(a, params.paramDict.get(a, params.ParamText)) 292 dstParamClass = dstComp.params.get(a, params.paramDict.get(a, params.ParamText)) 293 if srcParamClass is not dstParamClass: continue 294 # Style and exstyle are not in attributes and can be treated specially 295 if a == 'style': 296 styles = self.getAttribute(srcNode, a).split('|') 297 allStyles = dstComp.styles + params.genericStyles 298 dstStyles = [s for s in styles if s.strip() in allStyles] 299 if dstStyles: 300 dstComp.addAttribute(dstNode, a, '|'.join(dstStyles)) 301 elif a == 'exstyle': 302 styles = self.getAttribute(srcNode, a).split('|') 303 allStyles = dstComp.exStyles + params.genericExStyles 304 dstStyles = [s for s in styles if s.strip() in allStyles] 305 if dstStyles: 306 dstComp.addAttribute(dstNode, a, '|'.join(dstStyles)) 307 elif a in dstComp.attributes: 308 value = self.getAttribute(srcNode, a) 309 dstComp.addAttribute(dstNode, a, value)
310 311
312 -class SimpleComponent(Component):
313 '''Component without window attributes and styles.''' 314 windowAttributes = [] 315 genericStyles = genericExStyles = []
316 317
318 -class Container(Component):
319 '''Base class for containers.'''
320 - def canHaveChild(self, component):
321 # Test exclusion first 322 for g in self.groups: 323 if '!'+component.groups[0] in parentChildGroups.get(g, []): return False 324 # Test for any possible parent-child 325 groups = Set(component.groups) 326 for g in self.groups: 327 if groups.intersection(parentChildGroups.get(g, [])): 328 return True 329 return False
330
331 - def isSizer(self):
332 '''If this container manages children positions and sizes.''' 333 return False
334
335 - def requireImplicit(self, node):
336 '''If there are implicit nodes for this particular node.''' 337 return False
338
339 - def getTreeNode(self, node):
340 '''Some containers may hide some internal elements.''' 341 return node
342
343 - def getTreeOrImplicitNode(self, node):
344 '''Return topmost child (implicit if exists).''' 345 return node
346
347 - def appendChild(self, parentNode, node):
348 '''Append child node. Can be overriden to create implicit nodes.''' 349 parentNode.appendChild(node)
350
351 - def insertBefore(self, parentNode, node, nextNode):
352 '''Insert node before nextNode. Can be overriden to create implicit nodes.''' 353 parentNode.insertBefore(node, nextNode)
354
355 - def insertAfter(self, parentNode, node, prevNode):
356 '''Insert node after prevNode. Can be overriden to create implicit nodes.''' 357 parentNode.insertBefore(node, prevNode.nextSibling)
358
359 - def removeChild(self, parentNode, node):
360 ''' 361 Remove node and the implicit node (if present). Return 362 top-level removed child. 363 ''' 364 return parentNode.removeChild(node)
365
366 - def copyObjects(self, srcNode, dstNode):
367 # Copy child objects only for the same group 368 dstComp = Manager.getNodeComp(dstNode) 369 if self.groups[0] != dstComp.groups[0]: return 370 children = [] 371 for n in filter(is_object, srcNode.childNodes): 372 n = self.getTreeNode(n) 373 if dstComp.canHaveChild(Manager.getNodeComp(n)): 374 dstComp.appendChild(dstNode, n)
375
376 - def replaceChild(self, parentNode, newNode, oldNode):
377 '''Replace oldNode by newNode keeping relevant attributes.''' 378 # Keep compatible children 379 oldComp = Manager.getNodeComp(oldNode) 380 oldComp.copyAttributes(oldNode, newNode) 381 if oldComp.isContainer(): 382 oldComp.copyObjects(oldNode, newNode) 383 parentNode.replaceChild(newNode, oldNode)
384
385 - def getChildObject(self, node, obj, index):
386 """Get index'th child of a tested interface element.""" 387 if isinstance(obj, wx.Window) and obj.GetSizer(): 388 return obj.GetSizer() 389 try: 390 return obj.GetChildren()[index] 391 except IndexError: 392 return None
393 394
395 -class SimpleContainer(Container):
396 '''Container without window attributes and styles.''' 397 windowAttributes = [] 398 genericStyles = genericExStyles = []
399 400
401 -class RootComponent(Container):
402 '''Special root component.''' 403 windowAttributes = [] 404 genericStyles = genericExStyles = [] 405 hasName = False
406 407
408 -class SmartContainer(Container):
409 '''Base class for containers with implicit nodes.''' 410 implicitRenameDict = {}
411 - def __init__(self, klass, groups, attributes, **kargs):
412 Container.__init__(self, klass, groups, attributes, **kargs) 413 self.implicitKlass = kargs['implicit_klass'] 414 self.implicitPageName = kargs['implicit_page'] 415 self.implicitAttributes = kargs['implicit_attributes'] 416 # This is optional 417 self.implicitParams = kargs.get('implicit_params', {})
418
419 - def getTreeNode(self, node):
420 if node.getAttribute('class') == self.implicitKlass: 421 for n in node.childNodes: # find first object 422 if is_object(n): return n 423 # Maybe some children are not implicit 424 return node
425
426 - def getTreeOrImplicitNode(self, node):
427 '''Return topmost child (implicit if exists).''' 428 if node.parentNode.getAttribute('class') == self.implicitKlass: 429 return node.parentNode 430 else: 431 return node
432
433 - def appendChild(self, parentNode, node):
434 if self.requireImplicit(node): 435 elem = Model.createObjectNode(self.implicitKlass) 436 elem.appendChild(node) 437 parentNode.appendChild(elem) 438 else: 439 parentNode.appendChild(node)
440
441 - def insertBefore(self, parentNode, node, nextNode):
442 if self.requireImplicit(nextNode): 443 nextNode = nextNode.parentNode 444 if self.requireImplicit(node): 445 elem = Model.createObjectNode(self.implicitKlass) 446 elem.appendChild(node) 447 parentNode.insertBefore(elem, nextNode) 448 else: 449 parentNode.insertBefore(node, nextNode)
450
451 - def insertAfter(self, parentNode, node, prevNode):
452 if self.requireImplicit(prevNode): 453 nextNode = prevNode.parentNode.nextSibling 454 else: 455 nextNode = prevNode.nextSibling 456 if self.requireImplicit(node): 457 elem = Model.createObjectNode(self.implicitKlass) 458 elem.appendChild(node) 459 parentNode.insertBefore(elem, nextNode) 460 else: 461 parentNode.insertBefore(node, nextNode)
462
463 - def removeChild(self, parentNode, node):
464 if self.requireImplicit(node): 465 implicitNode = node.parentNode 466 #implicitNode.removeChild(node) 467 return parentNode.removeChild(implicitNode) 468 else: 469 return parentNode.removeChild(node)
470
471 - def replaceChild(self, parentNode, newNode, oldNode):
472 # Do similarly to Container for object child nodes 473 oldComp = Manager.getNodeComp(oldNode) 474 oldComp.copyAttributes(oldNode, newNode) 475 if oldComp.isContainer(): 476 oldComp.copyObjects(oldNode, newNode) 477 # Special treatment for implicit nodes 478 if self.requireImplicit(oldNode): 479 implicitNode = oldNode.parentNode 480 if self.requireImplicit(newNode): 481 implicitNode.replaceChild(newNode, oldNode) 482 else: 483 parentNode.replaceChild(newNode, implicitNode) 484 else: 485 if self.requireImplicit(newNode): 486 elem = Model.createObjectNode(self.implicitKlass) 487 elem.appendChild(newNode) 488 parentNode.replaceChild(elem, oldNode) 489 else: 490 parentNode.replaceChild(newNode, oldNode)
491
492 - def requireImplicit(self, node):
493 # SmartContainer by default requires implicit 494 return True
495
496 - def setImplicitParamClass(self, attrName, paramClass):
497 '''Set special Param class.''' 498 self.implicitParams[attrName] = paramClass
499 500
501 -class Sizer(SmartContainer):
502 '''Sizers are not windows and have common implicit node.''' 503 windowAttributes = [] 504 hasName = False 505 genericStyles = [] 506 genericExStyles = [] 507 renameDict = {'orient':'orientation'} 508 implicitRenameDict = {'option':'proportion'}
509 - def __init__(self, klass, groups, attributes, **kargs):
510 kargs.setdefault('implicit_klass', 'sizeritem') 511 kargs.setdefault('implicit_page', 'SizerItem') 512 kargs.setdefault('implicit_attributes', ['option', 'flag', 'border', 'minsize', 'ratio']) 513 kargs.setdefault('implicit_params', {'option': params.ParamInt, 514 'minsize': params.ParamPosSize, 515 'ratio': params.ParamPosSize}) 516 SmartContainer.__init__(self, klass, groups, attributes, **kargs)
517
518 - def isSizer(self):
519 return True
520
521 - def requireImplicit(self, node):
522 return node.getAttribute('class') != 'spacer'
523
524 - def getChildObject(self, node, obj, index):
525 obj = obj.GetChildren()[index] 526 if obj.IsSizer(): 527 return obj.GetSizer() 528 elif obj.IsWindow(): 529 return obj.GetWindow() 530 elif obj.IsSpacer(): 531 return obj.GetRect() 532 return None # normally this is an error
533
534 - def getRect(self, obj):
535 rects = [wx.RectPS(obj.GetPosition(), obj.GetSize())] 536 for sizerItem in obj.GetChildren(): 537 rect = sizerItem.GetRect() 538 rects.append(rect) 539 # Add lines to show borders 540 flag = sizerItem.GetFlag() 541 border = sizerItem.GetBorder() 542 if border == 0: continue 543 x = (rect.GetLeft() + rect.GetRight()) / 2 544 if flag & wx.TOP: 545 rects.append(wx.Rect(x, rect.GetTop() - border, 0, border)) 546 if flag & wx.BOTTOM: 547 rects.append(wx.Rect(x, rect.GetBottom() + 1, 0, border)) 548 y = (rect.GetTop() + rect.GetBottom()) / 2 549 if flag & wx.LEFT: 550 rects.append(wx.Rect(rect.GetLeft() - border, y, border, 0)) 551 if flag & wx.RIGHT: 552 rects.append(wx.Rect(rect.GetRight() + 1, y, border, 0)) 553 return rects
554 555
556 -class BoxSizer(Sizer):
557 '''Sizers are not windows and have common implicit node.''' 558
559 - def __init__(self, klass, groups, attributes, **kargs):
560 self.images = kargs.get('images', None) 561 Sizer.__init__(self, klass, groups, attributes, **kargs)
562
563 - def getTreeImageId(self, node):
564 if self.getAttribute(node, 'orient') == 'wxVERTICAL': 565 return self.images[0].Id 566 else: 567 return self.images[1].Id
568
569 - def getRect(self, obj):
570 rects = Sizer.getRect(self, obj) 571 for sizerItem in obj.GetChildren(): 572 rect = sizerItem.GetRect() 573 flag = sizerItem.GetFlag() 574 if flag & wx.EXPAND: 575 if obj.GetOrientation() == wx.VERTICAL: 576 y = (rect.GetTop() + rect.GetBottom()) / 2 577 rects.append(wx.Rect(rect.x, y, rect.width, 0)) 578 else: 579 x = (rect.GetLeft() + rect.GetRight()) / 2 580 rects.append(wx.Rect(x, rect.y, 0, rect.height)) 581 return rects
582 583 ################################################################################ 584
585 -class _ComponentManager:
586 '''Component manager used to register component plugins.'''
587 - def __init__(self):
588 self.rootComponent = RootComponent('root', ['root'], ['encoding'], 589 specials={'encoding': EncodingAttribute}, 590 params={'encoding': params.ParamEncoding}) 591 self.components = {} 592 self.ids = {} 593 self.firstId = self.lastId = -1 594 self.menus = {} 595 self.panels = {} 596 self.menuNames = ['TOP_LEVEL', 'ROOT', 'bar', 'control', 'button', 'box', 597 'container', 'sizer', 'custom'] 598 self.panelNames = ['Windows', 'Panels', 'Controls', 'Sizers', 'Menus', 599 'Gizmos', 'Custom'] 600 self.panelImages = {} 601 self.handlers = [] # registered XmlHandlers
602
603 - def init(self):
604 self.firstId = self.lastId = wx.NewId()
605
606 - def register(self, component):
607 '''Register component object.''' 608 TRACE('register %s' % component.klass) 609 self.components[component.klass] = component 610 # unique wx ID for event handling 611 component.id = self.lastId = wx.NewId() 612 self.ids[component.id] = component
613
614 - def forget(self, klass):
615 '''Remove registered component.''' 616 del self.components[klass] 617 for menu,iclh in self.menus.items(): 618 if iclh[1].klass == klass: 619 self.menus[menu].remove(iclh) 620 for panel,icb in self.panels.items(): 621 if icb[1].klass == klass: 622 self.panels[panel].remove(icb)
623
624 - def getNodeComp(self, node):
625 return self.components[node.getAttribute('class')]
626
627 - def getMenuData(self, menu):
628 return self.menus.get(menu, None)
629
630 - def setMenu(self, component, menu, label, help, index=1000):
631 '''Set pulldown menu data.''' 632 if menu not in self.menuNames: self.menuNames.append(menu) 633 if menu not in self.menus: self.menus[menu] = [] 634 bisect.insort_left(self.menus[menu], (index, component, label, help))
635
636 - def getPanelData(self, panel):
637 return self.panels.get(panel, None)
638
639 - def setTool(self, component, panel, bitmap=None, 640 pos=DEFAULT_POS, span=(1,1)):
641 '''Set toolpanel data.''' 642 if panel not in self.panelNames: self.panelNames.append(panel) 643 if panel not in self.panels: self.panels[panel] = [] 644 # Auto-select bitmap if not provided 645 if not bitmap: 646 bmpPath = os.path.join('bitmaps', component.klass + '.png') 647 if os.path.exists(bmpPath): 648 bitmap = wx.Bitmap(bmpPath) 649 else: 650 bitmap = images.getToolDefaultBitmap() 651 if g.conf.toolIconScale != 100: 652 im = bitmap.ConvertToImage().Scale( 653 bitmap.GetWidth() * g.conf.toolIconScale / 100, 654 bitmap.GetHeight() * g.conf.toolIconScale / 100) 655 bitmap = im.ConvertToBitmap() 656 bisect.insort_left(self.panels[panel], (pos, span, component, bitmap))
657
658 - def addXmlHandler(self, h):
659 ''' 660 Add an XML resource handler. h must be a class derived from 661 XmlResourceHandler or a function loaded from a dynamic library 662 using ctypes. 663 ''' 664 self.handlers.append(h)
665
666 - def findById(self, id):
667 return self.ids[id]
668
669 - def addXmlHandlers(self, res):
670 '''Register XML handlers before creating a test window.''' 671 for h in self.handlers: 672 TRACE('registering Xml handler %s', h) 673 if g._CFuncPtr and isinstance(h, g._CFuncPtr): 674 try: 675 apply(h, ()) 676 except: 677 logger.exception('error calling DL func "%s"', h) 678 wx.LogError('error calling DL func "%s"' % h) 679 else: # assume a python class handler 680 try: 681 res.AddHandler(apply(h, ())) 682 except: 683 logger.exception('error adding XmlHandler "%s"', h) 684 wx.LogError('error adding XmlHandler "%s"' % h)
685 686 687 # Singleton object 688 Manager = _ComponentManager() 689 '''Singleton global object of L{_ComponentManager} class.''' 690