]>
git.saurik.com Git - wxWidgets.git/blob - utils/configtool/src/configitem.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: configitem.cpp
3 // Purpose: wxWindows Configuration Tool config item class
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "configitem.h"
16 // Includes other headers for precompiled compilation
23 #include "wx/tokenzr.h"
25 #include "configitem.h"
26 #include "configtree.h"
27 #include "configtooldoc.h"
28 #include "configtoolview.h"
29 #include "wxconfigtool.h"
30 #include "mainframe.h"
32 IMPLEMENT_CLASS ( ctConfigItem
, wxObject
)
34 ctConfigItem :: ctConfigItem ()
37 m_type
= ctTypeBoolCheck
;
38 m_treeItemId
= wxTreeItemId ();
44 ctConfigItem :: ctConfigItem ( ctConfigItem
* parent
, ctConfigType type
, const wxString
& name
)
48 m_treeItemId
= wxTreeItemId ();
54 parent
-> AddChild ( this );
57 ctConfigItem ::~ ctConfigItem ()
59 ctConfigTreeCtrl
* treeCtrl
= wxGetApp (). GetMainFrame ()-> GetConfigTreeCtrl ();
60 if ( m_treeItemId
. IsOk () && treeCtrl
)
62 ctTreeItemData
* data
= ( ctTreeItemData
*) treeCtrl
-> GetItemData ( m_treeItemId
);
64 data
-> SetConfigItem ( NULL
);
67 GetParent ()-> RemoveChild ( this );
70 if ( wxGetApp (). GetMainFrame ()-> GetDocument () &&
71 wxGetApp (). GetMainFrame ()-> GetDocument ()-> GetTopItem () == this )
72 wxGetApp (). GetMainFrame ()-> GetDocument ()-> SetTopItem ( NULL
);
78 /// Can we edit this property?
79 bool ctConfigItem :: CanEditProperty ( const wxString
& propName
) const
81 ctProperty
* prop
= m_properties
. FindProperty ( propName
);
83 return ! prop
-> GetReadOnly ();
88 /// Assignment operator.
89 void ctConfigItem :: operator = ( const ctConfigItem
& item
)
91 m_properties
= item
. m_properties
;
92 m_modified
= item
. m_modified
;
93 m_defaultProperty
= item
. m_defaultProperty
;
95 m_enabled
= item
. m_enabled
;
96 m_active
= item
. m_active
;
99 /// Sets the name property.
100 void ctConfigItem :: SetName ( const wxString
& name
)
102 m_properties
. SetProperty ( wxT ( "name" ), name
);
106 void ctConfigItem :: Clear ()
108 wxNode
* node
= m_children
. GetFirst ();
111 wxNode
* next
= node
-> GetNext ();
112 ctConfigItem
* child
= ( ctConfigItem
*) node
-> GetData ();
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().
125 ctConfigItem
* ctConfigItem :: GetChild ( int n
) const
127 wxASSERT ( n
< GetChildCount () && n
> - 1 );
129 if ( n
< GetChildCount () && n
> - 1 )
131 ctConfigItem
* child
= wxDynamicCast ( m_children
. Item ( n
)-> GetData (), ctConfigItem
);
138 // Get the child count
139 int ctConfigItem :: GetChildCount () const
141 return m_children
. GetCount ();
145 void ctConfigItem :: AddChild ( ctConfigItem
* item
)
147 m_children
. Append ( item
);
148 item
-> SetParent ( this );
151 /// Remove (but don't delete) a child
152 void ctConfigItem :: RemoveChild ( ctConfigItem
* item
)
154 m_children
. DeleteObject ( item
);
155 item
-> SetParent ( NULL
);
158 /// Initialise standard properties
159 void ctConfigItem :: InitProperties ()
161 ctProperty
* prop
= m_properties
. FindProperty ( wxT ( "name" ));
164 prop
= new ctProperty
;
165 m_properties
. AddProperty ( prop
);
167 prop
-> SetDescription ( _ ( "<B>Name</B><P> The name of the configuration setting." ));
168 prop
-> SetReadOnly ( TRUE
);
170 m_properties
. AddProperty (
172 wxT ( "<B>Description</B><P> The setting description." ),
173 wxVariant ( wxT ( "" ), wxT ( "description" )),
176 m_properties
. AddProperty (
178 wxT ( "<B>Default-state</B><P> The default state." ),
179 wxVariant (( bool ) TRUE
, wxT ( "default-state" )),
182 if ( GetType () == ctTypeString
)
184 m_properties
. AddProperty (
186 wxT ( "<B>Default-value</B><P> The default value." ),
187 wxVariant (( bool ) TRUE
, wxT ( "default-value" )),
190 else if ( GetType () == ctTypeInteger
)
192 m_properties
. AddProperty (
194 wxT ( "<B>Default-value</B><P> The default value." ),
195 wxVariant (( long ) 0 , wxT ( "default-value" )),
199 m_properties
. AddProperty (
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" )));
205 m_properties
. AddProperty (
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" )));
211 m_properties
. AddProperty (
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" )));
217 m_properties
. AddProperty (
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" )));
223 m_properties
. AddProperty (
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" )));
229 m_properties
. AddProperty (
231 wxT ( "<B>Exclusivity</B><P> The settings that are mutually exclusive with this one." ),
232 wxVariant ( wxT ( "" ), wxT ( "exclusivity" )),
233 wxT ( "configitems" )));
235 m_properties
. AddProperty (
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> \n If empty, this item will always be used in dependency rules.<P> \n Mostly 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" )));
241 m_properties
. AddProperty (
243 wxT ( "<B>Configure-command</B><P> Configure command to generate if this is on." ),
244 wxVariant ( wxT ( "" ), wxT ( "configure-command" )),
247 m_properties
. AddProperty (
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" )),
253 m_properties
. AddProperty (
255 wxT ( "<B>Notes</B><P> User notes." ),
256 wxVariant ( wxT ( "" ), wxT ( "notes" )),
259 m_defaultProperty
= wxT ( "description" );
262 /// Do additional actions to apply the property to the internal
264 void ctConfigItem :: ApplyProperty ( ctProperty
* prop
, const wxVariant
& oldValue
)
266 ctConfigToolDoc
* doc
= GetDocument ();
267 bool oldModified
= doc
-> IsModified ();
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" ) ||
275 name
== wxT ( "indeterminate-if" ) ||
276 name
== wxT ( "context" ))
278 doc
-> RefreshDependencies ();
280 if ( doc
&& doc
-> GetFirstView () && oldModified
!= doc
-> IsModified ())
281 (( ctConfigToolView
*) doc
-> GetFirstView ())-> OnChangeFilename ();
284 /// Get the associated document (currently, assumes
285 /// there's only ever one document active)
286 ctConfigToolDoc
* ctConfigItem :: GetDocument ()
288 ctConfigToolDoc
* doc
= wxGetApp (). GetMainFrame ()-> GetDocument ();
292 /// Convert string containing config item names to
293 /// an array of config item names
294 void ctConfigItem :: StringToArray ( const wxString
& items
, wxArrayString
& itemsArray
)
296 wxStringTokenizer
tokenizer ( items
, wxT ( "," ));
297 while ( tokenizer
. HasMoreTokens ())
299 wxString token
= tokenizer
. GetNextToken ();
300 itemsArray
. Add ( token
);
304 /// Convert array containing config item names to
306 void ctConfigItem :: ArrayToString ( const wxArrayString
& itemsArray
, wxString
& items
)
308 items
= wxEmptyString
;
310 for ( i
= 0 ; i
< itemsArray
. GetCount (); i
++)
312 items
+= itemsArray
[ i
];
313 if ( i
< ( itemsArray
. GetCount () - 1 ))
318 /// Populate a list of items found in the string.
319 void ctConfigItem :: StringToItems ( ctConfigItem
* topItem
, const wxString
& items
, wxList
& list
)
321 wxArrayString strArray
;
322 StringToArray ( items
, strArray
);
324 for ( i
= 0 ; i
< strArray
. GetCount (); i
++)
326 wxString
str ( strArray
[ i
]);
327 ctConfigItem
* item
= topItem
-> FindItem ( str
);
333 /// Find an item in this hierarchy
334 ctConfigItem
* ctConfigItem :: FindItem ( const wxString
& name
)
336 if ( GetName () == name
)
339 for ( wxNode
* node
= GetChildren (). GetFirst (); node
; node
= node
-> GetNext () )
341 ctConfigItem
* child
= ( ctConfigItem
*) node
-> GetData ();
342 ctConfigItem
* found
= child
-> FindItem ( name
);
349 /// Find the next sibling
350 ctConfigItem
* ctConfigItem :: FindNextSibling ()
354 wxNode
* node
= GetParent ()-> GetChildren (). Member ( this );
355 if ( node
&& node
-> GetNext ())
357 return ( ctConfigItem
*) node
-> GetNext ()-> GetData ();
362 /// Find the previous sibling
363 ctConfigItem
* ctConfigItem :: FindPreviousSibling ()
367 wxNode
* node
= GetParent ()-> GetChildren (). Member ( this );
368 if ( node
&& node
-> GetPrevious ())
370 return ( ctConfigItem
*) node
-> GetPrevious ()-> GetData ();
376 void ctConfigItem :: Sync ()
380 ctConfigToolView
* view
= ( ctConfigToolView
*) GetDocument ()-> GetFirstView ();
383 view
-> SyncItem ( wxGetApp (). GetMainFrame ()-> GetConfigTreeCtrl (), this );
388 /// Create a clone of this and children
389 ctConfigItem
* ctConfigItem :: DeepClone ()
391 ctConfigItem
* newItem
= Clone ();
393 for ( wxNode
* node
= GetChildren (). GetFirst (); node
; node
= node
-> GetNext () )
395 ctConfigItem
* child
= ( ctConfigItem
*) node
-> GetData ();
396 ctConfigItem
* newChild
= child
-> DeepClone ();
397 newItem
-> AddChild ( newChild
);
402 /// Detach: remove from parent, and remove tree items
403 void ctConfigItem :: Detach ()
406 GetParent ()-> RemoveChild ( this );
408 GetDocument ()-> SetTopItem ( NULL
);
411 wxTreeItemId treeItem
= GetTreeItemId ();
415 // Will delete the branch, but not the config items.
416 wxGetApp (). GetMainFrame ()-> GetConfigTreeCtrl ()-> Delete ( treeItem
);
419 /// Hide from tree: make sure tree deletions won't delete
421 void ctConfigItem :: DetachFromTree ()
423 wxTreeItemId item
= GetTreeItemId ();
425 ctTreeItemData
* data
= ( ctTreeItemData
*) wxGetApp (). GetMainFrame ()-> GetConfigTreeCtrl ()-> GetItemData ( item
);
426 data
-> SetConfigItem ( NULL
);
427 m_treeItemId
= wxTreeItemId ();
429 for ( wxNode
* node
= GetChildren (). GetFirst (); node
; node
= node
-> GetNext () )
431 ctConfigItem
* child
= ( ctConfigItem
*) node
-> GetData ();
432 child
-> DetachFromTree ();
436 /// Attach: insert after the given position
437 void ctConfigItem :: Attach ( ctConfigItem
* parent
, ctConfigItem
* insertBefore
)
444 node
= parent
-> GetChildren (). Member ( insertBefore
);
447 parent
-> GetChildren (). Insert ( node
, this );
449 parent
-> GetChildren (). Append ( this );
453 GetDocument ()-> SetTopItem ( this );
457 /// Can have children?
458 bool ctConfigItem :: CanHaveChildren () const
460 return ( GetType () == ctTypeGroup
||
461 GetType () == ctTypeCheckGroup
||
462 GetType () == ctTypeRadioGroup
);
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 ()
470 wxString context
= GetPropertyString ( wxT ( "context" ));
471 if ( context
. IsEmpty ())
475 StringToItems ( GetDocument ()-> GetTopItem (), context
, contextItems
);
477 for ( wxNode
* node
= contextItems
. GetFirst (); node
; node
= node
-> GetNext () )
479 ctConfigItem
* otherItem
= ( ctConfigItem
*) node
-> GetData ();
480 if ( otherItem
-> IsEnabled ())
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 ()
491 // For debugging purposes
492 wxString name
= GetName ();
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" ));
498 wxString indeterminateIf
= GetPropertyString ( wxT ( "indeterminate-if" ));
501 bool enabled
= IsEnabled ();
502 bool oldEnabled
= enabled
;
503 bool oldActive
= IsActive ();
504 bool explicitlyEnabled
= FALSE
;
505 bool explicitlyDisabled
= FALSE
;
506 bool inActiveContext
= IsInActiveContext ();
508 // Add the parent to the list of dependencies, if the
509 // parent is a check or radio group.
510 ctConfigItem
* parent
= GetParent ();
512 ( parent
-> GetType () == ctTypeCheckGroup
||
513 parent
-> GetType () == ctTypeRadioGroup
))
514 items
. Append ( parent
);
517 StringToItems ( GetDocument ()-> GetTopItem (), requires , tempItems
);
520 for ( node
= tempItems
. GetFirst (); node
; node
= node
-> GetNext () )
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
);
533 int enabledCount
= 0 ;
534 for ( node
= items
. GetFirst (); node
; node
= node
-> GetNext () )
536 ctConfigItem
* otherItem
= ( ctConfigItem
*) node
-> GetData ();
538 if ( otherItem
-> IsEnabled ())
543 if ( items
. GetCount () > 0 && enabledCount
== 0 )
545 // None of the items were enabled
548 explicitlyDisabled
= TRUE
;
553 if (! enabledIfNot
. IsEmpty ())
555 StringToItems ( GetDocument ()-> GetTopItem (), enabledIfNot
, items
);
556 int disabledCount
= 0 ;
557 int inContextCount
= 0 ;
559 for ( wxNode
* node
= items
. GetFirst (); node
; node
= node
-> GetNext () )
561 ctConfigItem
* otherItem
= ( ctConfigItem
*) node
-> GetData ();
563 if ( inActiveContext
&& otherItem
-> IsInActiveContext ())
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 ())
575 // Enable if there were no related items that were enabled
576 if ( inContextCount
> 0 && ( disabledCount
== inContextCount
) && ! explicitlyDisabled
)
578 explicitlyEnabled
= TRUE
;
585 if (! enabledIf
. IsEmpty ())
587 StringToItems ( GetDocument ()-> GetTopItem (), enabledIf
, items
);
588 int enabledCount
= 0 ;
589 int inContextCount
= 0 ;
591 for ( wxNode
* node
= items
. GetFirst (); node
; node
= node
-> GetNext () )
593 ctConfigItem
* otherItem
= ( ctConfigItem
*) node
-> GetData ();
594 wxString otherName
= otherItem
-> GetName ();
596 if ( inActiveContext
&& otherItem
-> IsInActiveContext ())
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 ())
608 // Enable if there were no related items that were disabled
609 if ( inContextCount
> 0 && ( enabledCount
> 0 ) && ! explicitlyDisabled
)
611 explicitlyEnabled
= TRUE
;
618 if (! precludes
. IsEmpty ())
620 StringToItems ( GetDocument ()-> GetTopItem (), precludes
, items
);
621 int enabledCount
= 0 ;
622 // int disabledCount = 0;
623 int inContextCount
= 0 ;
625 for ( wxNode
* node
= items
. GetFirst (); node
; node
= node
-> GetNext () )
627 ctConfigItem
* otherItem
= ( ctConfigItem
*) node
-> GetData ();
629 if ( inActiveContext
&& otherItem
-> IsInActiveContext ())
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())
635 if ( otherItem
-> IsEnabled ())
643 // Disable if there were no related items that were disabled
644 if ( inContextCount
> 0 && ( enabledCount
> 0 ) && ! explicitlyEnabled
)
645 // if (inContextCount > 0 && (disabledCount > 0) && !explicitlyEnabled)
649 explicitlyDisabled
= TRUE
;
653 // Indeterminate overrides the others, and
654 // makes the item active.
656 if (! indeterminateIf
. IsEmpty ())
658 StringToItems ( GetDocument ()-> GetTopItem (), indeterminateIf
, items
);
659 int enabledCount
= 0 ;
660 int inContextCount
= 0 ;
662 for ( wxNode
* node
= items
. GetFirst (); node
; node
= node
-> GetNext () )
664 ctConfigItem
* otherItem
= ( ctConfigItem
*) node
-> GetData ();
666 if ( inActiveContext
&& otherItem
-> IsInActiveContext ())
668 if ( otherItem
-> IsEnabled ())
675 if ( inContextCount
> 0 && enabledCount
> 0 )
678 explicitlyEnabled
= FALSE
;
679 explicitlyDisabled
= FALSE
;
683 // Finally check a sort of dependency: whether our
684 // context is active. If not, make this inactive.
685 if (! IsInActiveContext ())
689 // If we didn't explicitly enable or disable it,
690 // then we should make it active.
691 if (! explicitlyEnabled
&& ! explicitlyDisabled
)
697 // If going active, set enabled state to the default state
699 oldActive
!= active
&&
700 ( GetType () == ctTypeBoolCheck
|| GetType () == ctTypeCheckGroup
) &&
701 m_properties
. FindProperty ( wxT ( "default-state" )))
703 bool defaultState
= m_properties
. FindProperty ( wxT ( "default-state" ))-> GetVariant (). GetBool ();
704 enabled
= defaultState
;
708 // Deal with setting a radio button
709 if ( enabled
&& enabled
!= oldEnabled
&&
710 ( GetType () == ctTypeBoolRadio
|| GetType () == ctTypeRadioGroup
))
713 PropagateRadioButton ( considered
);
717 /// Get description, which may be dynamically
718 /// generated depending on the property.
719 wxString
ctConfigItem :: GetDescription ( ctProperty
* property
)
721 if ( property
-> GetName () == wxT ( "description" ))
723 wxString
value ( property
-> GetValue ());
725 return wxT ( "Double-click on <B>description</B> to write a brief explanation of the setting.<P>" );
729 else if ( property
-> GetName () == wxT ( "notes" ))
731 wxString
value ( property
-> GetValue ());
733 return wxT ( "Double-click on <B>notes</B> to write notes about this setting.<P>" );
737 return property
-> GetDescription ();
740 /// Get the title for the property editor
741 wxString
ctConfigItem :: GetTitle ()
743 wxString
title ( GetName ());
744 if ( GetType () == ctTypeCheckGroup
||
745 GetType () == ctTypeRadioGroup
||
746 GetType () == ctTypeBoolCheck
||
747 GetType () == ctTypeBoolRadio
)
750 title
= title
+ _T ( " - enabled" );
752 title
= title
+ _T ( " - disabled" );
757 /// Propagate a change in enabled/disabled status
758 void ctConfigItem :: PropagateChange ( wxList
& considered
)
760 if ( GetType () == ctTypeCheckGroup
||
761 GetType () == ctTypeRadioGroup
||
762 GetType () == ctTypeBoolCheck
||
763 GetType () == ctTypeBoolRadio
)
765 // TODO: what about string, integer? Can they have
768 for ( wxNode
* node
= GetDependents (). GetFirst (); node
; node
= node
-> GetNext () )
770 ctConfigItem
* child
= ( ctConfigItem
*) node
-> GetData ();
773 if (! considered
. Member ( child
))
775 considered
. Append ( child
);
777 child
-> EvaluateDependencies ();
780 child
-> PropagateChange ( considered
);
786 /// Process radio button selection
787 void ctConfigItem :: PropagateRadioButton ( wxList
& considered
)
789 if (( GetType () == ctTypeBoolRadio
|| GetType () == ctTypeRadioGroup
) && IsEnabled ())
791 wxString
mutuallyExclusive ( GetPropertyString ( wxT ( "exclusivity" )));
794 StringToItems ( GetDocument ()-> GetTopItem (), mutuallyExclusive
, list
);
796 for ( wxNode
* node
= list
. GetFirst (); node
; node
= node
-> GetNext () )
798 ctConfigItem
* child
= ( ctConfigItem
*) node
-> GetData ();
799 if ( child
-> IsEnabled () && child
!= this )
801 child
-> Enable ( FALSE
);
804 if (! considered
. Member ( child
))
805 child
-> PropagateChange ( considered
);