]> git.saurik.com Git - wxWidgets.git/commitdiff
A new version of XRCed from Roman Rolinsky with a few tweaks by me.
authorRobin Dunn <robin@alldunn.com>
Wed, 6 Mar 2002 21:41:19 +0000 (21:41 +0000)
committerRobin Dunn <robin@alldunn.com>
Wed, 6 Mar 2002 21:41:19 +0000 (21:41 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@14470 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

wxPython/tools/XRCed/CHANGES
wxPython/tools/XRCed/README
wxPython/tools/XRCed/TODO
wxPython/tools/XRCed/images.py
wxPython/tools/XRCed/params.py
wxPython/tools/XRCed/xrced.py
wxPython/tools/XRCed/xrced.sh [new file with mode: 0644]
wxPython/tools/XRCed/xrced.xrc
wxPython/tools/XRCed/xxx.py

index 28061d36fe6d3531e65b2b4a3af9894752c48690..eecd2c0ebef730c074252ebb2086b517202c740a 100644 (file)
@@ -1,3 +1,32 @@
+0.0.7
+-----
+
+Some command-line arguments.
+
+"Test window" command and toolbar button.
+
+New panel interphace (wxHTMLWindow is not used anymore).
+
+Toggling between embedded and detached panel.
+
+Cache for already used windows.
+
+Current top-level control is bold, if test window shown.
+
+Undo/redo broken.
+
+CheckListBox does not work unless wxXRC source fixed (in both wxPytnon and
+wxWin):
+
+contrib/src/xrc/xmlrsall.cpp
+45,46c45,46
+<     AddHandler(new wxListCtrlXmlHandler);
+< #if CHECKLISTBOX
+---
+>     AddHandler(new wxListCtrlXmlHandler);    
+> #if wxUSE_CHECKLISTBOX
+
+
 0.0.6
 -----
 
index ee7108f4e224a23eec6cdccce2f7d7ecaf4d5a84..133ee2a2e55f019fa6a5e68d89fe165d53dde313 100644 (file)
@@ -7,53 +7,65 @@
 Installation on UNIX
 --------------------
 
-XRCed was developed using Python 2.1.1. xml.dom.minidom module should be
-available. XML support requires Expat package (http://expat.sourceforge.net),
-and you have to uncomment expat lines in Modules/Setup file of Python source:
+XRCed requires wxGTK and wxPython greater than 2.3.2, and Python 2.2 (it may
+work with earlier version, but was not tested).
 
-EXPAT_DIR=$(HOME)/expat
-pyexpat pyexpat.c -I$(EXPAT_DIR)/xmlparse -L$(EXPAT_DIR) -lexpat
+Of course wxGTK's XRC library (libwxxrc) must be installed.
 
-wxPython version used was 2.3.1, which itself uses wxGTK 2.3.1. wxPython
-should be modified to support some extra functions. To update it, go to
-wxPython source directory and untar "wxPython-update.tgz" (included with
-xrced) file there. Then recompile (run "b 21" for example) it and install as
-usual (or you can set your environment to use it from the source tree).
+Installation on Windows
+-----------------------
 
+Works with wxPython 2.3.2 for Python 2.2.
 
 Short manual
 ------------
 
+XRCed's idea is very straightforward: it is a visual tool for editing an XML
+file conforming to XRC format. Every operation performed in XRCed has direct
+correspondence to XML structure. So it is not really a usual point-and-click
+GUI builder, but don't let that scare you.
+
 To start xrced, change to the directory where you installed it and run
-"python2.1 xrced.py".
+"python2.2 xrced.py".
+
+On UNIX you can edit wrapper script "xrced.sh" to point to your installation
+directory.
 
 To create an object, first you should select some object in the tree (or the
-root item if it's empty) then press the right mouse button and select right
-(in another sense now :) ) command. The pulldown menu is context-dependent on
-the selected object.
+root item if it's empty) then press the right mouse button and select an
+appropriate command. The pulldown menu is context-dependent on the selected
+object.
 
 XRCed tries to guess if new object should be added as a next sibling or a
 child of current object, depending on the possibility of the object to have
 child objects and expanded state (if tree item is collapsed, new object will
 be sibling). You can change this behavior to create siblings by pressing and
-holding the Control key before clicking the mouse.
+holding the Shift and Control keys before clicking the mouse.
+
+Pressed Control key while pressing right button makes next item a sibling of
+selected item regardless of its expanded state.
 
-Same applies for copy/paste, but at the moment Control key is ignored.
+Pressed Shift key changes the place for inserting new child to be before
+selected child, not after as by default.
 
 Panel on the right contains object properties. Properties which are optional
-should be "checked" first. XMLID of the object is the textbox to the right of
-the class name.
+should be "checked" first. This panel can be made separate by unchecking
+"Embed Panel" in View menu.
 
 All properties can be edited as text, and some are supplied with special
 editing controls.
 
+The names of the properties are exactly as in XRC file, and it's usually not
+hard to guess what they do. XML ID is the name of the window, and must be
+present for top-level windows (though this is not enforced by XRCed).
+
 To display the preview window double-click a top-level object (you should
-assign an XMLID to it first). After that, if you select a child object, it
+assign an XMLID to it first), press "Test" toolbar button or select command
+from View menu, or press F5. After that, if you select a child object, it
 becomes highlighted, and if you change it, preview is updated when you select
 another item or press Ctrl-R (refresh). To turn off automatic update, toggle
-"View->Auto-refresh" or toolbar auto-refresh button (to the right of refresh
-button).
-
+"View->Auto-refresh" or toolbar auto-refresh button (to the right of the
+refresh button).
 
 --------------------------------------------------------------------------------
 
index da2aaf4be5cc70c79c54538c63395fed6398624f..4b9cc1b2b3dafca6be652774e5f1563773bb3c86 100644 (file)
@@ -1,33 +1,29 @@
 TODO for XRCed
 ==============
 
-* Undo/Redo
+- Undo/Redo
 
-* menu - accel not displayed in preview
+- menu - accel not displayed in preview
 
-* tree icons
++ tree icons
 
-* paste as sibling (toolbar toggle button)
+- replace object with another, keeping children
 
-* replace object with abother, keeping children
++ write tmp file for current dialog/panel/etc.
 
-* write tmp file for current dialog/panel/etc.
++ XML indents
 
-* XML indents
+? select same notebook pages after update
 
-* select same notebook pages after update
+- put some default values in tree ctrl etc.
 
-* put some default values in tree ctrl etc.
-
-* special (fast) update for some values: pos/size, value/content, sizeritem
+- special (fast) update for some values: pos/size, value/content, sizeritem
   stuff (?), well, as much as possible
 
-* highlighting with better method
-
-* import XRC/WXR files
+- highlighting with better method
 
-* disable some window creation when it's not valid
+- import XRC/WXR files
 
-* check for memory leaks from wx objects
++ disable some window creation when it's not valid
 
-* style defaults for `hidde' and `focused' should be false
+- check for memory leaks from wx objects
index f2957d15a9ec0cb6242153fcbc9a1ce42bb4749a..924c55d463a10879dd35e6b5798a1c76ddd26aa4 100644 (file)
@@ -119,15 +119,34 @@ def getPasteBitmap():
 def getPasteImage():
     return wxImageFromBitmap(getPasteBitmap())
 
+#----------------------------------------------------------------------
+def getTestData():
+    return cPickle.loads(zlib.decompress(
+'x\xda\x95\xd2=\x0b\xc20\x10\x06\xe0\xbd\xbf\xe2\xc0\xa1N\xa1\x1f\n\xba*t\
+\xf4\x86.\xb7\x96\xe2d\xf1\xfc\xff\x93\xb9$\xcd5M\xa9xY\xf2\xf2\x10r$w\x9c>u\
+\xd1\x97\xcd\t\x9a\x16\xceP\x97\xc5\xd0\x97\x06F\xb8M\xc3\xf8r\x89l:\xb4\x95\
+,\x97Q\xf2\xb5\x92\xe52K\xee.\xdd\xbd\xf2\x19l~\xf0\xfb\x19\xc2v\xfd\x81Fj\
+\x1b\xcd\\9\x12\xd1\x8cD+$f\x0efw\xb4\x8b\xb8D\xb1\xa0nG\xbb\x88\x8a\xde,r@w\
+4A\x07\x8b\xa3\x01\xb5\x95\xd8V\x86Fm\x03M\xb4\x05\xaaF\xcb1\xb9R_h\xd5\x10f\
+\xc8\x1c\x15\xd3_\x89&\x8a+\x04$\xff\x14D\xe8-\x9d\x04\xcb\xa4\x94\xcd\x10\
+\xa2\xd2\xef\x013_\xba\x1d\xa3N' ))
+
+def getTestBitmap():
+    return wxBitmapFromXPMData(getTestData())
+
+def getTestImage():
+    return wxImageFromBitmap(getTestBitmap())
+
 #----------------------------------------------------------------------
 def getRefreshData():
     return cPickle.loads(zlib.decompress(
-'x\xda\xad\xd2\xbb\x0e\xc20\x0c\x05\xd0\xbd_q%\x860]\xf55\xc0\x0f0\xb2t\xf1\
-\x8a\x10\x1bj\xf9\xff\x89\xbc\x9a\x9a\xe2\xc2Rg\x89u\x14+vr|\xbe\x9ajpm\x8f\
-\xb6C\x87\xc6U\xb7\xc1\t\xee8\x9c\xeb\xb0b\x0e\x9f_\xa7\xf1\x11\x13\x06\xbc\
-\x9cj\x1f\x19\xed\xd8\r\x19b\x03\xbd\x88R\x85\x8c&XTc\xb2\xb0\x11\x13\x89_\
-\xc8\xb4\xd9(\xab\xeb~`"\x13\x91\xc9F\xd5\xee\x9e8w@\x1bY\xae\xfd]6\x9f\xb0&\
-4\x1f\xa5\x8dQY\xaa\x9a\x8f]\x86\xb1nED\x8a\xfd\xfdC|\x03\xab\xaaw\xdd' ))
+'x\xda\xad\xd2\xbb\x0e\xc20\x0c\x05\xd0\xbd_q%\x860]\xf5\xc1\x00?\xc0\xc8\
+\xd2\xc5+Bl\xa8\xed\xffO\xcd\xab\xa9\x01\x17\t\x81\xb3\xc4:\x8a\x15;\xd9?\
+\xa6\xa6\xea]{@\xdb\xa1C\xe3\xaak\xef\x047\xecNuX1\x87\xcf/\xe3p\x8f\t\x03\
+\x9e\x8f\xb5\x8f\x8cv|\x83\x0c\xb1\x81^D\xa9BF\x13\xac\xaa1Y\xd8\x88\x89\xc4\
+\'d\xdal\x94\xd5u\x9f0\x91\x89\xc8d\xa3j\xf7\x9f\xb8t@\x1bY\xae\xfd^6\x9f\
+\xb0&\xb4\x1c\xa5\x8dQY\xaa\x9a\x8f]\x86\xf1\xda\x8a\x88\x14\xc3O\x1f\x8c3\
+\x1dNw\xdd' ))
 
 def getRefreshBitmap():
     return wxBitmapFromXPMData(getRefreshData())
@@ -138,14 +157,13 @@ def getRefreshImage():
 #----------------------------------------------------------------------
 def getAutoRefreshData():
     return cPickle.loads(zlib.decompress(
-'x\xda\xad\xd21\x0e\xc20\x0c\x05\xd0\xbd\xa7\xb0\xc4\x10&+-\x1d\xca\x05\x18Y\
-\xba\xfc\x15!6\x84\xb9\xffD\x9c8%R\x92\x8a\x01gh\xacW9\xb2\x93\xe3\xf3=\x0e\
-\xab\x9bf\x9aN4\xd3\xe8\x86\xdb\xea@w:\x9c\xbd\xae\x98S\xc8\xaf\xf2z\xc4D\
-\x14\xbd_\x16\x9f\x905\xbf\x84\xcc\xe7\x9f\xdb\xf17d\x8d\x0e\x06A\xa1\x05r4\
-\xd0WKL\xa6\x1b4\x91i\x0f9m:eA\x12\x025*\x05\x03\x9b\x96\xad\x00\xf6i\xa1\
-\x85luk\xec\x94\xdd\xc5\xd4\x81\xb4\xcb\xf2\xa6\x10\xa9\xca\xdahbO\xa8\xd1\
-\x06\x84\xce\x95Q\x1e\x7f\xe7\xb2\xb3U\xad\xc0\x8e\xfb\xe9\r\xf1\x07\xdbD\
-\x86\x9f' ))
+'x\xda\x95\xd2;\x0e\xc20\x0c\x06\xe0\xbd\xa7\xb0\xc4\x10&+-\x1d\xca\x05\x18Y\
+\xba\xfc+Bl\x08s\xff\x89<\x9c\x12\xc9I\xa5:Cc}\x95#;9\xbf\xbf\xe3\xb0\xbai\
+\xa6\xe9B3\x8dnx\xac\x0e\xf4\xa4\xd3\xd5\xc7\x95r\n\xf9]>\xaf\x94HD\xef\x97\
+\xc5g\xe4\x98\xdfB\xe6\xcb\xcf\xed8\x82\x1c\xa3\x83APi\x85\x9c\x0c\xf4\xd7\
+\x1a\xb3\xc5\r\x9a\xc8\xb4\x87\x9c7\x9d\xb2 \t\x01\x8b\x91\x82\x81U\xebV\x00\
+\xfd\xb4PC\xb6\xba\x16;ew1w \xed\xb2\xbc)DLY\x1dM\xea\t\x16u@\xe8\\\x19\x95\
+\xf1w.\xbb\x98i\x05z\xdc\xe17d\x90\x7f\x95\x07\x86\x9f' ))
 
 def getAutoRefreshBitmap():
     return wxBitmapFromXPMData(getAutoRefreshData())
