+0.1.8-5
+-------
+
+Implemented comment object for simple one-line comments. No 
+validation is performed.
+
 0.1.8-4
 -------
 
 
 # Global constants
 
 progname = 'XRCed'
-version = '0.1.8-4'
+version = '0.1.8-5'
 # Minimal wxWidgets version
 MinWxVersion = (2,6,0)
 if wx.VERSION[:3] < MinWxVersion:
 
         # Set common button size for parameter buttons
         bTmp = wx.Button(self, -1, '')
         import params
-        params.buttonSize = (self.DLG_SZE(buttonSize)[0], bTmp.GetSize()[1])
+        params.buttonSize = (self.DLG_SZE(buttonSizeD)[0], bTmp.GetSize()[1])
         bTmp.Destroy()
         del bTmp
 
         param = evt.GetEventObject().GetName()
         w = self.controls[param]
         w.Enable(True)
-        objElem = xxx.element
+        objElem = xxx.node
         if evt.IsChecked():
             # Ad  new text node in order of allParams
             w.SetValue('')              # set empty (default) value
             elem = g.tree.dom.createElement(param)
             # Some classes are special
             if param == 'font':
-                xxx.params[param] = xxxParamFont(xxx.element, elem)
+                xxx.params[param] = xxxParamFont(xxx.node, elem)
             elif param in xxxObject.bitmapTags:
                 xxx.params[param] = xxxParamBitmap(elem)
             else:
             name = self.controlName.GetValue()
             if xxx.name != name:
                 xxx.name = name
-                xxx.element.setAttribute('name', name)
+                xxx.node.setAttribute('name', name)
         for param, w in self.controls.items():
             if w.modified:
                 paramObj = xxx.params[param]
         for param in xxx.allParams:
             present = xxx.params.has_key(param)
             if param in xxx.required:
-                label = wx.StaticText(self, paramIDs[param], param + ':',
-                                     size = (LABEL_WIDTH,-1), name = param)
+                if isinstance(xxx, xxxComment):
+                    label = None
+                else:
+                    label = wx.StaticText(self, paramIDs[param], param + ':',
+                                          size = (LABEL_WIDTH,-1), name = param)
             else:
                 # Notebook has one very loooooong parameter
                 if param == 'usenotebooksizer': sParam = 'usesizer:'
                     typeClass = ParamText
             control = typeClass(self, param)
             control.Enable(present)
-            sizer.AddMany([ (label, 0, wx.ALIGN_CENTER_VERTICAL),
-                            (control, 0, wx.ALIGN_CENTER_VERTICAL | wx.GROW) ])
+            # Comment has only one parameter
+            if isinstance(xxx, xxxComment):
+                sizer.Add(control, 0, wx.ALIGN_CENTER_VERTICAL | wx.GROW)
+            else:
+                sizer.AddMany([ (label, 0, wx.ALIGN_CENTER_VERTICAL),
+                                (control, 0, wx.ALIGN_CENTER_VERTICAL | wx.GROW) ])
             self.controls[param] = control
         topSizer.Add(sizer, 1, wx.ALL | wx.EXPAND, 3)
-        self.SetAutoLayout(True)
         self.SetSizer(topSizer)
         topSizer.Fit(self)
     def SetValues(self, xxx):
 
     'wxWS_EX_PROCESS_UI_UPDATES'
     ]
 
-buttonSize = (35,-1)    # in dialog units, transformed to pixels in panel ctor
+# Global var initialized in Panel.__init__ for button size in screen pixels
+buttonSize = None
+# Button size in dialog units
+buttonSizeD = (35,-1)
 
 # Class that can properly disable children
 class PPanel(wx.Panel):
         sizer.Add(self.text, 0, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 5)
         self.button = wx.Button(self, self.ID_BUTTON_CHOICES, 'Edit...', size=buttonSize)
         sizer.Add(self.button, 0, wx.ALIGN_CENTER_VERTICAL)
