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