index 5ec0ac9516dd15978986eb665038f07b5771813d..89513a1fbf9402701808001d9d47076904900dfe 100644 (file)
@@ -23,8 +23,8 @@ genericStyles = ['wxSIMPLE_BORDER', 'wxDOUBLE_BORDER',
 
 # Class that can properly disable children
 class PPanel(wxPanel):
-    def __init__(self, parent, id, name):
-        wxPanel.__init__(self, parent, id, name=name)
+    def __init__(self, parent, name):
+        wxPanel.__init__(self, parent, -1, name=name)
         self.modified = self.freeze = false
     def Enable(self, value):
         # Something strange is going on with enable so we make sure...
@@ -36,8 +36,8 @@ class PPanel(wxPanel):
         panel.SetModified(true)
 
 class ParamBinaryOr(PPanel):
-    def __init__(self, parent, id, size, name):
-        PPanel.__init__(self, parent, id, name)
+    def __init__(self, parent, name):
+        PPanel.__init__(self, parent, name)
         self.ID_TEXT_CTRL = wxNewId()
         self.ID_BUTTON_CHOICES = wxNewId()
         self.SetBackgroundColour(panel.GetBackgroundColour())
@@ -97,7 +97,10 @@ class ParamBinaryOr(PPanel):
                     value.append(self.values[i])
             # Add ignored flags
             value.extend(ignored)
-            self.SetValue(reduce(lambda a,b: a+'|'+b, value))
+            if value:
+                self.SetValue(reduce(lambda a,b: a+'|'+b, value))
+            else:
+                self.SetValue('')
             self.SetModified()
         dlg.Destroy()
 
@@ -109,31 +112,31 @@ class ParamFlag(ParamBinaryOr):
     equal = {'wxALIGN_CENTER': 'wxALIGN_CENTRE',
              'wxALIGN_CENTER_VERTICAL': 'wxALIGN_CENTRE_VERTICAL',
              'wxALIGN_CENTER_HORIZONTAL': 'wxALIGN_CENTRE_HORIZONTAL'}
-    def __init__(self, parent, id, size, name):
-        ParamBinaryOr.__init__(self, parent, id, size, name)
+    def __init__(self, parent, name):
+        ParamBinaryOr.__init__(self, parent, name)
 
 class ParamStyle(ParamBinaryOr):
     equal = {'wxALIGN_CENTER': 'wxALIGN_CENTRE'}
-    def __init__(self, parent, id = -1, size = wxDefaultSize, name = ''):
+    def __init__(self, parent, name):
         self.values = currentXXX.winStyles + genericStyles
-        ParamBinaryOr.__init__(self, parent, id, size, name)
+        ParamBinaryOr.__init__(self, parent, name)
 
 class ParamNonGenericStyle(ParamBinaryOr):
-    def __init__(self, parent, id = -1, size = wxDefaultSize, name = ''):
+    def __init__(self, parent, name):
         self.values = currentXXX.winStyles
-        ParamBinaryOr.__init__(self, parent, id, size, name)
+        ParamBinaryOr.__init__(self, parent, name)
 
 class ParamExStyle(ParamBinaryOr):
-    def __init__(self, parent, id = -1, size = wxDefaultSize, name = ''):
+    def __init__(self, parent, name):
         if currentXXX:
             self.values = currentXXX.exStyles # constant at the moment
         else:
             self.values = []
-        ParamBinaryOr.__init__(self, parent, id, size, name)
+        ParamBinaryOr.__init__(self, parent, name)
 
 class ParamColour(PPanel):
-    def __init__(self, parent, id = -1, size = wxDefaultSize, name = ''):
-        PPanel.__init__(self, parent, id, name)
+    def __init__(self, parent, name):
+        PPanel.__init__(self, parent, name)
         self.ID_TEXT_CTRL = wxNewId()
         self.ID_BUTTON = wxNewId()
         self.SetBackgroundColour(panel.GetBackgroundColour())
@@ -153,7 +156,6 @@ class ParamColour(PPanel):
         return self.value
     def SetValue(self, value):
         self.freeze = true
-        value = string.strip(value)
         if not value: value = '#FFFFFF'
         self.value = value
         self.text.SetValue(str(value))  # update text ctrl
@@ -198,8 +200,8 @@ fontStylesXml2wx = ReverseMap(fontStylesWx2Xml)
 fontWeightsXml2wx = ReverseMap(fontWeightsWx2Xml)
 
 class ParamFont(PPanel):
-    def __init__(self, parent, id = -1, size = wxDefaultSize, name = ''):
-        PPanel.__init__(self, parent, id, name)
+    def __init__(self, parent, name):
+        PPanel.__init__(self, parent, name)
         self.ID_TEXT_CTRL = wxNewId()
         self.ID_BUTTON_SELECT = wxNewId()
         self.SetBackgroundColour(panel.GetBackgroundColour())
@@ -219,34 +221,56 @@ class ParamFont(PPanel):
         self.SetModified()
         self.textModified = true
         evt.Skip()
+    def _defaultValue(self):
+        return ['12', 'default', 'normal', 'normal', '0', '', '']
     def GetValue(self):
         if self.textModified:           # text has newer value
-            return eval(self.text.GetValue())
+            try:
+                return eval(self.text.GetValue())
+            except SyntaxError:
+                wxLogError('Syntax error in parameter value: ' + self.GetName())
+                return self._defaultValue()
         return self.value
     def SetValue(self, value):
         self.freeze = true              # disable other handlers
-        if not value: value = [''] * 7
+        if not value: value = self._defaultValue()
         self.value = value
         self.text.SetValue(str(value))  # update text ctrl
         self.freeze = false
     def OnButtonSelect(self, evt):
         if self.textModified:           # text has newer value
-            self.value = eval(self.text.GetValue())
+            try:
+                self.value = eval(self.text.GetValue())
+            except SyntaxError:
+                wxLogError('Syntax error in parameter value: ' + self.GetName())
+                self.value = self._defaultValue()
         # Make initial font
-        try: size = int(self.value[0])
-        except ValueError: size = 12
-        try: family = fontFamiliesXml2wx[self.value[1]]
-        except KeyError: family = wxDEFAULT
-        try: style = fontStylesXml2wx[self.value[2]]
-        except KeyError: style = wxNORMAL
-        try: weight = fontWeightsXml2wx[self.value[3]]
-        except KeyError: weight = wxNORMAL
-        try: underlined = int(self.value[4])
-        except ValueError: underlined = 0
-        face = self.value[5]
-        mapper = wxFontMapper()
+        # Default values
+        size = 12
+        family = wxDEFAULT
+        style = weight = wxNORMAL
+        underlined = 0
+        face = ''
         enc = wxFONTENCODING_DEFAULT
-        if not self.value[6]: enc = mapper.CharsetToEncoding(self.value[6])
+        # Fall back to default if exceptions
+        error = false
+        try:
+            try: size = int(self.value[0])
+            except ValueError: error = true
+            try: family = fontFamiliesXml2wx[self.value[1]]
+            except KeyError: error = true
+            try: style = fontStylesXml2wx[self.value[2]]
+            except KeyError: error = true
+            try: weight = fontWeightsXml2wx[self.value[3]]
+            except KeyError: error = true
+            try: underlined = int(self.value[4])
+            except ValueError: error = true
+            face = self.value[5]
+            mapper = wxFontMapper()
+            if not self.value[6]: enc = mapper.CharsetToEncoding(self.value[6])
+        except IndexError:
+            error = true
+        if error: wxLogError('Invalid font specification')
         if enc == wxFONTENCODING_DEFAULT: enc = wxFONTENCODING_SYSTEM
         font = wxFont(size, family, style, weight, underlined, face, enc)
         data = wxFontData()
@@ -254,11 +278,14 @@ class ParamFont(PPanel):
         dlg = wxFontDialog(self, data)
         if dlg.ShowModal() == wxID_OK:
             font = dlg.GetFontData().GetChosenFont()
-            value = [str(font.GetPointSize()), fontFamiliesWx2Xml[font.GetFamily()],
-                     fontStylesWx2Xml[font.GetStyle()],
-                     fontWeightsWx2Xml[font.GetWeight()],
-                     str(font.GetUnderlined()), font.GetFaceName(),
-                     wxFontMapper_GetEncodingName(font.GetEncoding())]
+            value = [str(font.GetPointSize()),
+                     fontFamiliesWx2Xml.get(font.GetFamily(), "default"),
+                     fontStylesWx2Xml.get(font.GetStyle(), "normal"),
+                     fontWeightsWx2Xml.get(font.GetWeight(), "normal"),
+                     str(font.GetUnderlined()),
+                     font.GetFaceName(),
+                     wxFontMapper_GetEncodingName(font.GetEncoding())
+                     ]
             # Add ignored flags
             self.SetValue(value)
             self.SetModified()
@@ -268,8 +295,8 @@ class ParamFont(PPanel):
 ################################################################################
 
 class ParamInt(PPanel):
-    def __init__(self, parent, id = -1, size = wxDefaultSize, name = ''):
-        PPanel.__init__(self, parent, id, name)
+    def __init__(self, parent, name):
+        PPanel.__init__(self, parent, name)
         self.ID_SPIN_CTRL = wxNewId()
         sizer = wxBoxSizer()
         self.spin = wxSpinCtrl(self, self.ID_SPIN_CTRL, size=wxSize(50,-1))
@@ -283,7 +310,6 @@ class ParamInt(PPanel):
         return str(self.spin.GetValue())
     def SetValue(self, value):
         self.freeze = true
-        value = string.strip(value)
         if not value: value = 0
         self.spin.SetValue(int(value))
         self.freeze = false
@@ -293,8 +319,8 @@ class ParamInt(PPanel):
         evt.Skip()
 
 class ParamText(PPanel):
-    def __init__(self, parent, id = -1, size = wxDefaultSize, name = '', textWidth=200):
-        PPanel.__init__(self, parent, id, name)
+    def __init__(self, parent, name, textWidth=200):
+        PPanel.__init__(self, parent, name)
         self.ID_TEXT_CTRL = wxNewId()
         # We use sizer even here to have the same size of text control
         sizer = wxBoxSizer()
@@ -317,29 +343,25 @@ class ParamText(PPanel):
         evt.Skip()
 
 class ParamAccel(ParamText):
-    def __init__(self, parent, id = -1, size = wxDefaultSize, name = ''):
-        ParamText.__init__(self, parent, id, size, name, 50)
+    def __init__(self, parent, name):
+        ParamText.__init__(self, parent, name, 50)
 
 class ParamPosSize(ParamText):
-    def __init__(self, parent, id = -1, size = wxDefaultSize, name = ''):
-        ParamText.__init__(self, parent, id, size, name, 80)
+    def __init__(self, parent, name):
+        ParamText.__init__(self, parent, name, 80)
 
-class ContentDialog(wxDialog):
+class ContentDialog(wxDialogPtr):
     def __init__(self, parent, value):
-        #wxPreDialog(self)
-        # Use another constructor
+        # Is this normal???
         w = frame.res.LoadDialog(parent, 'ID_DIALOG_CONTENT')
-        self.this = w.this
-        w.thisown = 0
+        wxDialogPtr.__init__(self, w.this)
         self.thisown = 1
-        #frame.res.LoadOnDialog(self, parent, 'ID_DIALOG_CONTENT')
         self.Center()
         self.list = self.FindWindowByName('ID_LIST')
         # Set list items
         for v in value:
             self.list.Append(v)
         self.SetAutoLayout(true)
-        # !!! self.SetSizer(sizer)
         self.GetSizer().Fit(self)
         # Callbacks
         self.ID_BUTTON_APPEND = XMLID('ID_BUTTON_APPEND')
@@ -379,9 +401,69 @@ class ContentDialog(wxDialog):
             evt.Enable(self.list.GetSelection() != -1 and \
                        self.list.GetSelection() < self.list.Number() - 1)
 
+class ContentCheckListDialog(wxDialogPtr):
+    def __init__(self, parent, value):
+        # Is this normal???
+        w = frame.res.LoadDialog(parent, 'ID_DIALOG_CONTENT_CHECK_LIST')
+        wxDialogPtr.__init__(self, w.this)
+        self.thisown = 1
+        self.Center()
+        self.list = self.FindWindowByName('ID_CHECK_LIST')
+        # Set list items
+        i = 0
+        for v,ch in value:
+            self.list.Append(v)
+            self.list.Check(i, ch)
+            i += 1
+        self.SetAutoLayout(true)
+        self.GetSizer().Fit(self)
+        # Callbacks
+        self.ID_BUTTON_APPEND = XMLID('ID_BUTTON_APPEND')
+        self.ID_BUTTON_REMOVE = XMLID('ID_BUTTON_REMOVE')
+        self.ID_BUTTON_UP = XMLID('ID_BUTTON_UP')
+        self.ID_BUTTON_DOWN = XMLID('ID_BUTTON_DOWN')
+        EVT_CHECKLISTBOX(self, self.list.GetId(), self.OnCheck)
+        EVT_BUTTON(self, self.ID_BUTTON_UP, self.OnButtonUp)
+        EVT_BUTTON(self, self.ID_BUTTON_DOWN, self.OnButtonDown)
+        EVT_BUTTON(self, self.ID_BUTTON_APPEND, self.OnButtonAppend)
+        EVT_BUTTON(self, self.ID_BUTTON_REMOVE, self.OnButtonRemove)
+        EVT_UPDATE_UI(self, self.ID_BUTTON_UP, self.OnUpdateUI)
+        EVT_UPDATE_UI(self, self.ID_BUTTON_DOWN, self.OnUpdateUI)
+        EVT_UPDATE_UI(self, self.ID_BUTTON_REMOVE, self.OnUpdateUI)
+    def OnCheck(self, evt):
+        # !!! Wrong wxGTK (wxMSW?) behavior: toggling selection if checking
+        self.list.Deselect(evt.GetSelection())
+    def OnButtonUp(self, evt):
+        i = self.list.GetSelection()
+        str, ch = self.list.GetString(i), self.list.IsChecked(i)
+        self.list.Delete(i)
+        self.list.InsertItems([str], i-1)
+        self.list.Check(i-1, ch)
+        self.list.SetSelection(i-1)
+    def OnButtonDown(self, evt):
+        i = self.list.GetSelection()
+        str, ch = self.list.GetString(i), self.list.IsChecked(i)
+        self.list.Delete(i)
+        self.list.InsertItems([str], i+1)
+        self.list.Check(i+1, ch)
+        self.list.SetSelection(i+1)
+    def OnButtonAppend(self, evt):
+        str = wxGetTextFromUser('Enter new item:', 'Append', '', self)
+        self.list.Append(str)
+    def OnButtonRemove(self, evt):
+        self.list.Delete(self.list.GetSelection())
+    def OnUpdateUI(self, evt):
+        if evt.GetId() == self.ID_BUTTON_REMOVE:
+            evt.Enable(self.list.GetSelection() != -1)
+        elif evt.GetId() == self.ID_BUTTON_UP:
+            evt.Enable(self.list.GetSelection() > 0)
+        elif evt.GetId() == self.ID_BUTTON_DOWN:
+            evt.Enable(self.list.GetSelection() != -1 and \
+                       self.list.GetSelection() < self.list.Number() - 1)
+
 class ParamContent(PPanel):
-    def __init__(self, parent, id = -1, size = wxDefaultSize, name = ''):
-        PPanel.__init__(self, parent, id, name)
+    def __init__(self, parent, name):
+        PPanel.__init__(self, parent, name)
         self.ID_TEXT_CTRL = wxNewId()
         self.ID_BUTTON_EDIT = wxNewId()
         self.SetBackgroundColour(panel.GetBackgroundColour())
@@ -403,7 +485,11 @@ class ParamContent(PPanel):
         evt.Skip()
     def GetValue(self):
         if self.textModified:           # text has newer value
-            return eval(self.text.GetValue())
+            try:
+                return eval(self.text.GetValue())
+            except SyntaxError:
+                wxLogError('Syntax error in parameter value: ' + self.GetName())
+                return []
         return self.value
     def SetValue(self, value):
         self.freeze = true
@@ -412,7 +498,11 @@ class ParamContent(PPanel):
         self.freeze = false
     def OnButtonEdit(self, evt):
         if self.textModified:           # text has newer value
-            self.value = eval(self.text.GetValue())
+            try:
+                self.value = eval(self.text.GetValue())
+            except SyntaxError:
+                wxLogError('Syntax error in parameter value: ' + self.GetName())
+                self.value = []
         dlg = ContentDialog(self, self.value)
         if dlg.ShowModal() == wxID_OK:
             value = []
@@ -424,11 +514,65 @@ class ParamContent(PPanel):
             self.textModified = false
         dlg.Destroy()
 
+# CheckList content
+class ParamContentCheckList(PPanel):
+    def __init__(self, parent, name):
+        PPanel.__init__(self, parent, name)
+        self.ID_TEXT_CTRL = wxNewId()
+        self.ID_BUTTON_EDIT = wxNewId()
+        self.SetBackgroundColour(panel.GetBackgroundColour())
+        sizer = wxBoxSizer()
+        self.text = wxTextCtrl(self, self.ID_TEXT_CTRL, size=wxSize(200,-1))
+        sizer.Add(self.text, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, 10)
+        self.button = wxButton(self, self.ID_BUTTON_EDIT, 'Edit...')
+        sizer.Add(self.button, 0, wxALIGN_CENTER_VERTICAL)
+        self.SetAutoLayout(true)
+        self.SetSizer(sizer)
+        sizer.Fit(self)
+        self.textModified = false
+        EVT_BUTTON(self, self.ID_BUTTON_EDIT, self.OnButtonEdit)
+        EVT_TEXT(self, self.ID_TEXT_CTRL, self.OnChange)
+    def OnChange(self, evt):
+        if self.freeze: return
+        self.SetModified()
+        self.textModified = true
+        evt.Skip()
+    def GetValue(self):
+        if self.textModified:           # text has newer value
+            try:
+                return eval(self.text.GetValue())
+            except SyntaxError:
+                wxLogError('Syntax error in parameter value: ' + self.GetName())
+                return []
+        return self.value
+    def SetValue(self, value):
+        self.freeze = true
+        self.value = value
+        self.text.SetValue(str(value))  # update text ctrl
+        self.freeze = false
+    def OnButtonEdit(self, evt):
+        if self.textModified:           # text has newer value
+            try:
+                self.value = eval(self.text.GetValue())
+            except SyntaxError:
+                wxLogError('Syntax error in parameter value: ' + self.GetName())
+                self.value = []
+        dlg = ContentCheckListDialog(self, self.value)
+        if dlg.ShowModal() == wxID_OK:
+            value = []
+            for i in range(dlg.list.Number()):
+                value.append((dlg.list.GetString(i), dlg.list.IsChecked(i)))
+            # Add ignored flags
+            self.SetValue(value)
+            self.SetModified()
+            self.textModified = false
+        dlg.Destroy()
+
 # Boxless radiobox
 class RadioBox(PPanel):
     def __init__(self, parent, id, choices,
-                 pos=wxDefaultPosition, size=wxDefaultSize, name='radiobox'):
-        PPanel.__init__(self, parent, id, name)
+                 pos=wxDefaultPosition, name='radiobox'):
+        PPanel.__init__(self, parent, name)
         self.SetBackgroundColour(panel.GetBackgroundColour())
         self.choices = choices
         topSizer = wxBoxSizer()
