]> git.saurik.com Git - wxWidgets.git/blobdiff - wxPython/wx/tools/XRCed/xxx.py
Use wx.FileHistory for the recent files menu
[wxWidgets.git] / wxPython / wx / tools / XRCed / xxx.py
index d4fa56d7443be2e71a496520fed951f7c94a717a..c0ef04012fc2e010ab7fa11f96e47c74ca4937c1 100644 (file)
@@ -7,6 +7,7 @@
 from xml.dom import minidom
 from globals import *
 from params import *
+import traceback, types
 
 # Base class for interface parameter classes
 class xxxNode:
@@ -40,16 +41,23 @@ class xxxParam(xxxNode):
         # Use convertion from unicode to current encoding
         self.textNode = text
     # Value returns string
-    if wxUSE_UNICODE:   # no conversion is needed
+    if wx.USE_UNICODE:   # no conversion is needed
         def value(self):
             return self.textNode.data
         def update(self, value):
             self.textNode.data = value
     else:
         def value(self):
-            return self.textNode.data.encode(g.currentEncoding)
+            try:
+                return self.textNode.data.encode(g.currentEncoding)
+            except LookupError:
+                return self.textNode.data.encode()
         def update(self, value):
-            self.textNode.data = unicode(value, g.currentEncoding)
+            try: # handle exception if encoding is wrong
+                self.textNode.data = unicode(value, g.currentEncoding)
+            except UnicodeDecodeError:
+                self.textNode.data = unicode(value)
+                #wx.LogMessage("Unicode error: set encoding in file\nglobals.py to something appropriate")
 
 # Integer parameter
 class xxxParamInt(xxxParam):
@@ -83,7 +91,7 @@ class xxxParamContent(xxxNode):
                     text = n.childNodes[0] # first child must be text node
                     assert text.nodeType == minidom.Node.TEXT_NODE
                 l.append(text)
-                data.append(str(text.data))
+                data.append(text.data)
             else:                       # remove other
                 node.removeChild(n)
                 n.unlink()
@@ -182,6 +190,7 @@ class xxxObject:
     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']
@@ -201,43 +210,55 @@ class xxxObject:
     #image = -1
     # Construct a new xxx object from DOM element
     # parent is parent xxx object (or None if none), element is DOM element object
-    def __init__(self, parent, element):
+    def __init__(self, parent, element, refElem=None):
         self.parent = parent
-        self.element = element
+        self.node = element
+        self.refElem = refElem
         self.undo = None
-        # Get attributes
-        self.className = element.getAttribute('class')
+        # Reference are dereferenced
+        if element.tagName == 'object_ref':
+            # Find original object
+            self.ref = element.getAttribute('ref')
+            if refElem:
+                self.className = self.refElem.getAttribute('class')
+            else:
+                self.className = 'xxxUnknown'
+            self.required = []
+        else:
+            # Get attributes
+            self.ref = None
+            self.className = element.getAttribute('class')
         self.subclass = element.getAttribute('subclass')
         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
-                if tag == 'object':
+        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
-                if tag not in self.allParams and tag not in self.styles:
+                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)
-            else:
-                # Remove all other nodes
-                element.removeChild(node)
-                node.unlink()
+                    self.params[tag] = xxxParam(n)
+            elif n.nodeType == minidom.Node.TEXT_NODE and n.data.isspace():
+                # Remove empty text nodes
+                element.removeChild(n)
+                n.unlink()
+
         # Check that all required params are set
         for param in self.required:
             if not self.params.has_key(param):
@@ -261,11 +282,11 @@ class xxxObject:
                             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:
