]> git.saurik.com Git - wxWidgets.git/blobdiff - utils/configtool/src/configtooldoc.cpp
Fix for saving in Unicode mode (Bug #1172299).
[wxWidgets.git] / utils / configtool / src / configtooldoc.cpp
index 5dd41d2461976c1876122658d04ee373ff890ac5..7754ba4ced79535bc69f5aad2b9af0ef5d78d5d4 100644 (file)
@@ -9,27 +9,29 @@
 // Licence:
 /////////////////////////////////////////////////////////////////////////////
 
-#ifdef __GNUG__
+#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
 #pragma implementation "configtooldoc.h"
 #endif
 
-#include "wx/wx.h"
+// For compilers that support precompilation, includes "wx/wx.h".
+#include "wx/wxprec.h"
 
 #ifdef __BORLANDC__
 #pragma hdrstop
 #endif
 
-#include "wx/config.h"
-#include "wx/textfile.h"
+#ifndef WX_PRECOMP
+
 #include "wx/process.h"
 #include "wx/mimetype.h"
 #include "wx/process.h"
-#include "wx/wfstream.h"
 
-#ifdef __BORLANDC__
-#pragma hdrstop
 #endif
 
+#include "wx/textfile.h"
+#include "wx/txtstrm.h"
+#include "wx/wfstream.h"
+#include "wx/config.h"
 #include "configtooldoc.h"
 #include "configtoolview.h"
 #include "configtree.h"
@@ -90,26 +92,24 @@ bool ctConfigToolDoc::OnCloseDocument()
         UpdateAllViews (NULL, & hint);
 
         DeleteItems();
-        return TRUE;
+        return true;
     }
     else
     {
-        return FALSE;
+        return false;
     }
 }
 
 // Saves the doc
 bool ctConfigToolDoc::Save()
 {
-    bool ret = FALSE;
+    if (!IsModified() && m_savedYet) return true;
 
-    if (!IsModified() && m_savedYet) return TRUE;
-    if (m_documentFile == wxT("") || !m_savedYet)
-        ret = SaveAs();
-    else
-        ret = OnSaveDocument(m_documentFile);
+    bool ret = (m_documentFile == wxT("") || !m_savedYet) ?
+                 SaveAs() :
+                 OnSaveDocument(m_documentFile);
     if ( ret )
-        SetDocumentSaved(TRUE);
+        SetDocumentSaved(true);
     return ret;
 }
 
@@ -138,8 +138,8 @@ bool ctConfigToolDoc::OnCreate(const wxString& path, long flags)
 
         SetTopItem(rootItem);
 
-        Modify(FALSE);
-        SetDocumentSaved(FALSE);
+        Modify(false);
+        SetDocumentSaved(false);
 
         wxString rootName(wxT("untitled"));
         wxStripExtension(rootName);
@@ -158,7 +158,7 @@ bool ctConfigToolDoc::OnCreate(const wxString& path, long flags)
             ctConfigToolHint hint(NULL, ctInitialUpdate);
             UpdateAllViews (NULL, & hint);
 
-            SetFilename(GetFilename(), TRUE);
+            SetFilename(GetFilename(), true);
         }
     }
     return success;
@@ -176,14 +176,14 @@ bool ctConfigToolDoc::OnSaveDocument(const wxString& filename)
     // This is the backup filename
     wxString backupFilename(filename);
     backupFilename += wxT(".bak");
-    
+
     // This is the temporary copy of the backup
     wxString tempFilename(filename);
     tempFilename += wxT(".tmp");
     if (wxFileExists(tempFilename))
         wxRemoveFile(tempFilename);
 
-    bool leaveBackup = TRUE;
+    bool leaveBackup = true;
 
     bool saved = DoSave(tempFilename);
 
@@ -194,7 +194,7 @@ bool ctConfigToolDoc::OnSaveDocument(const wxString& filename)
         {
             wxRemoveFile(backupFilename);
         }
-        
+
         // Copy the old file to the .bak
 
         if (leaveBackup)