-        self.SetAutoLayout(True)
-        self.SetSizerAndFit(sizer)
+        self.SetSizer(sizer)
         wx.EVT_BUTTON(self, self.ID_BUTTON_CHOICES, self.OnButtonChoices)
         wx.EVT_TEXT(self, self.ID_TEXT_CTRL, self.OnChange)
     def GetValue(self):
         sizer.Add(self.text, 0, wx.ALIGN_CENTER_VERTICAL | wx.TOP | wx.BOTTOM, 2)
         self.button = wx.Panel(self, self.ID_BUTTON, wx.DefaultPosition, wx.Size(20, 20))
         sizer.Add(self.button, 0, wx.ALIGN_CENTER_VERTICAL | wx.LEFT, 5)
-        self.SetAutoLayout(True)
-        self.SetSizerAndFit(sizer)
+        self.SetSizer(sizer)
         self.textModified = False
         wx.EVT_PAINT(self.button, self.OnPaintButton)
         wx.EVT_TEXT(self, self.ID_TEXT_CTRL, self.OnChange)
         sizer.Add(self.text, 0, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 5)
         self.button = wx.Button(self, self.ID_BUTTON_SELECT, 'Select...', size=buttonSize)
         sizer.Add(self.button, 0, wx.ALIGN_CENTER_VERTICAL)
-        self.SetAutoLayout(True)
-        self.SetSizerAndFit(sizer)
+        self.SetSizer(sizer)
         self.textModified = False
         wx.EVT_BUTTON(self, self.ID_BUTTON_SELECT, self.OnButtonSelect)
         wx.EVT_TEXT(self, self.ID_TEXT_CTRL, self.OnChange)
         self.spin = wx.SpinCtrl(self, self.ID_SPIN_CTRL, size=(60,-1))
         self.spin.SetRange(-2147483648, 2147483647) # min/max integers
         sizer.Add(self.spin)
-        self.SetAutoLayout(True)
-        self.SetSizerAndFit(sizer)
+        self.SetSizer(sizer)
         wx.EVT_SPINCTRL(self, self.ID_SPIN_CTRL, self.OnChange)
     def GetValue(self):
         return str(self.spin.GetValue())
         self.spin = wx.SpinCtrl(self, self.ID_SPIN_CTRL, size=(60,-1))
         self.spin.SetRange(0, 10000) # min/max integers
         sizer.Add(self.spin)
-        self.SetAutoLayout(True)
-        self.SetSizerAndFit(sizer)
+        self.SetSizer(sizer)
         wx.EVT_SPINCTRL(self, self.ID_SPIN_CTRL, self.OnChange)
     def GetValue(self):
         return str(self.spin.GetValue())
         self.spin.SetRange(-10000, 10000)
         sizer.Add(self.text, 0, wx.EXPAND)
         sizer.Add(self.spin, 0, wx.EXPAND)
-        self.SetAutoLayout(True)
-        self.SetSizerAndFit(sizer)
+        self.SetSizer(sizer)
         self.spin.Bind(wx.EVT_SPIN_UP, self.OnSpinUp)
         self.spin.Bind(wx.EVT_SPIN_DOWN, self.OnSpinDown)
     def GetValue(self):
         sizer.Add(self.text, 0, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 5)
         self.button = wx.Button(self, self.ID_BUTTON_EDIT, 'Edit...', size=buttonSize)
         sizer.Add(self.button, 0, wx.ALIGN_CENTER_VERTICAL)
-        self.SetAutoLayout(True)
         self.SetSizerAndFit(sizer)
         wx.EVT_BUTTON(self, self.ID_BUTTON_EDIT, self.OnButtonEdit)
         wx.EVT_TEXT(self, self.ID_TEXT_CTRL, self.OnChange)
         if textWidth == -1: option = 1
         else: option = 0
         sizer.Add(self.text, option, wx.ALIGN_CENTER_VERTICAL | wx.TOP | wx.BOTTOM, 2)
-        self.SetAutoLayout(True)
-        self.SetSizerAndFit(sizer)
+        self.SetSizer(sizer)
         wx.EVT_TEXT(self, self.ID_TEXT_CTRL, self.OnChange)
     def GetValue(self):
         return self.text.GetValue()
     def __init__(self, parent, name):
         ParamText.__init__(self, parent, name, 100)
 
