OpenWalnut
1.4.0
|
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