]> git.saurik.com Git - wxWidgets.git/blob - utils/configtool/src/configtooldoc.cpp
Updated version to 2.5.5
[wxWidgets.git] / utils / configtool / src / configtooldoc.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: configtooldoc.h
3 // Purpose: Document class
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 2003-06-04
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence:
10 /////////////////////////////////////////////////////////////////////////////
11
12 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
13 #pragma implementation "configtooldoc.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx/wx.h".
17 #include "wx/wxprec.h"
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #ifndef WX_PRECOMP
24
25 #include "wx/process.h"
26 #include "wx/mimetype.h"
27 #include "wx/process.h"
28
29 #endif
30
31 #include "wx/textfile.h"
32 #include "wx/wfstream.h"
33 #include "wx/config.h"
34 #include "configtooldoc.h"
35 #include "configtoolview.h"
36 #include "configtree.h"
37 #include "mainframe.h"
38 #include "utils.h"
39 #include "wxconfigtool.h"
40 #include "htmlparser.h"
41
42 IMPLEMENT_DYNAMIC_CLASS(ctConfigToolDoc, wxDocument)
43
44 // Ctor
45 ctConfigToolDoc::ctConfigToolDoc()
46 {
47 m_topItem = NULL;
48 m_clipboardItem = NULL;
49 }
50
51 // Dtor
52 ctConfigToolDoc::~ctConfigToolDoc()
53 {
54 DeleteItems();
55 ClearClipboard();
56 if (GetCommandProcessor())
57 GetCommandProcessor()->SetEditMenu(NULL);
58 }
59
60 // Delete all the items not already deleted
61 void ctConfigToolDoc::DeleteItems()
62 {
63 if (m_topItem)
64 delete m_topItem;
65 m_topItem = NULL;
66 }
67
68 /// Clears the clipboard item.
69 void ctConfigToolDoc::ClearClipboard()
70 {
71 if (m_clipboardItem)
72 delete m_clipboardItem;
73 m_clipboardItem = NULL;
74 }
75
76 /// Sets the clipboard item.
77 void ctConfigToolDoc::SetClipboardItem(ctConfigItem* item)
78 {
79 if (m_clipboardItem)
80 delete m_clipboardItem;
81 m_clipboardItem = item;
82 }
83
84
85 // Closes and clears the document
86 bool ctConfigToolDoc::OnCloseDocument()
87 {
88 if (wxDocument::OnCloseDocument())
89 {
90 ctConfigToolHint hint(NULL, ctClear);
91 UpdateAllViews (NULL, & hint);
92
93 DeleteItems();
94 return true;
95 }
96 else
97 {
98 return false;
99 }
100 }
101
102 // Saves the doc
103 bool ctConfigToolDoc::Save()
104 {
105 if (!IsModified() && m_savedYet) return true;
106
107 bool ret = (m_documentFile == wxT("") || !m_savedYet) ?
108 SaveAs() :
109 OnSaveDocument(m_documentFile);
110 if ( ret )
111 SetDocumentSaved(true);
112 return ret;
113 }
114
115 // Create the document
116 bool ctConfigToolDoc::OnCreate(const wxString& path, long flags)
117 {
118 GetCommandProcessor()->SetEditMenu(wxGetApp().GetMainFrame()->GetEditMenu());
119 GetCommandProcessor()->Initialize();
120 GetCommandProcessor()->ClearCommands();
121
122 // wxGetApp().m_currentDoc = this;
123
124 if (flags & wxDOC_NEW)
125 {
126 ctConfigItem* rootItem = new ctConfigItem(NULL, ctTypeGroup, _T("Configuration"));
127 //rootItem->InitProperties();
128 rootItem->GetProperties().AddProperty(
129 new ctProperty(
130 wxT("The item description."),
131 wxVariant(wxT(""), wxT("description")),
132 wxT("multiline")));
133
134 rootItem->SetPropertyString(_T("description"),
135 _T("<B>This is the top-level configuration item.</B>"));
136
137
138 SetTopItem(rootItem);
139
140 Modify(false);
141 SetDocumentSaved(false);
142
143 wxString rootName(wxT("untitled"));
144 wxStripExtension(rootName);
145 SetFilename(wxGetApp().GetSettings().GenerateFilename(rootName));
146 }
147
148 // Creates the view, so do any view updating after this
149 bool success = wxDocument::OnCreate(path, flags);
150
151 if (success)
152 {
153 if (flags & wxDOC_NEW)
154 {
155 wxBusyCursor wait;
156
157 ctConfigToolHint hint(NULL, ctInitialUpdate);
158 UpdateAllViews (NULL, & hint);
159
160 SetFilename(GetFilename(), true);
161 }
162 }
163 return success;
164 }
165
166 // Save the document
167 bool ctConfigToolDoc::OnSaveDocument(const wxString& filename)
168 {
169 wxBusyCursor cursor;
170
171 const wxString strOldPath(GetFilename());
172
173 // Do some backing up first
174
175 // This is the backup filename
176 wxString backupFilename(filename);
177 backupFilename += wxT(".bak");
178
179 // This is the temporary copy of the backup
180 wxString tempFilename(filename);
181 tempFilename += wxT(".tmp");
182 if (wxFileExists(tempFilename))
183 wxRemoveFile(tempFilename);
184
185 bool leaveBackup = true;
186
187 bool saved = DoSave(tempFilename);
188
189 if (saved)
190 {
191 // Remove the old .bak file
192 if (wxFileExists(backupFilename))
193 {
194 wxRemoveFile(backupFilename);
195 }
196
197 // Copy the old file to the .bak
198
199 if (leaveBackup)
200 {
201 if (wxFileExists(filename))
202 {
203 if (!wxRenameFile(filename, backupFilename))
204 {
205 wxCopyFile(filename, backupFilename);
206 wxRemoveFile(filename);
207 }
208 }
209 }
210 else
211 {
212 if (wxFileExists(filename))
213 wxRemoveFile(filename);
214 }
215
216 // Finally, copy the temporary file to the proper filename
217 if (!wxRenameFile(tempFilename, filename))
218 {
219 wxCopyFile(tempFilename, filename);
220 wxRemoveFile(tempFilename);
221 }
222
223 Modify(false);
224 ((ctConfigToolView*)GetFirstView())->OnChangeFilename();
225 SetDocumentSaved(true);
226 SetFilename(filename);
227 wxGetApp().GetSettings().m_lastFilename = filename;
228 } else
229 {
230 SetFilename(strOldPath);
231 }
232 wxGetApp().GetMainFrame()->UpdateFrameTitle();
233 return saved;
234 }
235
236 // Open the document
237 bool ctConfigToolDoc::OnOpenDocument(const wxString& filename)
238 {
239 wxBusyCursor cursor;
240
241 bool opened = DoOpen(filename);
242
243 if (opened)
244 {
245 SetFilename(filename);
246 wxGetApp().GetSettings().m_lastFilename = filename;
247
248 ((ctConfigToolView*)GetFirstView())->OnChangeFilename();
249
250 RefreshDependencies();
251
252 // ctConfigToolHint hint(NULL, ctFilenameChanged);
253 ctConfigToolHint hint(NULL, ctInitialUpdate);
254 UpdateAllViews (NULL, & hint);
255 }
256
257 SetDocumentSaved(true); // Necessary or it will pop up the Save As dialog
258
259 return opened;
260 }
261
262 /// Save the settings file
263 bool ctConfigToolDoc::DoSave(const wxString& filename)
264 {
265 wxFileOutputStream stream(filename);
266 if (!stream.Ok())
267 return false;
268
269 stream << wxT("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
270 stream << wxT("<settings xmlns=\"http://www.wxwidgets.org/wxs\" version=\"2.5.0.1\">");
271
272 DoSave(m_topItem, stream, 1);
273
274 stream << wxT("\n</settings>\n");
275
276 return true;
277 }
278
279 inline static void OutputIndentation(wxOutputStream& stream, int indent)
280 {
281 wxString str = wxT("\n");
282 for (int i = 0; i < indent; i++)
283 str << wxT(' ') << wxT(' ');
284 stream << str ;
285 }
286
287 /// Recursive helper function for file saving
288 bool ctConfigToolDoc::DoSave(ctConfigItem* item, wxOutputStream& stream, int indent)
289 {
290 OutputIndentation(stream, indent*2);
291
292 wxString name(item->GetName());
293 wxString s;
294 wxString typeStr;
295 if (item->GetType() == ctTypeGroup)
296 typeStr = wxT("group");
297 else if (item->GetType() == ctTypeCheckGroup)
298 typeStr = wxT("check-group");
299 else if (item->GetType() == ctTypeRadioGroup)
300 typeStr = wxT("radio-group");
301 else if (item->GetType() == ctTypeString)
302 typeStr = wxT("string");
303 else if (item->GetType() == ctTypeBoolCheck)
304 typeStr = wxT("bool-check");
305 else if (item->GetType() == ctTypeBoolRadio)
306 typeStr = wxT("bool-radio");
307 else if (item->GetType() == ctTypeInteger)
308 typeStr = wxT("integer");
309 else
310 typeStr = wxT("unknown");
311
312 stream << wxT("<setting type=\"") << typeStr << wxT("\">");
313
314 indent ++;
315
316 OutputIndentation(stream, indent*2);
317 if (item->IsActive())
318 stream << wxT("<active>1</active>");
319 else
320 stream << wxT("<active>0</active>");
321 OutputIndentation(stream, indent*2);
322 if (item->IsEnabled())
323 stream << wxT("<enabled>1</enabled>");
324 else
325 stream << wxT("<enabled>0</enabled>");
326
327 // Output properties
328 wxObjectList::compatibility_iterator node = item->GetProperties().GetList().GetFirst();
329 while (node)
330 {
331 ctProperty* prop = (ctProperty*) node->GetData();
332 OutputIndentation(stream, indent*2);
333 stream << wxT("<") << prop->GetName() ;
334
335 if (prop->IsCustom())
336 {
337 stream << wxT(" custom=\"true\"");
338 stream << wxT(" type=\"") << prop->GetVariant().GetType() << wxT("\"");
339 stream << wxT(" editor-type=\"") << prop->GetEditorType() << wxT("\"");
340 stream << wxT(" description=\"") << prop->GetDescription() << wxT("\"");
341 if (prop->GetChoices().GetCount() > 0)
342 {
343 wxString choices;
344 ctConfigItem::ArrayToString(prop->GetChoices(), choices);
345 stream << wxT(" choices=\"") << choices << wxT("\"");
346 }
347 }
348
349 stream << wxT(">");
350
351 stream << ctEscapeHTMLCharacters(prop->GetVariant().GetString()) ;
352 stream << wxT("</") << prop->GetName() << wxT(">");
353
354 node = node->GetNext();
355 }
356
357 // Output children
358 node = item->GetChildren().GetFirst();
359 while (node)
360 {
361 ctConfigItem* child = (ctConfigItem*) node->GetData();
362 DoSave(child, stream, indent);
363
364 node = node->GetNext();
365 }
366
367 indent --;
368
369 OutputIndentation(stream, indent*2);
370 stream << wxT("</setting>");
371
372 return true;
373 }
374
375 /// Open the settings file
376 bool ctConfigToolDoc::DoOpen(const wxString& filename)
377 {
378 wxSimpleHtmlParser parser;
379 if (parser.ParseFile(filename))
380 {
381 ctConfigToolHint hint(NULL, ctClear);
382 UpdateAllViews (NULL, & hint);
383 m_topItem = NULL;
384
385 if (parser.GetTopLevelTag()->GetChildren())
386 {
387 wxSimpleHtmlTag* settingsTag = parser.GetTopLevelTag()->GetChildren()->FindTag(wxT("settings"));
388 if (settingsTag && settingsTag->GetChildren())
389 {
390 wxSimpleHtmlTag* firstSettingTag = settingsTag->GetChildren();
391 if (firstSettingTag)
392 DoOpen(firstSettingTag, NULL);
393 return true;
394 }
395 return true;
396 }
397 }
398 return false;
399 }
400
401 static bool GetHtmlBoolValue(const wxString& value)
402 {
403 if (value == wxT("true") || value == wxT("TRUE") || value == wxT("1"))
404 return true;
405 else
406 return false;
407 }
408
409 static int GetHtmlIntegerValue(const wxString& value)
410 {
411 return wxAtoi(value);
412 }
413
414 static double GetHtmlDoubleValue(const wxString& value)
415 {
416 return wxAtof(value);
417 }
418
419 bool ctConfigToolDoc::DoOpen(wxSimpleHtmlTag* tag, ctConfigItem* parent)
420 {
421 ctConfigItem* newItem = NULL;
422 if (tag->NameIs(wxT("setting")))
423 {
424 wxSimpleHtmlAttribute* attr = tag->FindAttribute(wxT("type"));
425 if (attr)
426 {
427 ctConfigType type = ctTypeUnknown;
428 wxString typeStr(attr->GetValue());
429 if (typeStr == wxT("group"))
430 type = ctTypeGroup;
431 else if (typeStr == wxT("option-group") || typeStr == wxT("check-group"))
432 type = ctTypeCheckGroup;
433 else if (typeStr == wxT("radio-group"))
434 type = ctTypeRadioGroup;
435 else if (typeStr == wxT("bool-check"))
436 type = ctTypeBoolCheck;
437 else if (typeStr == wxT("bool-radio"))
438 type = ctTypeBoolRadio;
439 else if (typeStr == wxT("string"))
440 type = ctTypeString;
441 else if (typeStr == wxT("integer"))
442 type = ctTypeInteger;
443 else
444 {
445 wxLogError(wxT("Unknown type %s"), (const wxChar*) typeStr);
446 }
447 if (type != ctTypeUnknown)
448 {
449 newItem = new ctConfigItem(parent, type, wxT(""));
450 newItem->InitProperties();
451 if (!parent)
452 SetTopItem(newItem);
453 }
454 }
455 }
456 wxSimpleHtmlTag* childTag = tag->GetChildren();
457
458 while (childTag)
459 {
460 if (childTag->GetType() == wxSimpleHtmlTag_Open)
461 {
462 if (childTag->GetName() == wxT("setting"))
463 {
464 DoOpen(childTag, newItem);
465 }
466 else if (childTag->GetName() == wxT("name"))
467 {
468 if (newItem)
469 {
470 wxString name(childTag->GetNext()->GetTagText());
471 newItem->SetName(name);
472 }
473 }
474 else if (childTag->GetName() == wxT("active"))
475 {
476 if (newItem)
477 newItem->SetActive(GetHtmlBoolValue(childTag->GetNext()->GetTagText()));
478 }
479 else if (childTag->GetName() == wxT("enabled"))
480 {
481 if (newItem)
482 newItem->Enable(GetHtmlBoolValue(childTag->GetNext()->GetTagText()));
483 }
484 else
485 {
486 if (newItem)
487 {
488 ctProperty* prop = newItem->GetProperties().FindProperty(childTag->GetName());
489 if (!prop)
490 {
491 // A custom property, else an obsolete
492 // property that we should ignore.
493 wxString isCustom;
494 if (childTag->GetAttributeValue(isCustom, wxT("custom")) &&
495 isCustom == wxT("true"))
496 {
497 prop = new ctProperty;
498
499 wxString name(childTag->GetName());
500 wxString type(wxT("string"));
501 wxString choices;
502 wxString editorType(wxT("string"));
503 wxString description(wxT(""));
504 childTag->GetAttributeValue(type, wxT("type"));
505 childTag->GetAttributeValue(type, wxT("editor-type"));
506 childTag->GetAttributeValue(type, wxT("choices"));
507 childTag->GetAttributeValue(description, wxT("description"));
508
509 if (type == wxT("bool"))
510 prop->GetVariant() = wxVariant(false, name);
511 else if (type == wxT("double"))
512 prop->GetVariant() = wxVariant((double) 0.0, name);
513 else if (type == wxT("long"))
514 prop->GetVariant() = wxVariant((long) 0, name);
515 else
516 prop->GetVariant() = wxVariant(wxT(""), name);
517 prop->SetDescription(description);
518 prop->SetCustom(true);
519 prop->SetEditorType(editorType);
520 if (!choices.IsEmpty())
521 {
522 wxArrayString arr;
523 ctConfigItem::StringToArray(choices, arr);
524 prop->SetChoices(arr);
525 }
526 newItem->GetProperties().AddProperty(prop);
527 }
528 }
529 if (prop)
530 {
531 if (prop->GetVariant().GetType() == wxT("string"))
532 prop->GetVariant() = childTag->GetNext()->GetTagText();
533 else if (prop->GetVariant().GetType() == wxT("long"))
534 prop->GetVariant() = (long) GetHtmlIntegerValue(childTag->GetNext()->GetTagText());
535 else if (prop->GetVariant().GetType() == wxT("bool"))
536 prop->GetVariant() = GetHtmlBoolValue(childTag->GetNext()->GetTagText());
537 else if (prop->GetVariant().GetType() == wxT("double"))
538 prop->GetVariant() = (double) GetHtmlDoubleValue(childTag->GetNext()->GetTagText());
539 }
540 }
541 }
542 }
543 childTag = childTag->GetNext();
544 }
545 return true;
546 }
547
548 /// Clear dependencies
549 void ctConfigToolDoc::ClearDependencies(ctConfigItem* item)
550 {
551 if (!item) {
552 item = GetTopItem();
553 if (!item)
554 return;
555 }
556
557 item->GetDependents().Clear();
558 for ( wxObjectList::compatibility_iterator node = item->GetChildren().GetFirst(); node; node = node->GetNext() )
559 {
560 ctConfigItem* child = (ctConfigItem*) node->GetData();
561 ClearDependencies(child);
562 }
563 }
564
565 /// Refresh dependencies
566 void ctConfigToolDoc::RefreshDependencies()
567 {
568 ClearDependencies(GetTopItem());
569 RefreshDependencies(GetTopItem());
570 }
571
572 /// Refresh dependencies
573 void ctConfigToolDoc::RefreshDependencies(ctConfigItem* item)
574 {
575 if (item==NULL)
576 return;
577
578 wxArrayString requiresArr;
579 wxString requires = item->GetPropertyString(wxT("requires"));
580 wxString precludes = item->GetPropertyString(wxT("precludes"));
581 wxString enabledIf = item->GetPropertyString(wxT("enabled-if"));
582 wxString enabledIfNot = item->GetPropertyString(wxT("enabled-if-not"));
583 wxString indeterminateIf = item->GetPropertyString(wxT("indeterminate-if"));
584 wxString context = item->GetPropertyString(wxT("context"));
585
586 if (!requires.IsEmpty())
587 item->StringToArray(requires, requiresArr);
588
589 if (!precludes.IsEmpty())
590 item->StringToArray(precludes, requiresArr);
591
592 if (!enabledIfNot.IsEmpty())
593 item->StringToArray(enabledIfNot, requiresArr);
594
595 if (!enabledIf.IsEmpty())
596 item->StringToArray(enabledIf, requiresArr);
597
598 if (!indeterminateIf.IsEmpty())
599 item->StringToArray(indeterminateIf, requiresArr);
600
601 // Add the parent to the list of dependencies, if the
602 // parent is a check or radio group.
603 ctConfigItem* parent = item->GetParent();
604 if (parent &&
605 (parent->GetType() == ctTypeCheckGroup ||
606 parent->GetType() == ctTypeRadioGroup))
607 requiresArr.Add(parent->GetName());
608
609 // Also look in 'context' since these items
610 // are another kind of dependency (switching to
611 // a different platform may cause the dependencies
612 // to be evaluated differently).
613 if (!context.IsEmpty())
614 item->StringToArray(context, requiresArr);
615
616 size_t i;
617 for (i = 0; i < requiresArr.GetCount(); i++)
618 {
619 wxString itemName(requiresArr[i]);
620 ctConfigItem* otherItem = GetTopItem()->FindItem(itemName);
621 if (otherItem && !otherItem->GetDependents().Member(item))
622 {
623 otherItem->GetDependents().Append(item);
624 }
625 }
626 for ( wxObjectList::compatibility_iterator node = item->GetChildren().GetFirst(); node; node = node->GetNext() )
627 {
628 ctConfigItem* child = (ctConfigItem*) node->GetData();
629 RefreshDependencies(child);
630 }
631 }
632
633 /// Generate the text of a setup.h
634 wxString ctConfigToolDoc::GenerateSetup()
635 {
636 wxString str;
637 str << wxT("/*\n * setup.h\n * Generated by wxConfigTool\n *\n */\n\n");
638
639 GenerateSetup(GetTopItem(), str);
640
641 return str;
642 }
643
644 /// Helper function
645 void ctConfigToolDoc::GenerateSetup(ctConfigItem* item, wxString& str)
646 {
647 // Generate the setup.h entries for this item
648 wxString name = item->GetName();
649
650 // We don't process the platform choice
651 if (item->GetName() == wxT("Target"))
652 return;
653
654 if (item->IsInActiveContext() &&
655 (item->GetType() == ctTypeCheckGroup ||
656 item->GetType() == ctTypeRadioGroup ||
657 item->GetType() == ctTypeBoolCheck ||
658 item->GetType() == ctTypeBoolRadio))
659 {
660 // TODO: write description
661 wxString name = item->GetName();
662 if (name.Left(6) == wxT("wxUSE_") ||
663 name == wxT("REMOVE_UNUSED_ARG") || // Hack alert: change to wxUSE_UNUSED_ARG_REMOVAL
664 name.Find(wxT("COMPATIBILITY")) != wxNOT_FOUND)
665 {
666 str << wxT("#define ") << name ;
667 if (item->IsEnabled())
668 str << wxT(" 1");
669 else
670 str << wxT(" 0");
671 str << wxT("\n\n");
672 }
673 }
674
675 for ( wxObjectList::compatibility_iterator node = item->GetChildren().GetFirst(); node; node = node->GetNext() )
676 {
677 ctConfigItem* child = (ctConfigItem*) node->GetData();
678 GenerateSetup(child, str);
679 }
680 }
681
682
683 /// Generate a configure command
684 wxString ctConfigToolDoc::GenerateConfigureCommand()
685 {
686 wxString str;
687 str << wxT("# configurewx\n# Generated by wxConfigTool\n\n");
688
689 wxString path = GetFrameworkDir(true);
690 bool makeUnix = true;
691 if (!path.IsEmpty())
692 {
693 if (makeUnix)
694 path += wxT("/");
695 else
696 path += wxFILE_SEP_PATH ;
697 }
698
699 str << path << wxT("configure");
700
701 // Find the target to use
702 ctConfigItem* platformsFolder = GetTopItem()->FindItem(wxT("Target"));
703 if (platformsFolder)
704 {
705 for ( wxObjectList::compatibility_iterator node = platformsFolder->GetChildren().GetFirst(); node; node = node->GetNext() )
706 {
707 ctConfigItem* child = (ctConfigItem*) node->GetData();
708 if (child->GetType() == ctTypeBoolRadio && child->IsEnabled())
709 {
710 wxString configureCommand = child->GetPropertyString(wxT("configure-command"));
711 if (!configureCommand.IsEmpty())
712 str << wxT(" ") << configureCommand;
713 }
714 }
715 }
716
717 GenerateConfigureCommand(GetTopItem(), str);
718 return str;
719 }
720
721 /// Helper function
722 void ctConfigToolDoc::GenerateConfigureCommand(ctConfigItem* item, wxString& str)
723 {
724 // We don't process the platform group, since we've
725 // already done so.
726 if (item->GetName() == wxT("Target"))
727 return;
728
729 if (item->IsInActiveContext() &&
730 (item->GetType() == ctTypeCheckGroup ||
731 item->GetType() == ctTypeRadioGroup ||
732 item->GetType() == ctTypeBoolCheck ||
733 item->GetType() == ctTypeBoolRadio))
734 {
735 wxString name = item->GetName();
736 wxString configureCommand = item->GetPropertyString(wxT("configure-command"));
737 if (!configureCommand.IsEmpty())
738 {
739 if (!item->IsEnabled())
740 {
741 // Replace 'enable' with 'disable' if this
742 // option is off.
743 configureCommand.Replace(wxT("--enable-"), wxT("--disable-"));
744 configureCommand.Replace(wxT("--with-"), wxT("--without-"));
745 }
746 ctProperty* prop = item->GetProperties().FindProperty(wxT("builtin"));
747 if (prop && prop->GetVariant().GetType() == wxT("bool"))
748 {
749 bool builtin = prop->GetVariant().GetBool();
750 str << wxT(" ") << configureCommand;
751 if (builtin)
752 str << wxT("=builtin");
753 else
754 str << wxT("=sys");
755 }
756 else
757 {
758 ctProperty* prop = item->GetProperties().FindProperty(wxT("value"));
759 if (prop && prop->GetVariant().GetType() == wxT("string"))
760 {
761 wxString val = prop->GetVariant().GetString();
762 if (item->IsEnabled() && !val.IsEmpty())
763 {
764 str << wxT(" ") << configureCommand;
765 str << wxT("=\"") << val << wxT("\"");
766 }
767 // If the string is empty, ignore this parameter,
768 // since it's obviously intended to be supplied
769 // only if there's a string to use and it's enabled.
770 }
771 else
772 {
773 str << wxT(" ") << configureCommand;
774 }
775 }
776 }
777 }
778
779 for ( wxObjectList::compatibility_iterator node = item->GetChildren().GetFirst(); node; node = node->GetNext() )
780 {
781 ctConfigItem* child = (ctConfigItem*) node->GetData();
782 GenerateConfigureCommand(child, str);
783 }
784 }
785
786 /// Gets the current framework directory
787 wxString ctConfigToolDoc::GetFrameworkDir(bool makeUnix)
788 {
789 wxString path = wxGetApp().GetSettings().m_frameworkDir;
790 if (wxGetApp().GetSettings().m_useEnvironmentVariable)
791 {
792 // Should probably allow other variables
793 // to be used, and maybe expand variables within m_frameworkDir
794 wxString pathEnv(wxGetenv(wxT("WXWIN")));
795 path = pathEnv;
796 #ifdef __WXMSW__
797 if (makeUnix)
798 path.Replace(wxT("\\"), wxT("/"));
799 #endif
800 }
801 return path;
802 }
803
804 /// Finds the next item in the tree
805 ctConfigItem* ctConfigToolDoc::FindNextItem(ctConfigItem* item, bool wrap)
806 {
807 if (!item)
808 return GetTopItem();
809
810 // First, try to find the first child
811 if (item->GetChildCount() > 0)
812 {
813 return item->GetChild(0);
814 }
815 else
816 {
817 ctConfigItem* p = item;
818 while (p)
819 {
820 ctConfigItem* toFind = FindNextSibling(p);
821 if (toFind)
822 return toFind;
823 p = p->GetParent();
824 }
825 }
826
827 // Finally, wrap around to the root.
828 if (wrap)
829 return GetTopItem();
830 else
831 return NULL;
832 }
833
834 /// Finds the next sibling in the tree
835 ctConfigItem* ctConfigToolDoc::FindNextSibling(ctConfigItem* item)
836 {
837 if (item->GetParent())
838 {
839 wxObjectList::compatibility_iterator node = item->GetParent()->GetChildren().Member(item);
840 if (node && node->GetNext())
841 {
842 ctConfigItem* nextItem = (ctConfigItem*) node->GetNext()->GetData();
843 return nextItem;
844 }
845 }
846 return NULL;
847 }
848
849
850 /*
851 * Implements a document editing command.
852 */
853
854 ctConfigCommand::ctConfigCommand(const wxString& name, int cmdId,
855 ctConfigItem* activeState, ctConfigItem* savedState,
856 ctConfigItem* parent, ctConfigItem* insertBefore,
857 bool ignoreFirstTime): wxCommand(true, name)
858 {
859 m_activeState = activeState;
860 m_savedState = savedState;
861 m_ignoreThis = ignoreFirstTime;
862 m_cmdId = cmdId;
863 m_properties = NULL;
864 m_parent = parent;
865 m_insertBefore = insertBefore;
866 }
867
868 ctConfigCommand::ctConfigCommand(const wxString& name, int cmdId,
869 ctConfigItem* activeState, ctProperties* properties,
870 bool ignoreFirstTime): wxCommand(true, name)
871 {
872 m_activeState = activeState;
873 m_savedState = NULL;
874 m_properties = properties;
875 m_ignoreThis = ignoreFirstTime;
876 m_cmdId = cmdId;
877 m_properties = properties;
878 m_parent = NULL;
879 m_insertBefore = NULL;
880 }
881
882 ctConfigCommand::~ctConfigCommand()
883 {
884 if (m_savedState)
885 delete m_savedState;
886 if (m_properties)
887 delete m_properties;
888 }
889
890 bool ctConfigCommand::Do()
891 {
892 return DoAndUndo(true);
893 }
894
895 bool ctConfigCommand::Undo()
896 {
897 return DoAndUndo(false);
898 }
899
900 // Combine Do and Undo into one
901 bool ctConfigCommand::DoAndUndo(bool doCmd)
902 {
903 switch (m_cmdId)
904 {
905 case ctCMD_CUT:
906 {
907 if (doCmd)
908 {
909 wxASSERT(m_savedState == NULL);
910 wxASSERT(m_activeState != NULL);
911
912 ctConfigItem* newItem = m_activeState->DeepClone();
913 ctConfigToolDoc* doc = m_activeState->GetDocument();
914
915 // This will delete the old clipboard contents, if any.
916 doc->SetClipboardItem(newItem);
917
918 m_parent = m_activeState->GetParent();
919 m_insertBefore = m_activeState->FindNextSibling();
920
921 m_activeState->Detach();
922 m_savedState = m_activeState;
923 m_activeState = NULL;
924
925 m_savedState->GetDocument()->Modify(true);
926 ctConfigToolView* view = (ctConfigToolView*) m_savedState->GetDocument()->GetFirstView();
927 view->OnChangeFilename();
928 }
929 else
930 {
931 wxASSERT(m_savedState != NULL);
932 wxASSERT(m_activeState == NULL);
933
934 m_savedState->GetDocument()->Modify(true);
935 m_savedState->Attach(m_parent, m_insertBefore);
936 ctConfigToolView* view = (ctConfigToolView*) m_savedState->GetDocument()->GetFirstView();
937 view->AddItems(wxGetApp().GetMainFrame()->GetConfigTreeCtrl(), m_savedState);
938 m_activeState = m_savedState;
939 m_savedState = NULL;
940 m_parent = NULL;
941 m_insertBefore = NULL;
942 view->OnChangeFilename();
943 }
944 break;
945 }
946 case ctCMD_PASTE:
947 {
948 if (doCmd)
949 {
950 wxASSERT(m_savedState != NULL);
951 wxASSERT(m_activeState == NULL);
952
953 m_savedState->GetDocument()->Modify(true);
954 m_savedState->Attach(m_parent, m_insertBefore);
955 ctConfigToolView* view = (ctConfigToolView*) m_savedState->GetDocument()->GetFirstView();
956 view->AddItems(wxGetApp().GetMainFrame()->GetConfigTreeCtrl(), m_savedState);
957 wxGetApp().GetMainFrame()->GetConfigTreeCtrl()->SelectItem(m_savedState->GetTreeItemId());
958 m_activeState = m_savedState;
959 m_savedState = NULL;
960 view->OnChangeFilename();
961 }
962 else
963 {
964 wxASSERT(m_savedState == NULL);
965 wxASSERT(m_activeState != NULL);
966
967 m_activeState->GetDocument()->Modify(true);
968 ctConfigToolView* view = (ctConfigToolView*) m_activeState->GetDocument()->GetFirstView();
969 m_activeState->Detach();
970 m_savedState = m_activeState;
971 m_activeState = NULL;
972 view->OnChangeFilename();
973 }
974 break;
975 }
976 case ctCMD_NEW_ELEMENT:
977 {
978 if (doCmd)
979 {
980 wxASSERT(m_savedState != NULL);
981 wxASSERT(m_activeState == NULL);
982
983 m_savedState->GetDocument()->Modify(true);
984 m_savedState->Attach(m_parent, m_insertBefore);
985 ctConfigToolView* view = (ctConfigToolView*) m_savedState->GetDocument()->GetFirstView();
986 view->AddItems(wxGetApp().GetMainFrame()->GetConfigTreeCtrl(), m_savedState);
987 wxGetApp().GetMainFrame()->GetConfigTreeCtrl()->SelectItem(m_savedState->GetTreeItemId());
988
989 m_activeState = m_savedState;
990 m_savedState = NULL;
991 }
992 else
993 {
994 wxASSERT(m_savedState == NULL);
995 wxASSERT(m_activeState != NULL);
996
997 m_activeState->GetDocument()->Modify(true);
998 m_activeState->Detach();
999 m_savedState = m_activeState;
1000 m_activeState = NULL;
1001 }
1002 break;
1003 }
1004 case ctCMD_APPLY_PROPERTY:
1005 {
1006 wxASSERT(m_properties != NULL);
1007 wxASSERT(m_activeState != NULL);
1008
1009 // Don't update the properties editor first time
1010 // around since it will be done one property at a time
1011 // initially (and no property editor update required)
1012 if (!m_ignoreThis)
1013 {
1014 // Just swap the saved and current properties.
1015 ctProperties propsTemp = m_activeState->GetProperties() ;
1016 m_activeState->GetProperties() = (* m_properties);
1017 (* m_properties) = propsTemp;
1018
1019 // Apply only those that need applying
1020 // (those properties in activeState that are not in propsTemp)
1021 wxObjectList::compatibility_iterator node = m_activeState->GetProperties().GetList().GetFirst();
1022 while (node)
1023 {
1024 ctProperty* prop = (ctProperty*) node->GetData();
1025 ctProperty* otherProp = propsTemp.FindProperty(prop->GetName());
1026 if (otherProp && ((*prop) != (*otherProp)))
1027 {
1028 m_activeState->ApplyProperty(prop, otherProp->GetVariant());
1029 }
1030 node = node->GetNext();
1031 }
1032 m_activeState->GetDocument()->Modify(true);
1033 ctConfigToolView* view = (ctConfigToolView*) m_activeState->GetDocument()->GetFirstView();
1034 if (view)
1035 {
1036 ctConfigToolHint hint(NULL, ctValueChanged);
1037 m_activeState->GetDocument()->UpdateAllViews (NULL, & hint);
1038 }
1039 }
1040 m_ignoreThis = false;
1041
1042 break;
1043 }
1044 }
1045 return true;
1046 }
1047
1048 IMPLEMENT_CLASS(ctConfiguration, wxObject)
1049
1050 ctConfiguration::ctConfiguration()
1051 {
1052 m_treeItemId = wxTreeItemId();
1053 m_parent = NULL;
1054 m_topItem = NULL;
1055 }
1056
1057 ctConfiguration::ctConfiguration(ctConfiguration* parent, const wxString& name)
1058 {
1059 m_treeItemId = wxTreeItemId();
1060 SetName(name);
1061 m_parent = parent;
1062 if (parent)
1063 parent->AddChild(this);
1064 }
1065
1066 ctConfiguration::~ctConfiguration()
1067 {
1068 /*
1069 ctConfigTreeCtrl* treeCtrl = wxGetApp().GetMainFrame()->GetConfigTreeCtrl();
1070 if (m_treeItemId.IsOk() && treeCtrl)
1071 {
1072 ctTreeItemData* data = (ctTreeItemData*) treeCtrl->GetItemData(m_treeItemId);
1073 if (data)
1074 data->SetConfigItem(NULL);
1075 }
1076 if (GetParent())
1077 GetParent()->RemoveChild(this);
1078 else
1079 {
1080 if (wxGetApp().GetMainFrame()->GetDocument() &&
1081 wxGetApp().GetMainFrame()->GetDocument()->GetTopItem() == this)
1082 wxGetApp().GetMainFrame()->GetDocument()->SetTopItem(NULL);
1083 }
1084 */
1085
1086 Clear();
1087 }
1088
1089 /// Assignment operator.
1090 void ctConfiguration::operator= (const ctConfiguration& configuration)
1091 {
1092 m_name = configuration.m_name;
1093 m_description = configuration.m_description;
1094 }
1095
1096 /// Clear children
1097 void ctConfiguration::Clear()
1098 {
1099 wxObjectList::compatibility_iterator node = m_children.GetFirst();
1100 while (node)
1101 {
1102 wxObjectList::compatibility_iterator next = node->GetNext();
1103 ctConfiguration* child = (ctConfiguration*) node->GetData();
1104
1105 // This should delete 'node' too, assuming
1106 // child's m_parent points to 'this'. If not,
1107 // it'll be cleaned up by m_children.Clear().
1108 delete child;
1109
1110 node = next;
1111 }
1112 m_children.Clear();
1113 }
1114
1115 // Get the nth child
1116 ctConfiguration* ctConfiguration::GetChild(int n) const
1117 {
1118 wxASSERT ( n < GetChildCount() && n > -1 );
1119
1120 if ( n < GetChildCount() && n > -1 )
1121 {
1122 ctConfiguration* child = wxDynamicCast(m_children.Item(n)->GetData(), ctConfiguration);
1123 return child;
1124 }
1125 else
1126 return NULL;
1127 }
1128
1129 // Get the child count
1130 int ctConfiguration::GetChildCount() const
1131 {
1132 return m_children.GetCount();
1133 }
1134
1135 /// Add a child
1136 void ctConfiguration::AddChild(ctConfiguration* configuration)
1137 {
1138 m_children.Append(configuration);
1139 configuration->SetParent(this);
1140 }
1141
1142 /// Remove (but don't delete) a child
1143 void ctConfiguration::RemoveChild(ctConfiguration* configuration)
1144 {
1145 m_children.DeleteObject(configuration);
1146 configuration->SetParent(NULL);
1147 }
1148
1149 /// Get the associated document (currently, assumes
1150 /// there's only ever one document active)
1151 ctConfigToolDoc* ctConfiguration::GetDocument()
1152 {
1153 ctConfigToolDoc* doc = wxGetApp().GetMainFrame()->GetDocument();
1154 return doc;
1155 }
1156
1157 /// Find an item in this hierarchy
1158 // TODO: ensure that names are unique, somehow.
1159 ctConfiguration* ctConfiguration::FindConfiguration(const wxString& name)
1160 {
1161 if (GetName() == name)
1162 return this;
1163
1164 for ( wxObjectList::compatibility_iterator node = GetChildren().GetFirst(); node; node = node->GetNext() )
1165 {
1166 ctConfiguration* child = (ctConfiguration*) node->GetData();
1167 ctConfiguration* found = child->FindConfiguration(name);
1168 if (found)
1169 return found;
1170 }
1171 return NULL;
1172 }
1173
1174 /// Find the next sibling
1175 ctConfiguration* ctConfiguration::FindNextSibling()
1176 {
1177 if (!GetParent())
1178 return NULL;
1179 wxObjectList::compatibility_iterator node = GetParent()->GetChildren().Member(this);
1180 if (node && node->GetNext())
1181 {
1182 return (ctConfiguration*) node->GetNext()->GetData();
1183 }
1184 return NULL;
1185 }
1186
1187 /// Find the previous sibling
1188 ctConfiguration* ctConfiguration::FindPreviousSibling()
1189 {
1190 if (!GetParent())
1191 return NULL;
1192 wxObjectList::compatibility_iterator node = GetParent()->GetChildren().Member(this);
1193 if (node && node->GetPrevious())
1194 {
1195 return (ctConfiguration*) node->GetPrevious()->GetData();
1196 }
1197 return NULL;
1198 }
1199
1200 /// Create a clone of this and children
1201 ctConfiguration* ctConfiguration::DeepClone()
1202 {
1203 ctConfiguration* newItem = Clone();
1204
1205 for ( wxObjectList::compatibility_iterator node = GetChildren().GetFirst(); node; node = node->GetNext() )
1206 {
1207 ctConfiguration* child = (ctConfiguration*) node->GetData();
1208 ctConfiguration* newChild = child->DeepClone();
1209 newItem->AddChild(newChild);
1210 }
1211 return newItem;
1212 }
1213
1214 /// Detach: remove from parent, and remove tree items
1215 void ctConfiguration::Detach()
1216 {
1217 // TODO
1218 if (GetParent())
1219 GetParent()->RemoveChild(this);
1220 else
1221 GetDocument()->SetTopItem(NULL);
1222 SetParent(NULL);
1223
1224 /*
1225 wxTreeItemId treeItem = GetTreeItemId();
1226
1227 DetachFromTree();
1228
1229 // Will delete the branch, but not the config items.
1230 wxGetApp().GetMainFrame()->GetConfigTreeCtrl()->Delete(treeItem);
1231 */
1232 }
1233
1234 /// Hide from tree: make sure tree deletions won't delete
1235 /// the config items
1236 void ctConfiguration::DetachFromTree()
1237 {
1238 /*
1239 wxTreeItemId item = GetTreeItemId();
1240
1241 // TODO
1242 ctTreeItemData* data = (ctTreeItemData*) wxGetApp().GetMainFrame()->GetConfigTreeCtrl()->GetItemData(item);
1243 data->SetConfigItem(NULL);
1244 m_treeItemId = wxTreeItemId();
1245
1246 for ( wxNode* node = GetChildren().GetFirst(); node; node = node->GetNext() )
1247 {
1248 ctConfiguration* child = (ctConfiguration*) node->GetData();
1249 child->DetachFromTree();
1250 }
1251 */
1252 }
1253
1254