@@ -213,17 +213,17 @@ bool ctConfigToolDoc::OnSaveDocument(const wxString& filename)
             if (wxFileExists(filename))
                 wxRemoveFile(filename);
         }
-        
+
         // Finally, copy the temporary file to the proper filename
         if (!wxRenameFile(tempFilename, filename))
         {
             wxCopyFile(tempFilename, filename);
             wxRemoveFile(tempFilename);
-        }        
+        }
 
-        Modify(FALSE);
+        Modify(false);
         ((ctConfigToolView*)GetFirstView())->OnChangeFilename();
-        SetDocumentSaved(TRUE);
+        SetDocumentSaved(true);
         SetFilename(filename);
         wxGetApp().GetSettings().m_lastFilename = filename;
     } else
@@ -255,7 +255,7 @@ bool ctConfigToolDoc::OnOpenDocument(const wxString& filename)
         UpdateAllViews (NULL, & hint);
     }
 
-    SetDocumentSaved(TRUE); // Necessary or it will pop up the Save As dialog
+    SetDocumentSaved(true); // Necessary or it will pop up the Save As dialog
 
     return opened;
 }
@@ -263,32 +263,36 @@ bool ctConfigToolDoc::OnOpenDocument(const wxString& filename)
 /// Save the settings file
 bool ctConfigToolDoc::DoSave(const wxString& filename)
 {
-    wxFileOutputStream stream(filename);
-    if (!stream.Ok())
-        return FALSE;
+    wxFileOutputStream osFile(filename);
+    if (!osFile.Ok())
+        return false;
+
+    wxTextOutputStream stream(osFile);
 
     stream << wxT("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
-    stream << wxT("<settings xmlns=\"http://www.wxwindows.org/wxs\" version=\"2.5.0.1\">");
+    stream << wxT("<settings xmlns=\"http://www.wxwidgets.org/wxs\" version=\"2.5.0.1\">");
 
-    DoSave(m_topItem, stream, 1);
+    DoSave(m_topItem, osFile, 1);
 
     stream << wxT("\n</settings>\n");
 
-    return TRUE;
+    return true;
 }
 
-inline static void OutputIndentation(wxOutputStream& stream, int indent)
+inline static void OutputIndentation(wxOutputStream& osFile, int indent)
 {
+    wxTextOutputStream stream(osFile);
     wxString str = wxT("\n");
     for (int i = 0; i < indent; i++)
-        str << wxT(' ') << wxT(' ');
+        str << wxT("  ");
     stream << str ;
 }
 
 /// Recursive helper function for file saving
-bool ctConfigToolDoc::DoSave(ctConfigItem* item, wxOutputStream& stream, int indent)
+bool ctConfigToolDoc::DoSave(ctConfigItem* item, wxOutputStream& osFile, int indent)
 {
-    OutputIndentation(stream, indent*2);
+    OutputIndentation(osFile, indent*2);
+    wxTextOutputStream stream(osFile);
 
     wxString name(item->GetName());
     wxString s;
@@ -314,25 +318,25 @@ bool ctConfigToolDoc::DoSave(ctConfigItem* item, wxOutputStream& stream, int ind
 
     indent ++;
 
-    OutputIndentation(stream, indent*2);
+    OutputIndentation(osFile, indent*2);
     if (item->IsActive())
         stream << wxT("<active>1</active>");
     else
         stream << wxT("<active>0</active>");
-    OutputIndentation(stream, indent*2);
+    OutputIndentation(osFile, indent*2);
     if (item->IsEnabled())
         stream << wxT("<enabled>1</enabled>");
     else
         stream << wxT("<enabled>0</enabled>");
 
     // Output properties
-    wxNode* node = item->GetProperties().GetList().GetFirst();
+    wxObjectList::compatibility_iterator node = item->GetProperties().GetList().GetFirst();
     while (node)
     {
         ctProperty* prop = (ctProperty*) node->GetData();
-        OutputIndentation(stream, indent*2);
+        OutputIndentation(osFile, indent*2);
         stream << wxT("<") << prop->GetName() ;
-        
+
         if (prop->IsCustom())
         {
             stream << wxT(" custom=\"true\"");
@@ -346,7 +350,7 @@ bool ctConfigToolDoc::DoSave(ctConfigItem* item, wxOutputStream& stream, int ind
                 stream << wxT(" choices=\"") << choices << wxT("\"");
             }
         }
-        
+
         stream << wxT(">");
 
         stream << ctEscapeHTMLCharacters(prop->GetVariant().GetString()) ;
@@ -360,17 +364,17 @@ bool ctConfigToolDoc::DoSave(ctConfigItem* item, wxOutputStream& stream, int ind
     while (node)
     {
         ctConfigItem* child = (ctConfigItem*) node->GetData();
-        DoSave(child, stream, indent);
+        DoSave(child, osFile, indent);
 
         node = node->GetNext();
     }
 
     indent --;
 
-    OutputIndentation(stream, indent*2);
+    OutputIndentation(osFile, indent*2);
     stream << wxT("</setting>");
 
-    return TRUE;
+    return true;
 }
 
 /// Open the settings file
@@ -391,20 +395,20 @@ bool ctConfigToolDoc::DoOpen(const wxString& filename)
                 wxSimpleHtmlTag* firstSettingTag = settingsTag->GetChildren();
                 if (firstSettingTag)
                     DoOpen(firstSettingTag, NULL);
-                return TRUE;
+                return true;
             }
-            return TRUE;
+            return true;
         }
     }
-    return FALSE;
+    return false;
 }
 
 static bool GetHtmlBoolValue(const wxString& value)
 {
-    if (value == wxT("true") || value == wxT("TRUE") || value == wxT("1"))
-        return TRUE;
-     else
-         return FALSE;
+    if (value.IsSameAs(wxT("true"),false) || value == wxT("1"))
+        return true;
+    else
+        return false;
 }
 
 static int GetHtmlIntegerValue(const wxString& value)