-                    wxLogWarning('Required parameter %s of %s missing' %
+                    wx.LogWarning('Required parameter %s of %s missing' %
                                  (param, self.className))
     # Returns real tree object
     def treeObject(self):
@@ -284,14 +305,75 @@ class xxxObject:
         return className
     # Class name or subclass
     def panelName(self):
-        if self.subclass: return self.subclass + '(' + self.className + ')'
-        else: return self.className
+        if self.subclass: name = self.subclass + '(' + self.className + ')'
+        name = self.className
+        if self.ref: name = 'ref: ' + self.ref + ', ' + name
+        return name
+    # Sets name of tree object
+    def setTreeName(self, name):
+        if self.hasChild: obj = self.child
+        else: obj = self
+        obj.name = name
+        obj.node.setAttribute('name', name)
+    # Set normal (text) params
+    def set(self, param, value):
+        try:
+            self.params[param].update(value)
+        except KeyError:
+            elem = g.tree.dom.createElement(param)
+            p = xxxParam(elem)
+            p.update(value)
+            self.params[param] = p
+            self.node.appendChild(elem)
+    # 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):
+    for n in parent.childNodes:
+        if n.nodeType == minidom.Node.ELEMENT_NODE and \
+               n.tagName in ['object', 'object_ref'] and \
+               n.getAttribute('name') == name:
+            cls = n.getAttribute('class')
+            if not classname or cls == classname:  return n
+            if not cls or n.tagName == 'object_ref':
+                refName = n.getAttribute('ref')
+                if not refName:  continue
+                refNode = FindResource(refName)
+                if refName and refNode.getAttribute('class') == classname:
+                    return n
+    if recursive:
+        for n in parent.childNodes:
+            if n.nodeType == minidom.Node.ELEMENT_NODE and \
+                   n.tagName in ['object', 'object_ref']:
+                found = DoFindResource(n, name, classname, True)
+                if found:  return found
+def FindResource(name, classname='', recursive=True):
+    found = DoFindResource(g.tree.mainNode, name, classname, recursive)
+    if found:  return found
+    wx.LogError('XRC resource "%s" not found!' % name)
+                
 
 ################################################################################
 
 # This is a little special: it is both xxxObject and xxxNode
 class xxxParamFont(xxxObject, xxxNode):
-    allParams = ['size', 'style', 'weight', 'family', 'underlined',
+    allParams = ['size', 'family', 'style', 'weight', 'underlined',
                  'face', 'encoding']
     def __init__(self, parent, element):
         xxxObject.__init__(self, parent, element)
@@ -306,7 +388,7 @@ class xxxParamFont(xxxObject, xxxNode):
         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)
@@ -330,15 +412,14 @@ class xxxParamFont(xxxObject, xxxNode):
 
 class xxxContainer(xxxObject):
     hasChildren = True
+    exStyles = []
 
 # Simulate normal parameter for encoding
 class xxxEncoding:
-    def __init__(self, val):
-        self.encd = val
     def value(self):
-        return self.encd
+        return g.currentEncoding
     def update(self, val):
-        self.encd = val
+        g.currentEncoding = val
 
 # Special class for root node
 class xxxMainNode(xxxContainer):
@@ -350,61 +431,89 @@ class xxxMainNode(xxxContainer):
         # Reset required parameters after processing XML, because encoding is
         # a little special
         self.required = ['encoding']
-        self.params['encoding'] = xxxEncoding(dom.encoding)
+        self.params['encoding'] = xxxEncoding()
 
 ################################################################################
 # Top-level windwows
 
 class xxxPanel(xxxContainer):
     allParams = ['pos', 'size', 'style']
+    winStyles = ['wxNO_3D', 'wxTAB_TRAVERSAL']
     styles = ['fg', 'bg', 'font', 'enabled', 'focused', 'hidden', 'exstyle',
               'tooltip']
-    winStyles = ['wxNO_3D', 'wxTAB_TRAVERSAL', 'wxCLIP_CHILDREN']
-    exStyles = ['wxWS_EX_VALIDATE_RECURSIVELY']
 
 class xxxDialog(xxxContainer):
     allParams = ['title', 'centered', 'pos', 'size', 'style']
     paramDict = {'centered': ParamBool}
     required = ['title']
     default = {'title': ''}
-    winStyles = ['wxDEFAULT_DIALOG_STYLE', 'wxSTAY_ON_TOP',
-##                 'wxDIALOG_MODAL', 'wxDIALOG_MODELESS',
-                 'wxCAPTION', 'wxSYSTEM_MENU', 'wxRESIZE_BORDER', 'wxRESIZE_BOX',
-                 'wxTHICK_FRAME',
-                 'wxNO_3D', 'wxTAB_TRAVERSAL', 'wxCLIP_CHILDREN']
+    winStyles = ['wxDEFAULT_DIALOG_STYLE', 'wxCAPTION', 
+                 'wxSTAY_ON_TOP', 'wxSYSTEM_MENU', 'wxTHICK_FRAME',
+                 'wxRESIZE_BORDER', 'wxRESIZE_BOX', 'wxCLOSE_BOX',
+                 'wxMAXIMIZE_BOX', 'wxMINIMIZE_BOX',
+                 'wxDIALOG_MODAL', 'wxDIALOG_MODELESS', 'wxDIALOG_NO_PARENT'
+                 'wxNO_3D', 'wxTAB_TRAVERSAL']                 
+    exStyles = ['wxWS_EX_VALIDATE_RECURSIVELY', 'wxDIALOG_EX_METAL']
     styles = ['fg', 'bg', 'font', 'enabled', 'focused', 'hidden', 'exstyle',
               'tooltip']
-    exStyles = ['wxWS_EX_VALIDATE_RECURSIVELY']
 
 class xxxFrame(xxxContainer):
     allParams = ['title', 'centered', 'pos', 'size', 'style']
     paramDict = {'centered': ParamBool}
     required = ['title']
     default = {'title': ''}
-    winStyles = ['wxDEFAULT_FRAME_STYLE', 'wxDEFAULT_DIALOG_STYLE',
-                 'wxSTAY_ON_TOP',
-                 'wxCAPTION', 'wxSYSTEM_MENU', 'wxRESIZE_BORDER',
-                 'wxRESIZE_BOX', 'wxMINIMIZE_BOX', 'wxMAXIMIZE_BOX',
-                 'wxFRAME_FLOAT_ON_PARENT', 'wxFRAME_TOOL_WINDOW',
-                 'wxNO_3D', 'wxTAB_TRAVERSAL', 'wxCLIP_CHILDREN']
+    winStyles = ['wxDEFAULT_FRAME_STYLE', 'wxDEFAULT_DIALOG_STYLE', 'wxCAPTION', 
+                 'wxSTAY_ON_TOP', 'wxSYSTEM_MENU', 'wxTHICK_FRAME',
+                 'wxRESIZE_BORDER', 'wxRESIZE_BOX', 'wxCLOSE_BOX',
+                 'wxMAXIMIZE_BOX', 'wxMINIMIZE_BOX',
+                 'wxFRAME_NO_TASKBAR', 'wxFRAME_SHAPED', 'wxFRAME_TOOL_WINDOW',
+                 'wxFRAME_FLOAT_ON_PARENT',
+                 'wxNO_3D', 'wxTAB_TRAVERSAL']                 
+    exStyles = ['wxWS_EX_VALIDATE_RECURSIVELY', 'wxFRAME_EX_METAL']
     styles = ['fg', 'bg', 'font', 'enabled', 'focused', 'hidden', 'exstyle',
               'tooltip']
-    exStyles = ['wxWS_EX_VALIDATE_RECURSIVELY']
 
 class xxxTool(xxxObject):
-    allParams = ['bitmap', 'bitmap2', 'toggle', 'tooltip', 'longhelp']
+    allParams = ['bitmap', 'bitmap2', 'radio', 'toggle', 'tooltip', 'longhelp', 'label']
     required = ['bitmap']
-    paramDict = {'bitmap2': ParamBitmap, 'toggle': ParamBool}
+    paramDict = {'bitmap2': ParamBitmap, 'radio': ParamBool, 'toggle': ParamBool}
     hasStyle = False
 
 class xxxToolBar(xxxContainer):
-    allParams = ['bitmapsize', 'margins', 'packing', 'separation',
+    allParams = ['bitmapsize', 'margins', 'packing', 'separation', 'dontattachtoframe',
                  'pos', 'size', 'style']
     hasStyle = False
     paramDict = {'bitmapsize': ParamPosSize, 'margins': ParamPosSize,
-                 'packing': ParamInt, 'separation': ParamInt,
+                 'packing': ParamUnit, 'separation': ParamUnit,
+                 'dontattachtoframe': ParamBool, 'style': ParamNonGenericStyle}
+    winStyles = ['wxTB_FLAT', 'wxTB_DOCKABLE', 'wxTB_VERTICAL', 'wxTB_HORIZONTAL',
+                 'wxTB_3DBUTTONS','wxTB_TEXT', 'wxTB_NOICONS', 'wxTB_NODIVIDER',
+                 'wxTB_NOALIGN', 'wxTB_HORZ_LAYOUT', 'wxTB_HORZ_TEXT']
+
+class xxxStatusBar(xxxObject):
+    hasStyle = False
+    allParams = ['fields', 'widths', 'styles', 'style']
+    paramDict = {'fields': ParamIntNN, 'widths': ParamText, 'styles': ParamText,
                  'style': ParamNonGenericStyle}
-    winStyles = ['wxTB_FLAT', 'wxTB_DOCKABLE', 'wxTB_VERTICAL', 'wxTB_HORIZONTAL']
+    winStyles = ['wxST_SIZEGRIP']
+
+class xxxWizard(xxxContainer):
+    allParams = ['title', 'bitmap', 'pos']
+    required = ['title']
+    default = {'title': ''}
+    winStyles = []
+    exStyles = ['wxWIZARD_EX_HELPBUTTON']
+    styles = ['fg', 'bg', 'font', 'exstyle']
+
+class xxxWizardPage(xxxContainer):
+    allParams = ['bitmap']
+    winStyles = []
+    exStyles = []
+
+class xxxWizardPageSimple(xxxContainer):
+    allParams = ['bitmap']
+    winStyles = []
+    exStyles = []
 
 ################################################################################
 # Bitmap, Icon
@@ -415,8 +524,7 @@ class xxxBitmap(xxxObject):
 
 # Just like bitmap
 class xxxIcon(xxxObject):
-    allParams = ['icon']
-    required = ['icon']
+    allParams = []
 
 ################################################################################
 # Controls
@@ -437,8 +545,24 @@ class xxxStaticBitmap(xxxObject):
 
 class xxxTextCtrl(xxxObject):
     allParams = ['value', 'pos', 'size', 'style']
-    winStyles = ['wxTE_PROCESS_ENTER', 'wxTE_PROCESS_TAB', 'wxTE_MULTILINE',
-              'wxTE_PASSWORD', 'wxTE_READONLY', 'wxHSCROLL']
+    winStyles = ['wxTE_NO_VSCROLL',
+                 'wxTE_AUTO_SCROLL',
+                 'wxTE_PROCESS_ENTER',
+                 'wxTE_PROCESS_TAB',
+                 'wxTE_MULTILINE',
+                 'wxTE_PASSWORD',
+                 'wxTE_READONLY',
+                 'wxHSCROLL',
+                 'wxTE_RICH',
+                 'wxTE_RICH2',
+                 'wxTE_AUTO_URL',
+                 'wxTE_NOHIDESEL',
+                 'wxTE_LEFT',
+                 'wxTE_CENTRE',
+                 'wxTE_RIGHT',
+                 'wxTE_DONTWRAP',
+                 'wxTE_LINEWRAP',
+                 'wxTE_WORDWRAP']
     paramDict = {'value': ParamMultilineText}
 
 class xxxChoice(xxxObject):
@@ -451,60 +575,106 @@ class xxxSlider(xxxObject):
     allParams = ['value', 'min', 'max', 'pos', 'size', 'style',
                  'tickfreq', 'pagesize', 'linesize', 'thumb', 'tick',
                  'selmin', 'selmax']
-    paramDict = {'value': ParamInt, 'tickfreq': ParamInt, 'pagesize': ParamInt,
-                 'linesize': ParamInt, 'thumb': ParamInt, 'thumb': ParamInt,
+    paramDict = {'value': ParamInt, 'tickfreq': ParamIntNN, 'pagesize': ParamIntNN,
+                 'linesize': ParamIntNN, 'thumb': ParamUnit, 
                  'tick': ParamInt, 'selmin': ParamInt, 'selmax': ParamInt}
     required = ['value', 'min', 'max']
     winStyles = ['wxSL_HORIZONTAL', 'wxSL_VERTICAL', 'wxSL_AUTOTICKS', 'wxSL_LABELS',
                  'wxSL_LEFT', 'wxSL_RIGHT', 'wxSL_TOP', 'wxSL_BOTTOM',
-                 'wxSL_BOTH', 'wxSL_SELRANGE']
+                 'wxSL_BOTH', 'wxSL_SELRANGE', 'wxSL_INVERSE']
 
 class xxxGauge(xxxObject):
     allParams = ['range', 'pos', 'size', 'style', 'value', 'shadow', 'bezel']
-    paramDict = {'range': ParamInt, 'value': ParamInt,
-                 'shadow': ParamInt, 'bezel': ParamInt}
+    paramDict = {'range': ParamIntNN, 'value': ParamIntNN,
+                 'shadow': ParamIntNN, 'bezel': ParamIntNN}
     winStyles = ['wxGA_HORIZONTAL', 'wxGA_VERTICAL', 'wxGA_PROGRESSBAR', 'wxGA_SMOOTH']
 
 class xxxScrollBar(xxxObject):
     allParams = ['pos', 'size', 'style', 'value', 'thumbsize', 'range', 'pagesize']
-    paramDict = {'value': ParamInt, 'range': ParamInt, 'thumbsize': ParamInt,
-                 'pagesize': ParamInt}
+    paramDict = {'value': ParamIntNN, 'range': ParamIntNN, 'thumbsize': ParamIntNN,
+                 'pagesize': ParamIntNN}
     winStyles = ['wxSB_HORIZONTAL', 'wxSB_VERTICAL']
 
 class xxxListCtrl(xxxObject):
     allParams = ['pos', 'size', 'style']
     winStyles = ['wxLC_LIST', 'wxLC_REPORT', 'wxLC_ICON', 'wxLC_SMALL_ICON',
-              'wxLC_ALIGN_TOP', 'wxLC_ALIGN_LEFT', 'wxLC_AUTOARRANGE',
-              'wxLC_USER_TEXT', 'wxLC_EDIT_LABELS', 'wxLC_NO_HEADER',
-              'wxLC_SINGLE_SEL', 'wxLC_SORT_ASCENDING', 'wxLC_SORT_DESCENDING']
+                 'wxLC_ALIGN_TOP', 'wxLC_ALIGN_LEFT', 'wxLC_AUTOARRANGE',
+                 'wxLC_USER_TEXT', 'wxLC_EDIT_LABELS', 'wxLC_NO_HEADER',
+                 'wxLC_SINGLE_SEL', 'wxLC_SORT_ASCENDING', 'wxLC_SORT_DESCENDING',
+                 'wxLC_VIRTUAL', 'wxLC_HRULES', 'wxLC_VRULES', 'wxLC_NO_SORT_HEADER']
 
 class xxxTreeCtrl(xxxObject):
     allParams = ['pos', 'size', 'style']
-    winStyles = ['wxTR_HAS_BUTTONS', 'wxTR_NO_LINES', 'wxTR_LINES_AT_ROOT',
-              'wxTR_EDIT_LABELS', 'wxTR_MULTIPLE']
+    winStyles = ['wxTR_EDIT_LABELS',
+                 'wxTR_NO_BUTTONS',
+                 'wxTR_HAS_BUTTONS',
+                 'wxTR_TWIST_BUTTONS',
+                 'wxTR_NO_LINES',
+                 'wxTR_FULL_ROW_HIGHLIGHT',
+                 'wxTR_LINES_AT_ROOT',
+                 'wxTR_HIDE_ROOT',
+                 'wxTR_ROW_LINES',
+                 'wxTR_HAS_VARIABLE_ROW_HEIGHT',
+                 'wxTR_SINGLE',
+                 'wxTR_MULTIPLE',
+                 'wxTR_EXTENDED',
+                 'wxTR_DEFAULT_STYLE']
 
 class xxxHtmlWindow(xxxObject):
     allParams = ['pos', 'size', 'style', 'borders', 'url', 'htmlcode']
-    paramDict = {'borders': ParamInt, 'htmlcode':ParamMultilineText}
-    winStyles = ['wxHW_SCROLLBAR_NEVER', 'wxHW_SCROLLBAR_AUTO']
+    paramDict = {'htmlcode':ParamMultilineText}
+    winStyles = ['wxHW_SCROLLBAR_NEVER', 'wxHW_SCROLLBAR_AUTO', 'wxHW_NO_SELECTION']
 
 class xxxCalendarCtrl(xxxObject):
     allParams = ['pos', 'size', 'style']
+    winStyles = ['wxCAL_SUNDAY_FIRST', 'wxCAL_MONDAY_FIRST', 'wxCAL_SHOW_HOLIDAYS',
+                 'wxCAL_NO_YEAR_CHANGE', 'wxCAL_NO_MONTH_CHANGE',
+                 'wxCAL_SEQUENTIAL_MONTH_SELECTION', 'wxCAL_SHOW_SURROUNDING_WEEKS']
 
 class xxxNotebook(xxxContainer):
-    allParams = ['usenotebooksizer', 'pos', 'size', 'style']
-    paramDict = {'usenotebooksizer': ParamBool}
-    winStyles = ['wxNB_FIXEDWIDTH', 'wxNB_LEFT', 'wxNB_RIGHT', 'wxNB_BOTTOM']
+    allParams = ['pos', 'size', 'style']
+    winStyles = ['wxNB_TOP', 'wxNB_LEFT', 'wxNB_RIGHT', 'wxNB_BOTTOM',
+                 'wxNB_FIXEDWIDTH', 'wxNB_MULTILINE', 'wxNB_NOPAGETHEME', 'wxNB_FLAT']
+
+class xxxChoicebook(xxxContainer):
+    allParams = ['pos', 'size', 'style']
+    winStyles = ['wxCHB_DEFAULT', 'wxCHB_LEFT', 'wxCHB_RIGHT', 'wxCHB_TOP', 'wxCHB_BOTTOM']
+    
+class xxxListbook(xxxContainer):
+    allParams = ['pos', 'size', 'style']
+    winStyles = ['wxLB_DEFAULT', 'wxLB_LEFT', 'wxLB_RIGHT', 'wxLB_TOP', 'wxLB_BOTTOM']
+    
+class xxxSplitterWindow(xxxContainer):
+    allParams = ['orientation', 'sashpos', 'minsize', 'pos', 'size', 'style']
+    paramDict = {'orientation': ParamOrientation, 'sashpos': ParamUnit, 'minsize': ParamUnit }
+    winStyles = ['wxSP_3D', 'wxSP_3DSASH', 'wxSP_3DBORDER', 
+                 'wxSP_FULLSASH', 'wxSP_NOBORDER', 'wxSP_PERMIT_UNSPLIT', 'wxSP_LIVE_UPDATE',
+                 'wxSP_NO_XP_THEME' ]
 
 class xxxGenericDirCtrl(xxxObject):
     allParams = ['defaultfolder', 'filter', 'defaultfilter', 'pos', 'size', 'style']
-    paramDict = {'defaultfilter': ParamInt}
+    paramDict = {'defaultfilter': ParamIntNN}
     winStyles = ['wxDIRCTRL_DIR_ONLY', 'wxDIRCTRL_3D_INTERNAL', 'wxDIRCTRL_SELECT_FIRST',
-                 'wxDIRCTRL_SHOW_FILTERS', 'wxDIRCTRL_EDIT_LABELS']
+                 'wxDIRCTRL_SHOW_FILTERS']
 
 class xxxScrolledWindow(xxxContainer):
     allParams = ['pos', 'size', 'style']
