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