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