@@ -456,8 +600,8 @@ class RadioBox(PPanel):
 class ParamBool(RadioBox):
     values = {'yes': '1', 'no': '0'}
     seulav = {'1': 'yes', '0': 'no'}
-    def __init__(self, parent, id = -1, size = wxDefaultSize, name = ''):
-        RadioBox.__init__(self, parent, id, choices = self.values.keys(), name=name)
+    def __init__(self, parent, name):
+        RadioBox.__init__(self, parent, -1, choices = self.values.keys(), name=name)
     def GetValue(self):
         return self.values[self.GetStringSelection()]
     def SetValue(self, value):
@@ -467,8 +611,8 @@ class ParamBool(RadioBox):
 class ParamOrient(RadioBox):
     values = {'horizontal': 'wxHORIZONTAL', 'vertical': 'wxVERTICAL'}
     seulav = {'wxHORIZONTAL': 'horizontal', 'wxVERTICAL': 'vertical'}
-    def __init__(self, parent, id = -1, size = wxDefaultSize, name = ''):
-        RadioBox.__init__(self, parent, id, choices = self.values.keys(), name=name)
+    def __init__(self, parent, name):
+        RadioBox.__init__(self, parent, -1, choices = self.values.keys(), name=name)
     def GetValue(self):
         return self.values[self.GetStringSelection()]
     def SetValue(self, value):
@@ -476,8 +620,8 @@ class ParamOrient(RadioBox):
         self.SetStringSelection(self.seulav[value])
 
 class ParamFile(PPanel):
-    def __init__(self, parent, id = -1, size = wxDefaultSize, name = ''):
-        PPanel.__init__(self, parent, id, name)
+    def __init__(self, parent, name):
+        PPanel.__init__(self, parent, name)
         self.ID_TEXT_CTRL = wxNewId()
         self.ID_BUTTON_BROWSE = wxNewId()
         self.SetBackgroundColour(panel.GetBackgroundColour())
@@ -499,7 +643,7 @@ class ParamFile(PPanel):
         evt.Skip()
     def GetValue(self):
         if self.textModified:           # text has newer value
-            return eval(self.text.GetValue())
+            return self.text.GetValue()
         return self.value
     def SetValue(self, value):
         self.freeze = true
@@ -510,11 +654,12 @@ class ParamFile(PPanel):
         if self.textModified:           # text has newer value
             self.value = self.text.GetValue()
         dlg = wxFileDialog(self,
-                           defaultDir = os.path.abspath(os.path.dirname(self.value)),
+                           defaultDir = os.path.dirname(self.value),
                            defaultFile = os.path.basename(self.value))
         if dlg.ShowModal() == wxID_OK:
             # Make relative
-            common = os.path.commonprefix([frame.dataFile, dlg.GetPath()])
+            common = os.path.commonprefix([os.path.abspath(frame.dataFile),
+                                           dlg.GetPath()])
             self.SetValue(dlg.GetPath()[len(common):])
             self.SetModified()
             self.textModified = false
index ff07aff810ddfd9fa705ac17c41ee65eaaa12010..175c022f55b2dffd180fe8edc9ab56d5d5f4d568 100644 (file)
@@ -7,25 +7,23 @@
 from wxPython.wx import *
 from wxPython.xrc import *
 from wxPython.html import *
-import wxPython.lib.wxpTag
 from xml.dom import minidom
 import os
 import tempfile
+import getopt
 
+# Icons
 import images
 
-# String constants
+# Constants
 
-faceColour = wxSystemSettings_GetSystemColour(wxSYS_COLOUR_3DFACE)
-# Background colour problem on wxGTK
 if wxGetOsVersion()[1] == 1:
-    bgcolor = (faceColour.Red()-1, faceColour.Green()-1, faceColour.Blue()-1)
+    labelFont = wxFont(12, wxDEFAULT, wxNORMAL, wxBOLD)
 else:
-    bgcolor = (faceColour.Red(), faceColour.Green(), faceColour.Blue())
-htmlHeader = '<html><body bgcolor="#%02x%02x%02x">\n' % bgcolor
-htmlFooter = '</body></html>\n'
+    labelFont = wxFont(10, wxDEFAULT, wxNORMAL, wxBOLD)
+
 progname = 'XRCed'
-version = '0.0.6'
+version = '0.0.7-1'
 
 # Local modules
 from xxx import *
@@ -35,11 +33,19 @@ testWin = None
 testWinPos = wxDefaultPosition
 
 # 1 adds CMD command to Help menu
-debug = 1
+debug = 0
+
+helpText = """\
+<HTML><H2>Welcome to XRCed!</H2><H3><font color="green">DON'T PANIC :)</font></H3>
+To start select tree root, then popup menu with your right mouse button,
+select "Append Child", and then any command.<P>
+Enter XML ID, change properties, create children.<P>
+To test your interface select Test command (View menu).<P>
+Consult README file for the details.</HTML>
+"""
 
-if debug:
-    import traceback
-    import time
+defaultIDs = {xxxPanel:'PANEL', xxxDialog:'DIALOG', xxxFrame:'FRAME',
+              xxxMenuBar:'MENUBAR', xxxMenu:'MENU', xxxToolBar:'TOOLBAR'}
 
 # Set menu to list items.
 # Each menu command is a tuple (id, label, help)
@@ -63,78 +69,148 @@ class Panel(wxNotebook):
     def __init__(self, parent, id = -1):
         wxNotebook.__init__(self, parent, id, style=wxNB_BOTTOM)
         sys.modules['params'].panel = self
-        self.page1 = HtmlPage(self)
+        # List of child windows
+        self.pages = []
+        # Create scrolled windows for pages
+        self.page1 = wxScrolledWindow(self, -1)
+        sizer = wxBoxSizer()
+        sizer.Add(wxBoxSizer())         # dummy sizer
+        self.page1.SetAutoLayout(true)
+        self.page1.SetSizer(sizer)
         self.AddPage(self.page1, 'Properties')
-        self.page2 = None
+        # Second page
+        self.page2 = wxScrolledWindow(self, -1)
+        sizer = wxBoxSizer()
+        sizer.Add(wxBoxSizer())         # dummy sizer
+        self.page2.SetAutoLayout(true)
+        self.page2.SetSizer(sizer)
         # Cache for already used panels
-        self.styleCache = {}
+        self.pageCache = {}             # cached property panels
+        self.stylePageCache = {}        # cached style panels
+        # Dummy parent window for cache pages
+        self.cacheParent = wxFrame(None, -1, 'non visible')
+    # Delete child windows and recreate page sizer
+    def ResetPage(self, page):
+        topSizer = page.GetSizer()
+        sizer = topSizer.GetChildren()[0].GetSizer()
+        for w in page.GetChildren():
+            sizer.RemoveWindow(w)
+            if isinstance(w, ParamPage):
+                # With SetParent, we wouldn't need this
+                w.Reparent(self.cacheParent)
+            else:
+                w.Destroy()
+        topSizer.RemoveSizer(sizer)
+        # Create new windows
+        sizer = wxBoxSizer(wxVERTICAL)
+        # Special case - resize html window
+        if conf.panic:
+            topSizer.Add(sizer, 1, wxEXPAND)
+        else:
+            topSizer.Add(sizer, 0, wxALL, 5)
+        return sizer
     def SetData(self, xxx):
+        self.pages = []
         # First page
-        self.page1.SetPageData(xxx)
-        # Replace/remove style page
-        curPage = self.GetSelection()
-        if self.page2:
-            # If style page for a same class, don't need to recreate
-            if xxx and self.page2.cacheId == xxx.treeObject().__class__:
-                self.page2.SetData(xxx.treeObject())
-                return
-            # Else remove and then add if needed
-            self.RemovePage(1)
-            if not self.styleCache.has_key(self.page2.cacheId):
-                self.styleCache[self.page2.cacheId] = self.page2
-        self.Freeze()
+        # Set cached or new page
+        # Remove current objects and sizer
+        sizer = self.ResetPage(self.page1)
+        if not xxx or (not xxx.allParams and not xxx.hasName):
+            if tree.selection:
+                sizer.Add(wxStaticText(self.page1, -1, 'This item has no properties.'))
+            else:                       # nothing selected
+                # If first time, show some help
+                if conf.panic:
+                    html = wxHtmlWindow(self.page1, -1, wxDefaultPosition,
+                                        wxDefaultSize, wxSUNKEN_BORDER)
+                    html.SetPage(helpText)
+                    sizer.Add(html, 1, wxEXPAND)
+                    conf.panic = false
+                else:
+                    sizer.Add(wxStaticText(self.page1, -1, 'Select a tree item.'))
+        else:
+            SetCurrentXXX(xxx.treeObject())
+            try:
+                page = self.pageCache[xxx.__class__]
+                page.Reparent(self.page1)
+            except KeyError:
+                page = PropPage(self.page1, xxx.className, xxx)
+                self.pageCache[xxx.__class__] = page
+            page.SetValues(xxx)
+            self.pages.append(page)
+            sizer.Add(page, 1, wxEXPAND)
+            if xxx.hasChild:
+                # Special label for child objects - they may have different GUI
+                cacheID = (xxx.child.__class__, xxx.__class__)
+                try:
+                    page = self.pageCache[cacheID]
+                    page.Reparent(self.page1)
+                except KeyError:
+                    page = PropPage(self.page1, xxx.child.className, xxx.child)
+                    self.pageCache[cacheID] = page
+                page.SetValues(xxx.child)
+                self.pages.append(page)
+                sizer.Add(page, 0, wxEXPAND | wxTOP, 5)
+        self.page1.Layout()
+        size = self.page1.GetSizer().GetMinSize()
+        self.page1.SetScrollbars(1, 1, size.x, size.y, 0, 0, true)
+
+        # Second page
+        # Create if does not exist
         if xxx and xxx.treeObject().hasStyle:
-            cacheId = xxx.treeObject().__class__
-            if self.styleCache.has_key(cacheId):
-                self.page2 = self.styleCache[cacheId]
-                self.page2.SetData(xxx.treeObject())
-            else:
-                self.page2 = StylePage(self, xxx.treeObject())
-            self.AddPage(self.page2, 'Style')
+            xxx = xxx.treeObject()
+            # Simplest case: set data if class is the same
+            sizer = self.ResetPage(self.page2)
+            try:
+                page = self.stylePageCache[xxx.__class__]
+                page.Reparent(self.page2)
+            except KeyError:
+                page = StylePage(self.page2, xxx.className + ' style', xxx)
+                self.stylePageCache[xxx.__class__] = page
+            page.SetValues(xxx)
+            self.pages.append(page)
+            sizer.Add(page, 0, wxEXPAND)
+            # Add page if not exists
+            if not self.GetPageCount() == 2:
+                self.AddPage(self.page2, 'Style')
+            self.page2.Layout()
+            size = self.page2.GetSizer().GetMinSize()
+            self.page2.SetScrollbars(1, 1, size.x, size.y, 0, 0, true)
         else:
-            self.page2 = None
-        # Keep page selected
-        if self.page2 and curPage == 1:
-            self.SetSelection(curPage)
-        self.Thaw()
+            # Remove page if exists
+            if self.GetPageCount() == 2:
+                self.RemovePage(1)
     def Clear(self):
-        self.page1.Clear()
-        if self.page2:
-            self.RemovePage(1)
-            self.page2.Destroy()
-            self.page2 = None
-    # If some parameter on some page has changed
+        self.SetData(None)
+    # Check if some parameter on some page has changed
     def IsModified(self):
-        return self.page1.IsModified() or self.page2 and self.page2.IsModified()
+        for p in self.pages:
+            if p.IsModified(): return true
+        return false
+    # Reset changed state
     def SetModified(self, value):
-        self.page1.SetModified(value)
-        if self.page2:
-            self.page2.SetModified(value)
+        for p in self.pages: p.SetModified(value)
+    def Apply(self):
+        for p in self.pages: p.Apply()
 
 ################################################################################
 
 # General class for notebook pages
-class ParamPage:
-    def __init__(self):
+class ParamPage(wxPanel):
+    def __init__(self, parent, xxx):
+        wxPanel.__init__(self, parent, -1)
+        self.xxx = xxx
         # Register event handlers
         for id in paramIDs.values():
             EVT_CHECKBOX(self, id, self.OnCheckParams)
+        self.modified = false
+        self.checks = {}
+        self.controls = {}              # save python objects
+        self.controlName = None
     def OnCheckParams(self, evt):
-        selected = tree.GetSelection()
-        xxx = tree.GetPyData(selected)
-        winName = evt.GetEventObject().GetName()
-        sizerParam = false
-        if winName[0] == '_':
-            param = winName[7:]
-            sizerParam = true
-        else:
-            if xxx.hasChild: xxx = xxx.child
-            param = winName[6:]
-        # Set current object
-        if sizerParam:
-            w = self.FindWindowByName('_data_' + param)
-        else:
-            w = self.FindWindowByName('data_' + param)
+        xxx = self.xxx
+        param = evt.GetEventObject().GetName()
+        w = self.controls[param]
         objElem = xxx.element
         if evt.IsChecked():
             # Ad  new text node in order of allParams
@@ -160,108 +236,131 @@ class ParamPage:
             xxx.params[param].remove()
             del xxx.params[param]
             w.SetValue('')
+            w.modified = false          # mark as not changed
             # Set modified flas
             self.SetModified(true)
         w.Enable(evt.IsChecked())
-
+    # If some parameter has changed
+    def IsModified(self):
+        return self.modified
+    def SetModified(self, value):
+        self.modified = value
+    def Apply(self):
+        xxx = self.xxx
+        # !!! Save undo info
+#        if xxx.undo: xxx.undo.unlink()
+#        xxx.undo = xxx.element.cloneNode(false)
+        if self.controlName:
+            name = self.controlName.GetValue()
+            if xxx.name != name:
+                xxx.name = name
+                xxx.element.setAttribute('name', name)
+        for param, w in self.controls.items():
+            if w.modified:
+                paramObj = xxx.params[param]
+                value = w.GetValue()
+                if param in xxx.specials:
+                    xxx.setSpecial(param, value)
+                else:
+                    paramObj.update(value)
 
 ################################################################################
 
