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