-    winStyles = ['wxHSCROLL', 'wxVSCROLL']
+    winStyles = ['wxHSCROLL', 'wxVSCROLL', 'wxNO_3D', 'wxTAB_TRAVERSAL']
+
+class xxxDateCtrl(xxxObject):
+    allParams = ['pos', 'size', 'style', 'borders']
+    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
@@ -513,20 +683,23 @@ class xxxButton(xxxObject):
     allParams = ['label', 'default', 'pos', 'size', 'style']
     paramDict = {'default': ParamBool}
     required = ['label']
-    winStyles = ['wxBU_LEFT', 'wxBU_TOP', 'wxBU_RIGHT', 'wxBU_BOTTOM']
+    winStyles = ['wxBU_LEFT', 'wxBU_TOP', 'wxBU_RIGHT', 'wxBU_BOTTOM', 'wxBU_EXACTFIT',
+                 'wxNO_BORDER']
 
 class xxxBitmapButton(xxxObject):
     allParams = ['bitmap', 'selected', 'focus', 'disabled', 'default',
                  'pos', 'size', 'style']
+    paramDict = {'selected': ParamBitmap, 'focus': ParamBitmap, 'disabled': ParamBitmap,
+                 'default': ParamBool}
     required = ['bitmap']
-    winStyles = ['wxBU_AUTODRAW', 'wxBU_LEFT', 'wxBU_TOP',
-                 'wxBU_RIGHT', 'wxBU_BOTTOM']
+    winStyles = ['wxBU_AUTODRAW', 'wxBU_LEFT', 'wxBU_RIGHT',
+                 'wxBU_TOP', 'wxBU_BOTTOM']
 
 class xxxRadioButton(xxxObject):
     allParams = ['label', 'value', 'pos', 'size', 'style']
     paramDict = {'value': ParamBool}
     required = ['label']