+class ParamComment(ParamText):
+    def __init__(self, parent, name):
+        ParamText.__init__(self, parent, name, 330 + buttonSize[0])
+
 class ContentDialog(wx.Dialog):
     def __init__(self, parent, value):
         # Load from resource
         sizer.Add(self.text, 0, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 5)
         self.button = wx.Button(self, self.ID_BUTTON_EDIT, 'Edit...', size=buttonSize)
         sizer.Add(self.button, 0, wx.ALIGN_CENTER_VERTICAL)
-        self.SetAutoLayout(True)
-        self.SetSizerAndFit(sizer)
+        self.SetSizer(sizer)
         self.textModified = False
         wx.EVT_BUTTON(self, self.ID_BUTTON_EDIT, self.OnButtonEdit)
         wx.EVT_TEXT(self, self.ID_TEXT_CTRL, self.OnChange)
             button = wx.RadioButton(self, -1, i, size=(-1,buttonSize[1]), name=i)
             topSizer.Add(button, 0, wx.RIGHT, 5)
             wx.EVT_RADIOBUTTON(self, button.GetId(), self.OnRadioChoice)
-        self.SetAutoLayout(True)
-        self.SetSizerAndFit(topSizer)
+        self.SetSizer(topSizer)
     def SetStringSelection(self, value):
         self.freeze = True
         for i in self.choices:
         sizer.Add(self.text, 0, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 5)
         self.button = wx.Button(self, self.ID_BUTTON_BROWSE, 'Browse...',size=buttonSize)
         sizer.Add(self.button, 0, wx.ALIGN_CENTER_VERTICAL)
-        self.SetAutoLayout(True)
-        self.SetSizerAndFit(sizer)
+        self.SetSizer(sizer)
         self.textModified = False
         wx.EVT_BUTTON(self, self.ID_BUTTON_BROWSE, self.OnButtonBrowse)
         wx.EVT_TEXT(self, self.ID_TEXT_CTRL, self.OnChange)
     'fg': ParamColour, 'bg': ParamColour, 'font': ParamFont,
     'enabled': ParamBool, 'focused': ParamBool, 'hidden': ParamBool,
     'tooltip': ParamText, 'bitmap': ParamBitmap, 'icon': ParamBitmap,
-    'encoding': ParamEncoding, 'borders': ParamUnit
+    'encoding': ParamEncoding, 'borders': ParamUnit,
+    'comment': ParamComment
     }
 
     CHOICEBOOK = wx.NewId()
     LISTBOOK = wx.NewId()
     SPLITTER_WINDOW = wx.NewId()
+    GRID = wx.NewId()
     SCROLLED_WINDOW = wx.NewId()
     HTML_WINDOW = wx.NewId()
     CALENDAR_CTRL = wx.NewId()
     DATE_CTRL = wx.NewId()
+    FILE_PICKER_CTRL = wx.NewId()
     GENERIC_DIR_CTRL = wx.NewId()
     SPIN_CTRL = wx.NewId()
     UNKNOWN = wx.NewId()
     CONTEXT_HELP_BUTTON = wx.NewId()
 
     REF = wx.NewId()
+    COMMENT = wx.NewId()
 
     LAST = wx.NewId()
 
             ID_NEW.CHOICEBOOK: 'wxChoicebook',
             ID_NEW.LISTBOOK: 'wxListbook',
             ID_NEW.SPLITTER_WINDOW: 'wxSplitterWindow',
+            ID_NEW.GRID: 'wxGrid',
             ID_NEW.SCROLLED_WINDOW: 'wxScrolledWindow',
             ID_NEW.HTML_WINDOW: 'wxHtmlWindow',
             ID_NEW.CALENDAR_CTRL: 'wxCalendarCtrl',
             ID_NEW.DATE_CTRL: 'wxDatePickerCtrl',
