]> git.saurik.com Git - wxWidgets.git/blame - utils/configtool/src/configtooldoc.cpp
Changed version number
[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
d9ab621e
WS
16// For compilers that support precompilation, includes "wx/wx.h".
17#include "wx/wxprec.h"
d7463f75
JS
18
19#ifdef __BORLANDC__
20#pragma hdrstop
21#endif
22
d9ab621e
WS
23#ifndef WX_PRECOMP
24
d7463f75
JS
25#include "wx/process.h"
26#include "wx/mimetype.h"
27#include "wx/process.h"
d7463f75 28
d7463f75
JS
29#endif
30
d9ab621e 31#include "wx/textfile.h"
8d3261f9 32#include "wx/txtstrm.h"
d9ab621e
WS
33#include "wx/wfstream.h"
34#include "wx/config.h"
d7463f75
JS
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
43IMPLEMENT_DYNAMIC_CLASS(ctConfigToolDoc, wxDocument)
44
45// Ctor
46ctConfigToolDoc::ctConfigToolDoc()
47{
48 m_topItem = NULL;
49 m_clipboardItem = NULL;
50}
51
52// Dtor
53ctConfigToolDoc::~ctConfigToolDoc()
54{
55 DeleteItems();
56 ClearClipboard();
57 if (GetCommandProcessor())
58 GetCommandProcessor()->SetEditMenu(NULL);
59}
60
61// Delete all the items not already deleted
62void ctConfigToolDoc::DeleteItems()
63{
64 if (m_topItem)
65 delete m_topItem;
66 m_topItem = NULL;
67}
68
69/// Clears the clipboard item.
70void ctConfigToolDoc::ClearClipboard()
71{
72 if (m_clipboardItem)
73 delete m_clipboardItem;
74 m_clipboardItem = NULL;
75}
76
77/// Sets the clipboard item.
78void 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
87bool ctConfigToolDoc::OnCloseDocument()
88{
89 if (wxDocument::OnCloseDocument())
90 {
91 ctConfigToolHint hint(NULL, ctClear);
92 UpdateAllViews (NULL, & hint);
93
94 DeleteItems();
4fe30bce 95 return true;
d7463f75
JS
96 }
97 else
98 {
4fe30bce 99 return false;
d7463f75
JS
100 }
101}
102
103// Saves the doc
104bool ctConfigToolDoc::Save()
105{
4fe30bce 106 if (!IsModified() && m_savedYet) return true;
79830320
JS
107
108 bool ret = (m_documentFile == wxT("") || !m_savedYet) ?
109 SaveAs() :
110 OnSaveDocument(m_documentFile);
d7463f75 111 if ( ret )
4fe30bce 112 SetDocumentSaved(true);
d7463f75
JS
113 return ret;
114}
115
116// Create the document
117bool 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
4fe30bce
WS
141 Modify(false);
142 SetDocumentSaved(false);
d7463f75
JS
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
4fe30bce 161 SetFilename(GetFilename(), true);
d7463f75
JS
162 }
163 }
164 return success;
165}
166
167// Save the document
168bool 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");
8d3261f9 179
d7463f75
JS
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
4fe30bce 186 bool leaveBackup = true;
d7463f75
JS
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 }
8d3261f9 197
d7463f75
JS
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 }
8d3261f9 216
d7463f75
JS
217 // Finally, copy the temporary file to the proper filename
218 if (!wxRenameFile(tempFilename, filename))
219 {
220 wxCopyFile(tempFilename, filename);
221 wxRemoveFile(tempFilename);
8d3261f9 222 }
d7463f75 223
4fe30bce 224 Modify(false);
d7463f75 225 ((ctConfigToolView*)GetFirstView())->OnChangeFilename();
4fe30bce 226 SetDocumentSaved(true);
d7463f75
JS
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
238bool 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
4fe30bce 258 SetDocumentSaved(true); // Necessary or it will pop up the Save As dialog
d7463f75
JS
259
260 return opened;
261}
262
263/// Save the settings file
264bool ctConfigToolDoc::DoSave(const wxString& filename)
265{
8d3261f9
WS
266 wxFileOutputStream osFile(filename);
267 if (!osFile.Ok())
4fe30bce 268 return false;
d7463f75 269
8d3261f9
WS
270 wxTextOutputStream stream(osFile);
271
d7463f75 272 stream << wxT("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
be5a51fb 273 stream << wxT("<settings xmlns=\"http://www.wxwidgets.org/wxs\" version=\"2.5.0.1\">");
d7463f75 274
8d3261f9 275 DoSave(m_topItem, osFile, 1);
d7463f75
JS
276
277 stream << wxT("\n</settings>\n");
278
4fe30bce 279 return true;
d7463f75
JS
280}
281
8d3261f9 282inline static void OutputIndentation(wxOutputStream& osFile, int indent)
d7463f75 283{
8d3261f9 284 wxTextOutputStream stream(osFile);
d7463f75
JS
285 wxString str = wxT("\n");
286 for (int i = 0; i < indent; i++)
8d3261f9 287 str << wxT(" ");
d7463f75
JS
288 stream << str ;
289}
290
291/// Recursive helper function for file saving
8d3261f9 292bool ctConfigToolDoc::DoSave(ctConfigItem* item, wxOutputStream& osFile, int indent)
d7463f75 293{
8d3261f9
WS
294 OutputIndentation(osFile, indent*2);
295 wxTextOutputStream stream(osFile);
d7463f75
JS
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
8d3261f9 321 OutputIndentation(osFile, indent*2);
d7463f75
JS
322 if (item->IsActive())
323 stream << wxT("<active>1</active>");
324 else
325 stream << wxT("<active>0</active>");
8d3261f9 326 OutputIndentation(osFile, indent*2);
d7463f75
JS
327 if (item->IsEnabled())
328 stream << wxT("<enabled>1</enabled>");
329 else
330 stream << wxT("<enabled>0</enabled>");
331
332 // Output properties
d9ab621e 333 wxObjectList::compatibility_iterator node = item->GetProperties().GetList().GetFirst();
d7463f75
JS
334 while (node)
335 {
336 ctProperty* prop = (ctProperty*) node->GetData();
8d3261f9 337 OutputIndentation(osFile, indent*2);
d7463f75 338 stream << wxT("<") << prop->GetName() ;
8d3261f9 339
d7463f75
JS
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 }
8d3261f9 353
d7463f75
JS
354 stream << wxT(">");
355
356 stream << ctEscapeHTMLCharacters(prop->GetVariant().GetString()) ;
357 stream << wxT("</") << prop->GetName() << wxT(">");
358
f8105809 359 node = node->GetNext();
d7463f75
JS
360 }
361
362 // Output children
363 node = item->GetChildren().GetFirst();
364 while (node)
365 {
366 ctConfigItem* child = (ctConfigItem*) node->GetData();
8d3261f9 367 DoSave(child, osFile, indent);
d7463f75 368
f8105809 369 node = node->GetNext();
d7463f75
JS
370 }
371
372 indent --;
373
8d3261f9 374 OutputIndentation(osFile, indent*2);
d7463f75
JS
375 stream << wxT("</setting>");
376
4fe30bce 377 return true;
d7463f75
JS
378}
379
380/// Open the settings file
381bool 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);
4fe30bce 398 return true;
d7463f75 399 }
4fe30bce 400 return true;
d7463f75
JS
401 }
402 }
4fe30bce 403 return false;
d7463f75
JS
404}
405
406static bool GetHtmlBoolValue(const wxString& value)
407{
8d3261f9 408 if (value.IsSameAs(wxT("true"),false) || value == wxT("1"))
4fe30bce 409 return true;
8d3261f9
WS
410 else
411 return false;
d7463f75
JS
412}
413
414static int GetHtmlIntegerValue(const wxString& value)
415{
416 return wxAtoi(value);
417}
418
419static double GetHtmlDoubleValue(const wxString& value)
420{
421 return wxAtof(value);
422}
423
424bool 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"))
4fe30bce 515 prop->GetVariant() = wxVariant(false, name);
d7463f75
JS
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);
4fe30bce 523 prop->SetCustom(true);
d7463f75
JS
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"))
4fe30bce 541 prop->GetVariant() = GetHtmlBoolValue(childTag->GetNext()->GetTagText());
d7463f75
JS
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 }
4fe30bce 550 return true;
d7463f75
JS
551}
552
553/// Clear dependencies
554void ctConfigToolDoc::ClearDependencies(ctConfigItem* item)
555{
510c9b78 556 if (!item) {
d7463f75 557 item = GetTopItem();
510c9b78
JS
558 if (!item)
559 return;
560 }
d7463f75
JS
561
562 item->GetDependents().Clear();
d9ab621e 563 for ( wxObjectList::compatibility_iterator node = item->GetChildren().GetFirst(); node; node = node->GetNext() )
d7463f75
JS
564 {
565 ctConfigItem* child = (ctConfigItem*) node->GetData();
566 ClearDependencies(child);
567 }
568}
569
570/// Refresh dependencies
571void ctConfigToolDoc::RefreshDependencies()
572{
573 ClearDependencies(GetTopItem());
574 RefreshDependencies(GetTopItem());
575}
576
577/// Refresh dependencies
578void ctConfigToolDoc::RefreshDependencies(ctConfigItem* item)
579{
510c9b78
JS
580 if (item==NULL)
581 return;
582
d7463f75
JS
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"));
afc51590 588 wxString indeterminateIf = item->GetPropertyString(wxT("indeterminate-if"));
d7463f75
JS
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
afc51590
JS
603 if (!indeterminateIf.IsEmpty())
604 item->StringToArray(indeterminateIf, requiresArr);
605
d7463f75
JS
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 &&
8d3261f9 610 (parent->GetType() == ctTypeCheckGroup ||
d7463f75
JS
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 }
d9ab621e 631 for ( wxObjectList::compatibility_iterator node = item->GetChildren().GetFirst(); node; node = node->GetNext() )
d7463f75
JS
632 {
633 ctConfigItem* child = (ctConfigItem*) node->GetData();
634 RefreshDependencies(child);
635 }
636}
637
638/// Generate the text of a setup.h
639wxString 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
650void 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
d9a41dfe 656 if (item->GetName() == wxT("Target"))
d7463f75
JS
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
d9ab621e 680 for ( wxObjectList::compatibility_iterator node = item->GetChildren().GetFirst(); node; node = node->GetNext() )
d7463f75
JS
681 {
682 ctConfigItem* child = (ctConfigItem*) node->GetData();
683 GenerateSetup(child, str);
684 }
685}
686
687
688/// Generate a configure command
689wxString ctConfigToolDoc::GenerateConfigureCommand()
690{
691 wxString str;
692 str << wxT("# configurewx\n# Generated by wxConfigTool\n\n");
693
4fe30bce
WS
694 wxString path = GetFrameworkDir(true);
695 bool makeUnix = true;
d7463f75
JS
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
d9a41dfe
JS
706 // Find the target to use
707 ctConfigItem* platformsFolder = GetTopItem()->FindItem(wxT("Target"));
d7463f75
JS
708 if (platformsFolder)
709 {
d9ab621e 710 for ( wxObjectList::compatibility_iterator node = platformsFolder->GetChildren().GetFirst(); node; node = node->GetNext() )
d7463f75
JS
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
727void ctConfigToolDoc::GenerateConfigureCommand(ctConfigItem* item, wxString& str)
728{
729 // We don't process the platform group, since we've
730 // already done so.
d9a41dfe 731 if (item->GetName() == wxT("Target"))
d7463f75
JS
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 }
8d3261f9 780 }
d7463f75
JS
781 }
782 }
783
d9ab621e 784 for ( wxObjectList::compatibility_iterator node = item->GetChildren().GetFirst(); node; node = node->GetNext() )
d7463f75
JS
785 {
786 ctConfigItem* child = (ctConfigItem*) node->GetData();
787 GenerateConfigureCommand(child, str);
788 }
789}
790
791/// Gets the current framework directory
792wxString 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
d9ab621e
WS
799 wxString pathEnv(wxGetenv(wxT("WXWIN")));
800 path = pathEnv;
d7463f75
JS
801#ifdef __WXMSW__
802 if (makeUnix)
803 path.Replace(wxT("\\"), wxT("/"));
804#endif
805 }
806 return path;
807}
808
e7767867
JS
809/// Finds the next item in the tree
810ctConfigItem* 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
840ctConfigItem* ctConfigToolDoc::FindNextSibling(ctConfigItem* item)
841{
842 if (item->GetParent())
843 {
d9ab621e 844 wxObjectList::compatibility_iterator node = item->GetParent()->GetChildren().Member(item);
e7767867
JS
845 if (node && node->GetNext())
846 {
847 ctConfigItem* nextItem = (ctConfigItem*) node->GetNext()->GetData();
848 return nextItem;
849 }
850 }
851 return NULL;
852}
853
d7463f75
JS
854
855/*
856 * Implements a document editing command.
857 */
858
859ctConfigCommand::ctConfigCommand(const wxString& name, int cmdId,
860 ctConfigItem* activeState, ctConfigItem* savedState,
861 ctConfigItem* parent, ctConfigItem* insertBefore,
4fe30bce 862 bool ignoreFirstTime): wxCommand(true, name)
d7463f75
JS
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
873ctConfigCommand::ctConfigCommand(const wxString& name, int cmdId,
874 ctConfigItem* activeState, ctProperties* properties,
4fe30bce 875 bool ignoreFirstTime): wxCommand(true, name)
d7463f75
JS
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
887ctConfigCommand::~ctConfigCommand()
888{
889 if (m_savedState)
890 delete m_savedState;
891 if (m_properties)
892 delete m_properties;
893}
894
895bool ctConfigCommand::Do()
896{
4fe30bce 897 return DoAndUndo(true);
d7463f75
JS
898}
899
900bool ctConfigCommand::Undo()
901{
4fe30bce 902 return DoAndUndo(false);
d7463f75
JS
903}
904
905// Combine Do and Undo into one
906bool 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);
8d3261f9 922
d7463f75
JS
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
4fe30bce 930 m_savedState->GetDocument()->Modify(true);
d7463f75
JS
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
4fe30bce 939 m_savedState->GetDocument()->Modify(true);
d7463f75
JS
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
4fe30bce 958 m_savedState->GetDocument()->Modify(true);
d7463f75
JS
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
4fe30bce 972 m_activeState->GetDocument()->Modify(true);
d7463f75
JS
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
4fe30bce 988 m_savedState->GetDocument()->Modify(true);
d7463f75
JS
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
4fe30bce 1002 m_activeState->GetDocument()->Modify(true);
d7463f75
JS
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)
d9ab621e 1026 wxObjectList::compatibility_iterator node = m_activeState->GetProperties().GetList().GetFirst();
d7463f75
JS
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 }
4fe30bce 1037 m_activeState->GetDocument()->Modify(true);
d7463f75
JS
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 }
4fe30bce 1045 m_ignoreThis = false;
d7463f75
JS
1046
1047 break;
1048 }
1049 }
4fe30bce 1050 return true;
d7463f75
JS
1051}
1052
61775320
JS
1053IMPLEMENT_CLASS(ctConfiguration, wxObject)
1054
1055ctConfiguration::ctConfiguration()
1056{
1057 m_treeItemId = wxTreeItemId();
1058 m_parent = NULL;
1059 m_topItem = NULL;
1060}
1061
1062ctConfiguration::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
1071ctConfiguration::~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*/
8d3261f9 1090
61775320
JS
1091 Clear();
1092}
1093
1094/// Assignment operator.
1095void ctConfiguration::operator= (const ctConfiguration& configuration)
1096{
1097 m_name = configuration.m_name;
1098 m_description = configuration.m_description;
1099}
1100
1101/// Clear children
1102void ctConfiguration::Clear()
1103{
d9ab621e 1104 wxObjectList::compatibility_iterator node = m_children.GetFirst();
61775320
JS
1105 while (node)
1106 {
d9ab621e 1107 wxObjectList::compatibility_iterator next = node->GetNext();
61775320
JS
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
1121ctConfiguration* 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
1135int ctConfiguration::GetChildCount() const
1136{
1137 return m_children.GetCount();
1138}
1139
1140/// Add a child
1141void ctConfiguration::AddChild(ctConfiguration* configuration)
1142{
1143 m_children.Append(configuration);
1144 configuration->SetParent(this);
1145}
1146
1147/// Remove (but don't delete) a child
1148void 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)
1156ctConfigToolDoc* 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.
1164ctConfiguration* ctConfiguration::FindConfiguration(const wxString& name)
1165{
1166 if (GetName() == name)
1167 return this;
1168
d9ab621e 1169 for ( wxObjectList::compatibility_iterator node = GetChildren().GetFirst(); node; node = node->GetNext() )
61775320
JS
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
1180ctConfiguration* ctConfiguration::FindNextSibling()
1181{
1182 if (!GetParent())
1183 return NULL;
d9ab621e 1184 wxObjectList::compatibility_iterator node = GetParent()->GetChildren().Member(this);
61775320
JS
1185 if (node && node->GetNext())
1186 {
1187 return (ctConfiguration*) node->GetNext()->GetData();
1188 }
1189 return NULL;
1190}
1191
1192/// Find the previous sibling
1193ctConfiguration* ctConfiguration::FindPreviousSibling()
1194{
1195 if (!GetParent())
1196 return NULL;
d9ab621e 1197 wxObjectList::compatibility_iterator node = GetParent()->GetChildren().Member(this);
61775320
JS
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
1206ctConfiguration* ctConfiguration::DeepClone()
1207{
1208 ctConfiguration* newItem = Clone();
1209
d9ab621e 1210 for ( wxObjectList::compatibility_iterator node = GetChildren().GetFirst(); node; node = node->GetNext() )
61775320
JS
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
1220void 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
1241void ctConfiguration::DetachFromTree()
1242{
ddc4f3b5 1243/*
61775320
JS
1244 wxTreeItemId item = GetTreeItemId();
1245
1246 // TODO
61775320
JS
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}