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