-    winStyles = ['wxRB_GROUP']
+    winStyles = ['wxRB_GROUP', 'wxRB_SINGLE']
 
 class xxxSpinButton(xxxObject):
     allParams = ['value', 'min', 'max', 'pos', 'size', 'style']
@@ -538,6 +711,11 @@ class xxxSpinCtrl(xxxObject):
     paramDict = {'value': ParamInt}
     winStyles = ['wxSP_HORIZONTAL', 'wxSP_VERTICAL', 'wxSP_ARROW_KEYS', 'wxSP_WRAP']
 
+class xxxToggleButton(xxxObject):
+    allParams = ['label', 'checked', 'pos', 'size', 'style']
+    paramDict = {'checked': ParamBool}
+    required = ['label']
+
 ################################################################################
 # Boxes
 
@@ -547,14 +725,17 @@ class xxxStaticBox(xxxObject):
 
 class xxxRadioBox(xxxObject):
     allParams = ['label', 'content', 'selection', 'dimension', 'pos', 'size', 'style']
-    paramDict = {'dimension': ParamInt}
+    paramDict = {'dimension': ParamIntNN}
     required = ['label', 'content']
     default = {'content': '[]'}
-    winStyles = ['wxRA_SPECIFY_ROWS', 'wxRA_SPECIFY_COLS']
+    winStyles = ['wxRA_SPECIFY_ROWS', 'wxRA_SPECIFY_COLS', 'wxRA_HORIZONTAL',
+                 'wxRA_VERTICAL']
 
 class xxxCheckBox(xxxObject):
     allParams = ['label', 'checked', 'pos', 'size', 'style']
     paramDict = {'checked': ParamBool}
