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