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