///////////////////////////////////////////////////////////////////////////// // Name: configtooldoc.h // Purpose: Document class // Author: Julian Smart // Modified by: // Created: 2003-06-04 // RCS-ID: $Id$ // Copyright: (c) Julian Smart // Licence: ///////////////////////////////////////////////////////////////////////////// #ifdef __GNUG__ #pragma implementation "configtooldoc.h" #endif #include "wx/wx.h" #ifdef __BORLANDC__ #pragma hdrstop #endif #include "wx/config.h" #include "wx/textfile.h" #include "wx/process.h" #include "wx/mimetype.h" #include "wx/process.h" #include "wx/wfstream.h" #ifdef __BORLANDC__ #pragma hdrstop #endif #include "configtooldoc.h" #include "configtoolview.h" #include "configtree.h" #include "mainframe.h" #include "utils.h" #include "wxconfigtool.h" #include "htmlparser.h" IMPLEMENT_DYNAMIC_CLASS(ctConfigToolDoc, wxDocument) // Ctor ctConfigToolDoc::ctConfigToolDoc() { m_topItem = NULL; m_clipboardItem = NULL; } // Dtor ctConfigToolDoc::~ctConfigToolDoc() { DeleteItems(); ClearClipboard(); if (GetCommandProcessor()) GetCommandProcessor()->SetEditMenu(NULL); } // Delete all the items not already deleted void ctConfigToolDoc::DeleteItems() { if (m_topItem) delete m_topItem; m_topItem = NULL; } /// Clears the clipboard item. void ctConfigToolDoc::ClearClipboard() { if (m_clipboardItem) delete m_clipboardItem; m_clipboardItem = NULL; } /// Sets the clipboard item. void ctConfigToolDoc::SetClipboardItem(ctConfigItem* item) { if (m_clipboardItem) delete m_clipboardItem; m_clipboardItem = item; } // Closes and clears the document bool ctConfigToolDoc::OnCloseDocument() { if (wxDocument::OnCloseDocument()) { ctConfigToolHint hint(NULL, ctClear); UpdateAllViews (NULL, & hint); DeleteItems(); return TRUE; } else { return FALSE; } } // Saves the doc bool ctConfigToolDoc::Save() { bool ret = FALSE; if (!IsModified() && m_savedYet) return TRUE; if (m_documentFile == wxT("") || !m_savedYet) ret = SaveAs(); else ret = OnSaveDocument(m_documentFile); if ( ret ) SetDocumentSaved(TRUE); return ret; } // Create the document bool ctConfigToolDoc::OnCreate(const wxString& path, long flags) { GetCommandProcessor()->SetEditMenu(wxGetApp().GetMainFrame()->GetEditMenu()); GetCommandProcessor()->Initialize(); GetCommandProcessor()->ClearCommands(); // wxGetApp().m_currentDoc = this; if (flags & wxDOC_NEW) { ctConfigItem* rootItem = new ctConfigItem(NULL, ctTypeGroup, _T("Configuration")); //rootItem->InitProperties(); rootItem->GetProperties().AddProperty( new ctProperty( wxT("The item description."), wxVariant(wxT(""), wxT("description")), wxT("multiline"))); rootItem->SetPropertyString(_T("description"), _T("This is the top-level configuration item.")); SetTopItem(rootItem); Modify(FALSE); SetDocumentSaved(FALSE); wxString rootName(wxT("untitled")); wxStripExtension(rootName); SetFilename(wxGetApp().GetSettings().GenerateFilename(rootName)); } // Creates the view, so do any view updating after this bool success = wxDocument::OnCreate(path, flags); if (success) { if (flags & wxDOC_NEW) { wxBusyCursor wait; ctConfigToolHint hint(NULL, ctInitialUpdate); UpdateAllViews (NULL, & hint); SetFilename(GetFilename(), TRUE); } } return success; } // Save the document bool ctConfigToolDoc::OnSaveDocument(const wxString& filename) { wxBusyCursor cursor; const wxString strOldPath(GetFilename()); // Do some backing up first // 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 saved = DoSave(tempFilename); if (saved) { // Remove the old .bak file if (wxFileExists(backupFilename)) { wxRemoveFile(backupFilename); } // Copy the old file to the .bak if (leaveBackup) { if (wxFileExists(filename)) { if (!wxRenameFile(filename, backupFilename)) { wxCopyFile(filename, backupFilename); wxRemoveFile(filename); } } } else { 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); ((ctConfigToolView*)GetFirstView())->OnChangeFilename(); SetDocumentSaved(TRUE); SetFilename(filename); wxGetApp().GetSettings().m_lastFilename = filename; } else { SetFilename(strOldPath); } wxGetApp().GetMainFrame()->UpdateFrameTitle(); return saved; } // Open the document bool ctConfigToolDoc::OnOpenDocument(const wxString& filename) { wxBusyCursor cursor; bool opened = DoOpen(filename); if (opened) { SetFilename(filename); wxGetApp().GetSettings().m_lastFilename = filename; ((ctConfigToolView*)GetFirstView())->OnChangeFilename(); RefreshDependencies(); // ctConfigToolHint hint(NULL, ctFilenameChanged); ctConfigToolHint hint(NULL, ctInitialUpdate); UpdateAllViews (NULL, & hint); } SetDocumentSaved(TRUE); // Necessary or it will pop up the Save As dialog return opened; } /// Save the settings file bool ctConfigToolDoc::DoSave(const wxString& filename) { wxFileOutputStream stream(filename); if (!stream.Ok()) return FALSE; stream << wxT("\n"); stream << wxT(""); DoSave(m_topItem, stream, 1); stream << wxT("\n\n"); return TRUE; } inline static void OutputIndentation(wxOutputStream& stream, int indent) { wxString str = wxT("\n"); for (int i = 0; i < indent; i++) str << wxT(' ') << wxT(' '); stream << str ; } /// Recursive helper function for file saving bool ctConfigToolDoc::DoSave(ctConfigItem* item, wxOutputStream& stream, int indent) { OutputIndentation(stream, indent*2); wxString name(item->GetName()); wxString s; wxString typeStr; if (item->GetType() == ctTypeGroup) typeStr = wxT("group"); else if (item->GetType() == ctTypeCheckGroup) typeStr = wxT("check-group"); else if (item->GetType() == ctTypeRadioGroup) typeStr = wxT("radio-group"); else if (item->GetType() == ctTypeString) typeStr = wxT("string"); else if (item->GetType() == ctTypeBoolCheck) typeStr = wxT("bool-check"); else if (item->GetType() == ctTypeBoolRadio) typeStr = wxT("bool-radio"); else if (item->GetType() == ctTypeInteger) typeStr = wxT("integer"); else typeStr = wxT("unknown"); stream << wxT(""); indent ++; OutputIndentation(stream, indent*2); if (item->IsActive()) stream << wxT("1"); else stream << wxT("0"); OutputIndentation(stream, indent*2); if (item->IsEnabled()) stream << wxT("1"); else stream << wxT("0"); // Output properties wxNode* node = item->GetProperties().GetList().GetFirst(); while (node) { ctProperty* prop = (ctProperty*) node->GetData(); OutputIndentation(stream, indent*2); stream << wxT("<") << prop->GetName() ; if (prop->IsCustom()) { stream << wxT(" custom=\"true\""); stream << wxT(" type=\"") << prop->GetVariant().GetType() << wxT("\""); stream << wxT(" editor-type=\"") << prop->GetEditorType() << wxT("\""); stream << wxT(" description=\"") << prop->GetDescription() << wxT("\""); if (prop->GetChoices().GetCount() > 0) { wxString choices; ctConfigItem::ArrayToString(prop->GetChoices(), choices); stream << wxT(" choices=\"") << choices << wxT("\""); } } stream << wxT(">"); stream << ctEscapeHTMLCharacters(prop->GetVariant().GetString()) ; stream << wxT("GetName() << wxT(">"); node = node->GetNext(); } // Output children node = item->GetChildren().GetFirst(); while (node) { ctConfigItem* child = (ctConfigItem*) node->GetData(); DoSave(child, stream, indent); node = node->GetNext(); } indent --; OutputIndentation(stream, indent*2); stream << wxT(""); return TRUE; } /// Open the settings file bool ctConfigToolDoc::DoOpen(const wxString& filename) { wxSimpleHtmlParser parser; if (parser.ParseFile(filename)) { ctConfigToolHint hint(NULL, ctClear); UpdateAllViews (NULL, & hint); m_topItem = NULL; if (parser.GetTopLevelTag()->GetChildren()) { wxSimpleHtmlTag* settingsTag = parser.GetTopLevelTag()->GetChildren()->FindTag(wxT("settings")); if (settingsTag && settingsTag->GetChildren()) { wxSimpleHtmlTag* firstSettingTag = settingsTag->GetChildren(); if (firstSettingTag) DoOpen(firstSettingTag, NULL); return TRUE; } return TRUE; } } return FALSE; } static bool GetHtmlBoolValue(const wxString& value) { if (value == wxT("true") || value == wxT("TRUE") || value == wxT("1")) return TRUE; else return FALSE; } static int GetHtmlIntegerValue(const wxString& value) { return wxAtoi(value); } static double GetHtmlDoubleValue(const wxString& value) { return wxAtof(value); } bool ctConfigToolDoc::DoOpen(wxSimpleHtmlTag* tag, ctConfigItem* parent) { ctConfigItem* newItem = NULL; if (tag->NameIs(wxT("setting"))) { wxSimpleHtmlAttribute* attr = tag->FindAttribute(wxT("type")); if (attr) { ctConfigType type = ctTypeUnknown; wxString typeStr(attr->GetValue()); if (typeStr == wxT("group")) type = ctTypeGroup; else if (typeStr == wxT("option-group") || typeStr == wxT("check-group")) type = ctTypeCheckGroup; else if (typeStr == wxT("radio-group")) type = ctTypeRadioGroup; else if (typeStr == wxT("bool-check")) type = ctTypeBoolCheck; else if (typeStr == wxT("bool-radio")) type = ctTypeBoolRadio; else if (typeStr == wxT("string")) type = ctTypeString; else if (typeStr == wxT("integer")) type = ctTypeInteger; else { wxLogError(wxT("Unknown type %s"), (const wxChar*) typeStr); } if (type != ctTypeUnknown) { newItem = new ctConfigItem(parent, type, wxT("")); newItem->InitProperties(); if (!parent) SetTopItem(newItem); } } } wxSimpleHtmlTag* childTag = tag->GetChildren(); while (childTag) { if (childTag->GetType() == wxSimpleHtmlTag_Open) { if (childTag->GetName() == wxT("setting")) { DoOpen(childTag, newItem); } else if (childTag->GetName() == wxT("name")) { if (newItem) { wxString name(childTag->GetNext()->GetTagText()); newItem->SetName(name); } } else if (childTag->GetName() == wxT("active")) { if (newItem) newItem->SetActive(GetHtmlBoolValue(childTag->GetNext()->GetTagText())); } else if (childTag->GetName() == wxT("enabled")) { if (newItem) newItem->Enable(GetHtmlBoolValue(childTag->GetNext()->GetTagText())); } else { if (newItem) { ctProperty* prop = newItem->GetProperties().FindProperty(childTag->GetName()); if (!prop) { // A custom property, else an obsolete // property that we should ignore. wxString isCustom; if (childTag->GetAttributeValue(isCustom, wxT("custom")) && isCustom == wxT("true")) { prop = new ctProperty; wxString name(childTag->GetName()); wxString type(wxT("string")); wxString choices; wxString editorType(wxT("string")); wxString description(wxT("")); childTag->GetAttributeValue(type, wxT("type")); childTag->GetAttributeValue(type, wxT("editor-type")); childTag->GetAttributeValue(type, wxT("choices")); childTag->GetAttributeValue(description, wxT("description")); if (type == wxT("bool")) prop->GetVariant() = wxVariant((bool) FALSE, name); else if (type == wxT("double")) prop->GetVariant() = wxVariant((double) 0.0, name); else if (type == wxT("long")) prop->GetVariant() = wxVariant((long) 0, name); else prop->GetVariant() = wxVariant(wxT(""), name); prop->SetDescription(description); prop->SetCustom(TRUE); prop->SetEditorType(editorType); if (!choices.IsEmpty()) { wxArrayString arr; ctConfigItem::StringToArray(choices, arr); prop->SetChoices(arr); } newItem->GetProperties().AddProperty(prop); } } if (prop) { if (prop->GetVariant().GetType() == wxT("string")) prop->GetVariant() = childTag->GetNext()->GetTagText(); 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()); else if (prop->GetVariant().GetType() == wxT("double")) prop->GetVariant() = (double) GetHtmlDoubleValue(childTag->GetNext()->GetTagText()); } } } } childTag = childTag->GetNext(); } return TRUE; } /// Clear dependencies void ctConfigToolDoc::ClearDependencies(ctConfigItem* item) { if (!item) item = GetTopItem(); item->GetDependents().Clear(); for ( wxNode* node = item->GetChildren().GetFirst(); node; node = node->GetNext() ) { ctConfigItem* child = (ctConfigItem*) node->GetData(); ClearDependencies(child); } } /// Refresh dependencies void ctConfigToolDoc::RefreshDependencies() { ClearDependencies(GetTopItem()); RefreshDependencies(GetTopItem()); } /// Refresh dependencies void ctConfigToolDoc::RefreshDependencies(ctConfigItem* item) { 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 context = item->GetPropertyString(wxT("context")); if (!requires.IsEmpty()) item->StringToArray(requires, requiresArr); if (!precludes.IsEmpty()) item->StringToArray(precludes, requiresArr); if (!enabledIfNot.IsEmpty()) item->StringToArray(enabledIfNot, requiresArr); if (!enabledIf.IsEmpty()) item->StringToArray(enabledIf, 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() == ctTypeRadioGroup)) requiresArr.Add(parent->GetName()); // Also look in 'context' since these items // are another kind of dependency (switching to // a different platform may cause the dependencies // to be evaluated differently). if (!context.IsEmpty()) item->StringToArray(context, requiresArr); size_t i; for (i = 0; i < requiresArr.GetCount(); i++) { wxString itemName(requiresArr[i]); ctConfigItem* otherItem = GetTopItem()->FindItem(itemName); if (otherItem && !otherItem->GetDependents().Member(item)) { otherItem->GetDependents().Append(item); } } for ( wxNode* node = item->GetChildren().GetFirst(); node; node = node->GetNext() ) { ctConfigItem* child = (ctConfigItem*) node->GetData(); RefreshDependencies(child); } } /// Generate the text of a setup.h wxString ctConfigToolDoc::GenerateSetup() { wxString str; str << wxT("/*\n * setup.h\n * Generated by wxConfigTool\n *\n */\n\n"); GenerateSetup(GetTopItem(), str); return str; } /// Helper function void ctConfigToolDoc::GenerateSetup(ctConfigItem* item, wxString& str) { // Generate the setup.h entries for this item wxString name = item->GetName(); // We don't process the platform choice if (item->GetName() == wxT("Platform")) return; if (item->IsInActiveContext() && (item->GetType() == ctTypeCheckGroup || item->GetType() == ctTypeRadioGroup || item->GetType() == ctTypeBoolCheck || item->GetType() == ctTypeBoolRadio)) { // TODO: write description wxString name = item->GetName(); if (name.Left(6) == wxT("wxUSE_") || name == wxT("REMOVE_UNUSED_ARG") || // Hack alert: change to wxUSE_UNUSED_ARG_REMOVAL name.Find(wxT("COMPATIBILITY")) != wxNOT_FOUND) { str << wxT("#define ") << name ; if (item->IsEnabled()) str << wxT(" 1"); else str << wxT(" 0"); str << wxT("\n\n"); } } for ( wxNode* node = item->GetChildren().GetFirst(); node; node = node->GetNext() ) { ctConfigItem* child = (ctConfigItem*) node->GetData(); GenerateSetup(child, str); } } /// Generate a configure command wxString ctConfigToolDoc::GenerateConfigureCommand() { wxString str; str << wxT("# configurewx\n# Generated by wxConfigTool\n\n"); wxString path = GetFrameworkDir(TRUE); bool makeUnix = TRUE; if (!path.IsEmpty()) { if (makeUnix) path += wxT("/"); else path += wxFILE_SEP_PATH ; } str << path << wxT("configure"); // Find the platform option to use ctConfigItem* platformsFolder = GetTopItem()->FindItem(wxT("Platform")); if (platformsFolder) { for ( wxNode* node = platformsFolder->GetChildren().GetFirst(); node; node = node->GetNext() ) { ctConfigItem* child = (ctConfigItem*) node->GetData(); if (child->GetType() == ctTypeBoolRadio && child->IsEnabled()) { wxString configureCommand = child->GetPropertyString(wxT("configure-command")); if (!configureCommand.IsEmpty()) str << wxT(" ") << configureCommand; } } } GenerateConfigureCommand(GetTopItem(), str); return str; } /// Helper function 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")) return; if (item->IsInActiveContext() && (item->GetType() == ctTypeCheckGroup || item->GetType() == ctTypeRadioGroup || item->GetType() == ctTypeBoolCheck || item->GetType() == ctTypeBoolRadio)) { wxString name = item->GetName(); wxString configureCommand = item->GetPropertyString(wxT("configure-command")); if (!configureCommand.IsEmpty()) { if (!item->IsEnabled()) { // Replace 'enable' with 'disable' if this // option is off. configureCommand.Replace(wxT("--enable-"), wxT("--disable-")); configureCommand.Replace(wxT("--with-"), wxT("--without-")); } ctProperty* prop = item->GetProperties().FindProperty(wxT("builtin")); if (prop && prop->GetVariant().GetType() == wxT("bool")) { bool builtin = prop->GetVariant().GetBool(); str << wxT(" ") << configureCommand; if (builtin) str << wxT("=builtin"); else str << wxT("=sys"); } else { ctProperty* prop = item->GetProperties().FindProperty(wxT("value")); if (prop && prop->GetVariant().GetType() == wxT("string")) { wxString val = prop->GetVariant().GetString(); if (item->IsEnabled() && !val.IsEmpty()) { str << wxT(" ") << configureCommand; str << wxT("=\"") << val << wxT("\""); } // If the string is empty, ignore this parameter, // since it's obviously intended to be supplied // only if there's a string to use and it's enabled. } else { str << wxT(" ") << configureCommand; } } } } for ( wxNode* node = item->GetChildren().GetFirst(); node; node = node->GetNext() ) { ctConfigItem* child = (ctConfigItem*) node->GetData(); GenerateConfigureCommand(child, str); } } /// Gets the current framework directory wxString ctConfigToolDoc::GetFrameworkDir(bool makeUnix) { wxString path = wxGetApp().GetSettings().m_frameworkDir; if (wxGetApp().GetSettings().m_useEnvironmentVariable) { // Should probably allow other variables // to be used, and maybe expand variables within m_frameworkDir path = wxGetenv(wxT("WXWIN")); #ifdef __WXMSW__ if (makeUnix) path.Replace(wxT("\\"), wxT("/")); #endif } return path; } /* * Implements a document editing command. */ ctConfigCommand::ctConfigCommand(const wxString& name, int cmdId, ctConfigItem* activeState, ctConfigItem* savedState, ctConfigItem* parent, ctConfigItem* insertBefore, bool ignoreFirstTime): wxCommand(TRUE, name) { m_activeState = activeState; m_savedState = savedState; m_ignoreThis = ignoreFirstTime; m_cmdId = cmdId; m_properties = NULL; m_parent = parent; m_insertBefore = insertBefore; } ctConfigCommand::ctConfigCommand(const wxString& name, int cmdId, ctConfigItem* activeState, ctProperties* properties, bool ignoreFirstTime): wxCommand(TRUE, name) { m_activeState = activeState; m_savedState = NULL; m_properties = properties; m_ignoreThis = ignoreFirstTime; m_cmdId = cmdId; m_properties = properties; m_parent = NULL; m_insertBefore = NULL; } ctConfigCommand::~ctConfigCommand() { if (m_savedState) delete m_savedState; if (m_properties) delete m_properties; } bool ctConfigCommand::Do() { return DoAndUndo(TRUE); } bool ctConfigCommand::Undo() { return DoAndUndo(FALSE); } // Combine Do and Undo into one bool ctConfigCommand::DoAndUndo(bool doCmd) { switch (m_cmdId) { case ctCMD_CUT: { if (doCmd) { wxASSERT(m_savedState == NULL); wxASSERT(m_activeState != NULL); ctConfigItem* newItem = m_activeState->DeepClone(); ctConfigToolDoc* doc = m_activeState->GetDocument(); // This will delete the old clipboard contents, if any. doc->SetClipboardItem(newItem); m_parent = m_activeState->GetParent(); m_insertBefore = m_activeState->FindNextSibling(); m_activeState->Detach(); m_savedState = m_activeState; m_activeState = NULL; m_savedState->GetDocument()->Modify(TRUE); ctConfigToolView* view = (ctConfigToolView*) m_savedState->GetDocument()->GetFirstView(); view->OnChangeFilename(); } else { wxASSERT(m_savedState != NULL); wxASSERT(m_activeState == NULL); 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); m_activeState = m_savedState; m_savedState = NULL; m_parent = NULL; m_insertBefore = NULL; view->OnChangeFilename(); } break; } case ctCMD_PASTE: { if (doCmd) { wxASSERT(m_savedState != NULL); wxASSERT(m_activeState == NULL); 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); wxGetApp().GetMainFrame()->GetConfigTreeCtrl()->SelectItem(m_savedState->GetTreeItemId()); m_activeState = m_savedState; m_savedState = NULL; view->OnChangeFilename(); } else { wxASSERT(m_savedState == NULL); wxASSERT(m_activeState != NULL); m_activeState->GetDocument()->Modify(TRUE); ctConfigToolView* view = (ctConfigToolView*) m_activeState->GetDocument()->GetFirstView(); m_activeState->Detach(); m_savedState = m_activeState; m_activeState = NULL; view->OnChangeFilename(); } break; } case ctCMD_NEW_ELEMENT: { if (doCmd) { wxASSERT(m_savedState != NULL); wxASSERT(m_activeState == NULL); 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); wxGetApp().GetMainFrame()->GetConfigTreeCtrl()->SelectItem(m_savedState->GetTreeItemId()); m_activeState = m_savedState; m_savedState = NULL; } else { wxASSERT(m_savedState == NULL); wxASSERT(m_activeState != NULL); m_activeState->GetDocument()->Modify(TRUE); m_activeState->Detach(); m_savedState = m_activeState; m_activeState = NULL; } break; } case ctCMD_APPLY_PROPERTY: { wxASSERT(m_properties != NULL); wxASSERT(m_activeState != NULL); // Don't update the properties editor first time // around since it will be done one property at a time // initially (and no property editor update required) if (!m_ignoreThis) { // Just swap the saved and current properties. ctProperties propsTemp = m_activeState->GetProperties() ; m_activeState->GetProperties() = (* m_properties); (* m_properties) = propsTemp; // Apply only those that need applying // (those properties in activeState that are not in propsTemp) wxNode* node = m_activeState->GetProperties().GetList().GetFirst(); while (node) { ctProperty* prop = (ctProperty*) node->GetData(); ctProperty* otherProp = propsTemp.FindProperty(prop->GetName()); if (otherProp && ((*prop) != (*otherProp))) { m_activeState->ApplyProperty(prop, otherProp->GetVariant()); } node = node->GetNext(); } m_activeState->GetDocument()->Modify(TRUE); ctConfigToolView* view = (ctConfigToolView*) m_activeState->GetDocument()->GetFirstView(); if (view) { ctConfigToolHint hint(NULL, ctValueChanged); m_activeState->GetDocument()->UpdateAllViews (NULL, & hint); } } m_ignoreThis = FALSE; break; } } return TRUE; }