]> git.saurik.com Git - wxWidgets.git/blame - utils/configtool/src/configitem.cpp
overseeing the obvious, there is already a perfect scroll call for HIView...
[wxWidgets.git] / utils / configtool / src / configitem.cpp
CommitLineData
d7463f75
JS
1/////////////////////////////////////////////////////////////////////////////
2// Name: configitem.cpp
3// Purpose: wxWindows Configuration Tool config item class
4// Author: Julian Smart
5// Modified by:
6// Created: 2003-06-03
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 "configitem.h"
14#endif
15
16// Includes other headers for precompiled compilation
17#include "wx/wx.h"
18
19#ifdef __BORLANDC__
20#pragma hdrstop
21#endif
22
23#include "wx/tokenzr.h"
24
25#include "configitem.h"
26#include "configtree.h"
27#include "configtooldoc.h"
28#include "configtoolview.h"
29#include "wxconfigtool.h"
30#include "mainframe.h"
31
32IMPLEMENT_CLASS(ctConfigItem, wxObject)
33
34ctConfigItem::ctConfigItem()
35{
36 m_modified = FALSE;
37 m_type = ctTypeBoolCheck;
38 m_treeItemId = wxTreeItemId();
39 m_enabled = TRUE;
40 m_parent = NULL;
41 m_active = TRUE;
42}
43
44ctConfigItem::ctConfigItem(ctConfigItem* parent, ctConfigType type, const wxString& name)
45{
46 m_modified = FALSE;
47 m_type = type;
48 m_treeItemId = wxTreeItemId();
49 m_enabled = FALSE;
50 m_active = TRUE;
51 SetName(name);
52 m_parent = parent;
53 if (parent)
54 parent->AddChild(this);
55}
56
57ctConfigItem::~ctConfigItem()
58{
59 ctConfigTreeCtrl* treeCtrl = wxGetApp().GetMainFrame()->GetConfigTreeCtrl();
60 if (m_treeItemId.IsOk() && treeCtrl)
61 {
62 ctTreeItemData* data = (ctTreeItemData*) treeCtrl->GetItemData(m_treeItemId);
63 if (data)
64 data->SetConfigItem(NULL);
65 }
66 if (GetParent())
67 GetParent()->RemoveChild(this);
68 else
69 {
70 if (wxGetApp().GetMainFrame()->GetDocument() &&
71 wxGetApp().GetMainFrame()->GetDocument()->GetTopItem() == this)
72 wxGetApp().GetMainFrame()->GetDocument()->SetTopItem(NULL);
73 }
74
75 Clear();
76}
77
78/// Can we edit this property?
79bool ctConfigItem::CanEditProperty(const wxString& propName) const
80{
81 ctProperty* prop = m_properties.FindProperty(propName);
82 if (prop)
83 return !prop->GetReadOnly();
84 else
85 return FALSE;
86}
87
88/// Assignment operator.
89void ctConfigItem::operator= (const ctConfigItem& item)
90{
91 m_properties = item.m_properties;
92 m_modified = item.m_modified;
93 m_defaultProperty = item.m_defaultProperty;
94 m_type = item.m_type;
95 m_enabled = item.m_enabled;
96 m_active = item.m_active;
97}
98
99/// Sets the name property.
100void ctConfigItem::SetName(const wxString& name )
101{
102 m_properties.SetProperty(wxT("name"), name);
103}
104
105/// Clear children
106void ctConfigItem::Clear()
107{
108 wxNode* node = m_children.GetFirst();
109 while (node)
110 {
111 wxNode* next = node->GetNext();
112 ctConfigItem* child = (ctConfigItem*) node->GetData();
113
114 // This should delete 'node' too, assuming
115 // child's m_parent points to 'this'. If not,
116 // it'll be cleaned up by m_children.Clear().
117 delete child;
118
119 node = next;
120 }
121 m_children.Clear();
122}
123
124// Get the nth child
125ctConfigItem* ctConfigItem::GetChild(int n) const
126{
127 wxASSERT ( n < GetChildCount() && n > -1 );
128
129 if ( n < GetChildCount() && n > -1 )
130 {
f8105809 131 ctConfigItem* child = wxDynamicCast(m_children.Item(n)->GetData(), ctConfigItem);
d7463f75
JS
132 return child;
133 }
134 else
135 return NULL;
136}
137
138// Get the child count
139int ctConfigItem::GetChildCount() const
140{
141 return m_children.GetCount();
142}
143
144/// Add a child
145void ctConfigItem::AddChild(ctConfigItem* item)
146{
147 m_children.Append(item);
148 item->SetParent(this);
149}
150
151/// Remove (but don't delete) a child
152void ctConfigItem::RemoveChild(ctConfigItem* item)
153{
154 m_children.DeleteObject(item);
155 item->SetParent(NULL);
156}
157
158/// Initialise standard properties
159void ctConfigItem::InitProperties()
160{
161 ctProperty* prop = m_properties.FindProperty(wxT("name"));
162 if (!prop)
163 {
164 prop = new ctProperty;
165 m_properties.AddProperty(prop);
166 }
167 prop->SetDescription(_("<B>Name</B><P> The name of the configuration setting."));
168 prop->SetReadOnly(TRUE);
169
170 m_properties.AddProperty(
171 new ctProperty(
172 wxT("<B>Description</B><P> The setting description."),
173 wxVariant(wxT(""), wxT("description")),
174 wxT("multiline")));
175
176 m_properties.AddProperty(
177 new ctProperty(
178 wxT("<B>Default-state</B><P> The default state."),
179 wxVariant((bool) TRUE, wxT("default-state")),
180 wxT("bool")));
181
182 if (GetType() == ctTypeString)
183 {
184 m_properties.AddProperty(
185 new ctProperty(
186 wxT("<B>Default-value</B><P> The default value."),
187 wxVariant((bool) TRUE, wxT("default-value")),
188 wxT("")));
189 }
190 else if (GetType() == ctTypeInteger)
191 {
192 m_properties.AddProperty(
193 new ctProperty(
194 wxT("<B>Default-value</B><P> The default value."),
195 wxVariant((long) 0, wxT("default-value")),
196 wxT("")));
197 }
198
199 m_properties.AddProperty(
200 new ctProperty(
201 wxT("<B>Requires</B><P> When any of the given settings are 0, this setting <I>must</I> be 0. Taking wxUSE_ZIPSTREAM as an example:<P> If wxUSE_STREAMS is 0, then wxUSE_ZIPSTREAM must be 0.<BR>If wxUSE_STREAMS is 1, then wxUSE_ZIPSTREAM may be 0 or 1."),
202 wxVariant(wxT(""), wxT("requires")),
203 wxT("configitems")));
204
205 m_properties.AddProperty(
206 new ctProperty(
207 wxT("<B>Precludes</B><P> When any of these settings are 1, this setting <I>must</I> be 0. Taking wxUSE_ODBC as an example:<P> If wxUSE_UNICODE is 1, then wxUSE_ODBC must be 0.<BR>If wxUSE_UNICODE is 0, then wxUSE_ODBC may be 0 or 1."),
208 wxVariant(wxT(""), wxT("precludes")),
209 wxT("configitems")));
210
211 m_properties.AddProperty(
212 new ctProperty(
213 wxT("<B>Enabled-if</B><P> When any of these settings are 1, this setting <I>must</I> be 1."),
214 wxVariant(wxT(""), wxT("enabled-if")),
215 wxT("configitems")));
216
217 m_properties.AddProperty(
218 new ctProperty(
219 wxT("<B>Enabled-if-not</B><P> When any of these settings are 0, this setting <I>must</I> be 1. Taking wxUSE_TOOLBAR_SIMPLE as an example:<P>If wxUSE_TOOLBAR_NATIVE is 0, wxUSE_TOOLBAR_SIMPLE must be 1.<BR>If wxUSE_TOOLBAR_NATIVE is 1, wxUSE_TOOLBAR_SIMPLE may be 0 or 1."),
220 wxVariant(wxT(""), wxT("enabled-if-not")),
221 wxT("configitems")));
222
afc51590
JS
223 m_properties.AddProperty(
224 new ctProperty(
225 wxT("<B>Indeterminate-if</B><P> When any of these settings are 1, this setting becomes active and indeterminate. Taking wxUSE_UNICODE as an example:<P>If Custom is 1, wxUSE_UNICODE is indeterminate."),
226 wxVariant(wxT(""), wxT("indeterminate-if")),
227 wxT("configitems")));
228
d7463f75
JS
229 m_properties.AddProperty(
230 new ctProperty(
231 wxT("<B>Exclusivity</B><P> The settings that are mutually exclusive with this one."),
232 wxVariant(wxT(""), wxT("exclusivity")),
233 wxT("configitems")));
234
235 m_properties.AddProperty(
236 new ctProperty(
237 wxT("<B>Context</B><P> A list of symbols (config settings), at least one of which must be enabled for this item to participate in dependency rules.<P>\nIf empty, this item will always be used in dependency rules.<P>\nMostly this will be used to specify the applicable platforms, but it can contain other symbols, for example compilers."),
238 wxVariant(wxT(""), wxT("context")),
239 wxT("configitems")));
240
241 m_properties.AddProperty(
242 new ctProperty(
243 wxT("<B>Configure-command</B><P> Configure command to generate if this is on."),
244 wxVariant(wxT(""), wxT("configure-command")),
245 wxT("multiline")));
246
247 m_properties.AddProperty(
248 new ctProperty(
249 wxT("<B>Help-topic</B><P> The help topic in the wxWindows manual for this component or setting."),
250 wxVariant(wxT(""), wxT("help-topic")),
251 wxT("multiline")));
252
253 m_properties.AddProperty(
254 new ctProperty(
255 wxT("<B>Notes</B><P> User notes."),
256 wxVariant(wxT(""), wxT("notes")),
257 wxT("multiline")));
258
259 m_defaultProperty = wxT("description");
260}
261
262/// Do additional actions to apply the property to the internal
263/// representation.
69da0d99 264void ctConfigItem::ApplyProperty(ctProperty* prop, const wxVariant& WXUNUSED(oldValue))
d7463f75
JS
265{
266 ctConfigToolDoc* doc = GetDocument();
267 bool oldModified = doc->IsModified();
268 doc->Modify(TRUE);
269
270 wxString name = prop->GetName();
271 if (name == wxT("requires") ||
272 name == wxT("precludes") ||
273 name == wxT("enabled-if") ||
274 name == wxT("enabled-if-not") ||
afc51590 275 name == wxT("indeterminate-if") ||
d7463f75
JS
276 name == wxT("context"))
277 {
278 doc->RefreshDependencies();
279 }
280 if (doc && doc->GetFirstView() && oldModified != doc->IsModified())
281 ((ctConfigToolView*)doc->GetFirstView())->OnChangeFilename();
282}
283
284/// Get the associated document (currently, assumes
285/// there's only ever one document active)
286ctConfigToolDoc* ctConfigItem::GetDocument()
287{
288 ctConfigToolDoc* doc = wxGetApp().GetMainFrame()->GetDocument();
289 return doc;
290}
291
292/// Convert string containing config item names to
293/// an array of config item names
294void ctConfigItem::StringToArray(const wxString& items, wxArrayString& itemsArray)
295{
296 wxStringTokenizer tokenizer(items, wxT(","));
297 while (tokenizer.HasMoreTokens())
298 {
299 wxString token = tokenizer.GetNextToken();
300 itemsArray.Add(token);
301 }
302}
303
304/// Convert array containing config item names to
305/// a string
306void ctConfigItem::ArrayToString(const wxArrayString& itemsArray, wxString& items)
307{
308 items = wxEmptyString;
309 size_t i;
310 for (i = 0; i < itemsArray.GetCount(); i++)
311 {
312 items += itemsArray[i];
313 if (i < (itemsArray.GetCount() - 1))
314 items += wxT(",");
315 }
316}
317
318/// Populate a list of items found in the string.
319void ctConfigItem::StringToItems(ctConfigItem* topItem, const wxString& items, wxList& list)
320{
321 wxArrayString strArray;
322 StringToArray(items, strArray);
323 size_t i;
324 for (i = 0; i < strArray.GetCount(); i++)
325 {
326 wxString str(strArray[i]);
327 ctConfigItem* item = topItem->FindItem(str);
328 if (item)
329 list.Append(item);
330 }
331}
332
333/// Find an item in this hierarchy
334ctConfigItem* ctConfigItem::FindItem(const wxString& name)
335{
336 if (GetName() == name)
337 return this;
338
339 for ( wxNode* node = GetChildren().GetFirst(); node; node = node->GetNext() )
340 {
341 ctConfigItem* child = (ctConfigItem*) node->GetData();
342 ctConfigItem* found = child->FindItem(name);
343 if (found)
344 return found;
345 }
346 return NULL;
347}
348
349/// Find the next sibling
350ctConfigItem* ctConfigItem::FindNextSibling()
351{
352 if (!GetParent())
353 return NULL;
354 wxNode* node = GetParent()->GetChildren().Member(this);
355 if (node && node->GetNext())
356 {
357 return (ctConfigItem*) node->GetNext()->GetData();
358 }
359 return NULL;
360}
361
362/// Find the previous sibling
363ctConfigItem* ctConfigItem::FindPreviousSibling()
364{
365 if (!GetParent())
366 return NULL;
367 wxNode* node = GetParent()->GetChildren().Member(this);
368 if (node && node->GetPrevious())
369 {
370 return (ctConfigItem*) node->GetPrevious()->GetData();
371 }
372 return NULL;
373}
374
375/// Sync appearance
376void ctConfigItem::Sync()
377{
378 if (GetDocument())
379 {
380 ctConfigToolView* view = (ctConfigToolView*) GetDocument()->GetFirstView();
381 if (view)
382 {
383 view->SyncItem(wxGetApp().GetMainFrame()->GetConfigTreeCtrl(), this);
384 }
385 }
386}
387
388/// Create a clone of this and children
389ctConfigItem* ctConfigItem::DeepClone()
390{
391 ctConfigItem* newItem = Clone();
392
393 for ( wxNode* node = GetChildren().GetFirst(); node; node = node->GetNext() )
394 {
395 ctConfigItem* child = (ctConfigItem*) node->GetData();
396 ctConfigItem* newChild = child->DeepClone();
397 newItem->AddChild(newChild);
398 }
399 return newItem;
400}
401
402/// Detach: remove from parent, and remove tree items
403void ctConfigItem::Detach()
404{
405 if (GetParent())
406 GetParent()->RemoveChild(this);
407 else
408 GetDocument()->SetTopItem(NULL);
409 SetParent(NULL);
410
411 wxTreeItemId treeItem = GetTreeItemId();
412
413 DetachFromTree();
414
415 // Will delete the branch, but not the config items.
416 wxGetApp().GetMainFrame()->GetConfigTreeCtrl()->Delete(treeItem);
417}
418
419/// Hide from tree: make sure tree deletions won't delete
420/// the config items
421void ctConfigItem::DetachFromTree()
422{
423 wxTreeItemId item = GetTreeItemId();
424
425 ctTreeItemData* data = (ctTreeItemData*) wxGetApp().GetMainFrame()->GetConfigTreeCtrl()->GetItemData(item);
426 data->SetConfigItem(NULL);
427 m_treeItemId = wxTreeItemId();
428
429 for ( wxNode* node = GetChildren().GetFirst(); node; node = node->GetNext() )
430 {
431 ctConfigItem* child = (ctConfigItem*) node->GetData();
432 child->DetachFromTree();
433 }
434}
435
436/// Attach: insert after the given position
437void ctConfigItem::Attach(ctConfigItem* parent, ctConfigItem* insertBefore)
438{
439 if (parent)
440 {
441 SetParent(parent);
442 wxNode* node = NULL;
443 if (insertBefore)
444 node = parent->GetChildren().Member(insertBefore);
445
446 if (node)
447 parent->GetChildren().Insert(node, this);
448 else
449 parent->GetChildren().Append(this);
450 }
451 else
452 {
453 GetDocument()->SetTopItem(this);
454 }
455}
456
457/// Can have children?
458bool ctConfigItem::CanHaveChildren() const
459{
460 return (GetType() == ctTypeGroup ||
461 GetType() == ctTypeCheckGroup ||
462 GetType() == ctTypeRadioGroup);
463}
464
465// An item is in the active context if:
466// The context field is empty; or
467// The context field contains a symbol that is currently enabled.
468bool ctConfigItem::IsInActiveContext()
469{
470 wxString context = GetPropertyString(wxT("context"));
471 if (context.IsEmpty())
472 return TRUE;
473
474 wxList contextItems;
475 StringToItems(GetDocument()->GetTopItem(), context, contextItems);
476
477 for ( wxNode* node = contextItems.GetFirst(); node; node = node->GetNext() )
478 {
479 ctConfigItem* otherItem = (ctConfigItem*) node->GetData();
480 if (otherItem->IsEnabled())
481 return TRUE;
482 }
483 return FALSE;
484}
485
486/// Evaluate the requires properties:
487/// if any of the 'requires' items are disabled,
488/// then this one is disabled (and inactive).
489void ctConfigItem::EvaluateDependencies()
490{
afc51590
JS
491 // For debugging purposes
492 wxString name = GetName();
d7463f75
JS
493 wxList items;
494 wxString requires = GetPropertyString(wxT("requires"));
495 wxString precludes = GetPropertyString(wxT("precludes"));
496 wxString enabledIf = GetPropertyString(wxT("enabled-if"));
497 wxString enabledIfNot = GetPropertyString(wxT("enabled-if-not"));
afc51590 498 wxString indeterminateIf = GetPropertyString(wxT("indeterminate-if"));
d7463f75
JS
499
500 bool active = TRUE;
501 bool enabled = IsEnabled();
502 bool oldEnabled = enabled;
503 bool oldActive = IsActive();
504 bool explicitlyEnabled = FALSE;
505 bool explicitlyDisabled = FALSE;
506 bool inActiveContext = IsInActiveContext();
507
508 // Add the parent to the list of dependencies, if the
509 // parent is a check or radio group.
510 ctConfigItem* parent = GetParent();
511 if (parent &&
512 (parent->GetType() == ctTypeCheckGroup ||
513 parent->GetType() == ctTypeRadioGroup))
514 items.Append(parent);
515
516 wxList tempItems;
517 StringToItems(GetDocument()->GetTopItem(), requires, tempItems);
518
519 wxNode* node;
520 for ( node = tempItems.GetFirst(); node; node = node->GetNext() )
521 {
522 // Only consider the dependency if both items are in
523 // an active context.
524 // Each is in the active context if:
525 // The context field is empty; or
526 // The context field contains a symbol that is currently enabled.
527 ctConfigItem* otherItem = (ctConfigItem*) node->GetData();
528 if (inActiveContext && otherItem->IsInActiveContext())
529 items.Append(otherItem);
530 }
531
532 {
533 int enabledCount = 0;
534 for ( node = items.GetFirst(); node; node = node->GetNext() )
535 {
536 ctConfigItem* otherItem = (ctConfigItem*) node->GetData();
537
538 if (otherItem->IsEnabled())
539 {
540 enabledCount ++;
541 }
542 }
543 if (items.GetCount() > 0 && enabledCount == 0)
544 {
545 // None of the items were enabled
546 enabled = FALSE;
547 active = FALSE;
548 explicitlyDisabled = TRUE;
549 }
550 }
551
552 items.Clear();
553 if (!enabledIfNot.IsEmpty())
554 {
555 StringToItems(GetDocument()->GetTopItem(), enabledIfNot, items);
556 int disabledCount = 0;
557 int inContextCount = 0;
558
559 for ( wxNode* node = items.GetFirst(); node; node = node->GetNext() )
560 {
561 ctConfigItem* otherItem = (ctConfigItem*) node->GetData();
562
563 if (inActiveContext && otherItem->IsInActiveContext())
564 {
565 // Make this enabled and inactive, _unless_ it's
566 // already been explicitly disabled in the previous
567 // requires evaluation (it really _has_ to be off)
568 if (!otherItem->IsEnabled())
569 {
570 disabledCount ++;
571 }
572 inContextCount ++;
573 }
574 }
575 // Enable if there were no related items that were enabled
576 if (inContextCount > 0 && (disabledCount == inContextCount) && !explicitlyDisabled)
577 {
578 explicitlyEnabled = TRUE;
579 enabled = TRUE;
580 active = FALSE;
581 }
582 }
583
584 items.Clear();
585 if (!enabledIf.IsEmpty())
586 {
587 StringToItems(GetDocument()->GetTopItem(), enabledIf, items);
588 int enabledCount = 0;
589 int inContextCount = 0;
590
591 for ( wxNode* node = items.GetFirst(); node; node = node->GetNext() )
592 {
593 ctConfigItem* otherItem = (ctConfigItem*) node->GetData();
afc51590 594 wxString otherName = otherItem->GetName();
d7463f75
JS
595
596 if (inActiveContext && otherItem->IsInActiveContext())
597 {
598 // Make this enabled and inactive, _unless_ it's
599 // already been explicitly disabled in the previous
600 // requires evaluation (it really _has_ to be off)
601 if (otherItem->IsEnabled())
602 {
603 enabledCount ++;
604 }
605 inContextCount ++;
606 }
607 }
608 // Enable if there were no related items that were disabled
609 if (inContextCount > 0 && (enabledCount > 0) && !explicitlyDisabled)
610 {
611 explicitlyEnabled = TRUE;
612 enabled = TRUE;
613 active = FALSE;
614 }
615 }
616
617 items.Clear();
618 if (!precludes.IsEmpty())
619 {
620 StringToItems(GetDocument()->GetTopItem(), precludes, items);
621 int enabledCount = 0;
afc51590 622 // int disabledCount = 0;
d7463f75
JS
623 int inContextCount = 0;
624
625 for ( wxNode* node = items.GetFirst(); node; node = node->GetNext() )
626 {
627 ctConfigItem* otherItem = (ctConfigItem*) node->GetData();
628
629 if (inActiveContext && otherItem->IsInActiveContext())
630 {
afc51590
JS
631 // Make this disabled and inactive, _unless_ it's
632 // already been explicitly enabled in the previous
633 // requires evaluation (it really _has_ to be on)
634// if (!otherItem->IsEnabled())
d7463f75
JS
635 if (otherItem->IsEnabled())
636 {
637 enabledCount ++;
afc51590 638 // disabledCount ++;
d7463f75 639 }
afc51590 640 inContextCount ++;
d7463f75
JS
641 }
642 }
643 // Disable if there were no related items that were disabled
afc51590
JS
644 if (inContextCount > 0 && (enabledCount > 0) && !explicitlyEnabled)
645// if (inContextCount > 0 && (disabledCount > 0) && !explicitlyEnabled)
d7463f75
JS
646 {
647 enabled = FALSE;
648 active = FALSE;
afc51590
JS
649 explicitlyDisabled = TRUE;
650 }
651 }
652
653 // Indeterminate overrides the others, and
654 // makes the item active.
655 items.Clear();
656 if (!indeterminateIf.IsEmpty())
657 {
658 StringToItems(GetDocument()->GetTopItem(), indeterminateIf, items);
659 int enabledCount = 0;
660 int inContextCount = 0;
661
662 for ( wxNode* node = items.GetFirst(); node; node = node->GetNext() )
663 {
664 ctConfigItem* otherItem = (ctConfigItem*) node->GetData();
665
666 if (inActiveContext && otherItem->IsInActiveContext())
667 {
668 if (otherItem->IsEnabled())
669 {
670 enabledCount ++;
671 }
672 inContextCount ++;
673 }
674 }
675 if (inContextCount > 0 && enabledCount > 0)
676 {
677 active = TRUE;
678 explicitlyEnabled = FALSE;
679 explicitlyDisabled = FALSE;
d7463f75
JS
680 }
681 }
682
683 // Finally check a sort of dependency: whether our
684 // context is active. If not, make this inactive.
685 if (!IsInActiveContext())
686 active = FALSE;
afc51590
JS
687 else
688 {
689 // If we didn't explicitly enable or disable it,
690 // then we should make it active.
691 if (!explicitlyEnabled && !explicitlyDisabled)
692 active = TRUE;
693 }
d7463f75
JS
694
695 SetActive(active);
696
697 // If going active, set enabled state to the default state
698 if (active &&
699 oldActive != active &&
700 (GetType() == ctTypeBoolCheck || GetType() == ctTypeCheckGroup) &&
701 m_properties.FindProperty(wxT("default-state")))
702 {
703 bool defaultState = m_properties.FindProperty(wxT("default-state"))->GetVariant().GetBool();
704 enabled = defaultState;
705 }
706 Enable(enabled);
707
708 // Deal with setting a radio button
709 if (enabled && enabled != oldEnabled &&
710 (GetType() == ctTypeBoolRadio || GetType() == ctTypeRadioGroup))
711 {
712 wxList considered;
713 PropagateRadioButton(considered);
714 }
715}
716
717/// Get description, which may be dynamically
718/// generated depending on the property.
719wxString ctConfigItem::GetDescription(ctProperty* property)
720{
721 if (property->GetName() == wxT("description"))
722 {
723 wxString value(property->GetValue());
724 if (value.IsEmpty())
725 return wxT("Double-click on <B>description</B> to write a brief explanation of the setting.<P>");
726 else
727 return value;
728 }
729 else if (property->GetName() == wxT("notes"))
730 {
731 wxString value(property->GetValue());
732 if (value.IsEmpty())
733 return wxT("Double-click on <B>notes</B> to write notes about this setting.<P>");
734 else
735 return value;
736 }
737 return property->GetDescription();
738}
739
740/// Get the title for the property editor
741wxString ctConfigItem::GetTitle()
742{
743 wxString title(GetName());
744 if (GetType() == ctTypeCheckGroup ||
745 GetType() == ctTypeRadioGroup ||
746 GetType() == ctTypeBoolCheck ||
747 GetType() == ctTypeBoolRadio)
748 {
749 if (IsEnabled())
750 title = title + _T(" - enabled");
751 else
752 title = title + _T(" - disabled");
753 }
754 return title;
755}
756
757/// Propagate a change in enabled/disabled status
758void ctConfigItem::PropagateChange(wxList& considered)
759{
760 if (GetType() == ctTypeCheckGroup ||
761 GetType() == ctTypeRadioGroup ||
762 GetType() == ctTypeBoolCheck ||
763 GetType() == ctTypeBoolRadio)
764 {
765 // TODO: what about string, integer? Can they have
766 // dependencies?
767
768 for ( wxNode* node = GetDependents().GetFirst(); node; node = node->GetNext() )
769 {
770 ctConfigItem* child = (ctConfigItem*) node->GetData();
771
772 // Avoid loops
773 if (!considered.Member(child))
774 {
775 considered.Append(child);
776
777 child->EvaluateDependencies();
778 child->Sync();
779
780 child->PropagateChange(considered);
781 }
782 }
783 }
784}
785
786/// Process radio button selection
787void ctConfigItem::PropagateRadioButton(wxList& considered)
788{
789 if ((GetType() == ctTypeBoolRadio || GetType() == ctTypeRadioGroup) && IsEnabled())
790 {
791 wxString mutuallyExclusive(GetPropertyString(wxT("exclusivity")));
792
793 wxList list;
794 StringToItems(GetDocument()->GetTopItem(), mutuallyExclusive, list);
795
796 for ( wxNode* node = list.GetFirst(); node; node = node->GetNext() )
797 {
798 ctConfigItem* child = (ctConfigItem*) node->GetData();
799 if (child->IsEnabled() && child != this)
800 {
801 child->Enable(FALSE);
802 child->Sync();
803
804 if (!considered.Member(child))
805 child->PropagateChange(considered);
806 }
807 }
808 }
809}