+            ID_NEW.FILE_PICKER_CTRL: 'wxFilePickerCtrl',
             ID_NEW.GENERIC_DIR_CTRL: 'wxGenericDirCtrl',
             ID_NEW.SPIN_CTRL: 'wxSpinCtrl',
 
              (ID_NEW.SCROLL_BAR, 'ScrollBar', 'Create scroll bar'),
              (ID_NEW.TREE_CTRL, 'TreeCtrl', 'Create tree'),
              (ID_NEW.LIST_CTRL, 'ListCtrl', 'Create list'),
+#             (ID_NEW.GRID, 'Grid', 'Create grid'),
              (ID_NEW.SCROLLED_WINDOW, 'ScrolledWindow', 'Create scrolled window'),
              (ID_NEW.HTML_WINDOW, 'HtmlWindow', 'Create HTML window'),
              (ID_NEW.CALENDAR_CTRL, 'CalendarCtrl', 'Create calendar control'),
              (ID_NEW.DATE_CTRL, 'DatePickerCtrl', 'Create date picker control'),
+#             (ID_NEW.FILE_PICKER_CTRL, 'FilePickerCtrl', 'Create file picker control'),
              (ID_NEW.GENERIC_DIR_CTRL, 'GenericDirCtrl', 'Create generic dir control'),
              (ID_NEW.UNKNOWN, 'Unknown', 'Create custom control placeholder'),
              ],
     def __init__(self, parent, id):
         wx.TreeCtrl.__init__(self, parent, id, style = wx.TR_HAS_BUTTONS | wx.TR_MULTIPLE)
         self.SetBackgroundColour(wx.Colour(224, 248, 224))
+        self.fontComment = wx.Font(g.sysFont().GetPointSize(), wx.DEFAULT,
+                                   wx.FONTSTYLE_ITALIC, wx.NORMAL)
         # Register events
         wx.EVT_TREE_SEL_CHANGED(self, self.GetId(), self.OnSelChanged)
         # One works on Linux, another on Windows
         # Create image list
         il = wx.ImageList(16, 16, True)
         self.rootImage = il.Add(images.getTreeRootImage().Scale(16,16).ConvertToBitmap())
+        xxxComment.image = il.Add(images.getTreeCommentImage().Scale(16,16).ConvertToBitmap())
         xxxObject.image = il.Add(images.getTreeDefaultImage().Scale(16,16).ConvertToBitmap())
         xxxPanel.image = il.Add(images.getTreePanelImage().Scale(16,16).ConvertToBitmap())
         xxxDialog.image = il.Add(images.getTreeDialogImage().Scale(16,16).ConvertToBitmap())
         item = self.AppendItem(itemParent, treeObj.treeName(),
                                image=treeObj.treeImage(),
                                data=wx.TreeItemData(xxx))
-        # Different color for references
-        if treeObj.ref:
+        # Different color for comments and references
+        if xxx.className == 'comment':
+            self.SetItemTextColour(item, 'Blue')
+            self.SetItemFont(item, self.fontComment)
+        elif treeObj.ref:
             self.SetItemTextColour(item, 'DarkGreen')
         elif treeObj.hasStyle and treeObj.params.get('hidden', False):
             self.SetItemTextColour(item, 'Grey')
         # Try to find children objects
         if treeObj.hasChildren:
-            nodes = treeObj.element.childNodes[:]
+            nodes = treeObj.node.childNodes[:]
             for n in nodes:
                 if IsObject(n):
                     self.AddNode(item, treeObj, n)
                 elif n.nodeType != minidom.Node.ELEMENT_NODE:
-                    treeObj.element.removeChild(n)
+                    treeObj.node.removeChild(n)
                     n.unlink()
 
     # Insert new item at specific position
         xxx = MakeXXXFromDOM(parent, elem)
         # If nextItem is None, we append to parent, otherwise insert before it
         if nextItem.IsOk():