@@ -508,7 +512,7 @@ bool ctConfigToolDoc::DoOpen(wxSimpleHtmlTag* tag, ctConfigItem* parent)
                             childTag->GetAttributeValue(description, wxT("description"));
 
                             if (type == wxT("bool"))
-                                prop->GetVariant() = wxVariant((bool) FALSE, name);
+                                prop->GetVariant() = wxVariant(false, name);
                             else if (type == wxT("double"))
                                 prop->GetVariant() = wxVariant((double) 0.0, name);
                             else if (type == wxT("long"))
@@ -516,7 +520,7 @@ bool ctConfigToolDoc::DoOpen(wxSimpleHtmlTag* tag, ctConfigItem* parent)
                             else
                                 prop->GetVariant() = wxVariant(wxT(""), name);
                             prop->SetDescription(description);
-                            prop->SetCustom(TRUE);
+                            prop->SetCustom(true);
                             prop->SetEditorType(editorType);
                             if (!choices.IsEmpty())
                             {
@@ -534,7 +538,7 @@ bool ctConfigToolDoc::DoOpen(wxSimpleHtmlTag* tag, ctConfigItem* parent)
                         else if (prop->GetVariant().GetType() == wxT("long"))
                             prop->GetVariant() = (long) GetHtmlIntegerValue(childTag->GetNext()->GetTagText());
                         else if (prop->GetVariant().GetType() == wxT("bool"))
-                            prop->GetVariant() = (bool) GetHtmlBoolValue(childTag->GetNext()->GetTagText());
+                            prop->GetVariant() = GetHtmlBoolValue(childTag->GetNext()->GetTagText());
                         else if (prop->GetVariant().GetType() == wxT("double"))
                             prop->GetVariant() = (double) GetHtmlDoubleValue(childTag->GetNext()->GetTagText());
                     }
@@ -543,17 +547,20 @@ bool ctConfigToolDoc::DoOpen(wxSimpleHtmlTag* tag, ctConfigItem* parent)
         }
         childTag = childTag->GetNext();
     }
