]> git.saurik.com Git - wxWidgets.git/blob - utils/configtool/src/configtooldoc.cpp
3a50aadd83ef14d9a09c171bd674952fdf031946
[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 #ifdef __GNUG__
13 #pragma implementation "configtooldoc.h"
14 #endif
15
16 #include "wx/wx.h"
17
18 #ifdef __BORLANDC__
19 #pragma hdrstop
20 #endif
21
22 #include "wx/config.h"
23 #include "wx/textfile.h"
24 #include "wx/process.h"
25 #include "wx/mimetype.h"
26 #include "wx/process.h"
27 #include "wx/wfstream.h"
28
29 #ifdef __BORLANDC__
30 #pragma hdrstop
31 #endif
32
33 #include "configtooldoc.h"
34 #include "configtoolview.h"
35 #include "configtree.h"
36 #include "mainframe.h"
37 #include "utils.h"
38 #include "wxconfigtool.h"
39 #include "htmlparser.h"
40
41 IMPLEMENT_DYNAMIC_CLASS(ctConfigToolDoc, wxDocument)
42
43 // Ctor
44 ctConfigToolDoc::ctConfigToolDoc()
45 {
46 m_topItem = NULL;
47 m_clipboardItem = NULL;
48 }
49
50 // Dtor
51 ctConfigToolDoc::~ctConfigToolDoc()
52 {
53 DeleteItems();
54 ClearClipboard();
55 if (GetCommandProcessor())
56 GetCommandProcessor()->SetEditMenu(NULL);
57 }
58
59 // Delete all the items not already deleted
60 void ctConfigToolDoc::DeleteItems()
61 {
62 if (m_topItem)
63 delete m_topItem;
64 m_topItem = NULL;
65 }
66
67 /// Clears the clipboard item.
68 void ctConfigToolDoc::ClearClipboard()
69 {
70 if (m_clipboardItem)
71 delete m_clipboardItem;
72 m_clipboardItem = NULL;
73 }
74
75 /// Sets the clipboard item.
76 void ctConfigToolDoc::SetClipboardItem(ctConfigItem* item)
77 {
78 if (m_clipboardItem)
79 delete m_clipboardItem;
80 m_clipboardItem = item;
81 }
82
83
84 // Closes and clears the document
85 bool ctConfigToolDoc::OnCloseDocument()
86 {
87 if (wxDocument::OnCloseDocument())
88 {
89 ctConfigToolHint hint(NULL, ctClear);
90 UpdateAllViews (NULL, & hint);
91
92 DeleteItems();
93 return TRUE;
94 }
95 else
96 {
97 return FALSE;
98 }
99 }
100
101 // Saves the doc
102 bool ctConfigToolDoc::Save()
103 {
104 bool ret = FALSE;
105
106 if (!IsModified() && m_savedYet) return TRUE;
107 if (m_documentFile == wxT("") || !m_savedYet)
108 ret = SaveAs();
109 else
110 ret = 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 stream(filename);
267 if (!stream.Ok())
268 return FALSE;
269
270 stream << wxT("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
271 stream << wxT("<settings xmlns=\"http://www.wxwindows.org/wxs\" version=\"2.5.0.1\">");
272
273 DoSave(m_topItem, stream, 1);
274
275 stream << wxT("\n</settings>\n");
276
277 return TRUE;
278 }
279
280 inline static void OutputIndentation(wxOutputStream& stream, int indent)
281 {
282 wxString str = wxT("\n");
283 for (int i = 0; i < indent; i++)
284 str << wxT(' ') << wxT(' ');
285 stream << str ;
286 }
287
288 /// Recursive helper function for file saving
289 bool ctConfigToolDoc::DoSave(ctConfigItem* item, wxOutputStream& stream, int indent)
290 {
291 OutputIndentation(stream, indent*2);
292
293 wxString name(item->GetName());
294 wxString s;
295 wxString typeStr;
296 if (item->GetType() == ctTypeGroup)
297 typeStr = wxT("group");
298 else if (item->GetType() == ctTypeCheckGroup)
299 typeStr = wxT("check-group");
300 else if (item->GetType() == ctTypeRadioGroup)
301 typeStr = wxT("radio-group");
302 else if (item->GetType() == ctTypeString)
303 typeStr = wxT("string");
304 else if (item->GetType() == ctTypeBoolCheck)
305 typeStr = wxT("bool-check");
306 else if (item->GetType() == ctTypeBoolRadio)
307 typeStr = wxT("bool-radio");
308 else if (item->GetType() == ctTypeInteger)
309 typeStr = wxT("integer");
310 else
311 typeStr = wxT("unknown");
312
313 stream << wxT("<setting type=\"") << typeStr << wxT("\">");
314
315 indent ++;
316
317 OutputIndentation(stream, indent*2);
318 if (item->IsActive())
319 stream << wxT("<active>1</active>");
320 else
321 stream << wxT("<active>0</active>");
322 OutputIndentation(stream, indent*2);
323 if (item->IsEnabled())
324 stream << wxT("<enabled>1</enabled>");
325 else
326 stream << wxT("<enabled>0</enabled>");
327
328 // Output properties
329 wxNode* node = item->GetProperties().GetList().GetFirst();
330 while (node)
331 {
332 ctProperty* prop = (ctProperty*) node->GetData();
333 OutputIndentation(stream, indent*2);
334 stream << wxT("<") << prop->GetName() ;
335
336 if (prop->IsCustom())
337 {
338 stream << wxT(" custom=\"true\"");
339 stream << wxT(" type=\"") << prop->GetVariant().GetType() << wxT("\"");
340 stream << wxT(" editor-type=\"") << prop->GetEditorType() << wxT("\"");
341 stream << wxT(" description=\"") << prop->GetDescription() << wxT("\"");
342 if (prop->GetChoices().GetCount() > 0)
343 {
344 wxString choices;
345 ctConfigItem::ArrayToString(prop->GetChoices(), choices);
346 stream << wxT(" choices=\"") << choices << wxT("\"");
347 }
348 }
349
350 stream << wxT(">");
351
352 stream << ctEscapeHTMLCharacters(prop->GetVariant().GetString()) ;
353 stream << wxT("</") << prop->GetName() << wxT(">");
354
355 node = node->GetNext();
356 }
357
358 // Output children
359 node = item->GetChildren().GetFirst();
360 while (node)
361 {
362 ctConfigItem* child = (ctConfigItem*) node->GetData();
363 DoSave(child, stream, indent);
364
365 node = node->GetNext();
366 }
367
368 indent --;
369
370 OutputIndentation(stream, indent*2);
371 stream << wxT("</setting>");
372
373 return TRUE;
374 }
375
376 /// Open the settings file
377 bool ctConfigToolDoc::DoOpen(const wxString& filename)
378 {
379 wxSimpleHtmlParser parser;
380 if (parser.ParseFile(filename))
381 {
382 ctConfigToolHint hint(NULL, ctClear);
383 UpdateAllViews (NULL, & hint);
384 m_topItem = NULL;
385
386 if (parser.GetTopLevelTag()->GetChildren())
387 {
388 wxSimpleHtmlTag* settingsTag = parser.GetTopLevelTag()->GetChildren()->FindTag(wxT("settings"));
389 if (settingsTag && settingsTag->GetChildren())
390 {
391 wxSimpleHtmlTag* firstSettingTag = settingsTag->GetChildren();
392 if (firstSettingTag)
393 DoOpen(firstSettingTag, NULL);
394 return TRUE;
395 }
396 return TRUE;
397 }
398 }
399 return FALSE;
400 }
401
402 static bool GetHtmlBoolValue(const wxString& value)
403 {
404 if (value == wxT("true") || value == wxT("TRUE") || value == wxT("1"))
405 return TRUE;
406 else
407 return FALSE;
408 }
409
410 static int GetHtmlIntegerValue(const wxString& value)
411 {
412 return wxAtoi(value);
413 }
414
415 static double GetHtmlDoubleValue(const wxString& value)
416 {
417 return wxAtof(value);
418 }
419
420 bool ctConfigToolDoc::DoOpen(wxSimpleHtmlTag* tag, ctConfigItem* parent)
421 {
422 ctConfigItem* newItem = NULL;
423 if (tag->NameIs(wxT("setting")))
424 {
425 wxSimpleHtmlAttribute* attr = tag->FindAttribute(wxT("type"));
426 if (attr)
427 {
428 ctConfigType type = ctTypeUnknown;
429 wxString typeStr(attr->GetValue());
430 if (typeStr == wxT("group"))
431 type = ctTypeGroup;
432 else if (typeStr == wxT("option-group") || typeStr == wxT("check-group"))
433 type = ctTypeCheckGroup;
434 else if (typeStr == wxT("radio-group"))
435 type = ctTypeRadioGroup;
436 else if (typeStr == wxT("bool-check"))
437 type = ctTypeBoolCheck;
438 else if (typeStr == wxT("bool-radio"))
439 type = ctTypeBoolRadio;
440 else if (typeStr == wxT("string"))
441 type = ctTypeString;
442 else if (typeStr == wxT("integer"))
443 type = ctTypeInteger;
444 else
445 {
446 wxLogError(wxT("Unknown type %s"), (const wxChar*) typeStr);
447 }
448 if (type != ctTypeUnknown)
449 {
450 newItem = new ctConfigItem(parent, type, wxT(""));
451 newItem->InitProperties();
452 if (!parent)
453 SetTopItem(newItem);
454 }
455 }
456 }
457 wxSimpleHtmlTag* childTag = tag->GetChildren();
458
459 while (childTag)
460 {
461 if (childTag->GetType() == wxSimpleHtmlTag_Open)
462 {
463 if (childTag->GetName() == wxT("setting"))
464 {
465 DoOpen(childTag, newItem);
466 }
467 else if (childTag->GetName() == wxT("name"))
468 {
469 if (newItem)
470 {
471 wxString name(childTag->GetNext()->GetTagText());
472 newItem->SetName(name);
473 }
474 }
475 else if (childTag->GetName() == wxT("active"))
476 {
477 if (newItem)
478 newItem->SetActive(GetHtmlBoolValue(childTag->GetNext()->GetTagText()));
479 }
480 else if (childTag->GetName() == wxT("enabled"))
481 {
482 if (newItem)
483 newItem->Enable(GetHtmlBoolValue(childTag->GetNext()->GetTagText()));
484 }
485 else
486 {
487 if (newItem)
488 {
489 ctProperty* prop = newItem->GetProperties().FindProperty(childTag->GetName());
490 if (!prop)
491 {
492 // A custom property, else an obsolete
493 // property that we should ignore.
494 wxString isCustom;
495 if (childTag->GetAttributeValue(isCustom, wxT("custom")) &&
496 isCustom == wxT("true"))
497 {
498 prop = new ctProperty;
499
500 wxString name(childTag->GetName());
501 wxString type(wxT("string"));
502 wxString choices;
503 wxString editorType(wxT("string"));
504 wxString description(wxT(""));
505 childTag->GetAttributeValue(type, wxT("type"));
506 childTag->GetAttributeValue(type, wxT("editor-type"));
507 childTag->GetAttributeValue(type, wxT("choices"));
508 childTag->GetAttributeValue(description, wxT("description"));
509
510 if (type == wxT("bool"))
511 prop->GetVariant() = wxVariant((bool) FALSE, name);
512 else if (type == wxT("double"))
513 prop->GetVariant() = wxVariant((double) 0.0, name);
514 else if (type == wxT("long"))
515 prop->GetVariant() = wxVariant((long) 0, name);
516 else
517 prop->GetVariant() = wxVariant(wxT(""), name);
518 prop->SetDescription(description);
519 prop->SetCustom(TRUE);
520 prop->SetEditorType(editorType);
521 if (!choices.IsEmpty())
522 {
523 wxArrayString arr;
524 ctConfigItem::StringToArray(choices, arr);
525 prop->SetChoices(arr);
526 }
527 newItem->GetProperties().AddProperty(prop);
528 }
529 }
530 if (prop)
531 {
532 if (prop->GetVariant().GetType() == wxT("string"))
533 prop->GetVariant() = childTag->GetNext()->GetTagText();
534 else if (prop->GetVariant().GetType() == wxT("long"))
535 prop->GetVariant() = (long) GetHtmlIntegerValue(childTag->GetNext()->GetTagText());
536 else if (prop->GetVariant().GetType() == wxT("bool"))
537 prop->GetVariant() = (bool) GetHtmlBoolValue(childTag->GetNext()->GetTagText());
538 else if (prop->GetVariant().GetType() == wxT("double"))
539 prop->GetVariant() = (double) GetHtmlDoubleValue(childTag->GetNext()->GetTagText());
540 }
541 }
542 }
543 }
544 childTag = childTag->GetNext();
545 }
546 return TRUE;
547 }
548
549 /// Clear dependencies
550 void ctConfigToolDoc::ClearDependencies(ctConfigItem* item)
551 {
552 if (!item)
553 item = GetTopItem();
554
555 item->GetDependents().Clear();
556 for ( wxNode* node = item->GetChildren().GetFirst(); node; node = node->GetNext() )
557 {
558 ctConfigItem* child = (ctConfigItem*) node->GetData();
559 ClearDependencies(child);
560 }
561 }
562
563 /// Refresh dependencies
564 void ctConfigToolDoc::RefreshDependencies()
565 {
566 ClearDependencies(GetTopItem());
567 RefreshDependencies(GetTopItem());
568 }
569
570 /// Refresh dependencies
571 void ctConfigToolDoc::RefreshDependencies(ctConfigItem* item)
572 {
573 wxArrayString requiresArr;
574 wxString requires = item->GetPropertyString(wxT("requires"));
575 wxString precludes = item->GetPropertyString(wxT("precludes"));
576 wxString enabledIf = item->GetPropertyString(wxT("enabled-if"));
577 wxString enabledIfNot = item->GetPropertyString(wxT("enabled-if-not"));
578 wxString context = item->GetPropertyString(wxT("context"));
579
580 if (!requires.IsEmpty())
581 item->StringToArray(requires, requiresArr);
582
583 if (!precludes.IsEmpty())
584 item->StringToArray(precludes, requiresArr);
585
586 if (!enabledIfNot.IsEmpty())
587 item->StringToArray(enabledIfNot, requiresArr);
588
589 if (!enabledIf.IsEmpty())
590 item->StringToArray(enabledIf, requiresArr);
591
592 // Add the parent to the list of dependencies, if the
593 // parent is a check or radio group.
594 ctConfigItem* parent = item->GetParent();
595 if (parent &&
596 (parent->GetType() == ctTypeCheckGroup ||
597 parent->GetType() == ctTypeRadioGroup))
598 requiresArr.Add(parent->GetName());
599
600 // Also look in 'context' since these items
601 // are another kind of dependency (switching to
602 // a different platform may cause the dependencies
603 // to be evaluated differently).
604 if (!context.IsEmpty())
605 item->StringToArray(context, requiresArr);
606
607 size_t i;
608 for (i = 0; i < requiresArr.GetCount(); i++)
609 {
610 wxString itemName(requiresArr[i]);
611 ctConfigItem* otherItem = GetTopItem()->FindItem(itemName);
612 if (otherItem && !otherItem->GetDependents().Member(item))
613 {
614 otherItem->GetDependents().Append(item);
615 }
616 }
617 for ( wxNode* node = item->GetChildren().GetFirst(); node; node = node->GetNext() )
618 {
619 ctConfigItem* child = (ctConfigItem*) node->GetData();
620 RefreshDependencies(child);
621 }
622 }
623
624 /// Generate the text of a setup.h
625 wxString ctConfigToolDoc::GenerateSetup()
626 {
627 wxString str;
628 str << wxT("/*\n * setup.h\n * Generated by wxConfigTool\n *\n */\n\n");
629
630 GenerateSetup(GetTopItem(), str);
631
632 return str;
633 }
634
635 /// Helper function
636 void ctConfigToolDoc::GenerateSetup(ctConfigItem* item, wxString& str)
637 {
638 // Generate the setup.h entries for this item
639 wxString name = item->GetName();
640
641 // We don't process the platform choice
642 if (item->GetName() == wxT("Target"))
643 return;
644
645 if (item->IsInActiveContext() &&
646 (item->GetType() == ctTypeCheckGroup ||
647 item->GetType() == ctTypeRadioGroup ||
648 item->GetType() == ctTypeBoolCheck ||
649 item->GetType() == ctTypeBoolRadio))
650 {
651 // TODO: write description
652 wxString name = item->GetName();
653 if (name.Left(6) == wxT("wxUSE_") ||
654 name == wxT("REMOVE_UNUSED_ARG") || // Hack alert: change to wxUSE_UNUSED_ARG_REMOVAL
655 name.Find(wxT("COMPATIBILITY")) != wxNOT_FOUND)
656 {
657 str << wxT("#define ") << name ;
658 if (item->IsEnabled())
659 str << wxT(" 1");
660 else
661 str << wxT(" 0");
662 str << wxT("\n\n");
663 }
664 }
665
666 for ( wxNode* node = item->GetChildren().GetFirst(); node; node = node->GetNext() )
667 {
668 ctConfigItem* child = (ctConfigItem*) node->GetData();
669 GenerateSetup(child, str);
670 }
671 }
672
673
674 /// Generate a configure command
675 wxString ctConfigToolDoc::GenerateConfigureCommand()
676 {
677 wxString str;
678 str << wxT("# configurewx\n# Generated by wxConfigTool\n\n");
679
680 wxString path = GetFrameworkDir(TRUE);
681 bool makeUnix = TRUE;
682 if (!path.IsEmpty())
683 {
684 if (makeUnix)
685 path += wxT("/");
686 else
687 path += wxFILE_SEP_PATH ;
688 }
689
690 str << path << wxT("configure");
691
692 // Find the target to use
693 ctConfigItem* platformsFolder = GetTopItem()->FindItem(wxT("Target"));
694 if (platformsFolder)
695 {
696 for ( wxNode* node = platformsFolder->GetChildren().GetFirst(); node; node = node->GetNext() )
697 {
698 ctConfigItem* child = (ctConfigItem*) node->GetData();
699 if (child->GetType() == ctTypeBoolRadio && child->IsEnabled())
700 {
701 wxString configureCommand = child->GetPropertyString(wxT("configure-command"));
702 if (!configureCommand.IsEmpty())
703 str << wxT(" ") << configureCommand;
704 }
705 }
706 }
707
708 GenerateConfigureCommand(GetTopItem(), str);
709 return str;
710 }
711
712 /// Helper function
713 void ctConfigToolDoc::GenerateConfigureCommand(ctConfigItem* item, wxString& str)
714 {
715 // We don't process the platform group, since we've
716 // already done so.
717 if (item->GetName() == wxT("Target"))
718 return;
719
720 if (item->IsInActiveContext() &&
721 (item->GetType() == ctTypeCheckGroup ||
722 item->GetType() == ctTypeRadioGroup ||
723 item->GetType() == ctTypeBoolCheck ||
724 item->GetType() == ctTypeBoolRadio))
725 {
726 wxString name = item->GetName();
727 wxString configureCommand = item->GetPropertyString(wxT("configure-command"));
728 if (!configureCommand.IsEmpty())
729 {
730 if (!item->IsEnabled())
731 {
732 // Replace 'enable' with 'disable' if this
733 // option is off.
734 configureCommand.Replace(wxT("--enable-"), wxT("--disable-"));
735 configureCommand.Replace(wxT("--with-"), wxT("--without-"));
736 }
737 ctProperty* prop = item->GetProperties().FindProperty(wxT("builtin"));
738 if (prop && prop->GetVariant().GetType() == wxT("bool"))
739 {
740 bool builtin = prop->GetVariant().GetBool();
741 str << wxT(" ") << configureCommand;
742 if (builtin)
743 str << wxT("=builtin");
744 else
745 str << wxT("=sys");
746 }
747 else
748 {
749 ctProperty* prop = item->GetProperties().FindProperty(wxT("value"));
750 if (prop && prop->GetVariant().GetType() == wxT("string"))
751 {
752 wxString val = prop->GetVariant().GetString();
753 if (item->IsEnabled() && !val.IsEmpty())
754 {
755 str << wxT(" ") << configureCommand;
756 str << wxT("=\"") << val << wxT("\"");
757 }
758 // If the string is empty, ignore this parameter,
759 // since it's obviously intended to be supplied
760 // only if there's a string to use and it's enabled.
761 }
762 else
763 {
764 str << wxT(" ") << configureCommand;
765 }
766 }
767 }
768 }
769
770 for ( wxNode* node = item->GetChildren().GetFirst(); node; node = node->GetNext() )
771 {
772 ctConfigItem* child = (ctConfigItem*) node->GetData();
773 GenerateConfigureCommand(child, str);
774 }
775 }
776
777 /// Gets the current framework directory
778 wxString ctConfigToolDoc::GetFrameworkDir(bool makeUnix)
779 {
780 wxString path = wxGetApp().GetSettings().m_frameworkDir;
781 if (wxGetApp().GetSettings().m_useEnvironmentVariable)
782 {
783 // Should probably allow other variables
784 // to be used, and maybe expand variables within m_frameworkDir
785 path = wxGetenv(wxT("WXWIN"));
786 #ifdef __WXMSW__
787 if (makeUnix)
788 path.Replace(wxT("\\"), wxT("/"));
789 #endif
790 }
791 return path;
792 }
793
794 /// Finds the next item in the tree
795 ctConfigItem* ctConfigToolDoc::FindNextItem(ctConfigItem* item, bool wrap)
796 {
797 if (!item)
798 return GetTopItem();
799
800 // First, try to find the first child
801 if (item->GetChildCount() > 0)
802 {
803 return item->GetChild(0);
804 }
805 else
806 {
807 ctConfigItem* p = item;
808 while (p)
809 {
810 ctConfigItem* toFind = FindNextSibling(p);
811 if (toFind)
812 return toFind;
813 p = p->GetParent();
814 }
815 }
816
817 // Finally, wrap around to the root.
818 if (wrap)
819 return GetTopItem();
820 else
821 return NULL;
822 }
823
824 /// Finds the next sibling in the tree
825 ctConfigItem* ctConfigToolDoc::FindNextSibling(ctConfigItem* item)
826 {
827 if (item->GetParent())
828 {
829 wxNode* node = item->GetParent()->GetChildren().Member(item);
830 if (node && node->GetNext())
831 {
832 ctConfigItem* nextItem = (ctConfigItem*) node->GetNext()->GetData();
833 return nextItem;
834 }
835 }
836 return NULL;
837 }
838
839
840 /*
841 * Implements a document editing command.
842 */
843
844 ctConfigCommand::ctConfigCommand(const wxString& name, int cmdId,
845 ctConfigItem* activeState, ctConfigItem* savedState,
846 ctConfigItem* parent, ctConfigItem* insertBefore,
847 bool ignoreFirstTime): wxCommand(TRUE, name)
848 {
849 m_activeState = activeState;
850 m_savedState = savedState;
851 m_ignoreThis = ignoreFirstTime;
852 m_cmdId = cmdId;
853 m_properties = NULL;
854 m_parent = parent;
855 m_insertBefore = insertBefore;
856 }
857
858 ctConfigCommand::ctConfigCommand(const wxString& name, int cmdId,
859 ctConfigItem* activeState, ctProperties* properties,
860 bool ignoreFirstTime): wxCommand(TRUE, name)
861 {
862 m_activeState = activeState;
863 m_savedState = NULL;
864 m_properties = properties;
865 m_ignoreThis = ignoreFirstTime;
866 m_cmdId = cmdId;
867 m_properties = properties;
868 m_parent = NULL;
869 m_insertBefore = NULL;
870 }
871
872 ctConfigCommand::~ctConfigCommand()
873 {
874 if (m_savedState)
875 delete m_savedState;
876 if (m_properties)
877 delete m_properties;
878 }
879
880 bool ctConfigCommand::Do()
881 {
882 return DoAndUndo(TRUE);
883 }
884
885 bool ctConfigCommand::Undo()
886 {
887 return DoAndUndo(FALSE);
888 }
889
890 // Combine Do and Undo into one
891 bool ctConfigCommand::DoAndUndo(bool doCmd)
892 {
893 switch (m_cmdId)
894 {
895 case ctCMD_CUT:
896 {
897 if (doCmd)
898 {
899 wxASSERT(m_savedState == NULL);
900 wxASSERT(m_activeState != NULL);
901
902 ctConfigItem* newItem = m_activeState->DeepClone();
903 ctConfigToolDoc* doc = m_activeState->GetDocument();
904
905 // This will delete the old clipboard contents, if any.
906 doc->SetClipboardItem(newItem);
907
908 m_parent = m_activeState->GetParent();
909 m_insertBefore = m_activeState->FindNextSibling();
910
911 m_activeState->Detach();
912 m_savedState = m_activeState;
913 m_activeState = NULL;
914
915 m_savedState->GetDocument()->Modify(TRUE);
916 ctConfigToolView* view = (ctConfigToolView*) m_savedState->GetDocument()->GetFirstView();
917 view->OnChangeFilename();
918 }
919 else
920 {
921 wxASSERT(m_savedState != NULL);
922 wxASSERT(m_activeState == NULL);
923
924 m_savedState->GetDocument()->Modify(TRUE);
925 m_savedState->Attach(m_parent, m_insertBefore);
926 ctConfigToolView* view = (ctConfigToolView*) m_savedState->GetDocument()->GetFirstView();
927 view->AddItems(wxGetApp().GetMainFrame()->GetConfigTreeCtrl(), m_savedState);
928 m_activeState = m_savedState;
929 m_savedState = NULL;
930 m_parent = NULL;
931 m_insertBefore = NULL;
932 view->OnChangeFilename();
933 }
934 break;
935 }
936 case ctCMD_PASTE:
937 {
938 if (doCmd)
939 {
940 wxASSERT(m_savedState != NULL);
941 wxASSERT(m_activeState == NULL);
942
943 m_savedState->GetDocument()->Modify(TRUE);
944 m_savedState->Attach(m_parent, m_insertBefore);
945 ctConfigToolView* view = (ctConfigToolView*) m_savedState->GetDocument()->GetFirstView();
946 view->AddItems(wxGetApp().GetMainFrame()->GetConfigTreeCtrl(), m_savedState);
947 wxGetApp().GetMainFrame()->GetConfigTreeCtrl()->SelectItem(m_savedState->GetTreeItemId());
948 m_activeState = m_savedState;
949 m_savedState = NULL;
950 view->OnChangeFilename();
951 }
952 else
953 {
954 wxASSERT(m_savedState == NULL);
955 wxASSERT(m_activeState != NULL);
956
957 m_activeState->GetDocument()->Modify(TRUE);
958 ctConfigToolView* view = (ctConfigToolView*) m_activeState->GetDocument()->GetFirstView();
959 m_activeState->Detach();
960 m_savedState = m_activeState;
961 m_activeState = NULL;
962 view->OnChangeFilename();
963 }
964 break;
965 }
966 case ctCMD_NEW_ELEMENT:
967 {
968 if (doCmd)
969 {
970 wxASSERT(m_savedState != NULL);
971 wxASSERT(m_activeState == NULL);
972
973 m_savedState->GetDocument()->Modify(TRUE);
974 m_savedState->Attach(m_parent, m_insertBefore);
975 ctConfigToolView* view = (ctConfigToolView*) m_savedState->GetDocument()->GetFirstView();
976 view->AddItems(wxGetApp().GetMainFrame()->GetConfigTreeCtrl(), m_savedState);
977 wxGetApp().GetMainFrame()->GetConfigTreeCtrl()->SelectItem(m_savedState->GetTreeItemId());
978
979 m_activeState = m_savedState;
980 m_savedState = NULL;
981 }
982 else
983 {
984 wxASSERT(m_savedState == NULL);
985 wxASSERT(m_activeState != NULL);
986
987 m_activeState->GetDocument()->Modify(TRUE);
988 m_activeState->Detach();
989 m_savedState = m_activeState;
990 m_activeState = NULL;
991 }
992 break;
993 }
994 case ctCMD_APPLY_PROPERTY:
995 {
996 wxASSERT(m_properties != NULL);
997 wxASSERT(m_activeState != NULL);
998
999 // Don't update the properties editor first time
1000 // around since it will be done one property at a time
1001 // initially (and no property editor update required)
1002 if (!m_ignoreThis)
1003 {
1004 // Just swap the saved and current properties.
1005 ctProperties propsTemp = m_activeState->GetProperties() ;
1006 m_activeState->GetProperties() = (* m_properties);
1007 (* m_properties) = propsTemp;
1008
1009 // Apply only those that need applying
1010 // (those properties in activeState that are not in propsTemp)
1011 wxNode* node = m_activeState->GetProperties().GetList().GetFirst();
1012 while (node)
1013 {
1014 ctProperty* prop = (ctProperty*) node->GetData();
1015 ctProperty* otherProp = propsTemp.FindProperty(prop->GetName());
1016 if (otherProp && ((*prop) != (*otherProp)))
1017 {
1018 m_activeState->ApplyProperty(prop, otherProp->GetVariant());
1019 }
1020 node = node->GetNext();
1021 }
1022 m_activeState->GetDocument()->Modify(TRUE);
1023 ctConfigToolView* view = (ctConfigToolView*) m_activeState->GetDocument()->GetFirstView();
1024 if (view)
1025 {
1026 ctConfigToolHint hint(NULL, ctValueChanged);
1027 m_activeState->GetDocument()->UpdateAllViews (NULL, & hint);
1028 }
1029 }
1030 m_ignoreThis = FALSE;
1031
1032 break;
1033 }
1034 }
1035 return TRUE;
1036 }
1037
1038