-            node = self.GetPyData(nextItem).element
-            parent.element.insertBefore(elem, node)
+            node = self.GetPyData(nextItem).node
+            parent.node.insertBefore(elem, node)
             # Inserting before is difficult, se we insert after or first child
             index = self.ItemIndex(nextItem)
             newItem = self.InsertItemBefore(itemParent, index,
                         xxx.treeName(), image=xxx.treeImage())
             self.SetPyData(newItem, xxx)
         else:
-            parent.element.appendChild(elem)
+            parent.node.appendChild(elem)
             newItem = self.AppendItem(itemParent, xxx.treeName(), image=xxx.treeImage(),
                                       data=wx.TreeItemData(xxx))
-        # Different color for references
-        if xxx.treeObject().ref:  self.SetItemTextColour(newItem, 'DarkGreen')
+        treeObj = xxx.treeObject()
+        # Different color for references and comments
+        if xxx.className == 'comment':
+            self.SetItemTextColour(newItem, 'Blue')
+        elif treeObj.ref:
+            self.SetItemTextColour(newItem, 'DarkGreen')
+        elif treeObj.hasStyle and treeObj.params.get('hidden', False):
+            self.SetItemTextColour(newItem, 'Grey')
         # Add children items
         if xxx.hasChildren:
             treeObj = xxx.treeObject()
-            for n in treeObj.element.childNodes:
+            for n in treeObj.node.childNodes:
                 if IsObject(n):
                     self.AddNode(newItem, treeObj, n)
         return newItem
     # Remove leaf of tree, return it's data object
     def RemoveLeaf(self, leaf):
         xxx = self.GetPyData(leaf)
-        node = xxx.element
+        node = xxx.node
         parent = node.parentNode
         parent.removeChild(node)
         self.Delete(leaf)
         # Save in memory FS
         memFile = MemoryFile('xxx.xrc')
         # Create memory XML file
-        elem = xxx.element.cloneNode(True)
+        elem = xxx.node.cloneNode(True)
         if not xxx.name:
             name = 'noname'
         else:
                 SetMenu(m, pullDownMenu.topLevel)
                 m.AppendSeparator()
                 m.Append(ID_NEW.REF, 'reference...', 'Create object_ref node')
+                m.Append(ID_NEW.COMMENT, 'comment', 'Create comment node')
             else:
                 xxx = self.GetPyData(item).treeObject()
                 # Check parent for possible child nodes if inserting sibling
                         m.Enable(ID_NEW.MENU_BAR, False)
                 m.AppendSeparator()
                 m.Append(ID_NEW.REF, 'reference...', 'Create object_ref node')
+                m.Append(ID_NEW.COMMENT, 'comment', 'Create comment node')
             # Select correct label for create menu
             if not needInsert:
                 if self.shift:
                     SetMenu(m, pullDownMenu.sizers, shift=True)
                 else:
                     SetMenu(m, pullDownMenu.controls, shift=True)
-                id = wx.NewId()
-                menu.AppendMenu(id, 'Replace With', m)
-                if not m.GetMenuItemCount(): menu.Enable(id, False)
-                menu.Append(pullDownMenu.ID_SUBCLASS, 'Subclass...',
-                            'Set "subclass" property')
+                if xxx.isElement:
+                    id = wx.NewId()
+                    menu.AppendMenu(id, 'Replace With', m)
+                    if not m.GetMenuItemCount(): menu.Enable(id, False)
+                    menu.Append(pullDownMenu.ID_SUBCLASS, 'Subclass...',
+                                'Set "subclass" property')
             menu.AppendSeparator()
             # Not using standart IDs because we don't want to show shortcuts
             menu.Append(wx.ID_CUT, 'Cut', 'Cut to the clipboard')
             # Item width may have changed
             # !!! Tric to update tree width (wxGTK, ??)
             self.SetIndent(self.GetIndent())
+        elif xxx.className == 'comment':
+            self.SetItemText(item, xxx.treeName())
         # Change tree icon for sizers
         if isinstance(xxx, xxxBoxSizer):
             self.SetItemImage(item, xxx.treeImage())
 
         item = g.tree.ItemAtFullIndex(self.itemIndex)
         xxx = g.tree.GetPyData(item)
         # Replace with old element
