OpenWalnut  1.2.5
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
WPropertyVariable.h
1 //---------------------------------------------------------------------------
2 //
3 // Project: OpenWalnut ( http://www.openwalnut.org )
4 //
5 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
6 // For more information see http://www.openwalnut.org/copying
7 //
8 // This file is part of OpenWalnut.
9 //
10 // OpenWalnut is free software: you can redistribute it and/or modify
11 // it under the terms of the GNU Lesser General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // OpenWalnut is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public License
21 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
22 //
23 //---------------------------------------------------------------------------
24 
25 #ifndef WPROPERTYVARIABLE_H
26 #define WPROPERTYVARIABLE_H
27 
28 #include <stdint.h>
29 
30 #include <iostream>
31 #include <list>
32 #include <set>
33 #include <string>
34 #include <vector>
35 
36 // Use filesystem version 2 for compatibility with newer boost versions.
37 #ifndef BOOST_FILESYSTEM_VERSION
38  #define BOOST_FILESYSTEM_VERSION 2
39 #endif
40 #include <boost/filesystem.hpp>
41 #include <boost/lexical_cast.hpp>
42 #include <boost/thread.hpp>
43 
44 #include "constraints/WPropertyConstraintIsDirectory.h"
45 #include "constraints/WPropertyConstraintMax.h"
46 #include "constraints/WPropertyConstraintMin.h"
47 #include "constraints/WPropertyConstraintNotEmpty.h"
48 #include "constraints/WPropertyConstraintPathExists.h"
49 #include "constraints/WPropertyConstraintSelectOnlyOne.h"
50 #include "constraints/WPropertyConstraintTypes.h"
51 #include "WCondition.h"
52 #include "WFlag.h"
53 #include "WLogger.h"
54 #include "WPropertyBase.h"
55 #include "WSharedAssociativeContainer.h"
56 #include "WSharedObjectTicketRead.h"
57 #include "WSharedObjectTicketWrite.h"
58 
59 /**
60  * A named property class with a concrete type.
61  */
62 template< typename T >
63 class WPropertyVariable: public WFlag< T >,
64  public WPropertyBase
65 {
66 friend class WPropertyVariableTest;
67 public:
68  /**
69  * Convenience typedef for a shared_ptr of WPropertyVariable.
70  */
71  typedef boost::shared_ptr< WPropertyVariable< T > > SPtr;
72 
73  /**
74  * Convenience typedef for a shared_ptr of const WPropertyVariable.
75  */
76  typedef boost::shared_ptr< const WPropertyVariable< T > > ConstSPtr;
77 
78  /**
79  * Create an empty instance just containing a name.
80  *
81  * \param name the property name
82  * \param description the property description
83  * \param initial the initial value
84  */
85  WPropertyVariable( std::string name, std::string description, const T& initial );
86 
87  /**
88  * Create an empty instance just containing a name. This constructor allows an external condition to be used for notifiaction.
89  * This is practical if one would like to share a condition among several properties.
90  *
91  * \param name the property name
92  * \param description the property description
93  * \param initial the initial value
94  * \param condition use this external condition for notification.
95  */
96  WPropertyVariable( std::string name, std::string description, const T& initial, boost::shared_ptr< WCondition > condition );
97 
98  /**
99  * Create an empty instance just containing a name. This constructor allows an external callback to be used for notification.
100  *
101  * \param name the property name
102  * \param description the property description
103  * \param initial the initial value
104  * \param notifier use this notifier for change callbacks.
105  *
106  * \note: instead of setting another notifier, you should consider using the callbacks the condition offers.
107  * \note: the notifiers gets connected to the notification callback of the internal condition. So be careful when using the
108  * condition ( getCondition() ) for other properties, since they would also share the callbacks
109  *
110  */
111  WPropertyVariable( std::string name, std::string description, const T& initial, PropertyChangeNotifierType notifier );
112 
113  /**
114  * Create an empty instance just containing a name. This constructor allows an external callback and condition to be used for notification.
115  *
116  * \param name the property name
117  * \param description the property description
118  * \param initial the initial value
119  * \param notifier use this notifier for change callbacks.
120  * \param condition use this external condition for notification
121  *
122  * \note: instead of setting another notifier, you should consider using the callbacks the condition offers.
123  * \note: the notifiers gets connected to the notification callback of the internal condition. So be careful when using the
124  * condition ( getCondition() ) for other properties, since they would also share the callbacks
125  *
126  */
127  WPropertyVariable( std::string name, std::string description, const T& initial, boost::shared_ptr< WCondition > condition,
128  PropertyChangeNotifierType notifier );
129 
130  /**
131  * Copy constructor. Creates a deep copy of this property. As boost::signals2 and condition variables are non-copyable, new instances get
132  * created. The subscriptions to a signal are LOST as well as all listeners to a condition.
133  * The conditions you can grab using getValueChangeConditon and getCondition are not the same as in the original! This is because
134  * the class corresponds to the observer/observable pattern. You won't expect a clone to fire a condition if a original variable is changed
135  * (which after cloning is completely decoupled from the clone).
136  *
137  * \param from the instance to copy.
138  */
139  explicit WPropertyVariable( const WPropertyVariable< T >& from );
140 
141  /**
142  * Destructor.
143  */
144  virtual ~WPropertyVariable();
145 
146  /**
147  * 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
148  * correct type without explicitly requiring the user to specify it. It creates a NEW change condition and change signal. This means, alls
149  * subscribed signal handlers are NOT copied.
150  *
151  * \note this simply ensures the copy constructor of the runtime type is issued.
152  *
153  * \return the deep clone of this property.
154  */
155  virtual boost::shared_ptr< WPropertyBase > clone();
156 
157  /**
158  * Determines whether the specified value is acceptable.
159  *
160  * \param newValue the new value.
161  *
162  * \return true if it is a valid/acceptable value.
163  */
164  virtual bool accept( T newValue );
165 
166  /**
167  * 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
168  * 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
169  * 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
170  * only sets the new value if the old value is invalid.
171  *
172  * \param newValidValue the new value to set.
173  * \param suppressNotification true to avoid a firing condition.
174  *
175  * \return true if the new value has been accepted ( if it was valid ) - for short true if the property NOW is valid
176  */
177  virtual bool ensureValidity( T newValidValue, bool suppressNotification = false );
178 
179  /**
180  * Class building the base for user defined constraints on a property instance.
181  */
183  {
184  public:
185 
186  /**
187  * Default constructor.
188  */
190 
191  /**
192  * Destructor.
193  */
194  virtual ~PropertyConstraint();
195 
196  /**
197  * This method decides whether the specified value is valid for a specific property.
198  *
199  * \param value the new value.
200  * \param property the property to which the value should be set.
201  *
202  * \return true whenever the new value is acceptable for the property.
203  */
204  virtual bool accept( boost::shared_ptr< WPropertyVariable< T > > property, T value ) = 0;
205 
206  /**
207  * Allows simple identification of the real constraint type.
208  *
209  * \return the type
210  */
211  virtual PROPERTYCONSTRAINT_TYPE getType();
212 
213  /**
214  * This method creates a constraint using the specified type. This is a useful convenience class for easily adding
215  * constraints.
216  *
217  * \param type the type of the constraint to create
218  *
219  * \return NULL if the type is unknown or an constraint instance
220  */
221  static boost::shared_ptr< PropertyConstraint > create( PROPERTYCONSTRAINT_TYPE type );
222 
223  /**
224  * Method to clone the constraint and create a new one with the correct dynamic type.
225  *
226  * \return the constraint.
227  */
228  virtual boost::shared_ptr< PropertyConstraint > clone() = 0;
229  };
230 
231  /**
232  * The alias for a shared container.
233  */
235 
236  /**
237  * Alias for min constraints. It is an alias for convenience.
238  */
239  typedef boost::shared_ptr< WPropertyConstraintMin< T > > PropertyConstraintMin;
240 
241  /**
242  * Alias for max constraints. It is an alias for convenience.
243  */
244  typedef boost::shared_ptr< WPropertyConstraintMax< T > > PropertyConstraintMax;
245 
246  /**
247  * Add a new constraint. This is useful to disallow several (custom) values for this property.
248  *
249  * \param constraint the new constraint.
250  *
251  */
252  void addConstraint( boost::shared_ptr< PropertyConstraint > constraint );
253 
254  /**
255  * Returns all the current constraints of a WPropertyVariable. They can be iterated using the provided access object.
256  *
257  * \return the constraint access object
258  */
260 
261  /**
262  * Gets the condition, which gets notified whenever the list of constraints changes. It is notified AFTER the write lock has been released so
263  * a read lock can be acquired in the callback.
264  *
265  * \return the condition.
266  */
267  boost::shared_ptr< WCondition > getContraintsChangedCondition();
268 
269  /**
270  * Creates a new WPropertyConstraintMin for this WPropertyVariable.
271  *
272  * \param min the minimum value.
273  *
274  * \return the new constraint.
275  */
276  static PropertyConstraintMin minConstraint( T min );
277 
278  /**
279  * Creates a new WPropertyConstraintMax for this WPropertyVariable.
280  *
281  * \param max the maximum value of the property
282  *
283  * \return the new constraint.
284  */
285  static PropertyConstraintMax maxConstraint( T max );
286 
287  /**
288  * Set a minimum constraint.
289  *
290  * \param min the minimum value allowed.
291  *
292  * \return the newly created constraint.
293  */
294  PropertyConstraintMin setMin( T min );
295 
296  /**
297  * Set a maximum constraint.
298  *
299  * \param max the maximum value allowed.
300  *
301  * \return the newly created constraint.
302  */
303  PropertyConstraintMax setMax( T max );
304 
305  /**
306  * Gets the current minimum constraint value.
307  *
308  * \return the minimum constraint, or NULL if none.
309  */
311 
312  /**
313  * Gets the current maximum constraint value.
314  *
315  * \return the maximum constraint, or NULL if none.
316  */
318 
319  /**
320  * This replaces all existing constraints of a certain type by a new specified constraint.
321  *
322  * \param constraint the new constraint
323  * \param type the type of constraints to replace
324  */
325  void replaceConstraint( boost::shared_ptr< PropertyConstraint > constraint, PROPERTYCONSTRAINT_TYPE type );
326 
327  /**
328  * This replaces all existing constraints of a certain type by a new specified constraint.
329  *
330  * \param constraint the new constraint
331  * \param type the type of constraints to replace
332  * \return the constraint created
333  */
334  boost::shared_ptr< PropertyConstraint > replaceConstraint( PROPERTYCONSTRAINT_TYPE constraint, PROPERTYCONSTRAINT_TYPE type );
335 
336  /**
337  * Cleans list of constraints from all existing constrains of the specified type.
338  *
339  * \param type the type to remove.
340  */
341  void removeConstraint( PROPERTYCONSTRAINT_TYPE type );
342 
343  /**
344  * Removes the specified constraint if existent.
345  *
346  * \param constraint the constraint to remove.
347  */
348  void removeConstraint( boost::shared_ptr< PropertyConstraint > constraint );
349 
350  /**
351  * Method searching the first appearance of a constrained with the specified type.
352  *
353  * \param type the type of the searched constraint
354  *
355  * \return the constraint, or NULL if none.
356  */
357  boost::shared_ptr< PropertyConstraint > getFirstConstraint( PROPERTYCONSTRAINT_TYPE type );
358 
359  /**
360  * Method searching the first appearance of a constrained with the specified type.
361  *
362  * \param type the type of the searched constraint
363  *
364  * \return the constraint, or NULL if none.
365  */
366  int countConstraint( PROPERTYCONSTRAINT_TYPE type );
367 
368  /**
369  * 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
370  * real type of the property is unknown. This is a shortcut for casting the property and then setting the lexically casted value.
371  *
372  * \param value the new value to set.
373  *
374  * \return true if value could be set.
375  */
376  virtual bool setAsString( std::string value );
377 
378  /**
379  * Returns the current value as a string. This is useful for debugging or project files. It is not implemented as << operator, since the <<
380  * should also print min/max constraints and so on. This simply is the value.
381  *
382  * \return the value as a string.
383  */
384  virtual std::string getAsString();
385 
386  /**
387  * Sets the value from the specified property to this one. This is especially useful to copy a value without explicitly casting/knowing the
388  * dynamic type of the property.
389  *
390  * \param value the new value.
391  *
392  * \return true if the value has been accepted.
393  */
394  virtual bool set( boost::shared_ptr< WPropertyBase > value );
395 
396  /**
397  * Sets the new value for this flag. Also notifies waiting threads. After setting a value, changed() will be true.
398  *
399  * \param value the new value
400  * \param suppressNotification true to avoid a firing condition. This is useful for resetting values.
401  *
402  * \return true if the value has been set successfully.
403  *
404  * \note set( get() ) == true
405  * \note this is defined here to help the compiler to disambiguate between WFlag::set and the WPropertyBase::set.
406  */
407  virtual bool set( T value, bool suppressNotification = false );
408 
409  /**
410  * Sets the specified value as recommended value. The difference to \ref set is simple. If some value was set using the method \ref set
411  * earlier, the \ref setRecommendedValue call is ignored. This is very useful in modules, where incoming data yields some useful default values
412  * but you do not want to overwrite a user-value which might have been set.
413  *
414  * \param value the new value to set if the user did not yet set the value
415  *
416  * \return true if value has been set successfully.
417  */
418  virtual bool setRecommendedValue( T value );
419 
420 protected:
421 
422  /**
423  * The connection used for notification.
424  */
425  boost::signals2::connection m_notifierConnection;
426 
427  /**
428  * Uses typeid() to set the proper type constant.
429  */
430  virtual void updateType();
431 
432  /**
433  * Cleans list of constraints from all existing constrains of the specified type.
434  *
435  * \param type the type to remove.
436  * \param ticket the write ticket if already existent.
437  */
438  void removeConstraints( PROPERTYCONSTRAINT_TYPE type,
441 
442  /**
443  * This method gets called by WFlag whenever the value of the property changes. It re-emits the signal with a this pointer
444  */
445  void propertyChangeNotifier();
446 
447  /**
448  * A set of constraints applied on this property.
449  */
450  boost::shared_ptr< ConstraintContainerType > m_constraints;
451 
452 private:
453 
454  /**
455  * This is true, if the user did not set a value until now using \ref set.
456  */
458 };
459 
460 template < typename T >
461 WPropertyVariable< T >::WPropertyVariable( std::string name, std::string description, const T& initial ):
462  WFlag< T >( new WCondition(), initial ),
463  WPropertyBase( name, description ),
464  m_constraints( new ConstraintContainerType() ),
465  m_notYetSet( true )
466 {
467  updateType();
468 
469  // set constraint and change condition to update condition set of WPropertyBase
470  m_updateCondition->add( m_constraints->getChangeCondition() );
472 }
473 
474 template < typename T >
475 WPropertyVariable< T >::WPropertyVariable( std::string name, std::string description, const T& initial, boost::shared_ptr< WCondition > condition ):
476  WFlag< T >( condition, initial ),
477  WPropertyBase( name, description ),
478  m_constraints( new ConstraintContainerType() ),
479  m_notYetSet( true )
480 {
481  updateType();
482 
483  // set constraint and change condition to update condition set of WPropertyBase
484  m_updateCondition->add( m_constraints->getChangeCondition() );
486 }
487 
488 template < typename T >
489 WPropertyVariable< T >::WPropertyVariable( std::string name, std::string description, const T& initial,
490  PropertyChangeNotifierType notifier ):
491  WFlag< T >( new WCondition(), initial ),
492  WPropertyBase( name, description ),
493  m_constraints( new ConstraintContainerType() ),
494  m_notYetSet( true )
495 {
496  updateType();
497 
498  // set constraint and change condition to update condition set of WPropertyBase
499  m_updateCondition->add( m_constraints->getChangeCondition() );
501 
502  // set custom notifier
505  );
506  signal_PropertyChange.connect( notifier );
507 }
508 
509 template < typename T >
510 WPropertyVariable< T >::WPropertyVariable( std::string name, std::string description, const T& initial, boost::shared_ptr< WCondition > condition,
511  PropertyChangeNotifierType notifier ):
512  WFlag< T >( condition, initial ),
513  WPropertyBase( name, description ),
514  m_constraints( new ConstraintContainerType() ),
515  m_notYetSet( true )
516 {
517  updateType();
518 
519  // set constraint and change condition to update condition set of WPropertyBase
520  m_updateCondition->add( m_constraints->getChangeCondition() );
522 
523  // set custom notifier
526  );
527  signal_PropertyChange.connect( notifier );
528 }
529 
530 template < typename T >
532  WFlag< T >( from ),
533  WPropertyBase( from ),
534  m_constraints( new ConstraintContainerType() ),
535  m_notYetSet( from.m_notYetSet )
536 {
537  // copy the constraints
538 
539  // lock, unlocked if l looses focus
541  const_cast< WPropertyVariable< T >& >( from ).m_constraints->getReadTicket();
542 
543  // get write ticket too
545 
546  // we need to make a deep copy here.
547  for( typename ConstraintContainerType::ConstIterator iter = l->get().begin(); iter != l->get().end(); ++iter )
548  {
549  // clone them to keep dynamic type
550  w->get().insert( ( *iter )->clone() );
551  }
552 
553  // set constraint and change condition to update condition set of WPropertyBase
554  m_updateCondition->add( m_constraints->getChangeCondition() );
556 }
557 
558 template < typename T >
560 {
561  // clean up
562  m_updateCondition->remove( m_constraints->getChangeCondition() );
563  m_updateCondition->remove( WFlag< T >::getValueChangeCondition() );
564 
565  m_notifierConnection.disconnect();
566 
567  // lock, unlocked if l looses focus
568  typename WPropertyVariable< T >::ConstraintContainerType::WriteTicket l = m_constraints->getWriteTicket();
569  l->get().clear();
570 }
571 
572 template < typename T >
573 boost::shared_ptr< WPropertyBase > WPropertyVariable< T >::clone()
574 {
575  return boost::shared_ptr< WPropertyBase >( new WPropertyVariable< T >( *this ) );
576 }
577 
578 template < typename T >
580 {
581  // propagate change, include pointer to property
582  signal_PropertyChange( shared_from_this() );
583 }
584 
585 template < typename T >
587 {
588  // lock, lock vanishes if l looses focus
589  typename WPropertyVariable< T >::ConstraintContainerType::ReadTicket l = m_constraints->getReadTicket();
590 
591  // iterate through the set
592  bool acceptable = WFlag< T >::accept( newValue );
593  for( typename ConstraintContainerType::ConstIterator it = l->get().begin(); it != l->get().end(); ++it )
594  {
595  acceptable &= ( *it )->accept( boost::shared_static_cast< WPropertyVariable< T > >( shared_from_this() ), newValue );
596  }
597 
598  return acceptable;
599 }
600 
601 template < typename T >
602 bool WPropertyVariable< T >::setAsString( std::string value )
603 {
604  try
605  {
606  // use the helper class which can handle different kinds of properties for us
608  return set( h.create( WFlag< T >::get(), value ) );
609  }
610  catch( const boost::bad_lexical_cast &e )
611  {
612  return false;
613  }
614 }
615 
616 template < typename T >
618 {
619  std::string val;
620  // use the helper class which can handle different kinds of properties for us
622  return h.asString( WFlag< T >::get() );
623 
624  return val;
625 }
626 
627 template < typename T >
628 bool WPropertyVariable< T >::set( boost::shared_ptr< WPropertyBase > value )
629 {
630  // try to cast the given property to a WPropertyVariable of right type:
631  boost::shared_ptr< WPropertyVariable< T > > v = boost::shared_dynamic_cast< WPropertyVariable< T > >( value );
632  if( v )
633  {
634  return set( v->get() );
635  }
636  else
637  {
638  return false;
639  }
640 }
641 
642 template < typename T >
643 bool WPropertyVariable< T >::set( T value, bool suppressNotification )
644 {
645  m_notYetSet = false;
646  return WFlag< T >::set( value, suppressNotification );
647 }
648 
649 template < typename T >
651 {
652  // NOTE: well this is quite problematic when used multi-threaded ...
653  if( m_notYetSet )
654  {
655  bool ret = set( value );
656  m_notYetSet = true;
657  return ret;
658  }
659  else
660  {
661  return false;
662  }
663 }
664 
665 template < typename T >
666 bool WPropertyVariable< T >::ensureValidity( T newValidValue, bool suppressNotification )
667 {
668  if( !accept( WFlag< T >::get() ) )
669  {
670  // the currently set constraints forbid the current value.
671  // reset it to the new value
672  return WFlag< T >::set( newValidValue, suppressNotification );
673  }
674 
675  return true;
676 }
677 
678 template < typename T >
679 void WPropertyVariable< T >::addConstraint( boost::shared_ptr< PropertyConstraint > constraint )
680 {
681  // lock, unlocked if l looses focus
682  typename WPropertyVariable< T >::ConstraintContainerType::WriteTicket l = m_constraints->getWriteTicket();
683  l->get().insert( constraint );
684 
685  // unlock by hand
686  l.reset();
687 }
688 
689 template < typename T >
691 {
692  return m_constraints->getChangeCondition();
693 }
694 
695 template < typename T >
697 {
699  m_type = tid.getType();
700 }
701 
702 template < typename T >
703 boost::shared_ptr< WPropertyConstraintMin< T > > WPropertyVariable< T >::minConstraint( T min )
704 {
705  return boost::shared_ptr< WPropertyConstraintMin< T > >( new WPropertyConstraintMin< T >( min ) );
706 }
707 
708 template < typename T >
709 boost::shared_ptr< WPropertyConstraintMax< T > > WPropertyVariable< T >::maxConstraint( T max )
710 {
711  return boost::shared_ptr< WPropertyConstraintMax< T > >( new WPropertyConstraintMax< T >( max ) );
712 }
713 
714 template < typename T >
715 boost::shared_ptr< WPropertyConstraintMin< T > > WPropertyVariable< T >::setMin( T min )
716 {
717  boost::shared_ptr< WPropertyConstraintMin< T > > c = minConstraint( min );
718  replaceConstraint( c, PC_MIN );
719  return c;
720 }
721 
722 template < typename T >
723 boost::shared_ptr< WPropertyConstraintMax< T > > WPropertyVariable< T >::setMax( T max )
724 {
725  boost::shared_ptr< WPropertyConstraintMax< T > > c = maxConstraint( max );
726  replaceConstraint( c, PC_MAX );
727  return c;
728 }
729 
730 template < typename T >
731 void WPropertyVariable< T >::replaceConstraint( boost::shared_ptr< PropertyConstraint > constraint, PROPERTYCONSTRAINT_TYPE type )
732 {
733  // lock, unlocked if l looses focus
734  typename WPropertyVariable< T >::ConstraintContainerType::WriteTicket l = m_constraints->getWriteTicket();
735 
736  removeConstraints( type, l );
737  l->get().insert( constraint );
738 }
739 
740 template < typename T >
741 boost::shared_ptr< typename WPropertyVariable< T >::PropertyConstraint >
742 WPropertyVariable< T >::replaceConstraint( PROPERTYCONSTRAINT_TYPE constraint, PROPERTYCONSTRAINT_TYPE type )
743 {
744  boost::shared_ptr< typename WPropertyVariable< T >::PropertyConstraint > c = PropertyConstraint::create( constraint );
745  replaceConstraint( c, type );
746  return c;
747 }
748 
749 template < typename T >
750 boost::shared_ptr< typename WPropertyVariable< T >::PropertyConstraint >
751 WPropertyVariable< T >::getFirstConstraint( PROPERTYCONSTRAINT_TYPE type )
752 {
753  // lock, unlocked if l looses focus
754  typename WPropertyVariable< T >::ConstraintContainerType::ReadTicket l = m_constraints->getReadTicket();
755 
756  // search first appearance of a constraint of the specified type
757  for( typename ConstraintContainerType::ConstIterator it = l->get().begin(); it != l->get().end(); ++it )
758  {
759  if( ( *it )->getType() == type )
760  {
761  return ( *it );
762  }
763  }
764 
765  return boost::shared_ptr< PropertyConstraint >();
766 }
767 
768 template < typename T >
769 int WPropertyVariable< T >::countConstraint( PROPERTYCONSTRAINT_TYPE type )
770 {
771  // lock, unlocked if l looses focus
772  typename WPropertyVariable< T >::ConstraintContainerType::ReadTicket l = m_constraints->getReadTicket();
773 
774  int i = 0;
775  // search first appearance of a constraint of the specified type
776  for( typename ConstraintContainerType::ConstIterator it = l->get().begin(); it != l->get().end(); ++it )
777  {
778  if( ( *it )->getType() == type )
779  {
780  i++;
781  }
782  }
783 
784  return i;
785 }
786 
787 template < typename T >
788 boost::shared_ptr< WPropertyConstraintMin< T > > WPropertyVariable< T >::getMin()
789 {
790  // get min
791  boost::shared_ptr< PropertyConstraint > c = getFirstConstraint( PC_MIN );
792  if( !c.get() )
793  {
794  // return NULL if not found
795  return boost::shared_ptr< WPropertyConstraintMin< T > >();
796  }
797 
798  // cast to proper type
799  return boost::shared_static_cast< WPropertyConstraintMin< T > >( c );
800 }
801 
802 template < typename T >
803 boost::shared_ptr< WPropertyConstraintMax< T > > WPropertyVariable< T >::getMax()
804 {
805  // get min
806  boost::shared_ptr< PropertyConstraint > c = getFirstConstraint( PC_MAX );
807  if( !c.get() )
808  {
809  // return NULL if not found
810  return boost::shared_ptr< WPropertyConstraintMax< T > >();
811  }
812 
813  // cast to proper type
814  return boost::shared_static_cast< WPropertyConstraintMax< T > >( c );
815 }
816 
817 template< typename T >
819 {
820  return m_constraints;
821 }
822 
823 template < typename T >
824 void WPropertyVariable< T >::removeConstraints( PROPERTYCONSTRAINT_TYPE type,
826 {
828 
829  bool useLock = !ticket;
830 
831  // lock the constraints set
832  if( useLock )
833  {
834  // lock, unlocked if l looses focus
835  l = m_constraints->getWriteTicket();
836  }
837 
838  size_t nbErased = 0; // count how much items have been removed
839  for( typename ConstraintContainerType::ConstIterator it = l->get().begin(); it != l->get().end(); )
840  {
841  if( ( *it )->getType() == type )
842  {
843  l->get().erase( it++ );
844  ++nbErased;
845  }
846  else
847  {
848  ++it;
849  }
850  }
851 
852  // only notify and unlock if locked earlier.
853  if( useLock )
854  {
855  // no operations done? No condition fired
856  if( nbErased == 0 )
857  {
858  l->suppressUnlockCondition();
859  }
860 
861  // unlock by hand
862  l.reset();
863  }
864 }
865 
866 template < typename T >
867 void WPropertyVariable< T >::removeConstraint( PROPERTYCONSTRAINT_TYPE type )
868 {
869  // simply forward the call
870  removeConstraints( type, typename WPropertyVariable< T >::ConstraintContainerType::WriteTicket() );
871 }
872 
873 template < typename T >
874 void WPropertyVariable< T >::removeConstraint( boost::shared_ptr< PropertyConstraint > constraint )
875 {
876  // lock released automatically
877  typename WPropertyVariable< T >::ConstraintContainerType::WriteTicket l = m_constraints->getWriteTicket();
878 
879  if( l->get().erase( constraint ) == 0 )
880  {
881  // nothing changed. Suppress update condition to fire
882  l->suppressUnlockCondition();
883  }
884 }
885 
886 template < typename T >
888 {
889 }
890 
891 template < typename T >
893 {
894 }
895 
896 template < typename T >
898 {
899  return PC_UNKNOWN;
900 }
901 
902 #endif // WPROPERTYVARIABLE_H
903