from xml.dom import minidom
from globals import *
from params import *
+import traceback, types
# Base class for interface parameter classes
class xxxNode:
hasStyle = True # almost everyone
hasName = True # has name attribute?
isSizer = hasChild = False
+ isElement = True
allParams = None # Some nodes have no parameters
# Style parameters (all optional)
styles = ['fg', 'bg', 'font', 'enabled', 'focused', 'hidden', 'tooltip']
# parent is parent xxx object (or None if none), element is DOM element object
def __init__(self, parent, element, refElem=None):
self.parent = parent
- self.element = element
+ self.node = element
self.refElem = refElem
self.undo = None
# Reference are dereferenced
if self.hasName: self.name = element.getAttribute('name')
# Set parameters (text element children)
self.params = {}
- nodes = element.childNodes[:]
- for node in nodes:
- if node.nodeType == minidom.Node.ELEMENT_NODE:
- tag = node.tagName
+ for n in element.childNodes[:]:
+ if n.nodeType == minidom.Node.ELEMENT_NODE:
+ tag = n.tagName
if tag in ['object', 'object_ref']:
continue # do nothing for object children here
elif tag not in self.allParams and tag not in self.styles:
print 'WARNING: unknown parameter for %s: %s' % \
(self.className, tag)
elif tag in self.specials:
- self.special(tag, node)
+ self.special(tag, n)
elif tag == 'content':
if self.className == 'wxCheckListBox':
- self.params[tag] = xxxParamContentCheckList(node)
+ self.params[tag] = xxxParamContentCheckList(n)
else:
- self.params[tag] = xxxParamContent(node)
+ self.params[tag] = xxxParamContent(n)
elif tag == 'font': # has children
- self.params[tag] = xxxParamFont(element, node)
+ self.params[tag] = xxxParamFont(element, n)
elif tag in self.bitmapTags:
# Can have attributes
- self.params[tag] = xxxParamBitmap(node)
+ self.params[tag] = xxxParamBitmap(n)
else: # simple parameter
- self.params[tag] = xxxParam(node)
- elif node.nodeType == minidom.Node.TEXT_NODE and node.data.isspace():
+ self.params[tag] = xxxParam(n)
+ elif n.nodeType == minidom.Node.TEXT_NODE and n.data.isspace():
# Remove empty text nodes
- element.removeChild(node)
- node.unlink()
+ element.removeChild(n)
+ n.unlink()
# Check that all required params are set
for param in self.required:
break
if found:
nextTextElem = self.params[p].node
- self.element.insertBefore(elem, nextTextElem)
+ self.node.insertBefore(elem, nextTextElem)
else:
- self.element.appendChild(elem)
+ self.node.appendChild(elem)
else:
wx.LogWarning('Required parameter %s of %s missing' %
(param, self.className))
if self.hasChild: obj = self.child
else: obj = self
obj.name = name
- obj.element.setAttribute('name', name)
+ obj.node.setAttribute('name', name)
+ # Special processing for growablecols-like parameters
+ # represented by several nodes
+ def special(self, tag, node):
+ if not self.params.has_key(tag):
+ # Create new multi-group
+ self.params[tag] = xxxParamMulti(node)
+ self.params[tag].append(xxxParamInt(node))
+ def setSpecial(self, param, value):
+ # Straightforward implementation: remove, add again
+ self.params[param].remove()
+ del self.params[param]
+ for i in value:
+ node = g.tree.dom.createElement(param)
+ text = g.tree.dom.createTextNode(str(i))
+ node.appendChild(text)
+ self.node.appendChild(node)
+ self.special(param, node)
# Imitation of FindResource/DoFindResource from xmlres.cpp
def DoFindResource(parent, name, classname, recursive):
self.data = v
def update(self, value):
# `value' is a list of strings corresponding to all parameters
- elem = self.element
+ elem = self.node
# Remove old elements first
childNodes = elem.childNodes[:]
for node in childNodes: elem.removeChild(node)
winStyles = ['wxDP_DEFAULT', 'wxDP_SPIN', 'wxDP_DROPDOWN',
'wxDP_ALLOWNONE', 'wxDP_SHOWCENTURY']
+class xxxGrid(xxxObject):
+ allParams = ['pos', 'size', 'style']
+
+class xxxFilePickerCtrl(xxxObject):
+ allParams = ['value', 'message', 'wildcard', 'pos', 'size', 'style']
+ winStyles = ['wxFLP_OPEN', 'wxFLP_SAVE', 'wxFLP_OVERWRITE_PROMPT',
+ 'wxFLP_FILE_MUST_EXIST', 'wxFLP_CHANGE_DIR',
+ 'wxFLP_DEFAULT_STYLE']
+
+
################################################################################
# Buttons
specials = ['growablecols', 'growablerows']
allParams = ['cols', 'rows', 'vgap', 'hgap'] + specials
paramDict = {'growablecols': ParamIntList, 'growablerows': ParamIntList}
- # Special processing for growable* parameters
- # (they are represented by several nodes)
- def special(self, tag, node):
- if not self.params.has_key(tag):
- # Create new multi-group
- self.params[tag] = xxxParamMulti(node)
- self.params[tag].append(xxxParamInt(node))
- def setSpecial(self, param, value):
- # Straightforward implementation: remove, add again
- self.params[param].remove()
- del self.params[param]
- for i in value:
- node = g.tree.dom.createElement(param)
- text = g.tree.dom.createTextNode(str(i))
- node.appendChild(text)
- self.element.appendChild(node)
- self.special(param, node)
class xxxGridBagSizer(xxxSizer):
specials = ['growablecols', 'growablerows']
allParams = ['vgap', 'hgap'] + specials
- paramDict = {'growablecols':ParamIntList, 'growablerows':ParamIntList}
- # Special processing for growable* parameters
- # (they are represented by several nodes)
- def special(self, tag, node):
- if not self.params.has_key(tag):
- # Create new multi-group
- self.params[tag] = xxxParamMulti(node)
- self.params[tag].append(xxxParamInt(node))
- def setSpecial(self, param, value):
- # Straightforward implementation: remove, add again
- self.params[param].remove()
- del self.params[param]
- for i in value:
- node = g.tree.dom.createElement(param)
- text = g.tree.dom.createTextNode(str(i))
- node.appendChild(text)
- self.element.appendChild(node)
- self.special(param, node)
+ paramDict = {'growablecols': ParamIntList, 'growablerows': ParamIntList}
# Container with only one child.
# Not shown in tree.
winStyles = ['wxNO_FULL_REPAINT_ON_RESIZE']
################################################################################
+# Comment
+
+_handlers = [] # custom handler classes/funcs
+def getHandlers():
+ return _handlers
+def setHandlers(handlers):
+ global _handlers
+ _handlers = handlers
+_CFuncPtr = None # ctypes function type
+
+def register(hndlr):
+ """Register hndlr function or XmlResourceHandler class."""
+ if _CFuncPtr and isinstance(hndlr, _CFuncPtr):
+ _handlers.append(hndlr)
+ return
+ if not isinstance(hndlr, type):
+ wx.LogError('handler is not a type: %s' % hndlr)
+ elif not issubclass(hndlr, wx.xrc.XmlResourceHandler):
+ wx.LogError('handler is not a XmlResourceHandler: %s' % hndlr)
+ else:
+ _handlers.append(hndlr)
+
+def load_dl(path, localname=''):
+ """Load shared/dynamic library into xxx namespace.
+ If path is not absolute or relative, try to find in the module's directory.
+ """
+ if not localname:
+ localname = os.path.basename(os.path.splitext(path)[0])
+ try:
+ import ctypes
+ global _CFuncPtr
+ _CFuncPtr = ctypes._CFuncPtr # use as a flag of loaded ctypes
+ #if not os.path.dirname(path) and os.path.isfile(path):
+
+ except ImportError:
+ wx.LogError('ctypes module not found')
+ globals()[localname] = None
+ return
+ try:
+ dl = ctypes.CDLL(path)
+ globals()[localname] = dl
+ # Register AddXmlHandlers() if exists
+ try:
+ register(dl.AddXmlHandlers)
+ except:
+ pass
+ except:
+ wx.LogError('error loading dynamic library: %s' % path)
+ print traceback.print_exc()
+
+# Called when creating test window
+def addHandlers():
+ for h in _handlers:
+ if _CFuncPtr and isinstance(h, _CFuncPtr):
+ try:
+ apply(h, ())
+ except:
+ wx.LogError('error calling DL func: "%s"' % h)
+ print traceback.print_exc()
+ else:
+ try:
+ xrc.XmlResource.Get().AddHandler(apply(h, ()))
+ except:
+ wx.LogError('error adding XmlHandler: "%s"' % h)
+ print traceback.print_exc()
+
+def custom(klassName, klass='unknown'):
+ """Define custom control based on xrcClass.
+
+ klass: new object name
+ xrcClass: name of an existing XRC object class or
+ a class object defining class parameters.
+ """
+ if type(klass) is str:
+ # Copy correct xxx class under new name
+ kl = xxxDict[klass]
+ xxxClass = types.ClassType('xxx' + klassName, kl.__bases__, kl.__dict__)
+ else:
+ xxxClass = klass
+ # Register param IDs
+ for param in klass.allParams + klass.paramDict.keys():
+ if not paramIDs.has_key(param):
+ paramIDs[param] = wx.NewId()
+ # Insert in dictionaty
+ xxxDict[klassName] = xxxClass
+ # Add to menu
+ g.pullDownMenu.addCustom(klassName)
+
+class xxxParamComment(xxxParam):
+ def __init__(self, node):
+ xxxNode.__init__(self, node)
+ self.textNode = node
+ # Parse "pragma" comments
+ if node.data and node.data[0] == '%':
+ try:
+ code = node.data[1:]
+ exec code in globals()
+ except:
+ wx.LogError('exec error: "%s"' % code)
+ print traceback.print_exc()
+
+class xxxComment(xxxObject):
+ hasStyle = hasName = False
+ allParams = required = ['comment']
+
+ def __init__(self, parent, node):
+ self.parent = parent
+ self.node = node
+ self.isElement = False
+ self.undo = None
+ self.className = 'comment'
+ self.ref = self.subclass = None
+ self.params = {'comment': xxxParamComment(node)}
+
+ def treeName(self):
+ # Replace newlines by \n to avoid tree item resizing
+ return self.params['comment'].value().replace('\n', r'\n')
+
+################################################################################
+
+# Mapping of XRC names to xxx classes
xxxDict = {
'wxPanel': xxxPanel,
'wxDialog': xxxDialog,
'wxGenericDirCtrl': xxxGenericDirCtrl,
'wxSpinCtrl': xxxSpinCtrl,
'wxScrolledWindow': xxxScrolledWindow,
+ 'wxGrid': xxxGrid,
+ 'wxFilePickerCtrl': xxxFilePickerCtrl,
'wxDatePickerCtrl': xxxDateCtrl,
'wxBoxSizer': xxxBoxSizer,
'separator': xxxSeparator,
'unknown': xxxUnknown,
+ 'comment': xxxComment,
}
# Create IDs for all parameters of all classes
paramIDs = {'fg': wx.NewId(), 'bg': wx.NewId(), 'exstyle': wx.NewId(), 'font': wx.NewId(),
'enabled': wx.NewId(), 'focused': wx.NewId(), 'hidden': wx.NewId(),
'tooltip': wx.NewId(), 'encoding': wx.NewId(),
- 'cellpos': wx.NewId(), 'cellspan': wx.NewId()
+ 'cellpos': wx.NewId(), 'cellspan': wx.NewId(),
+ 'text': wx.NewId()
}
for cl in xxxDict.values():
if cl.allParams:
# Test for object elements
def IsObject(node):
- return node.nodeType == minidom.Node.ELEMENT_NODE and node.tagName in ['object', 'object_ref']
+ return node.nodeType == minidom.Node.ELEMENT_NODE and \
+ node.tagName in ['object', 'object_ref'] or \
+ node.nodeType == minidom.Node.COMMENT_NODE
# Make XXX object from some DOM object, selecting correct class
-def MakeXXXFromDOM(parent, element):
- if element.tagName == 'object_ref':
- ref = element.getAttribute('ref')
+def MakeXXXFromDOM(parent, node):
+ if node.nodeType == minidom.Node.COMMENT_NODE:
+ return xxxComment(parent, node)
+ if node.tagName == 'object_ref':
+ ref = node.getAttribute('ref')
refElem = FindResource(ref)
if refElem: cls = refElem.getAttribute('class')
- else: return xxxUnknown(parent, element)
+ else: return xxxUnknown(parent, node)
else:
refElem = None
- cls = element.getAttribute('class')
+ cls = node.getAttribute('class')
try:
klass = xxxDict[cls]
except KeyError:
# If we encounter a weird class, use unknown template
- print 'WARNING: unsupported class:', element.getAttribute('class')
+ print 'WARNING: unsupported class:', node.getAttribute('class')
klass = xxxUnknown
- return klass(parent, element, refElem)
+ return klass(parent, node, refElem)
# Make empty DOM element
def MakeEmptyDOM(className):
#xxx.allParams.remove('label')
return xxx
+# Make empty comment node
+def MakeEmptyCommentDOM():
+ node = g.tree.dom.createComment('')
+ return node
+
+# Make empty xxxComment
+def MakeEmptyCommentXXX(parent):
+ node = MakeEmptyCommentDOM()
+ # Now just make object
+ xxx = MakeXXXFromDOM(parent, node)
+ return xxx
+