-        parent = xxx.parent.element
+        parent = xxx.parent.node
         if xxx is self.xxx:   # sizeritem or notebookpage - replace child
-            parent.replaceChild(self.xxx.child.element, xxx.child.element)
+            parent.replaceChild(self.xxx.child.node, xxx.child.node)
         else:
-            parent.replaceChild(self.xxx.element, xxx.element)
+            parent.replaceChild(self.xxx.node, xxx.node)
         self.xxx.parent = xxx.parent
         xxx = self.xxx
         g.tree.SetPyData(item, xxx)
            ((parent.isSizer and not isinstance(xxx, xxxSizerItem)) or \
             (isinstance(parent, xxxNotebook) and not isinstance(xxx, xxxNotebookPage)) or \
            not (parent.isSizer or isinstance(parent, xxxNotebook))):
-            elem.removeChild(xxx.child.element) # detach child
+            elem.removeChild(xxx.child.node) # detach child
             elem.unlink()           # delete child container
-            elem = xxx.child.element # replace
+            elem = xxx.child.node # replace
             # This may help garbage collection
             xxx.child.parent = None
             isChildContainer = False
            ((parent.isSizer and not isinstance(xxx, xxxSizerItem)) or \
             (isinstance(parent, xxxNotebook) and not isinstance(xxx, xxxNotebookPage)) or \
            not (parent.isSizer or isinstance(parent, xxxNotebook))):
-            elem.removeChild(xxx.child.element) # detach child
+            elem.removeChild(xxx.child.node) # detach child
             elem.unlink()           # delete child container
-            elem = xxx.child.element # replace
+            elem = xxx.child.node # replace
             # This may help garbage collection
             xxx.child.parent = None
             isChildContainer = False
 
         if not selected: return         # key pressed event
         xxx = tree.GetPyData(selected)
         if wx.TheClipboard.Open():
-            data = wx.CustomDataObject('XRCED')
-            # Set encoding in header
-            # (False,True)
-            s = xxx.element.toxml(encoding=expat.native_encoding)
+            if xxx.isElement:
+                data = wx.CustomDataObject('XRCED')
+                # Set encoding in header
+                # (False,True)
+                s = xxx.node.toxml(encoding=expat.native_encoding)
+            else:
+                data = wx.CustomDataObject('XRCED_node')
+                s = xxx.node.data
             data.SetData(cPickle.dumps(s))
             wx.TheClipboard.SetData(data)
             wx.TheClipboard.Close()
         parent = tree.GetPyData(parentLeaf).treeObject()
 
         # Create a copy of clipboard pickled element
-        success = False
+        success = success_node = False
         if wx.TheClipboard.Open():
             data = wx.CustomDataObject('XRCED')
             if wx.TheClipboard.IsSupported(data.GetFormat()):
                 success = wx.TheClipboard.GetData(data)
+            if not success:             # try other format
+                data = wx.CustomDataObject('XRCED_node')
+                if wx.TheClipboard.IsSupported(data.GetFormat()):
+                    success_node = wx.TheClipboard.GetData(data)
             wx.TheClipboard.Close()
 
-        if not success:
+        if not success and not success_node:
             wx.MessageBox(
                 "There is no data in the clipboard in the required format",
                 "Error")
             return
 
         xml = cPickle.loads(data.GetData()) # xml representation of element
-        elem = minidom.parseString(xml).childNodes[0]
+        if success:
+            elem = minidom.parseString(xml).childNodes[0]
+        else:
+            elem = g.tree.dom.createComment(xml)
         
         # Tempopary xxx object to test things
         xxx = MakeXXXFromDOM(parent, elem)
            ((parent.isSizer and not isinstance(xxx, xxxSizerItem)) or \
             (parentIsBook and not isinstance(xxx, xxxPage)) or \
            not (parent.isSizer or parentIsBook)):
-            elem.removeChild(xxx.child.element) # detach child
+            elem.removeChild(xxx.child.node) # detach child
             elem.unlink()           # delete child container