-# Properties panel notebook page
-class HtmlPage(wxHtmlWindow, ParamPage):
-    def __init__(self, parent, id = -1):
-        wxHtmlWindow.__init__(self, parent, id)
-        ParamPage.__init__(self)
-        self.SetBorders(5)
-        if wxGetOsVersion()[1] == 1:
-            self.SetFonts('', '', [8, 10, 12, 14, 16, 19, 24])
-        else:
-            self.SetFonts("", "", [7, 8, 10, 12, 16, 22, 30])
-        self.modified = false
-        # Previous type
-        self.xxxClass = self.xxxChildClass = None
-    def Clear(self):
-        self.SetPage(htmlHeader + 'select a tree item on the left' + htmlFooter)
-    def SetPageData(self, xxx):
-        if not xxx:
-            self.SetPage(htmlHeader + 'this item has no properties' + htmlFooter)
-            return
-        self.Freeze()                   # doesn't seem to help
-        # Don't change interface if same class
-        compare = false
-        if self.xxxClass and self.xxxClass == xxx.__class__:
-            compare = true              # a little weird code
-            if xxx.hasChild:
-                if self.xxxChildClass != xxx.child.__class__:
-                    compare = false
-        if not compare:                 # not same
-            self.SetPage(htmlHeader + xxx.generateHtml() + htmlFooter)
-            self.xxxClass = xxx.__class__
-            if xxx.hasChild: self.xxxChildClass = xxx.child.__class__
-        self.SetValues(xxx)
-        if xxx.hasChild:
-            self.SetValues(xxx.child)
-        self.Thaw()
+# Panel for displaying properties
+class PropPage(ParamPage):
+    def __init__(self, parent, label, xxx):
+        ParamPage.__init__(self, parent, xxx)
+        box = wxStaticBox(self, -1, label)
+        box.SetFont(labelFont)
+        topSizer = wxStaticBoxSizer(box, wxVERTICAL)
+        sizer = wxFlexGridSizer(len(xxx.allParams), 2, 1, 1)
+        if xxx.hasName:
+            label = wxStaticText(self, -1, 'XML ID:', size=(80,-1))
+            control = ParamText(self, name='XML_name')
+            sizer.AddMany([ (label, 0, wxALIGN_CENTER_VERTICAL),
+                            (control, 0, wxALIGN_CENTER_VERTICAL) ])
+            self.controlName = control
+        for param in xxx.allParams:
+            present = param in xxx.params
+            if param in xxx.required:
+                label = wxStaticText(self, paramIDs[param], param + ':',
+                                     size = (80,-1), name = param)
+            else:
+                # Notebook has one very loooooong parameter
+                if param == 'usenotebooksizer': sParam = 'usesizer:'
+                else: sParam = param + ':'
+                label = wxCheckBox(self, paramIDs[param], sParam,
+                                   size = (80,-1), name = param)
+                self.checks[param] = label
+            try:
+                typeClass = xxx.paramDict[param]
+            except KeyError:
+                try:
+                    # Standart type
+                    typeClass = paramDict[param]
+                except KeyError:
+                    # Default
+                    typeClass = ParamText
+            control = typeClass(self, param)
+            control.Enable(present)
+            sizer.AddMany([ (label, 0, wxALIGN_CENTER_VERTICAL),
+                            (control, 0, wxALIGN_CENTER_VERTICAL) ])
+            self.controls[param] = control
+        topSizer.Add(sizer, 1, wxALL | wxEXPAND, 5)
+        self.SetAutoLayout(true)
+        self.SetSizer(topSizer)
+        topSizer.Fit(self)
     def SetValues(self, xxx):
+        self.xxx = xxx
         # Set values, checkboxes to false, disable defaults
-        if xxx.hasChild: prefix = '_'
-        else: prefix = ''
         if xxx.hasName:
-            self.FindWindowByName('data_name').SetValue(xxx.name)
+            self.controlName.SetValue(xxx.name)
         for param in xxx.allParams:
+            w = self.controls[param]
+            w.modified = false
             try:
                 value = xxx.params[param].value()
-                self.FindWindowByName(prefix + 'data_' + param).SetValue(value)
+                w.Enable(true)
+                w.SetValue(value)
                 if not param in xxx.required:
-                    self.FindWindowByName(prefix + 'check_' + param).SetValue(true)
+                    self.checks[param].SetValue(true)
             except KeyError:
-                self.FindWindowByName(prefix + 'data_' + param).Enable(false)
-    # If some parameter has changed
-    def IsModified(self):
-        return self.modified
-    def SetModified(self, value):
-        self.modified = value
+                self.checks[param].SetValue(false)
+                w.SetValue('')
+                w.Enable(false)
+        self.SetModified(false)
 
 ################################################################################
 
 # Style notebook page
-class StylePage(wxPanel, ParamPage):
-    def __init__(self, parent, xxx):
-        wxPanel.__init__(self, parent, -1)
-        ParamPage.__init__(self)
-        self.cacheId = xxx.__class__
-        if wxGetOsVersion()[1] == 1:
-            self.SetFont(wxFont(12, wxDEFAULT, wxNORMAL, wxNORMAL))
-        else:
-            self.SetFont(wxFont(10, wxDEFAULT, wxNORMAL, wxNORMAL))
-        topSizer = wxBoxSizer(wxVERTICAL)
+class StylePage(ParamPage):
+    def __init__(self, parent, label, xxx):
+        ParamPage.__init__(self, parent, xxx)
+        box = wxStaticBox(self, -1, label)
+        box.SetFont(labelFont)
+        topSizer = wxStaticBoxSizer(box, wxVERTICAL)
         sizer = wxFlexGridSizer(len(xxx.styles), 2, 1, 1)
-        self.controls = {}              # save python objects
         for param in xxx.styles:
             present = param in xxx.params.keys()
             check = wxCheckBox(self, paramIDs[param],
-                               param + ':', name = 'check_' + param)
+                               param + ':', size = (80,-1), name = param)
             check.SetValue(present)
-            control = paramDict[param](self, name = 'data_' + param)
-            if present:
-                control.SetValue(xxx.params[param].value())
-            else:
-                control.SetValue('')
+            control = paramDict[param](self, name = param)
             control.Enable(present)
             sizer.AddMany([ (check, 0, wxALIGN_CENTER_VERTICAL),
                             (control, 0, wxALIGN_CENTER_VERTICAL) ])
+            self.checks[param] = check
             self.controls[param] = control
-        topSizer.Add(sizer, 1, wxALL, 5)
+        topSizer.Add(sizer, 1, wxALL | wxEXPAND, 5)
         self.SetAutoLayout(true)
         self.SetSizer(topSizer)
-
-        self.modified = false
-
+        topSizer.Fit(self)
     # Set data for a cahced page
-    def SetData(self, xxx):
+    def SetValues(self, xxx):
+        self.xxx = xxx
         for param in xxx.styles:
             present = param in xxx.params.keys()
-            check = self.FindWindowByName('check_' + param)
+            check = self.checks[param]
             check.SetValue(present)
             control = self.controls[param]
             if present:
@@ -269,13 +368,7 @@ class StylePage(wxPanel, ParamPage):
             else:
                 control.SetValue('')
             control.Enable(present)
-        self.modified = false
-
-    # If some parameter has changed
-    def IsModified(self):
-        return self.modified
-    def SetModified(self, value):
-        self.modified = value
+        self.SetModified(false)
 
 ################################################################################
 
@@ -311,24 +404,22 @@ class MemoryFile:
         self.name = name
         self.buffer = ''
     def write(self, data):
-        self.buffer = self.buffer + data.encode()
+        self.buffer += data.encode()
     def close(self):
-        f = open(self.name, 'w')
-        f.write(self.buffer)
-        f.close()
-        # !!! memory FS will work someday
-        #self.file = wxMemoryFSHandler_AddFile(self.name, self.buffer)
+        wxMemoryFSHandler_AddFile(self.name, self.buffer)
 
 class XML_Tree(wxTreeCtrl):
     def __init__(self, parent, id):
-        wxTreeCtrl.__init__(self, parent, id,
-                            style=wxTR_HAS_BUTTONS | wxTR_LINES_AT_ROOT)
+        wxTreeCtrl.__init__(self, parent, id, style = wxTR_HAS_BUTTONS)
         self.SetBackgroundColour(wxColour(224, 248, 224))
         EVT_TREE_SEL_CHANGED(self, self.GetId(), self.OnSelChanged)
         # One works on Linux, another on Windows
-        EVT_TREE_ITEM_ACTIVATED(self, self.GetId(), self.OnItemActivated)
-        EVT_LEFT_DCLICK(self, self.OnDClick)
+        if wxGetOsVersion()[1] == 1:
+            EVT_TREE_ITEM_ACTIVATED(self, self.GetId(), self.OnItemActivated)
+        else:
+            EVT_LEFT_DCLICK(self, self.OnDClick)
         EVT_RIGHT_DOWN(self, self.OnRightDown)
+
         self.needUpdate = false
         self.pendingHighLight = None
         self.ctrl = false
@@ -352,12 +443,9 @@ class XML_Tree(wxTreeCtrl):
         self.il = il
         self.SetImageList(il)
 
-    # !!! temporary solution for GetOldItem problem
     def Unselect(self):
-        self.selection = wxTreeItemId()
+        self.selection = None
         wxTreeCtrl.Unselect(self)
-    def GetSelection(self):
-        return self.selection
 
     def ExpandAll(self, item):
         if self.ItemHasChildren(item):
@@ -369,18 +457,53 @@ class XML_Tree(wxTreeCtrl):
                 i, cookie = self.GetNextChild(item, cookie)
             for i in children:
                 self.ExpandAll(i)
+    def CollapseAll(self, item):
+        if self.ItemHasChildren(item):
+            i, cookie = self.GetFirstChild(item, 0)
+            children = []
+            while i.IsOk():
+                children.append(i)
+                i, cookie = self.GetNextChild(item, cookie)
+            for i in children:
+                self.CollapseAll(i)
+            self.Collapse(item)
 
+    # Clear tree
+    def Clear(self):
+        self.DeleteAllItems()
+        # Add minimal structure
+        if self.dom: self.dom.unlink()
+        self.dom = minidom.Document()
+        self.dummyNode = self.dom.createComment('dummy node')
+        # Create main node
+        self.mainNode = self.dom.createElement('resource')
+        self.dom.appendChild(self.mainNode)
+        xxx = xxxMainNode(None, self.mainNode)
+        self.root = self.AddRoot('XML tree', self.rootImage, data=wxTreeItemData(xxx))
+        self.SetItemHasChildren(self.root)
+        self.Expand(self.root)
+        self.Unselect()
+
+    # Clear old data and set new
     def SetData(self, dom):
+        self.DeleteAllItems()
+        # Add minimal structure
+        if self.dom: self.dom.unlink()
         self.dom = dom
+        self.dummyNode = self.dom.createComment('dummy node')
         # Find 'resource' child, add it's children
         self.mainNode = dom.getElementsByTagName('resource')[0]
+        xxx = xxxMainNode(None, self.mainNode)
+        self.root = self.AddRoot('XML tree', self.rootImage, data=wxTreeItemData(xxx))
+        self.SetItemHasChildren(self.root)
         nodes = self.mainNode.childNodes[:]
         for node in nodes:
             if IsObject(node):
-                self.AddNode(self.GetRootItem(), None, node)
+                self.AddNode(self.root, None, node)
             else:
                 self.mainNode.removeChild(node)
                 node.unlink()
+        self.Expand(self.root)
         self.Unselect()
 
     # Add tree item for given parent item if node is DOM element node with
@@ -390,7 +513,9 @@ class XML_Tree(wxTreeCtrl):
         try:
             xxx = MakeXXXFromDOM(xxxParent, node)
         except:
-            return
+            print 'ERROR: MakeXXXFromDom(%s, %s)' % (xxxParent, node)
+            raise
+#            return
         treeObj = xxx.treeObject()
         # Append tree item
         item = self.AppendItem(itemParent, treeObj.treeName(),
@@ -405,8 +530,6 @@ class XML_Tree(wxTreeCtrl):
                 elif n.nodeType != minidom.Node.ELEMENT_NODE:
                     treeObj.element.removeChild(n)
                     n.unlink()
-
-
     # Remove leaf of tree, return it's data object
     def RemoveLeaf(self, leaf):
         xxx = self.GetPyData(leaf)
@@ -414,30 +537,37 @@ class XML_Tree(wxTreeCtrl):
         parent = node.parentNode
         parent.removeChild(node)
         self.Delete(leaf)
-        # Update view?
-        #if testWin and self.GetItemAncestor(leaf) == testWin.item:
-        #    if testWin.highLight:
-        #        testWin.highLight.Remove()
-        #    self.needUpdate = true
+        # Reset selection object
+        self.selection = None
         return node
-
     # Find position relative to the top-level window
     def FindNodePos(self, item):
         itemParent = self.GetItemParent(item)
-        if itemParent == self.GetRootItem(): return wxPoint(0, 0)
+        # Select NB page
         obj = self.FindNodeObject(item)
+        if self.GetPyData(itemParent).treeObject().__class__ == xxxNotebook:
+            notebook = self.FindNodeObject(itemParent)
+            # Find position
+            for i in range(notebook.GetPageCount()):
+                if notebook.GetPage(i) == obj:
+                    if notebook.GetSelection() != i: notebook.SetSelection(i)
+                    break
+        # Root at (0,0)
+        if itemParent == self.root: return wxPoint(0, 0)
         # Find first ancestor which is a wxWindow (not a sizer)
         winParent = itemParent
         while self.GetPyData(winParent).isSizer:
             winParent = self.GetItemParent(winParent)
         parentPos = self.FindNodePos(winParent)
-        return parentPos + obj.GetPosition()
-
+        # Position (-1,-1) is really (0,0)
+        pos = obj.GetPosition()
+        if pos == (-1,-1): pos = (0,0)
+        return parentPos + pos
     # Find window (or sizer) corresponding to a tree item.
     def FindNodeObject(self, item):
         itemParent = self.GetItemParent(item)
         # If top-level, return testWin (or panel if wxFrame)
-        if itemParent == self.GetRootItem(): return testWin.panel
+        if itemParent == self.root: return testWin.panel
         xxx = self.GetPyData(item).treeObject()
         parentWin = self.FindNodeObject(itemParent)
         # Top-level sizer? return window's sizer
@@ -459,43 +589,41 @@ class XML_Tree(wxTreeCtrl):
                 if isinstance(child, wxNotebookSizerPtr):
                     child = child.GetNotebook()
         return child
-
     def OnSelChanged(self, evt):
         # Apply changes
-        # !!! problem with wxGTK
+        # !!! problem with wxGTK - GetOldItem is Ok if nothing selected
         #oldItem = evt.GetOldItem()
+        status = ''
         oldItem = self.selection
-        if oldItem.IsOk():
+        if oldItem:
             xxx = self.GetPyData(oldItem)
             # If some data was modified, apply changes
-            if xxx:
-                if panel.IsModified():
-                    self.Apply(xxx, oldItem)
-                    #if conf.autoRefresh:
-                    if testWin and testWin.highLight:
+            if panel.IsModified():
+                self.Apply(xxx, oldItem)
+                #if conf.autoRefresh:
+                if testWin and tree.GetItemAncestor(oldItem) == testWin.item:
+                    if testWin.highLight:
                         testWin.highLight.Remove()
                     self.needUpdate = true
-        # Generate HTML view
-        item = evt.GetItem()
-        self.selection = item           # !!! fix
-        xxx = self.GetPyData(item)
+                status = 'Changes were applied'
+        frame.SetStatusText(status)
+        # Generate view
+        self.selection = evt.GetItem()
+        if not self.selection.IsOk():
+            self.selection = None
+            return
+        xxx = self.GetPyData(self.selection)
         # Update panel
         panel.SetData(xxx)
-        # Remove highlight?
-        if not xxx and testWin and testWin.highLight:
-            testWin.highLight.Remove()
-            return
         # Clear flag
         panel.SetModified(false)
         # Hightlighting is done in OnIdle
-        tree.pendingHighLight = item
-
+        tree.pendingHighLight = self.selection
     # Find top-level parent
     def GetItemAncestor(self, item):
-        while self.GetItemParent(item) != self.GetRootItem():
+        while self.GetItemParent(item) != self.root:
             item = self.GetItemParent(item)
         return item
-
     # Highlight selected item
     def HighLight(self, item):
         self.pendingHighLight = None
@@ -503,72 +631,62 @@ class XML_Tree(wxTreeCtrl):
             not in ['wxDialog', 'wxPanel', 'wxFrame']:
             return
         # Top-level does not have highlight
-        if item == testWin.item or item == tree.GetRootItem():
+        if item == testWin.item or item == tree.root:
             if testWin.highLight: testWin.highLight.Remove()
             return
         # If a control from another window is selected, remove highlight
-        if self.GetItemAncestor(item) != testWin.item and testWin.highLight:
-            testWin.highLight.Remove()
+        if self.GetItemAncestor(item) != testWin.item:
+            if testWin.highLight: testWin.highLight.Remove()
             return
         # Get window/sizer object
         obj, pos = self.FindNodeObject(item), self.FindNodePos(item)
         size = obj.GetSize()
-        # For notebook, select item's page.
-        # For children of page, nothing happens (too much work)
-        if isinstance(self.GetPyData(item).parent, xxxNotebook):
-            notebook = self.FindNodeObject(self.GetItemParent(item))
-            # Find position
-            n = 0
-            prev = self.GetPrevSibling(item)
-            while prev.IsOk():
-                n += 1
-                prev = self.GetPrevSibling(prev)
-            notebook.SetSelection(n)
         # Highlight
-        try:                        # finally I use exceptions
+        # Nagative positions are not working wuite well
+        if testWin.highLight:
             testWin.highLight.Replace(pos, size)
-        except AttributeError:
+        else:
             testWin.highLight = HightLightBox(pos, size)
         testWin.highLight.item = item
-
-    # Double-click on Linux
-    def OnItemActivated(self, evt):
-        item = evt.GetItem()
+    def ShowTestWindow(self, item):
+        global testWin
         xxx = self.GetPyData(item)
-        if not xxx: return              # if root selected, do nothing
         if panel.IsModified():
             self.Apply(xxx, item)       # apply changes
+        treeObj = xxx.treeObject()
+        if treeObj.className not in ['wxFrame', 'wxPanel', 'wxDialog',
+                                     'wxMenuBar', 'wxToolBar']:
+            wxLogMessage('No view for this element (yet)')
+            return
+        if not treeObj.name:
+            wxLogError("Can't display a noname element!")
+            return
+        # Show item in bold
+        if testWin:
+            self.SetItemBold(testWin.item, false)
+        self.SetItemBold(item)
         self.CreateTestWin(item)
-
+    # Double-click on Linux
+    def OnItemActivated(self, evt):
+        if evt.GetItem() != self.root:
+            self.ShowTestWindow(evt.GetItem())
     # Double-click on Windows
     def OnDClick(self, evt):
-        id, flags = self.HitTest(evt.GetPosition())
+        item, flags = self.HitTest(evt.GetPosition())
         if flags in [wxTREE_HITTEST_ONITEMBUTTON, wxTREE_HITTEST_ONITEMLABEL]:
-            # !!! can't create a wxTreeItemId from int
-            item = self.selection           # assume item already selected
-            xxx = self.GetPyData(item)
-            if not xxx: return              # if root selected, do nothing
-            if panel.IsModified():
-                self.Apply(xxx, item)       # apply changes
-            self.CreateTestWin(item)
+            if item != self.root: self.ShowTestWindow(item)
         else:
             evt.Skip()
-
     # (re)create test window
-    def CreateTestWin(self, node):
+    def CreateTestWin(self, item):
         global testWin
         # Create a window with this resource
-        xxx = self.GetPyData(node).treeObject()
-        if not xxx: return            # if root selected, do nothing
-        # If noname element, display error
-        if not xxx.hasName or not xxx.name:
-            wxLogError("Can't display a noname element")
-            return
+        xxx = self.GetPyData(item).treeObject()
         # Close old window, remember where it was
         highLight = None
         if testWin:
             pos = testWin.GetPosition()
-            if node == testWin.item:
+            if item == testWin.item:
                 # Remember highlight if same top-level window
                 if testWin.highLight:
                     highLight = testWin.highLight.item
@@ -587,9 +705,8 @@ class XML_Tree(wxTreeCtrl):
                 testWin = None
         else:
             pos = testWinPos
-        # Save in temporary file before activating
-        memFile = MemoryFile(tempfile.mktemp('xrc'))
-        #memFile = MemoryFile('core.xrc') # to write debug file
+        # Save in memory FS
+        memFile = MemoryFile('xxx.xrc')
         # Create partial XML file - faster for big files
 
         dom = minidom.Document()
@@ -608,10 +725,9 @@ class XML_Tree(wxTreeCtrl):
         mainNode.removeChild(elem)
         dom.unlink()
         parent.replaceChild(elem, self.dummyNode)
-
         memFile.close()                 # write to wxMemoryFS
         res = wxXmlResource('')
-        res.Load(memFile.name)
+        res.Load('memory:xxx.xrc')
         if xxx.className == 'wxFrame':
             # Create new frame
             testWin = wxPreFrame()
@@ -624,12 +740,13 @@ class XML_Tree(wxTreeCtrl):
             if not testWin:
                 testWin = wxFrame(frame, -1, 'Panel: ' + xxx.name, pos=pos)
             testWin.panel = res.LoadPanel(testWin, xxx.name)
-            testWin.SetSize(testWin.panel.GetSize())
+            testWin.SetClientSize(testWin.panel.GetSize())
             testWin.Show(true)
         elif xxx.className == 'wxDialog':
             # Create new frame
             testWin = res.LoadDialog(None, xxx.name)
             testWin.panel = testWin
+            testWin.Layout()
             testWin.SetPosition(pos)
             testWin.Show(true)
         elif xxx.className == 'wxMenuBar':
@@ -639,11 +756,15 @@ class XML_Tree(wxTreeCtrl):
             testWin.menuBar = res.LoadMenuBar(xxx.name)
             testWin.SetMenuBar(testWin.menuBar)
             testWin.Show(true)
-        else:
-            wxLogMessage('No view for this element yet')
-            return
-        os.unlink(memFile.name)         # remove tmp file
-        testWin.item = node
+        elif xxx.className == 'wxToolBar':
+            testWin = wxFrame(frame, -1, 'ToolBar: ' + xxx.name, pos=pos)
+            # Set status bar to display help
+            testWin.CreateStatusBar()
+            testWin.toolBar = res.LoadToolBar(testWin, xxx.name)
+            testWin.SetToolBar(testWin.toolBar)
+            testWin.Show(true)
+        wxMemoryFSHandler_RemoveFile('xxx.xrc')
+        testWin.item = item
         testWin.Connect(testWin.GetId(), -1, wxEVT_CLOSE_WINDOW, self.OnCloseTestWin)
         testWin.highLight = None
         if highLight and not tree.pendingHighLight:
@@ -651,6 +772,7 @@ class XML_Tree(wxTreeCtrl):
 
     def OnCloseTestWin(self, evt):
         global testWin, testWinPos
+        self.SetItemBold(testWin.item, false)
         testWinPos = testWin.GetPosition()
         testWin.Destroy()
         testWin = None
@@ -659,28 +781,35 @@ class XML_Tree(wxTreeCtrl):
     # True if next item should be inserted after current (vs. appended to it)
     def NeedInsert(self, item):
         xxx = self.GetPyData(item)
-        if not xxx: return false        # root item
+        if item == self.root: return false        # root item
         if self.ctrl: return true       # if Ctrl pressed, always insert
-        if xxx.hasChildren and not self.ItemHasChildren(item):
+        if xxx.hasChildren and not self.GetChildrenCount(item, false):
             return false
-        return not (self.IsExpanded(item) and self.ItemHasChildren(item))
+        return not (self.IsExpanded(item) and self.GetChildrenCount(item, false))
 
     # Pull-down
     def OnRightDown(self, evt):
+        # select this item
+        pt = evt.GetPosition();
+        item, flags = self.HitTest(pt)
+        if item.Ok() and flags & wxTREE_HITTEST_ONITEM:
+            self.SelectItem(item)
+
         # Setup menu
         menu = wxMenu()
 
-        item = self.GetSelection()
-        if not item.IsOk():
+        item = self.selection
+        if not item:
             menu.Append(pullDownMenu.ID_EXPAND, 'Expand', 'Expand tree')
+            menu.Append(pullDownMenu.ID_COLLAPSE, 'Collapse', 'Collapse tree')
         else:
             self.ctrl = evt.ControlDown() # save Ctrl state
             self.shift = evt.ShiftDown()  # and Shift too
             m = wxMenu()                  # create menu
             needInsert = false
-            if item != self.GetRootItem(): needInsert = self.NeedInsert(item)
-            if item == self.GetRootItem() or \
-               self.GetItemParent(item) == self.GetRootItem() and needInsert:
+            if item != self.root: needInsert = self.NeedInsert(item)
+            if item == self.root or \
+               self.GetItemParent(item) == self.root and needInsert:
                 m.Append(pullDownMenu.ID_NEW_PANEL, 'Panel', 'Create panel')
                 m.Append(pullDownMenu.ID_NEW_DIALOG, 'Dialog', 'Create dialog')
                 m.Append(pullDownMenu.ID_NEW_FRAME, 'Frame', 'Create frame')
@@ -689,17 +818,21 @@ class XML_Tree(wxTreeCtrl):
                 m.Append(pullDownMenu.ID_NEW_MENU_BAR, 'MenuBar', 'Create menubar')
                 m.Append(pullDownMenu.ID_NEW_MENU, 'Menu', 'Create menu')
             else:
-                xxx = self.GetPyData(item)
+                xxx = self.GetPyData(item).treeObject()
+                # Check parent for possible child nodes if inserting sibling
+                if needInsert: xxx = xxx.parent
                 if xxx.__class__ == xxxMenuBar:
                     m.Append(pullDownMenu.ID_NEW_MENU, 'Menu', 'Create menu')
-                elif xxx.__class__ in [xxxToolBar, xxxTool]:
+                elif xxx.__class__ in [xxxToolBar, xxxTool] or \
+                     xxx.__class__ == xxxSeparator and xxx.parent.__class__ == xxxToolBar:
                     SetMenu(m, pullDownMenu.toolBarControls)
                 elif xxx.__class__ in [xxxMenu, xxxMenuItem]:
                     SetMenu(m, pullDownMenu.menuControls)
                 else:
                     SetMenu(m, pullDownMenu.controls)
-                    if not (xxx.isSizer or \
-                            xxx.parent and xxx.parent.isSizer):
+                    if xxx.__class__ == xxxNotebook:
+                        m.Enable(m.FindItem('sizer'), false)
+                    elif not (xxx.isSizer or xxx.parent and xxx.parent.isSizer):
                         m.Enable(pullDownMenu.ID_NEW_SPACER, false)
             # Select correct label for create menu
             if not needInsert:
@@ -717,60 +850,35 @@ class XML_Tree(wxTreeCtrl):
                     menu.AppendMenu(wxNewId(), 'Create Sibling', m,
                                     'Create sibling after selected object')
             menu.AppendSeparator()
+            # Not using standart IDs because we don't want to show shortcuts
             menu.Append(wxID_CUT, 'Cut', 'Cut to the clipboard')
             menu.Append(wxID_COPY, 'Copy', 'Copy to the clipboard')
-            menu.Append(wxID_PASTE, 'Paste', 'Paste from the clipboard')
+            if self.ctrl and item != tree.root:
+                menu.Append(wxID_PASTE, 'Paste Sibling',
+                            'Paste from the clipboard as a sibling')
+            else:
+                menu.Append(wxID_PASTE, 'Paste', 'Paste from the clipboard')
             menu.Append(pullDownMenu.ID_DELETE,
                                 'Delete', 'Delete object')
-            if item.IsOk() and self.ItemHasChildren(item):
+            if self.ItemHasChildren(item):
                 menu.AppendSeparator()
                 menu.Append(pullDownMenu.ID_EXPAND, 'Expand', 'Expand subtree')
+                menu.Append(pullDownMenu.ID_COLLAPSE, 'Collapse', 'Collapse subtree')
         self.PopupMenu(menu, evt.GetPosition())
         menu.Destroy()
 
-    # Clear tree
-    def Clear(self):
-        self.DeleteAllItems()
-        # Add minimal structure
-        root = self.AddRoot('XML tree', self.rootImage)
-        self.Unselect()
-        if self.dom: self.dom.unlink()
-        self.dom = minidom.Document()
-        self.dummyNode = self.dom.createComment('dummy node')
-        # Create main node
-        self.mainNode = self.dom.createElement('resource')
-        self.dom.appendChild(self.mainNode)
-
     # Apply changes
     def Apply(self, xxx, item):
-        if not xxx: return
-        # !!! Save undo info
-        if xxx.undo: xxx.undo.unlink()
-        xxx.undo = xxx.element.cloneNode(false)
-        if xxx.hasName:
-            name = panel.page1.FindWindowByName('data_name').GetValue()
-            if xxx.name != name:
-                xxx.name = name
-                xxx.element.setAttribute('name', name)
-                self.SetItemText(item, xxx.treeName())
-        if xxx.hasChild: prefix = '_'
-        else: prefix = ''
-        for param, paramObj in xxx.params.items():
-            paramWin = panel.FindWindowByName(prefix + 'data_' + param)
-            if not paramWin.modified: continue
-            value = paramWin.GetValue()
-            if param in xxx.specials:
-                xxx.setSpecial(param, value)
-            else:
-                paramObj.update(value)
-        if xxx.hasChild:
-            self.Apply(xxx.child, item)
-        else:
-            # Change tree icon for sizers
-            if isinstance(xxx, xxxBoxSizer):
-                self.SetItemImage(item, xxx.treeImage())
-            # Set global modified state
-            frame.modified = true
+        panel.Apply()
+        # Update tree view
+        xxx = xxx.treeObject()
+        if xxx.hasName and self.GetItemText(item) != xxx.name:
+            self.SetItemText(item, xxx.treeName())
+        # Change tree icon for sizers
+        if isinstance(xxx, xxxBoxSizer):
+            self.SetItemImage(item, xxx.treeImage())
+        # Set global modified state
+        frame.modified = true
 
 class PullDownMenu:
     ID_NEW_PANEL = wxNewId()
@@ -820,11 +928,13 @@ class PullDownMenu:
     ID_NEW_SEPARATOR = wxNewId()
     ID_NEW_LAST = wxNewId()
     ID_EXPAND = wxNewId()
+    ID_COLLAPSE = wxNewId()
 
     def __init__(self, parent):
         self.ID_DELETE = parent.ID_DELETE
         EVT_MENU_RANGE(parent, self.ID_NEW_PANEL,
                        self.ID_NEW_LAST, parent.OnCreate)
+        EVT_MENU(parent, self.ID_COLLAPSE, parent.OnCollapse)
         EVT_MENU(parent, self.ID_EXPAND, parent.OnExpand)
         # We connect to tree, but process in frame
         EVT_MENU_HIGHLIGHT_ALL(tree, parent.OnPullDownHighlight)
@@ -832,13 +942,22 @@ class PullDownMenu:
 ################################################################################
 
 class Frame(wxFrame):
-    def __init__(self, size):
-        wxFrame.__init__(self, None, -1, '', size=size)
+    def __init__(self, pos, size):
+        global frame
+        frame = self
+        wxFrame.__init__(self, None, -1, '', pos, size)
         self.CreateStatusBar()
+        #self.SetIcon(wxIconFromXPMData(images.getIconData()))
         #icon = wxIconFromXPMData(images.getIconData())
-        icon = wxIcon(os.path.join(sys.path[0], "xrced.ico"), wxBITMAP_TYPE_ICO)
+        icon = wxIcon(os.path.join(sys.path[0], 'xrced.ico'), wxBITMAP_TYPE_ICO)
         self.SetIcon(icon)
 
+        # Defaults
+        self.sashPos = 100
+        self.panelX = self.panelY = -1
+        self.panelWidth = 300
+        self.panelHeight = 200
+
         # Make menus
         menuBar = wxMenuBar()
 
@@ -853,7 +972,7 @@ class Frame(wxFrame):
 
         menu = wxMenu()
         menu.Append(wxID_UNDO, '&Undo\tCtrl-Z', 'Undo')
-        menu.Append(wxID_REDO, '&Redo\tCtrl-R', 'Redo')
+        menu.Append(wxID_REDO, '&Redo\tCtrl-Y', 'Redo')
         menu.AppendSeparator()
         menu.Append(wxID_CUT, 'Cut\tCtrl-X', 'Cut to the clipboard')
         menu.Append(wxID_COPY, '&Copy\tCtrl-C', 'Copy to the clipboard')
@@ -863,8 +982,15 @@ class Frame(wxFrame):
         menuBar.Append(menu, '&Edit')
 
         menu = wxMenu()
+        self.ID_EMBED_PANEL = wxNewId()
+        menu.Append(self.ID_EMBED_PANEL, '&Embed Panel',
+                    'Toggle embedding properties panel in the main window', true)
+        menu.Check(self.ID_EMBED_PANEL, conf.embedPanel)
+        menu.AppendSeparator()
+        self.ID_TEST = wxNewId()
+        menu.Append(self.ID_TEST, '&Test\tF5', 'Test window')
         self.ID_REFRESH = wxNewId()
-        menu.Append(self.ID_REFRESH, '&Refresh\tCtrl-R', 'Refresh view')
+        menu.Append(self.ID_REFRESH, '&Refresh\tCtrl-R', 'Refresh test window')
         self.ID_AUTO_REFRESH = wxNewId()
         menu.Append(self.ID_AUTO_REFRESH, '&Auto-refresh\tCtrl-A',
                     'Toggle auto-refresh mode', true)
@@ -872,7 +998,9 @@ class Frame(wxFrame):
         menuBar.Append(menu, '&View')
 
         menu = wxMenu()
-        menu.Append(wxID_ABOUT, 'About...', 'About XCRed')
+        menu.Append(wxID_ABOUT, '&About...', 'About XCRed')
+        self.ID_README = wxNewId()
+        menu.Append(self.ID_README, '&Readme...', 'View the README file')
         if debug:
             self.ID_DEBUG_CMD = wxNewId()
             menu.Append(self.ID_DEBUG_CMD, 'CMD', 'Python command line')
@@ -888,15 +1016,18 @@ class Frame(wxFrame):
         tb.AddSimpleTool(wxID_NEW, images.getNewBitmap(), 'New', 'New file')
         tb.AddSimpleTool(wxID_OPEN, images.getOpenBitmap(), 'Open', 'Open file')
         tb.AddSimpleTool(wxID_SAVE, images.getSaveBitmap(), 'Save', 'Save file')
-        tb.AddSeparator()
+        tb.AddControl(wxStaticLine(tb, -1, size=(-1,23), style=wxLI_VERTICAL))
         tb.AddSimpleTool(wxID_CUT, images.getCutBitmap(), 'Cut', 'Cut')
         tb.AddSimpleTool(wxID_COPY, images.getCopyBitmap(), 'Copy', 'Copy')
         tb.AddSimpleTool(wxID_PASTE, images.getPasteBitmap(), 'Paste', 'Paste')
-        tb.AddSeparator()
+        tb.AddControl(wxStaticLine(tb, -1, size=(-1,23), style=wxLI_VERTICAL))
+        tb.AddSimpleTool(self.ID_TEST, images.getTestBitmap(), 'Test', 'Test window')
         tb.AddSimpleTool(self.ID_REFRESH, images.getRefreshBitmap(),
                          'Refresh', 'Refresh view')
         tb.AddSimpleTool(self.ID_AUTO_REFRESH, images.getAutoRefreshBitmap(),
                          'Auto-refresh', 'Toggle auto-refresh mode', true)
+        if wxGetOsVersion()[1] == 1:
+            tb.AddSeparator()   # otherwise auto-refresh sticks in status line
         tb.ToggleTool(self.ID_AUTO_REFRESH, conf.autoRefresh)
         tb.Realize()
         self.tb = tb
@@ -915,16 +1046,21 @@ class Frame(wxFrame):
         EVT_MENU(self, wxID_PASTE, self.OnPaste)
         EVT_MENU(self, self.ID_DELETE, self.OnDelete)
         # View
+        EVT_MENU(self, self.ID_EMBED_PANEL, self.OnEmbedPanel)
+        EVT_MENU(self, self.ID_TEST, self.OnTest)
         EVT_MENU(self, self.ID_REFRESH, self.OnRefresh)
         EVT_MENU(self, self.ID_AUTO_REFRESH, self.OnAutoRefresh)
         # Help
         EVT_MENU(self, wxID_ABOUT, self.OnAbout)
+        EVT_MENU(self, self.ID_README, self.OnReadme)
 
         # Update events
         EVT_UPDATE_UI(self, wxID_CUT, self.OnUpdateUI)
         EVT_UPDATE_UI(self, wxID_COPY, self.OnUpdateUI)
         EVT_UPDATE_UI(self, wxID_PASTE, self.OnUpdateUI)
         EVT_UPDATE_UI(self, self.ID_DELETE, self.OnUpdateUI)
+        EVT_UPDATE_UI(self, self.ID_TEST, self.OnUpdateUI)
+        EVT_UPDATE_UI(self, self.ID_REFRESH, self.OnUpdateUI)
 
         # Build interface
         sizer = wxBoxSizer(wxVERTICAL)
@@ -936,11 +1072,27 @@ class Frame(wxFrame):
         global tree
         tree = XML_Tree(splitter, -1)
         sys.modules['xxx'].tree = tree
+        # !!! frame styles are broken
+        # Miniframe for not embedded mode
+        miniFrame = wxFrame(self, -1, 'Properties Panel',
+                            (conf.panelX, conf.panelY),
+                            (conf.panelWidth, conf.panelHeight))
+        self.miniFrame = miniFrame
+        sizer2 = wxBoxSizer()
+        miniFrame.SetAutoLayout(true)
+        miniFrame.SetSizer(sizer2)
+        EVT_CLOSE(self.miniFrame, self.OnCloseMiniFrame)
         # Create panel for parameters
         global panel
-        panel = Panel(splitter)
-        # Set plitter windows
-        splitter.SplitVertically(tree, panel, conf.sashPos)
+        if conf.embedPanel:
+            panel = Panel(splitter)
+            # Set plitter windows
+            splitter.SplitVertically(tree, panel, conf.sashPos)
+        else:
+            panel = Panel(miniFrame)
+            sizer2.Add(panel, 1, wxEXPAND)
+            miniFrame.Show(true)
+            splitter.Initialize(tree)
         sizer.Add(splitter, 1, wxEXPAND)
         self.SetAutoLayout(true)
         self.SetSizer(sizer)
@@ -1004,7 +1156,6 @@ class Frame(wxFrame):
              (pullDownMenu.ID_NEW_SCROLL_BAR, 'ScrollBar', 'Create scroll bar'),
              (pullDownMenu.ID_NEW_TREE_CTRL, 'TreeCtrl', 'Create tree control'),
              (pullDownMenu.ID_NEW_LIST_CTRL, 'ListCtrl', 'Create list control'),
-             (pullDownMenu.ID_NEW_CHECK_LIST, 'CheckList', 'Create check list control'),
              (pullDownMenu.ID_NEW_HTML_WINDOW, 'HtmlWindow', 'Create HTML window'),
              (pullDownMenu.ID_NEW_CALENDAR, 'Calendar', 'Create calendar control'),
              (pullDownMenu.ID_NEW_PANEL, 'Panel', 'Create panel'),
@@ -1022,6 +1173,8 @@ class Frame(wxFrame):
              (pullDownMenu.ID_NEW_RADIO_BOX, 'RadioBox', 'Create radio box'),
              (pullDownMenu.ID_NEW_COMBO_BOX, 'ComboBox', 'Create combo box'),
              (pullDownMenu.ID_NEW_LIST_BOX, 'ListBox', 'Create list box'),
+             (pullDownMenu.ID_NEW_CHECK_LIST, 'CheckListBox',
+              'Create check list control'),
              ],
             ['sizer', 'Sizers',
              (pullDownMenu.ID_NEW_BOX_SIZER, 'BoxSizer', 'Create box sizer'),
@@ -1041,6 +1194,31 @@ class Frame(wxFrame):
         pullDownMenu.toolBarControls = [
             (pullDownMenu.ID_NEW_TOOL, 'Tool', 'Create tool'),
             (pullDownMenu.ID_NEW_SEPARATOR, 'Separator', 'Create separator'),
+            ['control', 'Various controls',
+             (pullDownMenu.ID_NEW_STATIC_TEXT, 'Label', 'Create static label'),
+             (pullDownMenu.ID_NEW_STATIC_LINE, 'Line', 'Create static line'),
+             (pullDownMenu.ID_NEW_TEXT_CTRL, 'TextBox', 'Create text box control'),
+             (pullDownMenu.ID_NEW_CHOICE, 'Choice', 'Create choice control'),
+             (pullDownMenu.ID_NEW_SLIDER, 'Slider', 'Create slider control'),
+             (pullDownMenu.ID_NEW_GAUGE, 'Gauge', 'Create gauge control'),
+             (pullDownMenu.ID_NEW_SCROLL_BAR, 'ScrollBar', 'Create scroll bar'),
+             (pullDownMenu.ID_NEW_LIST_CTRL, 'ListCtrl', 'Create list control'),
+             ],
+            ['button', 'Buttons',
+             (pullDownMenu.ID_NEW_BUTTON, 'Button', 'Create button'),
+             (pullDownMenu.ID_NEW_BITMAP_BUTTON, 'BitmapButton', 'Create bitmap button'),
+             (pullDownMenu.ID_NEW_RADIO_BUTTON, 'RadioButton', 'Create radio button'),
+             (pullDownMenu.ID_NEW_SPIN_BUTTON, 'SpinButton', 'Create spin button'),
+             ],
+            ['box', 'Boxes',
+             (pullDownMenu.ID_NEW_STATIC_BOX, 'StaticBox', 'Create static box'),
+             (pullDownMenu.ID_NEW_CHECK_BOX, 'CheckBox', 'Create check box'),
+             (pullDownMenu.ID_NEW_RADIO_BOX, 'RadioBox', 'Create radio box'),
+             (pullDownMenu.ID_NEW_COMBO_BOX, 'ComboBox', 'Create combo box'),
+             (pullDownMenu.ID_NEW_LIST_BOX, 'ListBox', 'Create list box'),
+             (pullDownMenu.ID_NEW_CHECK_LIST, 'CheckListBox',
+              'Create check list control'),
+             ],
             ]
 
         # Initialize
@@ -1062,9 +1240,13 @@ class Frame(wxFrame):
             self.SetStatusText('Loading...')
             wxYield()
             wxBeginBusyCursor()
-            self.Open(path)
+            try:
+                self.Open(path)
+                self.SetStatusText('Data loaded')
+            except:
+                self.SetStatusText('Failed')
+                raise
             wxEndBusyCursor()
-            self.SetStatusText('Ready')
         dlg.Destroy()
 
     def OnSaveOrSaveAs(self, evt):
@@ -1085,16 +1267,20 @@ class Frame(wxFrame):
         self.SetStatusText('Saving...')
         wxYield()
         wxBeginBusyCursor()
-        self.Save(path)
-        self.dataFile = path
+        try:
+            self.Save(path)
+            self.dataFile = path
+            self.SetStatusText('Data saved')
+        except IOError:
+            self.SetStatusText('Failed')
         wxEndBusyCursor()
-        self.SetStatusText('Ready')
 
     def OnExit(self, evt):
         self.Close()
 
     def OnUndo(self, evt):
         print '*** being implemented'
+        return
         print self.lastOp, self.undo
         if self.lastOp == 'DELETE':
             parent, prev, elem = self.undo
@@ -1107,7 +1293,7 @@ class Frame(wxFrame):
         print '*** being implemented'
 
     def OnCut(self, evt):
-        selected = tree.GetSelection()
+        selected = tree.selection
         # Undo info
         self.lastOp = 'CUT'
         self.undo = [tree.GetItemParent(selected), tree.GetPrevSibling(selected)]
@@ -1128,14 +1314,16 @@ class Frame(wxFrame):
         tree.Unselect()
         panel.Clear()
         self.modified = true
+        self.SetStatusText('Removed to clipboard')
 
     def OnCopy(self, evt):
-        selected = tree.GetSelection()
+        selected = tree.selection
         xxx = tree.GetPyData(selected)
         self.clipboard = xxx.element.cloneNode(true)
+        self.SetStatusText('Copied')
 
     def OnPaste(self, evt):
-        selected = tree.GetSelection()
+        selected = tree.selection
         appendChild = not tree.NeedInsert(selected)
         xxx = tree.GetPyData(selected)
         if not appendChild:
@@ -1148,7 +1336,7 @@ class Frame(wxFrame):
                 appendChild = true
                 selected = tree.GetItemParent(selected)
         # Expanded container (must have children)
-        elif tree.IsExpanded(selected) and tree.ItemHasChildren(selected):
+        elif tree.IsExpanded(selected) and tree.GetChildrenCount(selected, false):
             appendChild = false
             nextItem = tree.GetFirstChild(selected, 0)[0]
             parentLeaf = selected
@@ -1157,56 +1345,71 @@ class Frame(wxFrame):
             parent = tree.GetPyData(selected)
         else:
             parent = tree.GetPyData(parentLeaf)
-        if parent and parent.hasChild: parent = parent.child
+        if parent.hasChild: parent = parent.child
 
         # Create a copy of clipboard element
         elem = self.clipboard.cloneNode(true)
         # Tempopary xxx object to test things
         xxx = MakeXXXFromDOM(parent, elem)
-        className = xxx.treeObject().className
-        # Check parent and child relationships
-        # Parent is sizer or notebook, child is of wrong class or
-        # parent is normal window, child is child container: detach child
+
+        # Check compatibility
+        error = false
+        # Top-level
+        x = xxx.treeObject()
+        if x.__class__ in [xxxDialog, xxxFrame, xxxMenuBar, xxxToolBar]:
+            if parent.__class__ != xxxMainNode: error = true
+        elif x.__class__ == xxxSpacer:
+            if not parent.isSizer: error = true
+        elif x.__class__ == xxxSeparator:
+            if not parent.__class__ in [xxxMenu, xxxToolBar]: error = true
+        elif x.__class__ == xxxTool:
+            if parent.__class__ != xxxToolBar: error = true
+        elif x.__class__ == xxxMenuItem:
+            if not parent.__class__ in [xxxMenuBar, xxxMenu]: error = true
+        elif x.isSizer and parent.__class__ == xxxNotebook: error = true
+        else:                           # normal controls can be almost anywhere
+            if parent.__class__ == xxxMainNode or \
+               parent.__class__ in [xxxMenuBar, xxxMenu]: error = true
+        if error:
+            if parent.__class__ == xxxMainNode: parentClass = 'root'
+            else: parentClass = parent.className
+            wxLogError('Incompatible parent/child: parent is %s, child is %s!' %
+                       (parentClass, x.className))
+            return
+
+        # Check parent and child relationships.
+        # If parent is sizer or notebook, child is of wrong class or
+        # parent is normal window, child is child container then detach child.
         isChildContainer = isinstance(xxx, xxxChildContainer)
-        if not parent and isChildContainer or \
-           (parent.isSizer and not isinstance(xxx, xxxSizerItem)) or \
+        if isChildContainer and \
+           ((parent.isSizer and not isinstance(xxx, xxxSizerItem)) or \
            (isinstance(parent, xxxNotebook) and not isinstance(xxx, xxxNotebookPage)) or \
-           (not parent.isSizer and not isinstance(parent, xxxNotebook) and \
-            isChildContainer):
-            if isChildContainer:
-                elem.removeChild(xxx.child.element) # detach child
-                elem.unlink()           # delete child container
-                elem = xxx.child.element # replace
-                # This should help garbage collection (!!! maybe not needed?)
-                xxx.child.parent = None
-                xxx.child = None
-        if parent:
-            # Parent is sizer or notebook, child is not child container
-            if parent.isSizer and not isChildContainer and \
-               not isinstance(xxx, xxxSpacer):
-                # Create sizer item element
-                sizerItemElem = MakeEmptyDOM('sizeritem')
-                sizerItemElem.appendChild(elem)
-                elem = sizerItemElem
-            elif isinstance(parent, xxxNotebook) and not isChildContainer:
-                pageElem = MakeEmptyDOM('notebookpage')
-                pageElem.appendChild(elem)
-                elem = pageElem
+           not (parent.isSizer or isinstance(parent, xxxNotebook))):
+            elem.removeChild(xxx.child.element) # detach child
+            elem.unlink()           # delete child container
+            elem = xxx.child.element # replace
+            # This may help garbage collection
+            xxx.child.parent = None
+            isChildContainer = false
+        # Parent is sizer or notebook, child is not child container
+        if parent.isSizer and not isChildContainer and not isinstance(xxx, xxxSpacer):
+            # Create sizer item element
+            sizerItemElem = MakeEmptyDOM('sizeritem')
+            sizerItemElem.appendChild(elem)
+            elem = sizerItemElem
+        elif isinstance(parent, xxxNotebook) and not isChildContainer:
+            pageElem = MakeEmptyDOM('notebookpage')
+            pageElem.appendChild(elem)
+            elem = pageElem
         xxx = MakeXXXFromDOM(parent, elem)
         # Figure out if we must append a new child or sibling
         if appendChild:
-            if parent: node = parent.element
-            else: node = tree.mainNode
-            node.appendChild(elem)
+            parent.element.appendChild(elem)
             newItem = tree.AppendItem(selected, xxx.treeName(), image=xxx.treeImage(),
                                       data=wxTreeItemData(xxx))
         else:
             node = tree.GetPyData(nextItem).element
-            if parent:
-                elemParent = parent.element
-            else:
-                elemParent = tree.mainNode
-            elemParent.insertBefore(elem, node)
+            parent.element.insertBefore(elem, node)
             # Inserting before is difficult, se we insert after or first child
             newItem = tree.InsertItem(parentLeaf, selected, xxx.treeName(),
                                       image=xxx.treeImage(), data=wxTreeItemData(xxx))
@@ -1230,9 +1433,10 @@ class Frame(wxFrame):
             else:
                 tree.pendingHighLight = None
         self.modified = true
+        self.SetStatusText('Pasted')
 
     def OnDelete(self, evt):
-        selected = tree.GetSelection()
+        selected = tree.selection
         # Undo info
         self.lastOp = 'DELETE'
         self.undo = [tree.GetItemParent(selected), tree.GetPrevSibling(selected)]
@@ -1249,17 +1453,41 @@ class Frame(wxFrame):
                     if testWin.highLight: testWin.highLight.Remove()
                     tree.needUpdate = true
         xnode = tree.RemoveLeaf(selected)
-        self.undo.append(xnode.cloneNode(true))
+        # !!! cloneNode is broken, or something is wrong
+#        self.undo.append(xnode.cloneNode(true))
         xnode.unlink()
         tree.pendingHighLight = None
         tree.Unselect()
         panel.Clear()
         self.modified = true
+        self.SetStatusText('Deleted')
+
+    def OnEmbedPanel(self, evt):
+        conf.embedPanel = evt.IsChecked()
+        if conf.embedPanel:
+            # Remember last dimentions
+            self.panelWidth, self.panelHeight = panel.GetSize()
+            panel.Reparent(self.splitter)
+            self.miniFrame.GetSizer().RemoveWindow(panel)
+            self.splitter.SplitVertically(tree, panel, self.sashPos)
+            self.miniFrame.Show(false)
+        else:
+            self.sashPos = self.splitter.GetSashPosition()
+            self.splitter.Unsplit(panel)
+            sizer = self.miniFrame.GetSizer()
+            panel.Reparent(self.miniFrame)
+            panel.Show(true)
+            sizer.Add(panel, 1, wxEXPAND)
+            self.miniFrame.Show(true)
+            self.miniFrame.SetSize((self.panelWidth, self.panelHeight))
+
+    def OnTest(self, evt):
+        tree.ShowTestWindow(tree.selection)
 
     def OnRefresh(self, evt):
         # If modified, apply first
-        selection = tree.GetSelection()
-        if selection.IsOk():
+        selection = tree.selection
+        if selection:
             xxx = tree.GetPyData(selection)
             if xxx and panel.IsModified():
                 tree.Apply(xxx, selection)
@@ -1280,8 +1508,17 @@ class Frame(wxFrame):
         dlg.ShowModal()
         dlg.Destroy()
 
+    def OnReadme(self, evt):
+        from wxPython.lib.dialogs import wxScrolledMessageDialog
+        text = open(os.path.join(sys.path[0], 'README'), 'r').read()
+        dlg = wxScrolledMessageDialog(self, text, "XRCed README")
+        dlg.ShowModal()
+        dlg.Destroy()
+
+
     # Simple emulation of python command line
     def OnDebugCMD(self, evt):
+        import traceback
         while 1:
             try:
                 exec raw_input('C:\> ')
@@ -1296,52 +1533,65 @@ class Frame(wxFrame):
                 print msg
 
     def OnCreate(self, evt):
-        selected = tree.GetSelection()
+        selected = tree.selection
         appendChild = not tree.NeedInsert(selected)
         xxx = tree.GetPyData(selected)
         if not appendChild:
-            # If has next item, insert, else append to parent
-            nextItem = tree.GetNextSibling(selected)
-            if nextItem.IsOk():
-                # Insert before nextItem
-                parentLeaf = tree.GetItemParent(selected)
-            else:                   # last child: change selected to parent
-                appendChild = true
-                selected = tree.GetItemParent(selected)
+            # If insert before
+            if tree.shift:
+                # If has previous item, insert after it, else append to parent
+                nextItem = selected
+                selected = tree.GetPrevSibling(selected)
+                if selected:
+                    # Insert before nextItem
+                    parentLeaf = tree.GetItemParent(selected)
+                else:                   # last child: change selected to parent
+                    parentLeaf = selected = tree.GetItemParent(nextItem)
+            else:
+                # If has next item, insert, else append to parent
+                nextItem = tree.GetNextSibling(selected)
+                if nextItem.IsOk():
+                    # Insert before nextItem
+                    parentLeaf = tree.GetItemParent(selected)
+                else:                   # last child: change selected to parent
+                    appendChild = true
+                    selected = tree.GetItemParent(selected)
         # Expanded container (must have children)
-        elif tree.IsExpanded(selected) and tree.ItemHasChildren(selected):
-            appendChild = false
-            nextItem = tree.GetFirstChild(selected, 0)[0]
-            parentLeaf = selected
+        else:
+            # Can't use HasChildren because root always has
+            if tree.shift and tree.IsExpanded(selected) \
+               and tree.GetChildrenCount(selected, false):
+                appendChild = false
+                nextItem = tree.GetFirstChild(selected, 0)[0]
+                parentLeaf = selected
         # Parent should be tree element or None
         if appendChild:
             parent = tree.GetPyData(selected)
         else:
             parent = tree.GetPyData(parentLeaf)
-        if parent and parent.hasChild: parent = parent.child
+        if parent.hasChild: parent = parent.child
 
         # Create element
         className = self.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.treeObject().name = '%s%d' % (defaultIDs[cl], frame.maxIDs[cl])
+            xxx.treeObject().element.setAttribute('name', xxx.treeObject().name)
+
         # Figure out if we must append a new child or sibling
         elem = xxx.element
         if appendChild:
-            if parent: node = parent.element
-            else: node = tree.mainNode
             # Insert newline for debug purposes
-            node.appendChild(tree.dom.createTextNode('\n'))
-            node.appendChild(elem)
+            parent.element.appendChild(elem)
             newItem = tree.AppendItem(selected, xxx.treeName(), image=xxx.treeImage(),
                                       data=wxTreeItemData(xxx))
         else:
             node = tree.GetPyData(nextItem).element
-            if parent:
-                elemParent = parent.element
-            else:
-                elemParent = tree.mainNode
-            elemParent.insertBefore(tree.dom.createTextNode('\n'), node)
-            elemParent.insertBefore(elem, node)
-            # Inserting before is difficult, se we insert after or first child
+            parent.element.insertBefore(elem, node)
             newItem = tree.InsertItem(parentLeaf, selected,
                                       xxx.treeName(), image=xxx.treeImage(),
                                       data=wxTreeItemData(xxx))
@@ -1358,11 +1608,13 @@ class Frame(wxFrame):
             else:
                 tree.pendingHighLight = None
 
+    # Expand/collapse subtree
     def OnExpand(self, evt):
-        if tree.GetSelection().IsOk():
-            tree.ExpandAll(tree.GetSelection())
-        else:
-            tree.ExpandAll(tree.GetRootItem())
+        if tree.selection: tree.ExpandAll(tree.selection)
+        else: tree.ExpandAll(tree.root)
+    def OnCollapse(self, evt):
+        if tree.selection: tree.CollapseAll(tree.selection)
+        else: tree.CollapseAll(tree.root)
 
     def OnPullDownHighlight(self, evt):
         menuId = evt.GetMenuId()
@@ -1375,14 +1627,13 @@ class Frame(wxFrame):
 
     def OnUpdateUI(self, evt):
         if evt.GetId() in [wxID_CUT, wxID_COPY, self.ID_DELETE]:
-            enable = tree.GetSelection().IsOk() and \
-                        tree.GetSelection() != tree.GetRootItem()
-            evt.Enable(enable)
+            evt.Enable(tree.selection != tree.root)
         elif evt.GetId() == wxID_PASTE:
-            enable = tree.GetSelection().IsOk() and \
-                     tree.GetSelection() != tree.GetRootItem() and \
-                     self.clipboard != None
-            evt.Enable(enable)
+            evt.Enable((self.clipboard and tree.selection) != None)
+        elif evt.GetId() == self.ID_TEST:
+            evt.Enable(tree.selection != tree.root)
+        elif evt.GetId() == self.ID_REFRESH:
+            evt.Enable(testWin != None)
 
     def OnIdle(self, evt):
         if tree.needUpdate:
@@ -1396,13 +1647,27 @@ class Frame(wxFrame):
         else:
             evt.Skip()
 
+    # We don't let close panel window
+    def OnCloseMiniFrame(self, evt):
+        return
+
     def OnCloseWindow(self, evt):
         if not self.AskSave(): return
         if testWin: testWin.Destroy()
         # Destroy cached windows
-        for w in panel.styleCache.values(): w.Destroy()
+        panel.cacheParent.Destroy()
+#        for w in panel.styleCache.values(): w.Destroy()
+        if not panel.GetPageCount() == 2:
+            panel.page2.Destroy()
+        conf.x, conf.y = self.GetPosition()
         conf.width, conf.height = self.GetSize()
-        conf.sashPos = self.splitter.GetSashPosition()
+        if conf.embedPanel:
+            conf.sashPos = self.splitter.GetSashPosition()
+            conf.panelWidth, conf.panelHeight = self.panelWidth, self.panelHeight
+        else:
+            conf.sashPos = self.sashPos
+            conf.panelX, conf.panelY = self.miniFrame.GetPosition()
+            conf.panelWidth, conf.panelHeight = self.miniFrame.GetSize()
         evt.Skip()
 
     def Clear(self):
@@ -1410,13 +1675,17 @@ class Frame(wxFrame):
         self.clipboard = None
         self.modified = false
         panel.SetModified(false)
-        panel.Clear()
         tree.Clear()
+        panel.Clear()
         global testWin
         if testWin:
             testWin.Destroy()
             testWin = None
         self.SetTitle(progname)
+        # Numbers for new controls
+        self.maxIDs = {}
+        self.maxIDs[xxxPanel] = self.maxIDs[xxxDialog] = self.maxIDs[xxxFrame] = \
+        self.maxIDs[xxxMenuBar] = self.maxIDs[xxxMenu] = self.maxIDs[xxxToolBar] = 0
 
     def Open(self, path):
         # Try to read the file
@@ -1429,19 +1698,42 @@ class Frame(wxFrame):
             self.dataFile = path
             self.SetTitle(progname + ': ' + os.path.basename(path))
         except:
-            wxLogError('Error reading file: ' + path)
+            wxLogError('Error reading file: %s' % path)
             raise
 
+    def Indent(self, node, indent = 0):
+        # Copy child list because it will change soon
+        children = node.childNodes[:]
+        # Main node doesn't need to be indented
+        if indent:
+            text = self.domCopy.createTextNode('\n' + ' ' * indent)
+            node.parentNode.insertBefore(text, node)
+        if children:
+            # Append newline after last child, except for text nodes
+            if children[-1].nodeType == minidom.Node.ELEMENT_NODE:
+                text = self.domCopy.createTextNode('\n' + ' ' * indent)
+                node.appendChild(text)
+            # Indent children which are elements
+            for n in children:
+                if n.nodeType == minidom.Node.ELEMENT_NODE:
+                    self.Indent(n, indent + 2)
+
     def Save(self, path):
         try:
+            # Apply changes
             self.OnRefresh(wxCommandEvent())
-            memFile = MemoryFile(path)
-            tree.dom.writexml(memFile)
-            memFile.close()
+            f = open(path, 'w')
+            # Make temporary copy
+            self.domCopy = domCopy = tree.dom.cloneNode(true)
+            self.Indent(domCopy.getElementsByTagName('resource')[0])
+            domCopy.writexml(f)
+#            domCopy.unlink()
+            self.domCopy = None
+            f.close()
             self.modified = false
             panel.SetModified(false)
         except:
-            wxLogError('Error writing file: ' + path)
+            wxLogError('Error writing file: %s' % path)
             raise
 
     def AskSave(self):
@@ -1463,36 +1755,80 @@ class Frame(wxFrame):
 
 ################################################################################
 
+def usage():
+    print >> sys.stderr, 'usage: xrced [-dvh] [file]'
+
 class App(wxApp):
     def OnInit(self):
-        self.SetAppName("xrced")
+        global debug, verbose
+        # Process comand-line
+        try:
+            opts, args = getopt.getopt(sys.argv[1:], 'dvh')
+        except getopt.GetoptError:
+            print >> sys.stderr, 'Unknown option'
+            usage()
+            sys.exit(1)
+        for o,a in opts:
+            if o == '-h':
+                usage()
+                sys.exit(0)
+            elif o == '-d':
+                debug = true
+            elif o == '-v':
+                print 'XRCed version', version
+                sys.exit(0)
+
+        self.SetAppName('xrced')
         # Settings
         global conf
-        # !!! wxConfigBase_Get doesn't seem to work
-        conf = wxConfig(style=wxCONFIG_USE_LOCAL_FILE)
+        conf = wxConfig(style = wxCONFIG_USE_LOCAL_FILE)
         conf.autoRefresh = conf.ReadInt('autorefresh', true)
+        pos = conf.ReadInt('x', -1), conf.ReadInt('y', -1)
         size = conf.ReadInt('width', 800), conf.ReadInt('height', 600)
+        conf.embedPanel = conf.ReadInt('embedPanel', true)
         conf.sashPos = conf.ReadInt('sashPos', 200)
+        if not conf.embedPanel:
+            conf.panelX = conf.ReadInt('panelX', -1)
+            conf.panelY = conf.ReadInt('panelY', -1)
+        else:
+            conf.panelX = conf.panelY = -1
+        conf.panelWidth = conf.ReadInt('panelWidth', 200)
+        conf.panelHeight = conf.ReadInt('panelHeight', 200)
+        conf.panic = not conf.HasEntry('nopanic')
         # Add handlers
         wxFileSystem_AddHandler(wxMemoryFSHandler())
         wxInitAllImageHandlers()
         # Create main frame
-        global frame
-        frame = self.frame = Frame(size)
-        self.frame.Show(true)
+        frame = Frame(pos, size)
+        frame.Show(true)
         # Load resources from XRC file (!!! should be transformed to .py later?)
         sys.modules['params'].frame = frame
         frame.res = wxXmlResource('')
         frame.res.Load(os.path.join(sys.path[0], 'xrced.xrc'))
+
+        # Load file after showing
+        if args:
+            conf.panic = false
+            frame.open = frame.Open(args[0])
+
         return true
 
     def OnExit(self):
         # Write config
         wc = wxConfigBase_Get()
         wc.WriteInt('autorefresh', conf.autoRefresh)
+        wc.WriteInt('x', conf.x)
+        wc.WriteInt('y', conf.y)
         wc.WriteInt('width', conf.width)
         wc.WriteInt('height', conf.height)
+        wc.WriteInt('embedPanel', conf.embedPanel)
+        if not conf.embedPanel:
+            wc.WriteInt('panelX', conf.panelX)
+            wc.WriteInt('panelY', conf.panelY)
         wc.WriteInt('sashPos', conf.sashPos)
+        wc.WriteInt('panelWidth', conf.panelWidth)
+        wc.WriteInt('panelHeight', conf.panelHeight)
+        wc.WriteInt('nopanic', 1)
         wc.Flush()
 
 def main():
diff --git a/wxPython/tools/XRCed/xrced.sh b/wxPython/tools/XRCed/xrced.sh
new file mode 100644 (file)
index 0000000..70f983b
--- /dev/null
@@ -0,0 +1 @@
+python2.2 YOUR_PATH_TO_XRCED/xrced.py $*
index ee21945bfb6e4e0c1289326d5da69717976f4b9c..1a9be61a7d3a6ab89532911cf1408d4e0c1cc81a 100644 (file)
@@ -1,2 +1,167 @@
 <?xml version="1.0" ?>
-<resource><object class="wxDialog" name="ID_DIALOG_CONTENT"><title>Content</title><size>250,300</size><object class="wxBoxSizer"><orient>wxVERTICAL</orient><object class="sizeritem"><object class="wxBoxSizer"><orient>wxHORIZONTAL</orient><object class="sizeritem"><object class="wxListBox" name="ID_LIST"><content/></object><option>1</option><flag>wxTOP|wxBOTTOM|wxLEFT|wxEXPAND</flag><border>5</border></object><object class="sizeritem"><object class="wxBoxSizer"><orient>wxVERTICAL</orient><object class="sizeritem"><object class="wxButton" name="ID_BUTTON_UP"><label>Move Up</label></object><flag>wxBOTTOM</flag><border>5</border></object><object class="sizeritem"><object class="wxButton" name="ID_BUTTON_DOWN"><label>Move Down</label></object></object><object class="spacer"><size>10,20</size><option>1</option></object><object class="sizeritem"><object class="wxButton" name="ID_BUTTON_APPEND"><label>Append...</label></object><flag>wxBOTTOM</flag><border>5</border></object><object class="sizeritem"><object class="wxButton" name="ID_BUTTON_REMOVE"><label>Remove</label></object></object></object><flag>wxALL|wxEXPAND</flag><border>5</border></object></object><option>1</option><flag>wxEXPAND</flag></object><object class="sizeritem"><object class="wxStaticLine"/><flag>wxEXPAND</flag></object><object class="sizeritem"><object class="wxBoxSizer"><orient>wxHORIZONTAL</orient><object class="sizeritem"><object class="wxButton" name="wxID_OK"><label>OK</label><default>1</default></object><flag>wxRIGHT</flag><border>10</border></object><object class="sizeritem"><object class="wxButton" name="wxID_CANCEL"><label>Cancel</label></object></object></object><flag>wxALL|wxALIGN_CENTRE_HORIZONTAL</flag><border>10</border></object></object><style>wxRESIZE_BORDER</style></object></resource>
\ No newline at end of file
+<resource>
+  <object class="wxDialog" name="ID_DIALOG_CONTENT">
+    <title>Content</title>
+    <size>250,300</size>
+    <object class="wxBoxSizer">
+      <orient>wxVERTICAL</orient>
+      <object class="sizeritem">
+        <object class="wxBoxSizer">
+          <orient>wxHORIZONTAL</orient>
+          <object class="sizeritem">
+            <object class="wxListBox" name="ID_LIST">
+              <content/>
+            </object>
+            <option>1</option>
+            <flag>wxTOP|wxBOTTOM|wxLEFT|wxEXPAND</flag>
+            <border>5</border>
+          </object>
+          <object class="sizeritem">
+            <object class="wxBoxSizer">
+              <orient>wxVERTICAL</orient>
+              <object class="sizeritem">
+                <object class="wxButton" name="ID_BUTTON_UP">
+                  <label>Move Up</label>
+                </object>
+                <flag>wxBOTTOM</flag>
+                <border>5</border>
+              </object>
+              <object class="sizeritem">
+                <object class="wxButton" name="ID_BUTTON_DOWN">
+                  <label>Move Down</label>
+                </object>
+              </object>
+              <object class="spacer">
+                <size>10,20</size>
+                <option>1</option>
+              </object>
+              <object class="sizeritem">
+                <object class="wxButton" name="ID_BUTTON_APPEND">
+                  <label>Append...</label>
+                </object>
+                <flag>wxBOTTOM</flag>
+                <border>5</border>
+              </object>
+              <object class="sizeritem">
+                <object class="wxButton" name="ID_BUTTON_REMOVE">
+                  <label>Remove</label>
+                </object>
+              </object>
+            </object>
+            <flag>wxALL|wxEXPAND</flag>
+            <border>5</border>
+          </object>
+        </object>
+        <option>1</option>
+        <flag>wxEXPAND</flag>
+      </object>
+      <object class="sizeritem">
+        <object class="wxStaticLine"/>
+        <flag>wxEXPAND</flag>
+      </object>
+      <object class="sizeritem">
+        <object class="wxBoxSizer">
+          <orient>wxHORIZONTAL</orient>
+          <object class="sizeritem">
+            <object class="wxButton" name="wxID_OK">
+              <label>OK</label>
+              <default>1</default>
+            </object>
+            <flag>wxRIGHT</flag>
+            <border>10</border>
+          </object>
+          <object class="sizeritem">
+            <object class="wxButton" name="wxID_CANCEL">
+              <label>Cancel</label>
+            </object>
+          </object>
+        </object>
+        <flag>wxALL|wxALIGN_CENTRE_HORIZONTAL</flag>
+        <border>10</border>
+      </object>
+    </object>
+    <style>wxRESIZE_BORDER</style>
+  </object>
+  <object class="wxDialog" name="ID_DIALOG_CONTENT_CHECK_LIST">
+    <title>Content</title>
+    <size>250,300</size>
+    <object class="wxBoxSizer">
+      <orient>wxVERTICAL</orient>
+      <object class="sizeritem">
+        <object class="wxBoxSizer">
+          <orient>wxHORIZONTAL</orient>
+          <object class="sizeritem">
+            <object class="wxCheckList" name="ID_CHECK_LIST">
+              <content/>
+            </object>
+            <option>1</option>
+            <flag>wxTOP|wxBOTTOM|wxLEFT|wxEXPAND</flag>
+            <border>5</border>
+          </object>
+          <object class="sizeritem">
+            <object class="wxBoxSizer">
+              <orient>wxVERTICAL</orient>
+              <object class="sizeritem">
+                <object class="wxButton" name="ID_BUTTON_UP">
+                  <label>Move Up</label>
+                </object>
+                <flag>wxBOTTOM</flag>
+                <border>5</border>
+              </object>
+              <object class="sizeritem">
+                <object class="wxButton" name="ID_BUTTON_DOWN">
+                  <label>Move Down</label>
+                </object>
+              </object>
+              <object class="spacer">
+                <size>10,20</size>
+                <option>1</option>
+              </object>
+              <object class="sizeritem">
+                <object class="wxButton" name="ID_BUTTON_APPEND">
+                  <label>Append...</label>
+                </object>
+                <flag>wxBOTTOM</flag>
+                <border>5</border>
+              </object>
+              <object class="sizeritem">
+                <object class="wxButton" name="ID_BUTTON_REMOVE">
+                  <label>Remove</label>
+                </object>
+              </object>
+            </object>
+            <flag>wxALL|wxEXPAND</flag>
+            <border>5</border>
+          </object>
+        </object>
+        <option>1</option>
+        <flag>wxEXPAND</flag>
+      </object>
+      <object class="sizeritem">
+        <object class="wxStaticLine"/>
+        <flag>wxEXPAND</flag>
+      </object>
+      <object class="sizeritem">
+        <object class="wxBoxSizer">
+          <orient>wxHORIZONTAL</orient>
+          <object class="sizeritem">
+            <object class="wxButton" name="wxID_OK">
+              <label>OK</label>
+              <default>1</default>
+            </object>
+            <flag>wxRIGHT</flag>
+            <border>10</border>
+          </object>
+          <object class="sizeritem">
+            <object class="wxButton" name="wxID_CANCEL">
+              <label>Cancel</label>
+            </object>
+          </object>
+        </object>
+        <flag>wxALL|wxALIGN_CENTRE_HORIZONTAL</flag>
+        <border>10</border>
+      </object>
+    </object>
+    <style>wxRESIZE_BORDER</style>
+  </object>
+</resource>
\ No newline at end of file
index 47d8b0a03f66c766b693209711a25446fb731a2b..0435ea573766033c28df2965ce2bad5bedf5f49d 100644 (file)
@@ -51,7 +51,7 @@ class xxxParamContent:
                     text = n.childNodes[0] # first child must be text node
                     assert text.nodeType == minidom.Node.TEXT_NODE
                 l.append(text)
-                data.append(text.data)
+                data.append(str(text.data))
             else:                       # remove other
                 node.removeChild(n)
                 n.unlink()
@@ -61,7 +61,8 @@ class xxxParamContent:
     def update(self, value):
         # If number if items is not the same, recreate children
         if len(value) != len(self.l):   # remove first if number of items has changed
-            for n in self.node.childNodes:
+            childNodes = self.node.childNodes[:]
+            for n in childNodes:
                 self.node.removeChild(n)
             l = []
             for str in value:
@@ -70,11 +71,59 @@ class xxxParamContent:
                 itemElem.appendChild(itemText)
                 self.node.appendChild(itemElem)
                 l.append(itemText)
+            self.l = l
         else:
             for i in range(len(value)):
                 self.l[i].data = value[i]
         self.data = value
 
+# Content parameter for checklist
+class xxxParamContentCheckList:
+    def __init__(self, node):
+        self.node = node
+        data, l = [], []                # data is needed to quicker value retrieval
+        nodes = node.childNodes[:]      # make a copy of the child list
+        for n in nodes:
+            if n.nodeType == minidom.Node.ELEMENT_NODE:
+                assert n.tagName == 'item', 'bad content content'
+                checked = n.getAttribute('checked')
+                if not n.hasChildNodes():
+                    # If does not have child nodes, create empty text node
+                    text = tree.dom.createTextNode('')
+                    node.appendChild(text)
+                else:
+                    # !!! normalize?
+                    text = n.childNodes[0] # first child must be text node
+                    assert text.nodeType == minidom.Node.TEXT_NODE
+                l.append((text, n))
+                data.append((str(text.data), int(checked)))
+            else:                       # remove other
+                node.removeChild(n)
+                n.unlink()
+        self.l, self.data = l, data
+    def value(self):
+        return self.data
+    def update(self, value):
+        # If number if items is not the same, recreate children
+        if len(value) != len(self.l):   # remove first if number of items has changed
+            childNodes = self.node.childNodes[:]
+            for n in childNodes:
+                self.node.removeChild(n)
+            l = []
+            for (s,ch) in value:
+                itemElem = tree.dom.createElement('item')
+                itemElem.setAttribute('checked', str(ch))
+                itemText = tree.dom.createTextNode(s)
+                itemElem.appendChild(itemText)
+                self.node.appendChild(itemElem)
+                l.append((itemText, itemElem))
+            self.l = l
+#        else:
+#            for i in range(len(value)):
+#                self.l[i][0].data = value[i]
+#                self.l[i][1].setAttributedata = value[i]
+        self.data = value
+
 ################################################################################
 
 # Classes to interface DOM objects
@@ -84,6 +133,7 @@ class xxxObject:
     hasStyle = true                     # almost everyone
     hasName = true                      # has name attribute?
     isSizer = hasChild = false
+    allParams = None                    # Some nodes have no parameters
     # Style parameters (all optional)
     styles = ['fg', 'bg', 'font', 'enabled', 'focused', 'hidden', 'tooltip']
     # Special parameters
@@ -121,7 +171,10 @@ class xxxObject:
                 elif tag in self.specials:
                     self.special(tag, node)
                 elif tag == 'content':
-                    self.params[tag] = xxxParamContent(node)
+                    if self.className == 'wxCheckList':
+                        self.params[tag] = xxxParamContentCheckList(node)
+                    else:
+                        self.params[tag] = xxxParamContent(node)
                 elif tag == 'font': # has children
                     self.params[tag] = xxxParamFont(self, node)
                 else:                   # simple parameter
@@ -130,52 +183,6 @@ class xxxObject:
                 # Remove all other nodes
                 element.removeChild(node)
                 node.unlink()
-    # Generate HTML
-    def generateHtml(self, prefix=''):
-        SetCurrentXXX(self)
-        html = '<table cellspacing=0 cellpadding=0><tr><td width=120>\
-<font size="+1"><b>%s</b></font></td>' % self.className
-        # Has id (name) attribute
-        if self.hasName:
-            html += """\
-<td><wxp module="xxx" class="ParamText" width=150>
-<param name="name" value="data_name">
-</wxp></td>"""
-        html += '</table><p>'
-        html += '<table cellspacing=0 cellpadding=0>\n'
-        # Add required parameters
-        for param in self.allParams:
-            # Add checkbox or just text
-            if param in self.required:
-                html += '<tr><td width=20></td><td width=100>%s: </td>' % param
-            else:                       # optional parameter
-                html += """\
-<tr><td width=20><wxp class="wxCheckBox">
-<param name="id" value="%d">
-<param name="size" value="(20,-1)">
-<param name="name" value="%s">
-<param name="label" value=("")>
-</wxp></td><td width=100>%s: </td>
-""" % (paramIDs[param], prefix + 'check_' + param, param)
-            # Get parameter type
-            try:
-                # Local or overriden type
-                typeClass = self.paramDict[param].__name__
-            except KeyError:
-                try:
-                    # Standart type
-                    typeClass = paramDict[param].__name__
-                except KeyError:
-                    # Default
-                    typeClass = 'ParamText'
-            html += """\
-<td><wxp module="xxx" class="%s">
-<param name="id" value="%d">
-<param name="name" value="%s">
-</wxp></td>
-""" % (typeClass, -1, prefix + 'data_' + param)
-        html += '</table>\n'
-        return html
     # Returns real tree object
     def treeObject(self):
         if self.hasChild: return self.child
@@ -229,8 +236,12 @@ class xxxParamFont(xxxParam):
 class xxxContainer(xxxObject):
     hasChildren = true
 
+# Special class for root node
+class xxxMainNode(xxxContainer):
+    hasStyle = hasName = false
+
 ################################################################################
-# Top-level windwos
+# Top-level windwows
 
 class xxxPanel(xxxContainer):
     allParams = ['pos', 'size', 'style']
@@ -347,9 +358,6 @@ class xxxListCtrl(xxxObject):
               'wxLC_USER_TEXT', 'wxLC_EDIT_LABELS', 'wxLC_NO_HEADER',
               'wxLC_SINGLE_SEL', 'wxLC_SORT_ASCENDING', 'wxLC_SORT_DESCENDING']
 
