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