-            elem = xxx.child.element # replace
+            elem = xxx.child.node # replace
             # This may help garbage collection
             xxx.child.parent = None
             isChildContainer = False
     def ItemsAreCompatible(self, parent, child):
         # Check compatibility
         error = False
+        # Comments are always compatible
+        if child.__class__ == xxxComment:
+            return True
         # Top-level
         if child.__class__ in [xxxDialog, xxxFrame, xxxWizard]:
             # Top-level classes
            ((parent.isSizer and not isinstance(xxx, xxxSizerItem)) or \
             (isinstance(parent, xxxNotebook) and not isinstance(xxx, xxxNotebookPage)) or \
            not (parent.isSizer or isinstance(parent, xxxNotebook))):
-            elem.removeChild(xxx.child.element) # detach child
+            elem.removeChild(xxx.child.node) # detach child
             elem.unlink()           # delete child container
-            elem = xxx.child.element # replace
+            elem = xxx.child.node # replace
             # This may help garbage collection
             xxx.child.parent = None
             isChildContainer = False
            ((parent.isSizer and not isinstance(xxx, xxxSizerItem)) or \
             (isinstance(parent, xxxNotebook) and not isinstance(xxx, xxxNotebookPage)) or \
            not (parent.isSizer or isinstance(parent, xxxNotebook))):
-            elem.removeChild(xxx.child.element) # detach child
+            elem.removeChild(xxx.child.node) # detach child
             elem.unlink()           # delete child container
-            elem = xxx.child.element # replace
+            elem = xxx.child.node # replace
             # This may help garbage collection
             xxx.child.parent = None
             isChildContainer = False
         # Prepare undo data
         panel.Apply()
         index = tree.ItemFullIndex(selected)
+        xxx = tree.GetPyData(selected)
         parent = tree.GetPyData(tree.GetItemParent(selected)).treeObject()
         elem = tree.RemoveLeaf(selected)
         undoMan.RegisterUndo(UndoCutDelete(index, parent, elem))
         if evt.GetId() == wx.ID_CUT:
             if wx.TheClipboard.Open():
-                data = wx.CustomDataObject('XRCED')
-                # (False, True)
-                s = elem.toxml(encoding=expat.native_encoding)
+                if xxx.isElement:
+                    data = wx.CustomDataObject('XRCED')
+                    # (False, True)
+                    s = elem.toxml(encoding=expat.native_encoding)
+                else:
+                    data = wx.CustomDataObject('XRCED_node')
+                    s = xxx.node.data
                 data.SetData(cPickle.dumps(s))
                 wx.TheClipboard.SetData(data)
                 wx.TheClipboard.Close()
     def OnSubclass(self, evt):
         selected = tree.selection
         xxx = tree.GetPyData(selected).treeObject()
-        elem = xxx.element
+        elem = xxx.node
         subclass = xxx.subclass
         dlg = wx.TextEntryDialog(self, 'Subclass:', defaultValue=subclass)
         if dlg.ShowModal() == wx.ID_OK:
             ref = wx.GetTextFromUser('Create reference to:', 'Create reference')
             if not ref: return
             xxx = MakeEmptyRefXXX(parent, ref)
+        elif evt.GetId() == ID_NEW.COMMENT:
+            xxx = MakeEmptyCommentXXX(parent)
         else:
             # Create empty element
             className = pullDownMenu.createMap[evt.GetId()]
             xxx = MakeEmptyXXX(parent, className)
 
-        # Set default name for top-level windows
-        if parent.__class__ == xxxMainNode:
-            cl = xxx.treeObject().__class__
-            frame.maxIDs[cl] += 1
-            xxx.setTreeName('%s%d' % (defaultIDs[cl], frame.maxIDs[cl]))
-        # And for some other standard controls
-        elif parent.__class__ == xxxStdDialogButtonSizer:
-            xxx.setTreeName(pullDownMenu.stdButtonIDs[evt.GetId()][0])
-            # We can even set label
-            obj = xxx.treeObject()
-            elem = g.tree.dom.createElement('label')
-            elem.appendChild(g.tree.dom.createTextNode(pullDownMenu.stdButtonIDs[evt.GetId()][1]))
-            obj.params['label'] = xxxParam(elem)
-            xxx.treeObject().element.appendChild(elem)
-
         # Insert new node, register undo
