OpenWalnut  1.4.0
WPropertyVariable.h
00001 //---------------------------------------------------------------------------
00002 //
00003 // Project: OpenWalnut ( http://www.openwalnut.org )
00004 //
00005 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
00006 // For more information see http://www.openwalnut.org/copying
00007 //
00008 // This file is part of OpenWalnut.
00009 //
00010 // OpenWalnut is free software: you can redistribute it and/or modify
00011 // it under the terms of the GNU Lesser General Public License as published by
00012 // the Free Software Foundation, either version 3 of the License, or
00013 // (at your option) any later version.
00014 //
00015 // OpenWalnut is distributed in the hope that it will be useful,
00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 // GNU Lesser General Public License for more details.
00019 //
00020 // You should have received a copy of the GNU Lesser General Public License
00021 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
00022 //
00023 //---------------------------------------------------------------------------
00024 
00025 #ifndef WPROPERTYVARIABLE_H
00026 #define WPROPERTYVARIABLE_H
00027 
00028 #include <stdint.h>
00029 
00030 #include <list>
00031 #include <set>
00032 #include <string>
00033 
00034 #include <boost/shared_ptr.hpp>
00035 #include <boost/signals2.hpp>
00036 
00037 #include "constraints/WPropertyConstraintIsDirectory.h"
00038 #include "constraints/WPropertyConstraintMax.h"
00039 #include "constraints/WPropertyConstraintMin.h"
00040 #include "constraints/WPropertyConstraintNotEmpty.h"
00041 #include "constraints/WPropertyConstraintPathExists.h"
00042 #include "constraints/WPropertyConstraintSelectOnlyOne.h"
00043 #include "constraints/WPropertyConstraintTypes.h"
00044 #include "WCondition.h"
00045 #include "WFlag.h"
00046 #include "WPropertyBase.h"
00047 #include "WSharedAssociativeContainer.h"
00048 #include "WSharedObjectTicketRead.h"
00049 #include "WSharedObjectTicketWrite.h"
00050 
00051 /**
00052  * A named property class with a concrete type.
00053  */
00054 template< typename T >
00055 class WPropertyVariable: public WFlag< T >,
00056                          public WPropertyBase
00057 {
00058 friend class WPropertyVariableTest;
00059 public:
00060     /**
00061      * Convenience typedef for a shared_ptr of WPropertyVariable.
00062      */
00063     typedef boost::shared_ptr< WPropertyVariable< T > > SPtr;
00064 
00065     /**
00066      * Convenience typedef for a shared_ptr of const WPropertyVariable.
00067      */
00068     typedef boost::shared_ptr< const WPropertyVariable< T > > ConstSPtr;
00069 
00070     /**
00071      * Create an empty instance just containing a name.
00072      *
00073      * \param name  the property name
00074      * \param description the property description
00075      * \param initial the initial value
00076      */
00077     WPropertyVariable( std::string name, std::string description, const T& initial );
00078 
00079     /**
00080      * Create an empty instance just containing a name. This constructor allows an external condition to be used for notifiaction.
00081      * This is practical if one would like to share a condition among several properties.
00082      *
00083      * \param name  the property name
00084      * \param description the property description
00085      * \param initial the initial value
00086      * \param condition use this external condition for notification.
00087      */
00088     WPropertyVariable( std::string name, std::string description, const T& initial, boost::shared_ptr< WCondition > condition );
00089 
00090     /**
00091      * Create an empty instance just containing a name. This constructor allows an external callback to be used for notification.
00092      *
00093      * \param name  the property name
00094      * \param description the property description
00095      * \param initial the initial value
00096      * \param notifier use this notifier for change callbacks.
00097      *
00098      * \note: instead of setting another notifier, you should consider using the callbacks the condition offers.
00099      * \note: the notifiers gets connected to the notification callback of the internal condition. So be careful when using the
00100      *        condition ( getCondition() ) for other properties, since they would also share the callbacks
00101      *
00102      */
00103     WPropertyVariable( std::string name, std::string description, const T& initial, PropertyChangeNotifierType notifier );
00104 
00105     /**
00106      * Create an empty instance just containing a name. This constructor allows an external callback and condition to be used for notification.
00107      *
00108      * \param name  the property name
00109      * \param description the property description
00110      * \param initial the initial value
00111      * \param notifier use this notifier for change callbacks.
00112      * \param condition use this external condition for notification
00113      *
00114      * \note: instead of setting another notifier, you should consider using the callbacks the condition offers.
00115      * \note: the notifiers gets connected to the notification callback of the internal condition. So be careful when using the
00116      *        condition ( getCondition() ) for other properties, since they would also share the callbacks
00117      *
00118      */
00119     WPropertyVariable( std::string name, std::string description, const T& initial, boost::shared_ptr< WCondition > condition,
00120                        PropertyChangeNotifierType notifier );
00121 
00122     /**
00123      * Copy constructor. Creates a deep copy of this property. As boost::signals2 and condition variables are non-copyable, new instances get
00124      * created. The subscriptions to a signal are LOST as well as all listeners to a condition.
00125      * The conditions you can grab using getValueChangeConditon and getCondition are not the same as in the original! This is because
00126      * the class corresponds to the observer/observable pattern. You won't expect a clone to fire a condition if a original variable is changed
00127      * (which after cloning is completely decoupled from the clone).
00128      *
00129      * \param from the instance to copy.
00130      */
00131     explicit WPropertyVariable( const WPropertyVariable< T >& from );
00132 
00133     /**
00134      * Destructor.
00135      */
00136     virtual ~WPropertyVariable();
00137 
00138     /**
00139      * This method clones a property and returns the clone. It does a deep copy and, in contrast to a copy constructor, creates property with the
00140      * correct type without explicitly requiring the user to specify it. It creates a NEW change condition and change signal. This means, alls
00141      * subscribed signal handlers are NOT copied.
00142      *
00143      * \note this simply ensures the copy constructor of the runtime type is issued.
00144      *
00145      * \return the deep clone of this property.
00146      */
00147     virtual boost::shared_ptr< WPropertyBase > clone();
00148 
00149     /**
00150      * Determines whether the specified value is acceptable.
00151      *
00152      * \param newValue the new value.
00153      *
00154      * \return true if it is a valid/acceptable value.
00155      */
00156     virtual bool accept( const T& newValue );
00157 
00158     /**
00159      * This method is useful to ensure, that there is a valid value in the property. Assume the following situation. The property p got a min
00160      * value of 10. p->setMin( 10 ). Now, p gets set by the GUI to 11. Now your module sets another min value: p->setMin( 15 ). As the property
00161      * already has been set, the property can't decide what to do; it simply stays invalid. To ensure a valid value, you can use this method. It
00162      * only sets the new value if the old value is invalid.
00163      *
00164      * \param newValidValue the new value to set.
00165      * \param suppressNotification true to avoid a firing condition.
00166      *
00167      * \return true if the new value has been accepted ( if it was valid ) - for short true if the property NOW is valid
00168      */
00169     virtual bool ensureValidity( const T& newValidValue, bool suppressNotification = false );
00170 
00171     /**
00172      * Class building the base for user defined constraints on a property instance.
00173      */
00174     class PropertyConstraint
00175     {
00176     public:
00177         /**
00178          * Default constructor.
00179          */
00180         PropertyConstraint();
00181 
00182         /**
00183          * Destructor.
00184          */
00185         virtual ~PropertyConstraint();
00186 
00187         /**
00188          * This method decides whether the specified value is valid for a specific property.
00189          *
00190          * \param value the new value.
00191          * \param property the property to which the value should be set.
00192          *
00193          * \return true whenever the new value is acceptable for the property.
00194          */
00195         virtual bool accept( boost::shared_ptr< WPropertyVariable< T > > property, const T& value ) = 0;
00196 
00197         /**
00198          * Allows simple identification of the real constraint type.
00199          *
00200          * \return the type
00201          */
00202         virtual PROPERTYCONSTRAINT_TYPE getType();
00203 
00204         /**
00205          * This method creates a constraint using the specified type. This is a useful convenience class for easily adding
00206          * constraints.
00207          *
00208          * \param type the type of the constraint to create
00209          *
00210          * \return NULL if the type is unknown or an constraint instance
00211          */
00212         static boost::shared_ptr< PropertyConstraint > create( PROPERTYCONSTRAINT_TYPE type );
00213 
00214         /**
00215          * Method to clone the constraint and create a new one with the correct dynamic type.
00216          *
00217          * \return the constraint.
00218          */
00219         virtual boost::shared_ptr< PropertyConstraint > clone() = 0;
00220     };
00221 
00222     /**
00223      * The alias for a shared container.
00224      */
00225     typedef WSharedAssociativeContainer< std::set< boost::shared_ptr< PropertyConstraint > > > ConstraintContainerType;
00226 
00227     /**
00228      * Alias for min constraints. It is an alias for convenience.
00229      */
00230     typedef boost::shared_ptr< WPropertyConstraintMin< T > > PropertyConstraintMin;
00231 
00232     /**
00233      * Alias for max constraints. It is an alias for convenience.
00234      */
00235     typedef boost::shared_ptr< WPropertyConstraintMax< T > > PropertyConstraintMax;
00236 
00237     /**
00238      * Add a new constraint. This is useful to disallow several (custom) values for this property.
00239      *
00240      * \param constraint the new constraint.
00241      *
00242      */
00243     void addConstraint( boost::shared_ptr< PropertyConstraint > constraint );
00244 
00245     /**
00246      * Returns all the current constraints of a WPropertyVariable. They can be iterated using the provided access object.
00247      *
00248      * \return the constraint access object
00249      */
00250     ConstraintContainerType getConstraints();
00251 
00252     /**
00253      * Gets the condition, which gets notified whenever the list of constraints changes. It is notified AFTER the write lock has been released so
00254      * a read lock can be acquired in the callback.
00255      *
00256      * \return the condition.
00257      */
00258     boost::shared_ptr< WCondition > getContraintsChangedCondition();
00259 
00260     /**
00261      * Creates a new WPropertyConstraintMin for this WPropertyVariable.
00262      *
00263      * \param min the minimum value.
00264      *
00265      * \return the new constraint.
00266      */
00267     static PropertyConstraintMin minConstraint( const T& min );
00268 
00269     /**
00270      * Creates a new WPropertyConstraintMax for this WPropertyVariable.
00271      *
00272      * \param max the maximum value of the property
00273      *
00274      * \return the new constraint.
00275      */
00276     static PropertyConstraintMax maxConstraint( const T& max );
00277 
00278     /**
00279      * Set a minimum constraint.
00280      *
00281      * \param min the minimum value allowed.
00282      *
00283      * \return the newly created constraint.
00284      */
00285     PropertyConstraintMin setMin( const T& min );
00286 
00287     /**
00288      * Set a maximum constraint.
00289      *
00290      * \param max the maximum value allowed.
00291      *
00292      * \return the newly created constraint.
00293      */
00294     PropertyConstraintMax setMax( const T& max );
00295 
00296     /**
00297      * Gets the current minimum constraint value.
00298      *
00299      * \return the minimum constraint, or NULL if none.
00300      */
00301     PropertyConstraintMin getMin();
00302 
00303     /**
00304      * Gets the current maximum constraint value.
00305      *
00306      * \return the maximum constraint, or NULL if none.
00307      */
00308     PropertyConstraintMax getMax();
00309 
00310     /**
00311      * This replaces all existing constraints of a certain type by a new specified constraint.
00312      *
00313      * \param constraint the new constraint
00314      * \param type the type of constraints to replace
00315      */
00316     void replaceConstraint( boost::shared_ptr< PropertyConstraint > constraint, PROPERTYCONSTRAINT_TYPE type );
00317 
00318     /**
00319      * This replaces all existing constraints of a certain type by a new specified constraint.
00320      *
00321      * \param constraint the new constraint
00322      * \param type the type of constraints to replace
00323      * \return the constraint created
00324      */
00325     boost::shared_ptr< PropertyConstraint > replaceConstraint( PROPERTYCONSTRAINT_TYPE constraint, PROPERTYCONSTRAINT_TYPE type );
00326 
00327     /**
00328      * Cleans list of constraints from all existing constrains of the specified type.
00329      *
00330      * \param type the type to remove.
00331      */
00332     void removeConstraint( PROPERTYCONSTRAINT_TYPE type );
00333 
00334     /**
00335      * Removes the specified constraint if existent.
00336      *
00337      * \param constraint the constraint to remove.
00338      */
00339     void removeConstraint( boost::shared_ptr< PropertyConstraint > constraint );
00340 
00341     /**
00342      * Method searching the first appearance of a constrained with the specified type.
00343      *
00344      * \param type the type of the searched constraint
00345      *
00346      * \return the constraint, or NULL if none.
00347      */
00348     boost::shared_ptr< PropertyConstraint > getFirstConstraint( PROPERTYCONSTRAINT_TYPE type );
00349 
00350     /**
00351      * Method searching the first appearance of a constrained with the specified type.
00352      *
00353      * \param type the type of the searched constraint
00354      *
00355      * \return the constraint, or NULL if none.
00356      */
00357     int countConstraint( PROPERTYCONSTRAINT_TYPE type );
00358 
00359     /**
00360      * This methods allows properties to be set by a string value. This is especially useful when a property is only available as string and the
00361      * real type of the property is unknown. This is a shortcut for casting the property and then setting the lexically casted value.
00362      *
00363      * \param value the new value to set.
00364      *
00365      * \return true if value could be set.
00366      */
00367     virtual bool setAsString( std::string value );
00368 
00369     /**
00370      * Returns the current value as a string. This is useful for debugging or project files. It is not implemented as << operator, since the <<
00371      * should also print min/max constraints and so on. This simply is the value.
00372      *
00373      * \return the value as a string.
00374      */
00375     virtual std::string getAsString();
00376 
00377     /**
00378      * Sets the value from the specified property to this one. This is especially useful to copy a value without explicitly casting/knowing the
00379      * dynamic type of the property.
00380      *
00381      * \param value the new value.
00382      * \param recommendedOnly if true, property types which support recommended values apply the given value as recommendation.
00383      *
00384      * \return true if the value has been accepted.
00385      */
00386     virtual bool set( boost::shared_ptr< WPropertyBase > value, bool recommendedOnly = false );
00387 
00388     /**
00389      * Sets the new value for this flag. Also notifies waiting threads. After setting a value, changed() will be true.
00390      *
00391      * \param value the new value
00392      * \param suppressNotification true to avoid a firing condition. This is useful for resetting values.
00393      *
00394      * \return true if the value has been set successfully.
00395      *
00396      * \note set( get() ) == true
00397      * \note this is defined here to help the compiler to disambiguate between WFlag::set and the WPropertyBase::set.
00398      */
00399     virtual bool set( const T& value, bool suppressNotification = false );
00400 
00401     /**
00402      * Sets the specified value as recommended value. The difference to \ref set is simple. If some value was set using the method \ref set
00403      * earlier, the \ref setRecommendedValue call is ignored. This is very useful in modules, where incoming data yields some useful default values
00404      * but you do not want to overwrite a user-value which might have been set.
00405      *
00406      * \param value the new value to set if the user did not yet set the value
00407      *
00408      * \return true if value has been set successfully.
00409      */
00410     virtual bool setRecommendedValue( const T& value );
00411 
00412 protected:
00413     /**
00414      * The connection used for notification.
00415      */
00416     boost::signals2::connection m_notifierConnection;
00417 
00418     /**
00419      * Uses typeid() to set the proper type constant.
00420      */
00421     virtual void updateType();
00422 
00423     /**
00424      * Cleans list of constraints from all existing constrains of the specified type.
00425      *
00426      * \param type the type to remove.
00427      * \param ticket the write ticket if already existent.
00428      */
00429     void removeConstraints( PROPERTYCONSTRAINT_TYPE type,
00430                             typename WPropertyVariable< T >::ConstraintContainerType::WriteTicket ticket
00431                             = ConstraintContainerType::WriteTicket() );
00432 
00433     /**
00434      * This method gets called by WFlag whenever the value of the property changes. It re-emits the signal with a this pointer
00435      */
00436     void propertyChangeNotifier();
00437 
00438     /**
00439      * A set of constraints applied on this property.
00440      */
00441     boost::shared_ptr< ConstraintContainerType > m_constraints;
00442 
00443 private:
00444     /**
00445      * This is true, if the user did not set a value until now using \ref set.
00446      */
00447     bool m_notYetSet;
00448 };
00449 
00450 template < typename T >
00451 WPropertyVariable< T >::WPropertyVariable( std::string name, std::string description, const T& initial ):
00452         WFlag< T >( new WCondition(), initial ),
00453         WPropertyBase( name, description ),
00454         m_constraints( new ConstraintContainerType() ),
00455         m_notYetSet( true )
00456 {
00457     updateType();
00458 
00459     // set constraint and change condition to update condition set of WPropertyBase
00460     m_updateCondition->add( m_constraints->getChangeCondition() );
00461     m_updateCondition->add( WFlag< T >::getValueChangeCondition() );
00462 }
00463 
00464 template < typename T >
00465 WPropertyVariable< T >::WPropertyVariable( std::string name, std::string description, const T& initial, boost::shared_ptr< WCondition > condition ):
00466         WFlag< T >( condition, initial ),
00467         WPropertyBase( name, description ),
00468         m_constraints( new ConstraintContainerType() ),
00469         m_notYetSet( true )
00470 {
00471     updateType();
00472 
00473     // set constraint and change condition to update condition set of WPropertyBase
00474     m_updateCondition->add( m_constraints->getChangeCondition() );
00475     m_updateCondition->add( WFlag< T >::getValueChangeCondition() );
00476 }
00477 
00478 template < typename T >
00479 WPropertyVariable< T >::WPropertyVariable( std::string name, std::string description, const T& initial,
00480                                            PropertyChangeNotifierType notifier ):
00481         WFlag< T >( new WCondition(), initial ),
00482         WPropertyBase( name, description ),
00483         m_constraints( new ConstraintContainerType() ),
00484         m_notYetSet( true )
00485 {
00486     updateType();
00487 
00488     // set constraint and change condition to update condition set of WPropertyBase
00489     m_updateCondition->add( m_constraints->getChangeCondition() );
00490     m_updateCondition->add( WFlag< T >::getValueChangeCondition() );
00491 
00492     // set custom notifier
00493     m_notifierConnection = WFlag< T >::getValueChangeCondition()->subscribeSignal(
00494             boost::bind( &WPropertyVariable< T >::propertyChangeNotifier, this )
00495     );
00496     signal_PropertyChange.connect( notifier );
00497 }
00498 
00499 template < typename T >
00500 WPropertyVariable< T >::WPropertyVariable( std::string name, std::string description, const T& initial, boost::shared_ptr< WCondition > condition,
00501                                            PropertyChangeNotifierType notifier ):
00502         WFlag< T >( condition, initial ),
00503         WPropertyBase( name, description ),
00504         m_constraints( new ConstraintContainerType() ),
00505         m_notYetSet( true )
00506 {
00507     updateType();
00508 
00509     // set constraint and change condition to update condition set of WPropertyBase
00510     m_updateCondition->add( m_constraints->getChangeCondition() );
00511     m_updateCondition->add( WFlag< T >::getValueChangeCondition() );
00512 
00513     // set custom notifier
00514     m_notifierConnection = WFlag< T >::getValueChangeCondition()->subscribeSignal(
00515             boost::bind( &WPropertyVariable< T >::propertyChangeNotifier, this )
00516     );
00517     signal_PropertyChange.connect( notifier );
00518 }
00519 
00520 template < typename T >
00521 WPropertyVariable< T >::WPropertyVariable( const WPropertyVariable< T >& from ):
00522     WFlag< T >( from ),
00523     WPropertyBase( from ),
00524     m_constraints( new ConstraintContainerType() ),
00525     m_notYetSet( from.m_notYetSet )
00526 {
00527     // copy the constraints
00528 
00529     // lock, unlocked if l looses focus
00530     typename WPropertyVariable< T >::ConstraintContainerType::ReadTicket l =
00531         const_cast< WPropertyVariable< T >& >( from ).m_constraints->getReadTicket();
00532 
00533     // get write ticket too
00534     typename WPropertyVariable< T >::ConstraintContainerType::WriteTicket w = m_constraints->getWriteTicket();
00535 
00536     // we need to make a deep copy here.
00537     for( typename ConstraintContainerType::ConstIterator iter = l->get().begin(); iter != l->get().end(); ++iter )
00538     {
00539         // clone them to keep dynamic type
00540         w->get().insert( ( *iter )->clone() );
00541     }
00542 
00543     // set constraint and change condition to update condition set of WPropertyBase
00544     m_updateCondition->add( m_constraints->getChangeCondition() );
00545     m_updateCondition->add( WFlag< T >::getValueChangeCondition() );
00546 }
00547 
00548 template < typename T >
00549 WPropertyVariable< T >::~WPropertyVariable()
00550 {
00551     // clean up
00552     m_updateCondition->remove( m_constraints->getChangeCondition() );
00553     m_updateCondition->remove( WFlag< T >::getValueChangeCondition() );
00554 
00555     m_notifierConnection.disconnect();
00556 
00557     // lock, unlocked if l looses focus
00558     typename WPropertyVariable< T >::ConstraintContainerType::WriteTicket l = m_constraints->getWriteTicket();
00559     l->get().clear();
00560 }
00561 
00562 template < typename T >
00563 boost::shared_ptr< WPropertyBase > WPropertyVariable< T >::clone()
00564 {
00565     return boost::shared_ptr< WPropertyBase >( new WPropertyVariable< T >( *this ) );
00566 }
00567 
00568 template < typename T >
00569 void WPropertyVariable< T >::propertyChangeNotifier()
00570 {
00571     // propagate change, include pointer to property
00572     signal_PropertyChange( shared_from_this() );
00573 }
00574 
00575 template < typename T >
00576 bool WPropertyVariable< T >::accept( const T& newValue )
00577 {
00578     // lock, lock vanishes if l looses focus
00579     typename WPropertyVariable< T >::ConstraintContainerType::ReadTicket l = m_constraints->getReadTicket();
00580 
00581     // iterate through the set
00582     bool acceptable = WFlag< T >::accept( newValue );
00583     for( typename ConstraintContainerType::ConstIterator it = l->get().begin(); it !=  l->get().end(); ++it )
00584     {
00585         acceptable &= ( *it )->accept( boost::static_pointer_cast< WPropertyVariable< T > >( shared_from_this() ), newValue );
00586     }
00587 
00588     return acceptable;
00589 }
00590 
00591 template < typename T >
00592 bool WPropertyVariable< T >::setAsString( std::string value )
00593 {
00594     try
00595     {
00596         // use the helper class which can handle different kinds of properties for us
00597         PROPERTY_TYPE_HELPER::WStringConversion< T > h = PROPERTY_TYPE_HELPER::WStringConversion< T >();
00598         return set( h.create( WFlag< T >::get(), value ) );
00599     }
00600     catch( const std::exception &e )
00601     {
00602         return false;
00603     }
00604 }
00605 
00606 template < typename T >
00607 std::string WPropertyVariable< T >::getAsString()
00608 {
00609     std::string val;
00610     // use the helper class which can handle different kinds of properties for us
00611     PROPERTY_TYPE_HELPER::WStringConversion< T > h = PROPERTY_TYPE_HELPER::WStringConversion< T >();
00612     return h.asString( WFlag< T >::get() );
00613 
00614     return val;
00615 }
00616 
00617 template < typename T >
00618 bool WPropertyVariable< T >::set( boost::shared_ptr< WPropertyBase > value, bool recommendedOnly )
00619 {
00620     // try to cast the given property to a WPropertyVariable of right type:
00621     boost::shared_ptr< WPropertyVariable< T > > v = boost::dynamic_pointer_cast< WPropertyVariable< T > >( value );
00622     if( v )
00623     {
00624         if( recommendedOnly )
00625         {
00626             return setRecommendedValue( v->get() );
00627         }
00628         else
00629         {
00630             return set( v->get() );
00631         }
00632     }
00633     else
00634     {
00635         return false;
00636     }
00637 }
00638 
00639 template < typename T >
00640 bool WPropertyVariable< T >::set( const T& value, bool suppressNotification )
00641 {
00642     m_notYetSet = false;
00643     return WFlag< T >::set( value, suppressNotification );
00644 }
00645 
00646 template < typename T >
00647 bool WPropertyVariable< T >::setRecommendedValue( const T& value )
00648 {
00649     // NOTE: well this is quite problematic when used multi-threaded ...
00650     if( m_notYetSet )
00651     {
00652         bool ret = set( value );
00653         m_notYetSet = true;
00654         return ret;
00655     }
00656     else
00657     {
00658         return false;
00659     }
00660 }
00661 
00662 template < typename T >
00663 bool WPropertyVariable< T >::ensureValidity( const T& newValidValue, bool suppressNotification )
00664 {
00665     if( !accept( WFlag< T >::get() ) )
00666     {
00667         // the currently set constraints forbid the current value.
00668         // reset it to the new value
00669         return WFlag< T >::set( newValidValue, suppressNotification );
00670     }
00671 
00672     return true;
00673 }
00674 
00675 template < typename T >
00676 void WPropertyVariable< T >::addConstraint( boost::shared_ptr< PropertyConstraint > constraint )
00677 {
00678     // lock, unlocked if l looses focus
00679     typename WPropertyVariable< T >::ConstraintContainerType::WriteTicket l = m_constraints->getWriteTicket();
00680     l->get().insert( constraint );
00681 
00682     // unlock by hand
00683     l.reset();
00684 }
00685 
00686 template < typename T >
00687 boost::shared_ptr< WCondition > WPropertyVariable< T >::getContraintsChangedCondition()
00688 {
00689     return m_constraints->getChangeCondition();
00690 }
00691 
00692 template < typename T >
00693 void WPropertyVariable< T >::updateType()
00694 {
00695     PROPERTY_TYPE_HELPER::WTypeIdentifier< T > tid;
00696     m_type = tid.getType();
00697 }
00698 
00699 template < typename T >
00700 boost::shared_ptr< WPropertyConstraintMin< T > > WPropertyVariable< T >::minConstraint( const T& min )
00701 {
00702     return boost::shared_ptr< WPropertyConstraintMin< T > >( new WPropertyConstraintMin< T >( min ) );
00703 }
00704 
00705 template < typename T >
00706 boost::shared_ptr< WPropertyConstraintMax< T > > WPropertyVariable< T >::maxConstraint( const T& max )
00707 {
00708     return boost::shared_ptr< WPropertyConstraintMax< T > >( new WPropertyConstraintMax< T >( max ) );
00709 }
00710 
00711 template < typename T >
00712 boost::shared_ptr< WPropertyConstraintMin< T > > WPropertyVariable< T >::setMin( const T& min )
00713 {
00714     boost::shared_ptr< WPropertyConstraintMin< T > > c = minConstraint( min );
00715     replaceConstraint( c, PC_MIN );
00716     return c;
00717 }
00718 
00719 template < typename T >
00720 boost::shared_ptr< WPropertyConstraintMax< T > > WPropertyVariable< T >::setMax( const T& max )
00721 {
00722     boost::shared_ptr< WPropertyConstraintMax< T > > c = maxConstraint( max );
00723     replaceConstraint( c, PC_MAX );
00724     return c;
00725 }
00726 
00727 template < typename T >
00728 void WPropertyVariable< T >::replaceConstraint( boost::shared_ptr< PropertyConstraint > constraint, PROPERTYCONSTRAINT_TYPE type )
00729 {
00730     // lock, unlocked if l looses focus
00731     typename WPropertyVariable< T >::ConstraintContainerType::WriteTicket l = m_constraints->getWriteTicket();
00732 
00733     removeConstraints( type, l );
00734     l->get().insert( constraint );
00735 }
00736 
00737 template < typename T >
00738 boost::shared_ptr< typename WPropertyVariable< T >::PropertyConstraint >
00739 WPropertyVariable< T >::replaceConstraint( PROPERTYCONSTRAINT_TYPE constraint, PROPERTYCONSTRAINT_TYPE type )
00740 {
00741     boost::shared_ptr< typename WPropertyVariable< T >::PropertyConstraint > c = PropertyConstraint::create( constraint );
00742     replaceConstraint( c, type );
00743     return c;
00744 }
00745 
00746 template < typename T >
00747 boost::shared_ptr< typename WPropertyVariable< T >::PropertyConstraint >
00748 WPropertyVariable< T >::getFirstConstraint( PROPERTYCONSTRAINT_TYPE type )
00749 {
00750     // lock, unlocked if l looses focus
00751     typename WPropertyVariable< T >::ConstraintContainerType::ReadTicket l = m_constraints->getReadTicket();
00752 
00753     // search first appearance of a constraint of the specified type
00754     for( typename ConstraintContainerType::ConstIterator it = l->get().begin(); it != l->get().end(); ++it )
00755     {
00756         if( ( *it )->getType() == type )
00757         {
00758             return ( *it );
00759         }
00760     }
00761 
00762     return boost::shared_ptr< PropertyConstraint >();
00763 }
00764 
00765 template < typename T >
00766 int WPropertyVariable< T >::countConstraint( PROPERTYCONSTRAINT_TYPE type )
00767 {
00768     // lock, unlocked if l looses focus
00769     typename WPropertyVariable< T >::ConstraintContainerType::ReadTicket l = m_constraints->getReadTicket();
00770 
00771     int i = 0;
00772     // search first appearance of a constraint of the specified type
00773     for( typename ConstraintContainerType::ConstIterator it =  l->get().begin(); it != l->get().end(); ++it )
00774     {
00775         if( ( *it )->getType() == type )
00776         {
00777             i++;
00778         }
00779     }
00780 
00781     return i;
00782 }
00783 
00784 template < typename T >
00785 boost::shared_ptr< WPropertyConstraintMin< T > > WPropertyVariable< T >::getMin()
00786 {
00787     // get min
00788     boost::shared_ptr< PropertyConstraint > c = getFirstConstraint( PC_MIN );
00789     if( !c.get() )
00790     {
00791         // return NULL if not found
00792         return boost::shared_ptr< WPropertyConstraintMin< T > >();
00793     }
00794 
00795     // cast to proper type
00796     return boost::static_pointer_cast< WPropertyConstraintMin< T > >( c );
00797 }
00798 
00799 template < typename T >
00800 boost::shared_ptr< WPropertyConstraintMax< T > > WPropertyVariable< T >::getMax()
00801 {
00802     // get min
00803     boost::shared_ptr< PropertyConstraint > c = getFirstConstraint( PC_MAX );
00804     if( !c.get() )
00805     {
00806         // return NULL if not found
00807         return boost::shared_ptr< WPropertyConstraintMax< T > >();
00808     }
00809 
00810     // cast to proper type
00811     return boost::static_pointer_cast< WPropertyConstraintMax< T > >( c );
00812 }
00813 
00814 template< typename T >
00815 typename WPropertyVariable<T>::ConstraintContainerType WPropertyVariable<T>::getConstraints()
00816 {
00817     return m_constraints;
00818 }
00819 
00820 template < typename T >
00821 void WPropertyVariable< T >::removeConstraints( PROPERTYCONSTRAINT_TYPE type,
00822                                                 typename WPropertyVariable< T >::ConstraintContainerType::WriteTicket ticket )
00823 {
00824     typename WPropertyVariable< T >::ConstraintContainerType::WriteTicket l = ticket;
00825 
00826     bool useLock = !ticket;
00827 
00828     // lock the constraints set
00829     if( useLock )
00830     {
00831         // lock, unlocked if l looses focus
00832         l = m_constraints->getWriteTicket();
00833     }
00834 
00835     size_t nbErased = 0;    // count how much items have been removed
00836     for( typename ConstraintContainerType::ConstIterator it = l->get().begin(); it != l->get().end(); )
00837     {
00838         if( ( *it )->getType() == type )
00839         {
00840             l->get().erase( it++ );
00841             ++nbErased;
00842         }
00843         else
00844         {
00845             ++it;
00846         }
00847     }
00848 
00849     // only notify and unlock if locked earlier.
00850     if( useLock )
00851     {
00852         // no operations done? No condition fired
00853         if( nbErased == 0 )
00854         {
00855             l->suppressUnlockCondition();
00856         }
00857 
00858         // unlock by hand
00859         l.reset();
00860     }
00861 }
00862 
00863 template < typename T >
00864 void WPropertyVariable< T >::removeConstraint( PROPERTYCONSTRAINT_TYPE type )
00865 {
00866     // simply forward the call
00867     removeConstraints( type, typename WPropertyVariable< T >::ConstraintContainerType::WriteTicket() );
00868 }
00869 
00870 template < typename T >
00871 void WPropertyVariable< T >::removeConstraint( boost::shared_ptr< PropertyConstraint > constraint )
00872 {
00873     // lock released automatically
00874     typename WPropertyVariable< T >::ConstraintContainerType::WriteTicket l = m_constraints->getWriteTicket();
00875 
00876     if( l->get().erase( constraint ) == 0 )
00877     {
00878         // nothing changed. Suppress update condition to fire
00879         l->suppressUnlockCondition();
00880     }
00881 }
00882 
00883 template < typename T >
00884 WPropertyVariable< T >::PropertyConstraint::PropertyConstraint()
00885 {
00886 }
00887 
00888 template < typename T >
00889 WPropertyVariable< T >::PropertyConstraint::~PropertyConstraint()
00890 {
00891 }
00892 
00893 template < typename T >
00894 PROPERTYCONSTRAINT_TYPE WPropertyVariable< T >::PropertyConstraint::getType()
00895 {
00896     return PC_UNKNOWN;
00897 }
00898 
00899 #endif  // WPROPERTYVARIABLE_H
00900