+    winStyles = ['wxCHK_2STATE', 'wxCHK_3STATE', 'wxCHK_ALLOW_3RD_STATE_FOR_USER',
+                 'wxALIGN_RIGHT']
     required = ['label']
 
 class xxxComboBox(xxxObject):
@@ -568,16 +749,14 @@ class xxxListBox(xxxObject):
     required = ['content']
     default = {'content': '[]'}
     winStyles = ['wxLB_SINGLE', 'wxLB_MULTIPLE', 'wxLB_EXTENDED', 'wxLB_HSCROLL',
-              'wxLB_ALWAYS_SB', 'wxLB_NEEDED_SB', 'wxLB_SORT']
+                 'wxLB_ALWAYS_SB', 'wxLB_NEEDED_SB', 'wxLB_SORT']
 
 class xxxCheckList(xxxObject):
     allParams = ['content', 'pos', 'size', 'style']
     required = ['content']
     default = {'content': '[]'}
-    winStyles = ['wxLC_LIST', 'wxLC_REPORT', 'wxLC_ICON', 'wxLC_SMALL_ICON',
-              'wxLC_ALIGN_TOP', 'wxLC_ALIGN_LEFT', 'wxLC_AUTOARRANGE',
-              'wxLC_USER_TEXT', 'wxLC_EDIT_LABELS', 'wxLC_NO_HEADER',
-              'wxLC_SINGLE_SEL', 'wxLC_SORT_ASCENDING', 'wxLC_SORT_DESCENDING']
+    winStyles = ['wxLB_SINGLE', 'wxLB_MULTIPLE', 'wxLB_EXTENDED', 'wxLB_HSCROLL',
+                 'wxLB_ALWAYS_SB', 'wxLB_NEEDED_SB', 'wxLB_SORT']
     paramDict = {'content': ParamContentCheckList}
 
 ################################################################################