-        elem = xxx.element
-        newItem = tree.InsertNode(parentLeaf, parent, elem, nextItem)
+        if xxx.isElement:                 # true object
+            # Set default name for top-level windows
+            if parent.__class__ == xxxMainNode:
+                cl = xxx.treeObject().__class__
+                frame.maxIDs[cl] += 1
+                xxx.setTreeName('%s%d' % (defaultIDs[cl], frame.maxIDs[cl]))
+            # And for some other standard controls
+            elif parent.__class__ == xxxStdDialogButtonSizer:
+                xxx.setTreeName(pullDownMenu.stdButtonIDs[evt.GetId()][0])
+                # We can even set label
+                obj = xxx.treeObject()
+                elem = g.tree.dom.createElement('label')
+                elem.appendChild(g.tree.dom.createTextNode(pullDownMenu.stdButtonIDs[evt.GetId()][1]))
+                obj.params['label'] = xxxParam(elem)
+                xxx.treeObject().node.appendChild(elem)
+
+            newItem = tree.InsertNode(parentLeaf, parent, xxx.node, nextItem)
+        else:                           # comment node
+            newItem = tree.InsertNode(parentLeaf, parent, xxx.node, nextItem)
         undoMan.RegisterUndo(UndoPasteCreate(parentLeaf, parent, newItem, selected))
         tree.EnsureVisible(newItem)
         tree.SelectItem(newItem)
             tree.ScrollTo(newItem)
             tree.Refresh()
         # Update view?
-        if g.testWin and tree.IsHighlatable(newItem):
+        if xxx.isElement and g.testWin and tree.IsHighlatable(newItem):
             if conf.autoRefresh:
                 tree.needUpdate = True
                 tree.pendingHighLight = newItem
     def OnReplace(self, evt):
         selected = tree.selection
         xxx = tree.GetPyData(selected).treeObject()
-        elem = xxx.element
+        elem = xxx.node
         parent = elem.parentNode
         undoMan.RegisterUndo(UndoReplace(selected))
         # New class
         return True
 
     def Indent(self, node, indent = 0):
+        if node.nodeType == minidom.Node.COMMENT_NODE:
+            text = self.domCopy.createTextNode('\n' + ' ' * indent)
+            node.parentNode.insertBefore(text, node)
+            return                      # no children
         # Copy child list because it will change soon
         children = node.childNodes[:]
         # Main node doesn't need to be indented
                 node.appendChild(text)
             # Indent children which are elements
             for n in children:
-                if n.nodeType == minidom.Node.ELEMENT_NODE:
+                if n.nodeType == minidom.Node.ELEMENT_NODE or \
+                       n.nodeType == minidom.Node.COMMENT_NODE:
                     self.Indent(n, indent + 2)
 
     def Save(self, path):
 
 <?xml version="1.0" ?>
 <resource>
+  <!-- The beginning is here -->
   <object class="wxDialog" name="DIALOG_TEXT">
     <title>Text Dialog</title>
     <centered>1</centered>
       </object>
     </object>
   </object>
-</resource>
\ No newline at end of file
+</resource>
 
     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):
             node = g.tree.dom.createElement(param)
             text = g.tree.dom.createTextNode(str(i))
             node.appendChild(text)
-            self.element.appendChild(node)
+            self.node.appendChild(node)
             self.special(param, node)
 
 # Imitation of FindResource/DoFindResource from xmlres.cpp
         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
 
     allParams = ['pos', 'size', 'style']
     winStyles = ['wxNO_FULL_REPAINT_ON_RESIZE']
 
+################################################################################
+# Comment
+
+class xxxParamComment(xxxParam):
+    def __init__(self, node):
+        xxxNode.__init__(self, node)
+        self.textNode = node
+
+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')
+
 ################################################################################
 
 xxxDict = {
     '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
+