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