@@ -587,6 +766,7 @@ class xxxSizer(xxxContainer):
     hasName = hasStyle = False
     paramDict = {'orient': ParamOrient}
     isSizer = True
+    itemTag = 'sizeritem'               # different for some sizers
 
 class xxxBoxSizer(xxxSizer):
     allParams = ['orient']
@@ -606,6 +786,10 @@ class xxxGridSizer(xxxSizer):
     required = ['cols']
     default = {'cols': '2', 'rows': '2'}
 
+class xxxStdDialogButtonSizer(xxxSizer):
+    allParams = []
+    itemTag = 'button'
+
 # For repeated parameters
 class xxxParamMulti:
     def __init__(self, node):
@@ -624,59 +808,25 @@ class xxxParamMulti:
 class xxxFlexGridSizer(xxxGridSizer):
     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)
+    paramDict = {'growablecols': ParamIntList, 'growablerows': ParamIntList}
 
 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.
 class xxxChildContainer(xxxObject):
     hasName = hasStyle = False
     hasChild = True
-    def __init__(self, parent, element):
-        xxxObject.__init__(self, parent, element)
+    def __init__(self, parent, element, refElem=None):
+        xxxObject.__init__(self, parent, element, refElem)
         # Must have one child with 'object' tag, but we don't check it
         nodes = element.childNodes[:]   # create copy
         for node in nodes:
             if node.nodeType == minidom.Node.ELEMENT_NODE:
-                if node.tagName == 'object':
+                if node.tagName in ['object', 'object_ref']:
                     # Create new xxx object for child node
                     self.child = MakeXXXFromDOM(self, node)
                     self.child.parent = parent
@@ -688,27 +838,49 @@ class xxxChildContainer(xxxObject):
                 element.removeChild(node)
                 node.unlink()
         assert 0, 'no child found'
+    def resetChild(self, xxx):
+        '''Reset child info (for replacing with another class).'''
+        self.child = xxx
+        self.hasChildren = xxx.hasChildren
+        self.isSizer = xxx.isSizer        
 
 class xxxSizerItem(xxxChildContainer):
     allParams = ['option', 'flag', 'border', 'minsize', 'ratio']
     paramDict = {'option': ParamInt, 'minsize': ParamPosSize, 'ratio': ParamPosSize}
-    #default = {'cellspan': '1,1'}
-    def __init__(self, parent, element):
+    defaults_panel = {}
+    defaults_control = {}
+    def __init__(self, parent, element, refElem=None):
         # For GridBag sizer items, extra parameters added
         if isinstance(parent, xxxGridBagSizer):
             self.allParams = self.allParams + ['cellpos', 'cellspan']
