]>
Commit | Line | Data |
---|---|---|
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 | ||
32 | IMPLEMENT_CLASS(ctConfigItem, wxObject) | |
33 | ||
34 | ctConfigItem::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 | ||
44 | ctConfigItem::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 | ||
57 | ctConfigItem::~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? | |
79 | bool 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. | |
89 | void 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. | |
100 | void ctConfigItem::SetName(const wxString& name ) | |
101 | { | |
102 | m_properties.SetProperty(wxT("name"), name); | |
103 | } | |
104 | ||
105 | /// Clear children | |
106 | void 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 | |
125 | ctConfigItem* 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 | |
139 | int ctConfigItem::GetChildCount() const | |
140 | { | |
141 | return m_children.GetCount(); | |
142 | } | |
143 | ||
144 | /// Add a child | |
145 | void ctConfigItem::AddChild(ctConfigItem* item) | |
146 | { | |
147 | m_children.Append(item); | |
148 | item->SetParent(this); | |
149 | } | |
150 | ||
151 | /// Remove (but don't delete) a child | |
152 | void ctConfigItem::RemoveChild(ctConfigItem* item) | |
153 | { | |
154 | m_children.DeleteObject(item); | |
155 | item->SetParent(NULL); | |
156 | } | |
157 | ||
158 | /// Initialise standard properties | |
159 | void 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 | 264 | void 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) | |
286 | ctConfigToolDoc* 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 | |
294 | void 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 | |
306 | void 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. | |
319 | void 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 | |
334 | ctConfigItem* 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 | |
350 | ctConfigItem* 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 | |
363 | ctConfigItem* 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 | |
376 | void 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 | |
389 | ctConfigItem* 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 | |
403 | void 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 | |
421 | void 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 | |
437 | void 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? | |
458 | bool 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. | |
468 | bool 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). | |
489 | void 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. | |
719 | wxString 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 | |
741 | wxString 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 | |
758 | void 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 | |
787 | void 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 | } |