-    return TRUE;
+    return true;
 }
 
 /// Clear dependencies
 void ctConfigToolDoc::ClearDependencies(ctConfigItem* item)
 {
-    if (!item)
+    if (!item) {
         item = GetTopItem();
+        if (!item)
+            return;
+    }
 
     item->GetDependents().Clear();
-    for ( wxNode* node = item->GetChildren().GetFirst(); node; node = node->GetNext() )
+    for ( wxObjectList::compatibility_iterator node = item->GetChildren().GetFirst(); node; node = node->GetNext() )
     {
         ctConfigItem* child = (ctConfigItem*) node->GetData();
         ClearDependencies(child);
@@ -570,11 +577,15 @@ void ctConfigToolDoc::RefreshDependencies()
 /// Refresh dependencies
 void ctConfigToolDoc::RefreshDependencies(ctConfigItem* item)
 {
+    if (item==NULL)
+        return;
+
     wxArrayString requiresArr;
     wxString requires = item->GetPropertyString(wxT("requires"));
     wxString precludes = item->GetPropertyString(wxT("precludes"));
     wxString enabledIf = item->GetPropertyString(wxT("enabled-if"));
     wxString enabledIfNot = item->GetPropertyString(wxT("enabled-if-not"));
+    wxString indeterminateIf = item->GetPropertyString(wxT("indeterminate-if"));
     wxString context = item->GetPropertyString(wxT("context"));
 
     if (!requires.IsEmpty())
@@ -589,11 +600,14 @@ void ctConfigToolDoc::RefreshDependencies(ctConfigItem* item)
     if (!enabledIf.IsEmpty())
         item->StringToArray(enabledIf, requiresArr);
 
+    if (!indeterminateIf.IsEmpty())
+        item->StringToArray(indeterminateIf, requiresArr);
+
     // Add the parent to the list of dependencies, if the
     // parent is a check or radio group.
     ctConfigItem* parent = item->GetParent();
     if (parent &&
-        (parent->GetType() == ctTypeCheckGroup || 
+        (parent->GetType() == ctTypeCheckGroup ||
         parent->GetType() == ctTypeRadioGroup))
         requiresArr.Add(parent->GetName());
 
@@ -614,7 +628,7 @@ void ctConfigToolDoc::RefreshDependencies(ctConfigItem* item)
             otherItem->GetDependents().Append(item);
         }
     }
-    for ( wxNode* node = item->GetChildren().GetFirst(); node; node = node->GetNext() )
+    for ( wxObjectList::compatibility_iterator node = item->GetChildren().GetFirst(); node; node = node->GetNext() )
     {
         ctConfigItem* child = (ctConfigItem*) node->GetData();
         RefreshDependencies(child);
@@ -639,7 +653,7 @@ void ctConfigToolDoc::GenerateSetup(ctConfigItem* item, wxString& str)
     wxString name = item->GetName();
 
     // We don't process the platform choice
-    if (item->GetName() == wxT("Platform"))
+    if (item->GetName() == wxT("Target"))
         return;
 
     if (item->IsInActiveContext() &&
@@ -663,7 +677,7 @@ void ctConfigToolDoc::GenerateSetup(ctConfigItem* item, wxString& str)
         }
     }
 
-    for ( wxNode* node = item->GetChildren().GetFirst(); node; node = node->GetNext() )
+    for ( wxObjectList::compatibility_iterator node = item->GetChildren().GetFirst(); node; node = node->GetNext() )
     {
         ctConfigItem* child = (ctConfigItem*) node->GetData();
         GenerateSetup(child, str);
@@ -677,8 +691,8 @@ wxString ctConfigToolDoc::GenerateConfigureCommand()
     wxString str;
     str << wxT("# configurewx\n# Generated by wxConfigTool\n\n");
 
-    wxString path = GetFrameworkDir(TRUE);
-    bool makeUnix = TRUE;
+    wxString path = GetFrameworkDir(true);
+    bool makeUnix = true;
     if (!path.IsEmpty())
     {
         if (makeUnix)
@@ -689,11 +703,11 @@ wxString ctConfigToolDoc::GenerateConfigureCommand()
 
     str << path << wxT("configure");
 
-    // Find the platform option to use
-    ctConfigItem* platformsFolder = GetTopItem()->FindItem(wxT("Platform"));
+    // Find the target to use
+    ctConfigItem* platformsFolder = GetTopItem()->FindItem(wxT("Target"));
     if (platformsFolder)
     {
-        for ( wxNode* node = platformsFolder->GetChildren().GetFirst(); node; node = node->GetNext() )
+        for ( wxObjectList::compatibility_iterator node = platformsFolder->GetChildren().GetFirst(); node; node = node->GetNext() )
         {
             ctConfigItem* child = (ctConfigItem*) node->GetData();
             if (child->GetType() == ctTypeBoolRadio && child->IsEnabled())
@@ -714,7 +728,7 @@ void ctConfigToolDoc::GenerateConfigureCommand(ctConfigItem* item, wxString& str
 {
     // We don't process the platform group, since we've
     // already done so.
-    if (item->GetName() == wxT("Platform"))
+    if (item->GetName() == wxT("Target"))
         return;
 
     if (item->IsInActiveContext() &&
@@ -763,11 +777,11 @@ void ctConfigToolDoc::GenerateConfigureCommand(ctConfigItem* item, wxString& str
                 {
                     str << wxT(" ") << configureCommand;
                 }
-            }            
+            }
         }
     }
 
-    for ( wxNode* node = item->GetChildren().GetFirst(); node; node = node->GetNext() )
+    for ( wxObjectList::compatibility_iterator node = item->GetChildren().GetFirst(); node; node = node->GetNext() )
     {
         ctConfigItem* child = (ctConfigItem*) node->GetData();
         GenerateConfigureCommand(child, str);
@@ -782,7 +796,8 @@ wxString ctConfigToolDoc::GetFrameworkDir(bool makeUnix)
     {
         // Should probably allow other variables
         // to be used, and maybe expand variables within m_frameworkDir
-        path = wxGetenv(wxT("WXWIN"));
+        wxString pathEnv(wxGetenv(wxT("WXWIN")));
+        path = pathEnv;
 #ifdef __WXMSW__
         if (makeUnix)
             path.Replace(wxT("\\"), wxT("/"));
@@ -791,6 +806,51 @@ wxString ctConfigToolDoc::GetFrameworkDir(bool makeUnix)
     return path;
 }
 
+/// Finds the next item in the tree
+ctConfigItem* ctConfigToolDoc::FindNextItem(ctConfigItem* item, bool wrap)
+{
+    if (!item)
+        return GetTopItem();
+
+    // First, try to find the first child
+    if (item->GetChildCount() > 0)
+    {
+        return item->GetChild(0);
+    }
+    else
+    {
+        ctConfigItem* p = item;
+        while (p)
+        {
+            ctConfigItem* toFind = FindNextSibling(p);
+            if (toFind)
+                return toFind;
+            p = p->GetParent();
+        }
+    }
+
+    // Finally, wrap around to the root.
+    if (wrap)
+        return GetTopItem();
+    else
+        return NULL;
+}
+
+/// Finds the next sibling in the tree
+ctConfigItem* ctConfigToolDoc::FindNextSibling(ctConfigItem* item)
+{
+    if (item->GetParent())
+    {
+        wxObjectList::compatibility_iterator node = item->GetParent()->GetChildren().Member(item);
+        if (node && node->GetNext())
+        {
+            ctConfigItem* nextItem = (ctConfigItem*) node->GetNext()->GetData();
+            return nextItem;
+        }
+    }
+    return NULL;
+}
+
 
 /*
  * Implements a document editing command.
@@ -799,7 +859,7 @@ wxString ctConfigToolDoc::GetFrameworkDir(bool makeUnix)
 ctConfigCommand::ctConfigCommand(const wxString& name, int cmdId,
         ctConfigItem* activeState, ctConfigItem* savedState,
         ctConfigItem* parent, ctConfigItem* insertBefore,
-        bool ignoreFirstTime): wxCommand(TRUE, name)
+        bool ignoreFirstTime): wxCommand(true, name)
 {
     m_activeState = activeState;
     m_savedState = savedState;
@@ -812,7 +872,7 @@ ctConfigCommand::ctConfigCommand(const wxString& name, int cmdId,
 
 ctConfigCommand::ctConfigCommand(const wxString& name, int cmdId,
         ctConfigItem* activeState,  ctProperties* properties,
-        bool ignoreFirstTime): wxCommand(TRUE, name)
+        bool ignoreFirstTime): wxCommand(true, name)
 {
     m_activeState = activeState;
     m_savedState = NULL;
@@ -834,12 +894,12 @@ ctConfigCommand::~ctConfigCommand()
 
 bool ctConfigCommand::Do()
 {
-    return DoAndUndo(TRUE);
+    return DoAndUndo(true);
 }
 
 bool ctConfigCommand::Undo()
 {
-    return DoAndUndo(FALSE);
+    return DoAndUndo(false);
 }
 
 // Combine Do and Undo into one
@@ -859,7 +919,7 @@ bool ctConfigCommand::DoAndUndo(bool doCmd)
 
                 // This will delete the old clipboard contents, if any.
                 doc->SetClipboardItem(newItem);
-                
+
                 m_parent = m_activeState->GetParent();
                 m_insertBefore = m_activeState->FindNextSibling();
 
@@ -867,7 +927,7 @@ bool ctConfigCommand::DoAndUndo(bool doCmd)
                 m_savedState = m_activeState;
                 m_activeState = NULL;
 
-                m_savedState->GetDocument()->Modify(TRUE);
+                m_savedState->GetDocument()->Modify(true);
                 ctConfigToolView* view = (ctConfigToolView*) m_savedState->GetDocument()->GetFirstView();
                 view->OnChangeFilename();
             }
@@ -876,7 +936,7 @@ bool ctConfigCommand::DoAndUndo(bool doCmd)
                 wxASSERT(m_savedState != NULL);
                 wxASSERT(m_activeState == NULL);
 
-                m_savedState->GetDocument()->Modify(TRUE);
+                m_savedState->GetDocument()->Modify(true);
                 m_savedState->Attach(m_parent, m_insertBefore);
                 ctConfigToolView* view = (ctConfigToolView*) m_savedState->GetDocument()->GetFirstView();
                 view->AddItems(wxGetApp().GetMainFrame()->GetConfigTreeCtrl(), m_savedState);
@@ -895,7 +955,7 @@ bool ctConfigCommand::DoAndUndo(bool doCmd)
                 wxASSERT(m_savedState != NULL);
                 wxASSERT(m_activeState == NULL);
 
-                m_savedState->GetDocument()->Modify(TRUE);
+                m_savedState->GetDocument()->Modify(true);
                 m_savedState->Attach(m_parent, m_insertBefore);
                 ctConfigToolView* view = (ctConfigToolView*) m_savedState->GetDocument()->GetFirstView();
                 view->AddItems(wxGetApp().GetMainFrame()->GetConfigTreeCtrl(), m_savedState);
@@ -909,7 +969,7 @@ bool ctConfigCommand::DoAndUndo(bool doCmd)
                 wxASSERT(m_savedState == NULL);
                 wxASSERT(m_activeState != NULL);
 
-                m_activeState->GetDocument()->Modify(TRUE);
+                m_activeState->GetDocument()->Modify(true);
                 ctConfigToolView* view = (ctConfigToolView*) m_activeState->GetDocument()->GetFirstView();
                 m_activeState->Detach();
                 m_savedState = m_activeState;
@@ -925,7 +985,7 @@ bool ctConfigCommand::DoAndUndo(bool doCmd)
                 wxASSERT(m_savedState != NULL);
                 wxASSERT(m_activeState == NULL);
 
-                m_savedState->GetDocument()->Modify(TRUE);
+                m_savedState->GetDocument()->Modify(true);
                 m_savedState->Attach(m_parent, m_insertBefore);
                 ctConfigToolView* view = (ctConfigToolView*) m_savedState->GetDocument()->GetFirstView();
                 view->AddItems(wxGetApp().GetMainFrame()->GetConfigTreeCtrl(), m_savedState);
@@ -939,7 +999,7 @@ bool ctConfigCommand::DoAndUndo(bool doCmd)
                 wxASSERT(m_savedState == NULL);
                 wxASSERT(m_activeState != NULL);
 
-                m_activeState->GetDocument()->Modify(TRUE);
+                m_activeState->GetDocument()->Modify(true);
                 m_activeState->Detach();
                 m_savedState = m_activeState;
                 m_activeState = NULL;
@@ -963,7 +1023,7 @@ bool ctConfigCommand::DoAndUndo(bool doCmd)
 
                 // Apply only those that need applying
                 // (those properties in activeState that are not in propsTemp)
-                wxNode* node = m_activeState->GetProperties().GetList().GetFirst();
+                wxObjectList::compatibility_iterator node = m_activeState->GetProperties().GetList().GetFirst();
                 while (node)
                 {
                     ctProperty* prop = (ctProperty*) node->GetData();
@@ -974,7 +1034,7 @@ bool ctConfigCommand::DoAndUndo(bool doCmd)
                     }
                     node = node->GetNext();
                 }
-                m_activeState->GetDocument()->Modify(TRUE);
+                m_activeState->GetDocument()->Modify(true);
                 ctConfigToolView* view = (ctConfigToolView*) m_activeState->GetDocument()->GetFirstView();
                 if (view)
                 {
@@ -982,11 +1042,216 @@ bool ctConfigCommand::DoAndUndo(bool doCmd)
                     m_activeState->GetDocument()->UpdateAllViews (NULL, & hint);
                 }
             }
-            m_ignoreThis = FALSE;
+            m_ignoreThis = false;
 
             break;
         }
     }
-    return TRUE;
+    return true;
 }
 
+IMPLEMENT_CLASS(ctConfiguration, wxObject)
+
+ctConfiguration::ctConfiguration()
+{
+    m_treeItemId = wxTreeItemId();
+    m_parent = NULL;
+    m_topItem = NULL;
+}
+
+ctConfiguration::ctConfiguration(ctConfiguration* parent, const wxString& name)
+{
+    m_treeItemId = wxTreeItemId();
+    SetName(name);
+    m_parent = parent;
+    if (parent)
+        parent->AddChild(this);
+}
+
+ctConfiguration::~ctConfiguration()
+{
+/*
+    ctConfigTreeCtrl* treeCtrl = wxGetApp().GetMainFrame()->GetConfigTreeCtrl();
+    if (m_treeItemId.IsOk() && treeCtrl)
+    {
+        ctTreeItemData* data = (ctTreeItemData*) treeCtrl->GetItemData(m_treeItemId);
+        if (data)
+            data->SetConfigItem(NULL);
+    }
+    if (GetParent())
+        GetParent()->RemoveChild(this);
+    else
+    {
+        if (wxGetApp().GetMainFrame()->GetDocument() &&
+            wxGetApp().GetMainFrame()->GetDocument()->GetTopItem() == this)
+            wxGetApp().GetMainFrame()->GetDocument()->SetTopItem(NULL);
+    }
+*/
+
+    Clear();
+}
+
+/// Assignment operator.
+void ctConfiguration::operator= (const ctConfiguration& configuration)
+{
+    m_name = configuration.m_name;
+    m_description = configuration.m_description;
+}
+
+/// Clear children
+void ctConfiguration::Clear()
+{
+    wxObjectList::compatibility_iterator node = m_children.GetFirst();
+    while (node)
+    {
+        wxObjectList::compatibility_iterator next = node->GetNext();
+        ctConfiguration* child = (ctConfiguration*) node->GetData();
+
+        // This should delete 'node' too, assuming
+        // child's m_parent points to 'this'. If not,
+        // it'll be cleaned up by m_children.Clear().
+        delete child;
+
+        node = next;
+    }
+    m_children.Clear();
+}
+
+// Get the nth child
+ctConfiguration* ctConfiguration::GetChild(int n) const
+{
+    wxASSERT ( n < GetChildCount() && n > -1 );
+
+    if ( n < GetChildCount() && n > -1 )
+    {
+        ctConfiguration* child = wxDynamicCast(m_children.Item(n)->GetData(), ctConfiguration);
+        return child;
+    }
+    else
+        return NULL;
+}
+
+// Get the child count
+int ctConfiguration::GetChildCount() const
+{
+    return m_children.GetCount();
+}
+
+/// Add a child
+void ctConfiguration::AddChild(ctConfiguration* configuration)
+{
+    m_children.Append(configuration);
+    configuration->SetParent(this);
+}
+
+/// Remove (but don't delete) a child
+void ctConfiguration::RemoveChild(ctConfiguration* configuration)
+{
+    m_children.DeleteObject(configuration);
+    configuration->SetParent(NULL);
+}
+
+/// Get the associated document (currently, assumes
+/// there's only ever one document active)
+ctConfigToolDoc* ctConfiguration::GetDocument()
+{
+    ctConfigToolDoc* doc = wxGetApp().GetMainFrame()->GetDocument();
+    return doc;
+}
+
+/// Find an item in this hierarchy
+// TODO: ensure that names are unique, somehow.
+ctConfiguration* ctConfiguration::FindConfiguration(const wxString& name)
+{
+    if (GetName() == name)
+        return this;
+
+    for ( wxObjectList::compatibility_iterator node = GetChildren().GetFirst(); node; node = node->GetNext() )
+    {
+        ctConfiguration* child = (ctConfiguration*) node->GetData();
+        ctConfiguration* found = child->FindConfiguration(name);
+        if (found)
+            return found;
+    }
+    return NULL;
+}
+
+/// Find the next sibling
+ctConfiguration* ctConfiguration::FindNextSibling()
+{
+    if (!GetParent())
+        return NULL;
+    wxObjectList::compatibility_iterator node = GetParent()->GetChildren().Member(this);
+    if (node && node->GetNext())
+    {
+        return (ctConfiguration*) node->GetNext()->GetData();
+    }
+    return NULL;
+}
+
+/// Find the previous sibling
+ctConfiguration* ctConfiguration::FindPreviousSibling()
+{
+    if (!GetParent())
+        return NULL;
+    wxObjectList::compatibility_iterator node = GetParent()->GetChildren().Member(this);
+    if (node && node->GetPrevious())
+    {
+        return (ctConfiguration*) node->GetPrevious()->GetData();
+    }
+    return NULL;
+}
+
+/// Create a clone of this and children
+ctConfiguration* ctConfiguration::DeepClone()
+{
+    ctConfiguration* newItem = Clone();
+
+    for ( wxObjectList::compatibility_iterator node = GetChildren().GetFirst(); node; node = node->GetNext() )
+    {
+        ctConfiguration* child = (ctConfiguration*) node->GetData();
+        ctConfiguration* newChild = child->DeepClone();
+        newItem->AddChild(newChild);
+    }
+    return newItem;
+}
+
+/// Detach: remove from parent, and remove tree items
+void ctConfiguration::Detach()
+{
+    // TODO
+    if (GetParent())
+        GetParent()->RemoveChild(this);
+    else
+        GetDocument()->SetTopItem(NULL);
+    SetParent(NULL);
+
+/*
+    wxTreeItemId treeItem = GetTreeItemId();
+
+    DetachFromTree();
+
+    // Will delete the branch, but not the config items.
+    wxGetApp().GetMainFrame()->GetConfigTreeCtrl()->Delete(treeItem);
+*/
+}
+
+/// Hide from tree: make sure tree deletions won't delete
+/// the config items
+void ctConfiguration::DetachFromTree()
+{
+/*
+    wxTreeItemId item = GetTreeItemId();
+
+    // TODO
+    ctTreeItemData* data = (ctTreeItemData*) wxGetApp().GetMainFrame()->GetConfigTreeCtrl()->GetItemData(item);
+    data->SetConfigItem(NULL);
+    m_treeItemId = wxTreeItemId();
+
+    for ( wxNode* node = GetChildren().GetFirst(); node; node = node->GetNext() )
+    {
+        ctConfiguration* child = (ctConfiguration*) node->GetData();
+        child->DetachFromTree();
+    }
+*/
+}