-# !!! temporary
-xxxCheckList = xxxListCtrl
-
 class xxxTreeCtrl(xxxObject):
     allParams = ['pos', 'size', 'style']
     winStyles = ['wxTR_HAS_BUTTONS', 'wxTR_NO_LINES', 'wxTR_LINES_AT_ROOT',
@@ -422,6 +430,15 @@ class xxxListBox(xxxObject):
     winStyles = ['wxLB_SINGLE', 'wxLB_MULTIPLE', 'wxLB_EXTENDED', 'wxLB_HSCROLL',
               'wxLB_ALWAYS_SB', 'wxLB_NEEDED_SB', 'wxLB_SORT']
 
+class xxxCheckList(xxxObject):
+    allParams = ['content', 'pos', 'size', 'style']
+    required = ['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']
+    paramDict = {'content': ParamContentCheckList}
+    
 ################################################################################
 # Sizers
 
@@ -507,16 +524,13 @@ class xxxChildContainer(xxxObject):
                 element.removeChild(node)
                 node.unlink()
         assert 0, 'no child found'
-    def generateHtml(self):
-        return xxxObject.generateHtml(self, '_') + '<hr>\n' + \
-               self.child.generateHtml()
 
 class xxxSizerItem(xxxChildContainer):
     allParams = ['option', 'flag', 'border']
     paramDict = {'option': ParamInt}
     def __init__(self, parent, element):
         xxxChildContainer.__init__(self, parent, element)
-        # Remove pos parameter - unnecessary for sizeritems
+        # Remove pos parameter - not needed for sizeritems
         if 'pos' in self.child.allParams:
             self.child.allParams = self.child.allParams[:]
             self.child.allParams.remove('pos')
@@ -556,7 +570,6 @@ class xxxMenuItem(xxxObject):
 
 class xxxSeparator(xxxObject):
     hasName = hasStyle = false
-    allParams = []
 
 ################################################################################
 
@@ -616,9 +629,10 @@ paramIDs = {'fg': wxNewId(), 'bg': wxNewId(), 'exstyle': wxNewId(), 'font': wxNe
             'tooltip': wxNewId()
             }
 for cl in xxxDict.values():
-    for param in cl.allParams + cl.paramDict.keys():
-        if not paramIDs.has_key(param):
-            paramIDs[param] = wxNewId()
+    if cl.allParams:
+        for param in cl.allParams + cl.paramDict.keys():
+            if not paramIDs.has_key(param):
+                paramIDs[param] = wxNewId()
 
 ################################################################################
 # Helper functions
@@ -633,7 +647,7 @@ def MakeXXXFromDOM(parent, element):
         return xxxDict[element.getAttribute('class')](parent, element)
     except KeyError:
         # Verify that it's not recursive exception
-        if element.getAttribute('class') not in xxxDict.keys():
+        if element.getAttribute('class') not in xxxDict:
             print 'ERROR: unknown class:', element.getAttribute('class')
         raise