]>
Commit | Line | Data |
---|---|---|
d7463f75 JS |
1 | ///////////////////////////////////////////////////////////////////////////// |
2 | // Name: configitem.cpp | |
be5a51fb | 3 | // Purpose: wxWidgets Configuration Tool config item class |
d7463f75 JS |
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 | ||
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 | ||
19 | #include "wx/tokenzr.h" | |
d7463f75 JS |
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 | { | |
4fe30bce | 31 | m_modified = false; |
d7463f75 JS |
32 | m_type = ctTypeBoolCheck; |
33 | m_treeItemId = wxTreeItemId(); | |
4fe30bce | 34 | m_enabled = true; |
d7463f75 | 35 | m_parent = NULL; |
4fe30bce | 36 | m_active = true; |
d7463f75 JS |
37 | } |
38 | ||
39 | ctConfigItem::ctConfigItem(ctConfigItem* parent, ctConfigType type, const wxString& name) | |
40 | { | |
4fe30bce | 41 | m_modified = false; |
d7463f75 JS |
42 | m_type = type; |
43 | m_treeItemId = wxTreeItemId(); | |
4fe30bce WS |
44 | m_enabled = false; |
45 | m_active = true; | |
d7463f75 JS |
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 | |
4fe30bce | 80 | return false; |
d7463f75 JS |
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 | { | |
8d0f1c1c | 103 | wxObjectList::compatibility_iterator node = m_children.GetFirst(); |
d7463f75 JS |
104 | while (node) |
105 | { | |
8d0f1c1c | 106 | wxObjectList::compatibility_iterator next = node->GetNext(); |
d7463f75 JS |
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 | { | |
f8105809 | 126 | ctConfigItem* child = wxDynamicCast(m_children.Item(n)->GetData(), ctConfigItem); |
d7463f75 JS |
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.")); | |
4fe30bce | 163 | prop->SetReadOnly(true); |
d7463f75 JS |
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."), | |
4fe30bce | 174 | wxVariant(true, wxT("default-state")), |
d7463f75 JS |
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."), | |
4fe30bce | 182 | wxVariant(true, wxT("default-value")), |
d7463f75 JS |
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 | ||
afc51590 JS |
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 | ||
d7463f75 JS |
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( | |
be5a51fb | 244 | wxT("<B>Help-topic</B><P> The help topic in the wxWidgets manual for this component or setting."), |
d7463f75 JS |
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. | |
69da0d99 | 259 | void ctConfigItem::ApplyProperty(ctProperty* prop, const wxVariant& WXUNUSED(oldValue)) |
d7463f75 JS |
260 | { |
261 | ctConfigToolDoc* doc = GetDocument(); | |
262 | bool oldModified = doc->IsModified(); | |
4fe30bce | 263 | doc->Modify(true); |
d7463f75 JS |
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") || | |
afc51590 | 270 | name == wxT("indeterminate-if") || |
d7463f75 JS |
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 | ||
8d0f1c1c | 334 | for ( wxObjectList::compatibility_iterator node = GetChildren().GetFirst(); node; node = node->GetNext() ) |
d7463f75 JS |
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; | |
8d0f1c1c | 349 | wxObjectList::compatibility_iterator node = GetParent()->GetChildren().Member(this); |
d7463f75 JS |
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; | |
8d0f1c1c | 362 | wxObjectList::compatibility_iterator node = GetParent()->GetChildren().Member(this); |
d7463f75 JS |
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 | ||
8d0f1c1c | 388 | for ( wxObjectList::compatibility_iterator node = GetChildren().GetFirst(); node; node = node->GetNext() ) |
d7463f75 JS |
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 | ||
8d0f1c1c | 424 | for ( wxObjectList::compatibility_iterator node = GetChildren().GetFirst(); node; node = node->GetNext() ) |
d7463f75 JS |
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); | |
d7463f75 | 437 | if (insertBefore) |
d9ab621e WS |
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 | } | |
d7463f75 JS |
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()) | |
4fe30bce | 469 | return true; |
d7463f75 JS |
470 | |
471 | wxList contextItems; | |
472 | StringToItems(GetDocument()->GetTopItem(), context, contextItems); | |
473 | ||
8d0f1c1c | 474 | for ( wxObjectList::compatibility_iterator node = contextItems.GetFirst(); node; node = node->GetNext() ) |
d7463f75 JS |
475 | { |
476 | ctConfigItem* otherItem = (ctConfigItem*) node->GetData(); | |
477 | if (otherItem->IsEnabled()) | |
4fe30bce | 478 | return true; |
d7463f75 | 479 | } |
4fe30bce | 480 | return false; |
d7463f75 JS |
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 | { | |
afc51590 JS |
488 | // For debugging purposes |
489 | wxString name = GetName(); | |
d7463f75 JS |
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")); | |
afc51590 | 495 | wxString indeterminateIf = GetPropertyString(wxT("indeterminate-if")); |
d7463f75 | 496 | |
4fe30bce | 497 | bool active = true; |
d7463f75 JS |
498 | bool enabled = IsEnabled(); |
499 | bool oldEnabled = enabled; | |
500 | bool oldActive = IsActive(); | |
4fe30bce WS |
501 | bool explicitlyEnabled = false; |
502 | bool explicitlyDisabled = false; | |
d7463f75 JS |
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 | ||
8d0f1c1c | 516 | wxObjectList::compatibility_iterator node; |
d7463f75 JS |
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 | |
4fe30bce WS |
543 | enabled = false; |
544 | active = false; | |
545 | explicitlyDisabled = true; | |
d7463f75 JS |
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 | ||
8d0f1c1c | 556 | for ( wxObjectList::compatibility_iterator node = items.GetFirst(); node; node = node->GetNext() ) |
d7463f75 JS |
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 | { | |
4fe30bce WS |
575 | explicitlyEnabled = true; |
576 | enabled = true; | |
577 | active = false; | |
d7463f75 JS |
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 | ||
8d0f1c1c | 588 | for ( wxObjectList::compatibility_iterator node = items.GetFirst(); node; node = node->GetNext() ) |
d7463f75 JS |
589 | { |
590 | ctConfigItem* otherItem = (ctConfigItem*) node->GetData(); | |
afc51590 | 591 | wxString otherName = otherItem->GetName(); |
d7463f75 JS |
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 | { | |
4fe30bce WS |
608 | explicitlyEnabled = true; |
609 | enabled = true; | |
610 | active = false; | |
d7463f75 JS |
611 | } |
612 | } | |
613 | ||
614 | items.Clear(); | |
615 | if (!precludes.IsEmpty()) | |
616 | { | |
617 | StringToItems(GetDocument()->GetTopItem(), precludes, items); | |
618 | int enabledCount = 0; | |
afc51590 | 619 | // int disabledCount = 0; |
d7463f75 JS |
620 | int inContextCount = 0; |
621 | ||
8d0f1c1c | 622 | for ( wxObjectList::compatibility_iterator node = items.GetFirst(); node; node = node->GetNext() ) |
d7463f75 JS |
623 | { |
624 | ctConfigItem* otherItem = (ctConfigItem*) node->GetData(); | |
625 | ||
626 | if (inActiveContext && otherItem->IsInActiveContext()) | |
627 | { | |
afc51590 JS |
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()) | |
d7463f75 JS |
632 | if (otherItem->IsEnabled()) |
633 | { | |
634 | enabledCount ++; | |
afc51590 | 635 | // disabledCount ++; |
d7463f75 | 636 | } |
afc51590 | 637 | inContextCount ++; |
d7463f75 JS |
638 | } |
639 | } | |
640 | // Disable if there were no related items that were disabled | |
afc51590 JS |
641 | if (inContextCount > 0 && (enabledCount > 0) && !explicitlyEnabled) |
642 | // if (inContextCount > 0 && (disabledCount > 0) && !explicitlyEnabled) | |
d7463f75 | 643 | { |
4fe30bce WS |
644 | enabled = false; |
645 | active = false; | |
646 | explicitlyDisabled = true; | |
afc51590 JS |
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 | ||
8d0f1c1c | 659 | for ( wxObjectList::compatibility_iterator node = items.GetFirst(); node; node = node->GetNext() ) |
afc51590 JS |
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 | { | |
4fe30bce WS |
674 | active = true; |
675 | explicitlyEnabled = false; | |
676 | explicitlyDisabled = false; | |
d7463f75 JS |
677 | } |
678 | } | |
679 | ||
680 | // Finally check a sort of dependency: whether our | |
681 | // context is active. If not, make this inactive. | |
682 | if (!IsInActiveContext()) | |
4fe30bce | 683 | active = false; |
afc51590 JS |
684 | else |
685 | { | |
686 | // If we didn't explicitly enable or disable it, | |
687 | // then we should make it active. | |
688 | if (!explicitlyEnabled && !explicitlyDisabled) | |
4fe30bce | 689 | active = true; |
afc51590 | 690 | } |
d7463f75 JS |
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 | ||
8d0f1c1c | 765 | for ( wxObjectList::compatibility_iterator node = GetDependents().GetFirst(); node; node = node->GetNext() ) |
d7463f75 JS |
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 | ||
8d0f1c1c | 793 | for ( wxObjectList::compatibility_iterator node = list.GetFirst(); node; node = node->GetNext() ) |
d7463f75 JS |
794 | { |
795 | ctConfigItem* child = (ctConfigItem*) node->GetData(); | |
796 | if (child->IsEnabled() && child != this) | |
797 | { | |
4fe30bce | 798 | child->Enable(false); |
d7463f75 JS |
799 | child->Sync(); |
800 | ||
801 | if (!considered.Member(child)) | |
802 | child->PropagateChange(considered); | |
803 | } | |
804 | } | |
805 | } | |
806 | } |