-        xxxChildContainer.__init__(self, parent, element)
+        xxxChildContainer.__init__(self, parent, element, refElem)
         # Remove pos parameter - not needed for sizeritems
         if 'pos' in self.child.allParams:
             self.child.allParams = self.child.allParams[:]
             self.child.allParams.remove('pos')
+    def resetChild(self, xxx):
+        xxxChildContainer.resetChild(self, xxx)
+        # Remove pos parameter - not needed for sizeritems
+        if 'pos' in self.child.allParams:
+            self.child.allParams = self.child.allParams[:]
+            self.child.allParams.remove('pos')        
 
-class xxxNotebookPage(xxxChildContainer):
+class xxxSizerItemButton(xxxSizerItem):
+    allParams = []
+    paramDict = {}
+    def __init__(self, parent, element, refElem=None):
+        xxxChildContainer.__init__(self, parent, element, refElem=None)
+        # Remove pos parameter - not needed for sizeritems
+        if 'pos' in self.child.allParams:
+            self.child.allParams = self.child.allParams[:]
+            self.child.allParams.remove('pos')
+
+class xxxPage(xxxChildContainer):
     allParams = ['label', 'selected']
     paramDict = {'selected': ParamBool}
     required = ['label']
-    def __init__(self, parent, element):
-        xxxChildContainer.__init__(self, parent, element)
+    def __init__(self, parent, element, refElem=None):
+        xxxChildContainer.__init__(self, parent, element, refElem)
         # pos and size dont matter for notebookpages
         if 'pos' in self.child.allParams:
             self.child.allParams = self.child.allParams[:]
@@ -722,6 +894,11 @@ class xxxSpacer(xxxObject):
     allParams = ['size', 'option', 'flag', 'border']
     paramDict = {'option': ParamInt}
     default = {'size': '0,0'}
+    def __init__(self, parent, element, refElem=None):
+        # For GridBag sizer items, extra parameters added
+        if isinstance(parent, xxxGridBagSizer):
+            self.allParams = self.allParams + ['cellpos', 'cellspan']
+        xxxObject.__init__(self, parent, element, refElem)
 
 class xxxMenuBar(xxxContainer):
     allParams = ['style']
@@ -748,16 +925,156 @@ class xxxSeparator(xxxObject):
 
 class xxxUnknown(xxxObject):
     allParams = ['pos', 'size', 'style']
-    paramDict = {'style': ParamNonGenericStyle}    # no generic styles
+    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):
+    locals = {}                         # namespace for comment directives
+    allow = None                        # undefined initial state for current file
+    def __init__(self, node):
+        xxxNode.__init__(self, node)
+        self.textNode = node
+        # Parse "pragma" comments if enabled
+        if node.data and node.data[0] == '%' and g.conf.allowExec != 'no' and \
+               xxxParamComment.allow is not False:
+            # Show warning
+            if g.conf.allowExec == 'ask' and xxxParamComment.allow is None:
+                flags = wx.ICON_EXCLAMATION | wx.YES_NO | wx.CENTRE
+                dlg = wx.MessageDialog(g.frame, '''
+This file contains executable %comment directives. Allow to execute?''',
+                                       'Warning', flags)
+                say = dlg.ShowModal()
+                dlg.Destroy()
+                if say == wx.ID_YES:
+                    xxxParamComment.allow = True
+                else:
+                    xxxParamComment.allow = False
+            try:
+                code = node.data[1:]
+                exec code in globals(), self.locals
+            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,
     'wxFrame': xxxFrame,
     'tool': xxxTool,
     'wxToolBar': xxxToolBar,
+    'wxStatusBar': xxxStatusBar,
+    'wxWizard': xxxWizard,
+    'wxWizardPage': xxxWizardPage,
+    'wxWizardPageSimple': xxxWizardPageSimple,
 
     'wxBitmap': xxxBitmap,
     'wxIcon': xxxIcon,
@@ -766,6 +1083,7 @@ xxxDict = {
     'wxBitmapButton': xxxBitmapButton,
     'wxRadioButton': xxxRadioButton,
     'wxSpinButton': xxxSpinButton,
+    'wxToggleButton' : xxxToggleButton,
 
     'wxStaticBox': xxxStaticBox,
     'wxStaticBitmap': xxxStaticBitmap,
@@ -784,20 +1102,29 @@ xxxDict = {
     'wxTreeCtrl': xxxTreeCtrl,
     'wxListCtrl': xxxListCtrl,
     'wxCheckListBox': xxxCheckList,
+    'notebookpage': xxxPage,
+    'choicebookpage': xxxPage,
+    'listbookpage': xxxPage,
     'wxNotebook': xxxNotebook,
-    'notebookpage': xxxNotebookPage,
+    'wxChoicebook': xxxChoicebook,
+    'wxListbook': xxxListbook,
+    'wxSplitterWindow': xxxSplitterWindow,
     'wxHtmlWindow': xxxHtmlWindow,
     'wxCalendarCtrl': xxxCalendarCtrl,
     'wxGenericDirCtrl': xxxGenericDirCtrl,
     'wxSpinCtrl': xxxSpinCtrl,
     'wxScrolledWindow': xxxScrolledWindow,
+    'wxGrid': xxxGrid,
+    'wxFilePickerCtrl': xxxFilePickerCtrl,
+    'wxDatePickerCtrl': xxxDateCtrl,
 
     'wxBoxSizer': xxxBoxSizer,
     'wxStaticBoxSizer': xxxStaticBoxSizer,
     'wxGridSizer': xxxGridSizer,
     'wxFlexGridSizer': xxxFlexGridSizer,
     'wxGridBagSizer': xxxGridBagSizer,
-    'sizeritem': xxxSizerItem,
+    'wxStdDialogButtonSizer': xxxStdDialogButtonSizer,
+    'sizeritem': xxxSizerItem, 'button': xxxSizerItemButton,
     'spacer': xxxSpacer,
 
     'wxMenuBar': xxxMenuBar,
@@ -806,36 +1133,50 @@ xxxDict = {
     'separator': xxxSeparator,
 
     'unknown': xxxUnknown,
+    'comment': xxxComment,
     }
 
 # Create IDs for all parameters of all classes
-paramIDs = {'fg': wxNewId(), 'bg': wxNewId(), 'exstyle': wxNewId(), 'font': wxNewId(),
-            'enabled': wxNewId(), 'focused': wxNewId(), 'hidden': wxNewId(),
-            'tooltip': wxNewId(), 'encoding': wxNewId(),
-            'cellpos': wxNewId(), 'cellspan': wxNewId()
+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(),
+            'text': wx.NewId()
             }
 for cl in xxxDict.values():
     if cl.allParams:
         for param in cl.allParams + cl.paramDict.keys():
             if not paramIDs.has_key(param):
-                paramIDs[param] = wxNewId()
+                paramIDs[param] = wx.NewId()
 
 ################################################################################
 # Helper functions
 
 # Test for object elements
 def IsObject(node):
-    return node.nodeType == minidom.Node.ELEMENT_NODE and node.tagName == 'object'
+    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):
+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, node)
+    else:
+        refElem = None
+        cls = node.getAttribute('class')
     try:
-        klass = xxxDict[element.getAttribute('class')]
+        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)
+    return klass(parent, node, refElem)
 
 # Make empty DOM element
 def MakeEmptyDOM(className):
@@ -859,16 +1200,81 @@ def MakeEmptyDOM(className):
 def MakeEmptyXXX(parent, className):
     # Make corresponding DOM object first
     elem = MakeEmptyDOM(className)
-    # If parent is a sizer, we should create sizeritem object, except for spacers
+    # Special handling, e.g. if parent is a sizer, we should create
+    # sizeritem object, except for spacers, etc.
     if parent:
         if parent.isSizer and className != 'spacer':
-            sizerItemElem = MakeEmptyDOM('sizeritem')
+            sizerItemElem = MakeEmptyDOM(parent.itemTag)
             sizerItemElem.appendChild(elem)
             elem = sizerItemElem
         elif isinstance(parent, xxxNotebook):
             pageElem = MakeEmptyDOM('notebookpage')
             pageElem.appendChild(elem)
             elem = pageElem
+        elif isinstance(parent, xxxChoicebook):
+            pageElem = MakeEmptyDOM('choicebookpage')
+            pageElem.appendChild(elem)
+            elem = pageElem
+        elif isinstance(parent, xxxListbook):
+            pageElem = MakeEmptyDOM('listbookpage')
+            pageElem.appendChild(elem)
+            elem = pageElem
+    # Now just make object
+    xxx = MakeXXXFromDOM(parent, elem)
+    # Special defaults for new panels and controls
+    if isinstance(xxx, xxxSizerItem):
+        if isinstance(xxx.child, xxxContainer) and not xxx.child.isSizer:
+            for param,v in xxxSizerItem.defaults_panel.items():
+                xxx.set(param, v)
+        elif isinstance(xxx.child, xxxObject):
+            for param,v in xxxSizerItem.defaults_control.items():
+                xxx.set(param, v)
+    return xxx            
+
+# Make empty DOM element for reference
+def MakeEmptyRefDOM(ref):
+    elem = g.tree.dom.createElement('object_ref')
+    elem.setAttribute('ref', ref)
+    return elem
+
+# Make empty XXX object
+def MakeEmptyRefXXX(parent, ref):
+    # Make corresponding DOM object first
+    elem = MakeEmptyRefDOM(ref)
+    # If parent is a sizer, we should create sizeritem object, except for spacers
+    if parent:
+        if parent.isSizer:
+            sizerItemElem = MakeEmptyDOM(parent.itemTag)
+            sizerItemElem.appendChild(elem)
+            elem = sizerItemElem
+        elif isinstance(parent, xxxNotebook):
+            pageElem = MakeEmptyDOM('notebookpage')
+            pageElem.appendChild(elem)
+            elem = pageElem
+        elif isinstance(parent, xxxChoicebook):
+            pageElem = MakeEmptyDOM('choicebookpage')
+            pageElem.appendChild(elem)
+            elem = pageElem
+        elif isinstance(parent, xxxListbook):
+            pageElem = MakeEmptyDOM('listbookpage')
+            pageElem.appendChild(elem)
+            elem = pageElem
+    # Now just make object
+    xxx = MakeXXXFromDOM(parent, elem)
+    # Label is not used for references
+    xxx.allParams = xxx.allParams[:]
+    #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
-    return MakeXXXFromDOM(parent, elem)
+    xxx = MakeXXXFromDOM(parent, node)
+    return xxx