WPropertyVariable.h 30.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
// For more information see http://www.openwalnut.org/copying
//
// This file is part of OpenWalnut.
//
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenWalnut is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------

#ifndef WPROPERTYVARIABLE_H
#define WPROPERTYVARIABLE_H

#include <stdint.h>

30
#include <list>
31
#include <set>
32
#include <string>
33

34 35
#include <boost/shared_ptr.hpp>
#include <boost/signals2.hpp>
36

37 38 39 40 41 42 43 44
#include "constraints/WPropertyConstraintIsDirectory.h"
#include "constraints/WPropertyConstraintMax.h"
#include "constraints/WPropertyConstraintMin.h"
#include "constraints/WPropertyConstraintNotEmpty.h"
#include "constraints/WPropertyConstraintPathExists.h"
#include "constraints/WPropertyConstraintSelectOnlyOne.h"
#include "constraints/WPropertyConstraintTypes.h"
#include "WCondition.h"
45
#include "WFlag.h"
46
#include "WPropertyBase.h"
47
#include "WSharedAssociativeContainer.h"
48 49
#include "WSharedObjectTicketRead.h"
#include "WSharedObjectTicketWrite.h"
50

51 52 53 54
/**
 * A named property class with a concrete type.
 */
template< typename T >
55 56
class WPropertyVariable: public WFlag< T >,
                         public WPropertyBase
57
{
58
friend class WPropertyVariableTest;
59
public:
60 61 62 63 64 65 66 67 68
    /**
     * Convenience typedef for a shared_ptr of WPropertyVariable.
     */
    typedef boost::shared_ptr< WPropertyVariable< T > > SPtr;

    /**
     * Convenience typedef for a shared_ptr of const WPropertyVariable.
     */
    typedef boost::shared_ptr< const WPropertyVariable< T > > ConstSPtr;
69 70 71 72 73 74 75 76

    /**
     * Create an empty instance just containing a name.
     *
     * \param name  the property name
     * \param description the property description
     * \param initial the initial value
     */
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
    WPropertyVariable( std::string name, std::string description, const T& initial );

    /**
     * Create an empty instance just containing a name. This constructor allows an external condition to be used for notifiaction.
     * This is practical if one would like to share a condition among several properties.
     *
     * \param name  the property name
     * \param description the property description
     * \param initial the initial value
     * \param condition use this external condition for notification.
     */
    WPropertyVariable( std::string name, std::string description, const T& initial, boost::shared_ptr< WCondition > condition );

    /**
     * Create an empty instance just containing a name. This constructor allows an external callback to be used for notification.
     *
     * \param name  the property name
     * \param description the property description
     * \param initial the initial value
     * \param notifier use this notifier for change callbacks.
     *
     * \note: instead of setting another notifier, you should consider using the callbacks the condition offers.
     * \note: the notifiers gets connected to the notification callback of the internal condition. So be careful when using the
     *        condition ( getCondition() ) for other properties, since they would also share the callbacks
     *
     */
103
    WPropertyVariable( std::string name, std::string description, const T& initial, PropertyChangeNotifierType notifier );
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119

    /**
     * Create an empty instance just containing a name. This constructor allows an external callback and condition to be used for notification.
     *
     * \param name  the property name
     * \param description the property description
     * \param initial the initial value
     * \param notifier use this notifier for change callbacks.
     * \param condition use this external condition for notification
     *
     * \note: instead of setting another notifier, you should consider using the callbacks the condition offers.
     * \note: the notifiers gets connected to the notification callback of the internal condition. So be careful when using the
     *        condition ( getCondition() ) for other properties, since they would also share the callbacks
     *
     */
    WPropertyVariable( std::string name, std::string description, const T& initial, boost::shared_ptr< WCondition > condition,
120
                       PropertyChangeNotifierType notifier );
121

122 123 124
    /**
     * Copy constructor. Creates a deep copy of this property. As boost::signals2 and condition variables are non-copyable, new instances get
     * created. The subscriptions to a signal are LOST as well as all listeners to a condition.
Sebastian Eichelbaum's avatar
[DOC]  
Sebastian Eichelbaum committed
125 126 127
     * The conditions you can grab using getValueChangeConditon and getCondition are not the same as in the original! This is because
     * the class corresponds to the observer/observable pattern. You won't expect a clone to fire a condition if a original variable is changed
     * (which after cloning is completely decoupled from the clone).
128 129 130
     *
     * \param from the instance to copy.
     */
131
    explicit WPropertyVariable( const WPropertyVariable< T >& from );
132

133 134 135
    /**
     * Destructor.
     */
136 137
    virtual ~WPropertyVariable();

138 139 140 141 142 143 144 145 146 147 148
    /**
     * 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
     * correct type without explicitly requiring the user to specify it. It creates a NEW change condition and change signal. This means, alls
     * subscribed signal handlers are NOT copied.
     *
     * \note this simply ensures the copy constructor of the runtime type is issued.
     *
     * \return the deep clone of this property.
     */
    virtual boost::shared_ptr< WPropertyBase > clone();

149 150 151 152 153 154 155
    /**
     * Determines whether the specified value is acceptable.
     *
     * \param newValue the new value.
     *
     * \return true if it is a valid/acceptable value.
     */
156
    virtual bool accept( const T& newValue );
157

158 159 160 161 162 163 164 165 166 167 168
    /**
     * 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
     * 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
     * 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
     * only sets the new value if the old value is invalid.
     *
     * \param newValidValue the new value to set.
     * \param suppressNotification true to avoid a firing condition.
     *
     * \return true if the new value has been accepted ( if it was valid ) - for short true if the property NOW is valid
     */
169
    virtual bool ensureValidity( const T& newValidValue, bool suppressNotification = false );
170

171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
    /**
     * Class building the base for user defined constraints on a property instance.
     */
    class PropertyConstraint
    {
    public:
        /**
         * Default constructor.
         */
        PropertyConstraint();

        /**
         * Destructor.
         */
        virtual ~PropertyConstraint();

        /**
         * This method decides whether the specified value is valid for a specific property.
         *
         * \param value the new value.
         * \param property the property to which the value should be set.
         *
         * \return true whenever the new value is acceptable for the property.
         */
195
        virtual bool accept( boost::shared_ptr< WPropertyVariable< T > > property, const T& value ) = 0;
196 197

        /**
198
         * Allows simple identification of the real constraint type.
199
         *
200
         * \return the type
201 202
         */
        virtual PROPERTYCONSTRAINT_TYPE getType();
203 204 205 206 207 208 209 210 211 212

        /**
         * This method creates a constraint using the specified type. This is a useful convenience class for easily adding
         * constraints.
         *
         * \param type the type of the constraint to create
         *
         * \return NULL if the type is unknown or an constraint instance
         */
        static boost::shared_ptr< PropertyConstraint > create( PROPERTYCONSTRAINT_TYPE type );
213 214 215 216 217 218 219

        /**
         * Method to clone the constraint and create a new one with the correct dynamic type.
         *
         * \return the constraint.
         */
        virtual boost::shared_ptr< PropertyConstraint > clone() = 0;
220 221
    };

222 223 224
    /**
     * The alias for a shared container.
     */
225
    typedef WSharedAssociativeContainer< std::set< boost::shared_ptr< PropertyConstraint > > > ConstraintContainerType;
226

227 228 229 230 231 232 233 234 235 236
    /**
     * Alias for min constraints. It is an alias for convenience.
     */
    typedef boost::shared_ptr< WPropertyConstraintMin< T > > PropertyConstraintMin;

    /**
     * Alias for max constraints. It is an alias for convenience.
     */
    typedef boost::shared_ptr< WPropertyConstraintMax< T > > PropertyConstraintMax;

237 238 239 240 241 242 243 244
    /**
     * Add a new constraint. This is useful to disallow several (custom) values for this property.
     *
     * \param constraint the new constraint.
     *
     */
    void addConstraint( boost::shared_ptr< PropertyConstraint > constraint );

245
    /**
246
     * Returns all the current constraints of a WPropertyVariable. They can be iterated using the provided access object.
247
     *
248
     * \return the constraint access object
249
     */
250
    ConstraintContainerType getConstraints();
251

252 253 254 255 256 257 258
    /**
     * Gets the condition, which gets notified whenever the list of constraints changes. It is notified AFTER the write lock has been released so
     * a read lock can be acquired in the callback.
     *
     * \return the condition.
     */
    boost::shared_ptr< WCondition > getContraintsChangedCondition();
259

260 261 262 263 264 265 266
    /**
     * Creates a new WPropertyConstraintMin for this WPropertyVariable.
     *
     * \param min the minimum value.
     *
     * \return the new constraint.
     */
267
    static PropertyConstraintMin minConstraint( const T& min );
268 269 270 271 272 273 274 275

    /**
     * Creates a new WPropertyConstraintMax for this WPropertyVariable.
     *
     * \param max the maximum value of the property
     *
     * \return the new constraint.
     */
276
    static PropertyConstraintMax maxConstraint( const T& max );
277 278 279 280 281 282 283 284

    /**
     * Set a minimum constraint.
     *
     * \param min the minimum value allowed.
     *
     * \return the newly created constraint.
     */
285
    PropertyConstraintMin setMin( const T& min );
286 287 288 289 290 291 292 293

    /**
     * Set a maximum constraint.
     *
     * \param max the maximum value allowed.
     *
     * \return the newly created constraint.
     */
294
    PropertyConstraintMax setMax( const T& max );
295 296 297 298

    /**
     * Gets the current minimum constraint value.
     *
299
     * \return the minimum constraint, or NULL if none.
300
     */
301
    PropertyConstraintMin getMin();
302 303 304 305

    /**
     * Gets the current maximum constraint value.
     *
306
     * \return the maximum constraint, or NULL if none.
307
     */
308
    PropertyConstraintMax getMax();
309

310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
    /**
     * This replaces all existing constraints of a certain type by a new specified constraint.
     *
     * \param constraint the new constraint
     * \param type the type of constraints to replace
     */
    void replaceConstraint( boost::shared_ptr< PropertyConstraint > constraint, PROPERTYCONSTRAINT_TYPE type );

    /**
     * This replaces all existing constraints of a certain type by a new specified constraint.
     *
     * \param constraint the new constraint
     * \param type the type of constraints to replace
     * \return the constraint created
     */
    boost::shared_ptr< PropertyConstraint > replaceConstraint( PROPERTYCONSTRAINT_TYPE constraint, PROPERTYCONSTRAINT_TYPE type );

327 328 329 330 331 332 333 334 335 336 337 338 339 340
    /**
     * Cleans list of constraints from all existing constrains of the specified type.
     *
     * \param type the type to remove.
     */
    void removeConstraint( PROPERTYCONSTRAINT_TYPE type );

    /**
     * Removes the specified constraint if existent.
     *
     * \param constraint the constraint to remove.
     */
    void removeConstraint( boost::shared_ptr< PropertyConstraint > constraint );

341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358
    /**
     * Method searching the first appearance of a constrained with the specified type.
     *
     * \param type the type of the searched constraint
     *
     * \return the constraint, or NULL if none.
     */
    boost::shared_ptr< PropertyConstraint > getFirstConstraint( PROPERTYCONSTRAINT_TYPE type );

    /**
     * Method searching the first appearance of a constrained with the specified type.
     *
     * \param type the type of the searched constraint
     *
     * \return the constraint, or NULL if none.
     */
    int countConstraint( PROPERTYCONSTRAINT_TYPE type );

359 360 361 362 363 364 365 366 367 368
    /**
     * 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
     * real type of the property is unknown. This is a shortcut for casting the property and then setting the lexically casted value.
     *
     * \param value the new value to set.
     *
     * \return true if value could be set.
     */
    virtual bool setAsString( std::string value );

369 370 371 372 373 374 375 376
    /**
     * Returns the current value as a string. This is useful for debugging or project files. It is not implemented as << operator, since the <<
     * should also print min/max constraints and so on. This simply is the value.
     *
     * \return the value as a string.
     */
    virtual std::string getAsString();

377 378 379 380 381
    /**
     * Sets the value from the specified property to this one. This is especially useful to copy a value without explicitly casting/knowing the
     * dynamic type of the property.
     *
     * \param value the new value.
382
     * \param recommendedOnly if true, property types which support recommended values apply the given value as recommendation.
383 384 385
     *
     * \return true if the value has been accepted.
     */
386
    virtual bool set( boost::shared_ptr< WPropertyBase > value, bool recommendedOnly = false );
387 388 389 390 391 392 393 394 395 396 397 398

    /**
     * Sets the new value for this flag. Also notifies waiting threads. After setting a value, changed() will be true.
     *
     * \param value the new value
     * \param suppressNotification true to avoid a firing condition. This is useful for resetting values.
     *
     * \return true if the value has been set successfully.
     *
     * \note set( get() ) == true
     * \note this is defined here to help the compiler to disambiguate between WFlag::set and the WPropertyBase::set.
     */
399
    virtual bool set( const T& value, bool suppressNotification = false );
400

401 402 403 404 405 406 407 408 409
    /**
     * Sets the specified value as recommended value. The difference to \ref set is simple. If some value was set using the method \ref set
     * earlier, the \ref setRecommendedValue call is ignored. This is very useful in modules, where incoming data yields some useful default values
     * but you do not want to overwrite a user-value which might have been set.
     *
     * \param value the new value to set if the user did not yet set the value
     *
     * \return true if value has been set successfully.
     */
410
    virtual bool setRecommendedValue( const T& value );
411

412 413
protected:
    /**
414
     * The connection used for notification.
415
     */
416
    boost::signals2::connection m_notifierConnection;
417 418

    /**
419
     * Uses typeid() to set the proper type constant.
420
     */
421
    virtual void updateType();
422

423
    /**
424
     * Cleans list of constraints from all existing constrains of the specified type.
425 426
     *
     * \param type the type to remove.
427
     * \param ticket the write ticket if already existent.
428
     */
429
    void removeConstraints( PROPERTYCONSTRAINT_TYPE type,
430 431
                            typename WPropertyVariable< T >::ConstraintContainerType::WriteTicket ticket
                            = ConstraintContainerType::WriteTicket() );
432

433 434 435 436 437
    /**
     * This method gets called by WFlag whenever the value of the property changes. It re-emits the signal with a this pointer
     */
    void propertyChangeNotifier();

438 439 440
    /**
     * A set of constraints applied on this property.
     */
441
    boost::shared_ptr< ConstraintContainerType > m_constraints;
442

443
private:
444 445 446 447
    /**
     * This is true, if the user did not set a value until now using \ref set.
     */
    bool m_notYetSet;
448 449
};

450 451 452
template < typename T >
WPropertyVariable< T >::WPropertyVariable( std::string name, std::string description, const T& initial ):
        WFlag< T >( new WCondition(), initial ),
453
        WPropertyBase( name, description ),
454 455
        m_constraints( new ConstraintContainerType() ),
        m_notYetSet( true )
456
{
457
    updateType();
458 459

    // set constraint and change condition to update condition set of WPropertyBase
460
    m_updateCondition->add( m_constraints->getChangeCondition() );
461
    m_updateCondition->add( WFlag< T >::getValueChangeCondition() );
462 463 464 465 466
}

template < typename T >
WPropertyVariable< T >::WPropertyVariable( std::string name, std::string description, const T& initial, boost::shared_ptr< WCondition > condition ):
        WFlag< T >( condition, initial ),
467
        WPropertyBase( name, description ),
468 469
        m_constraints( new ConstraintContainerType() ),
        m_notYetSet( true )
470
{
471
    updateType();
472 473

    // set constraint and change condition to update condition set of WPropertyBase
474
    m_updateCondition->add( m_constraints->getChangeCondition() );
475
    m_updateCondition->add( WFlag< T >::getValueChangeCondition() );
476 477 478 479
}

template < typename T >
WPropertyVariable< T >::WPropertyVariable( std::string name, std::string description, const T& initial,
480
                                           PropertyChangeNotifierType notifier ):
481
        WFlag< T >( new WCondition(), initial ),
482
        WPropertyBase( name, description ),
483 484
        m_constraints( new ConstraintContainerType() ),
        m_notYetSet( true )
485
{
486 487
    updateType();

488
    // set constraint and change condition to update condition set of WPropertyBase
489
    m_updateCondition->add( m_constraints->getChangeCondition() );
490 491
    m_updateCondition->add( WFlag< T >::getValueChangeCondition() );

492
    // set custom notifier
493 494 495
    m_notifierConnection = WFlag< T >::getValueChangeCondition()->subscribeSignal(
            boost::bind( &WPropertyVariable< T >::propertyChangeNotifier, this )
    );
496
    signal_PropertyChange.connect( notifier );
497 498 499 500
}

template < typename T >
WPropertyVariable< T >::WPropertyVariable( std::string name, std::string description, const T& initial, boost::shared_ptr< WCondition > condition,
501
                                           PropertyChangeNotifierType notifier ):
502
        WFlag< T >( condition, initial ),
503
        WPropertyBase( name, description ),
504 505
        m_constraints( new ConstraintContainerType() ),
        m_notYetSet( true )
506
{
507
    updateType();
508

509
    // set constraint and change condition to update condition set of WPropertyBase
510
    m_updateCondition->add( m_constraints->getChangeCondition() );
511 512
    m_updateCondition->add( WFlag< T >::getValueChangeCondition() );

513
    // set custom notifier
514 515 516
    m_notifierConnection = WFlag< T >::getValueChangeCondition()->subscribeSignal(
            boost::bind( &WPropertyVariable< T >::propertyChangeNotifier, this )
    );
517
    signal_PropertyChange.connect( notifier );
518 519
}

520 521 522 523
template < typename T >
WPropertyVariable< T >::WPropertyVariable( const WPropertyVariable< T >& from ):
    WFlag< T >( from ),
    WPropertyBase( from ),
524 525
    m_constraints( new ConstraintContainerType() ),
    m_notYetSet( from.m_notYetSet )
526 527
{
    // copy the constraints
528 529

    // lock, unlocked if l looses focus
530 531
    typename WPropertyVariable< T >::ConstraintContainerType::ReadTicket l =
        const_cast< WPropertyVariable< T >& >( from ).m_constraints->getReadTicket();
532

533
    // get write ticket too
534
    typename WPropertyVariable< T >::ConstraintContainerType::WriteTicket w = m_constraints->getWriteTicket();
535

536
    // we need to make a deep copy here.
537
    for( typename ConstraintContainerType::ConstIterator iter = l->get().begin(); iter != l->get().end(); ++iter )
538 539
    {
        // clone them to keep dynamic type
540
        w->get().insert( ( *iter )->clone() );
541
    }
542 543

    // set constraint and change condition to update condition set of WPropertyBase
544
    m_updateCondition->add( m_constraints->getChangeCondition() );
545
    m_updateCondition->add( WFlag< T >::getValueChangeCondition() );
546 547
}

548 549 550 551
template < typename T >
WPropertyVariable< T >::~WPropertyVariable()
{
    // clean up
552
    m_updateCondition->remove( m_constraints->getChangeCondition() );
553 554
    m_updateCondition->remove( WFlag< T >::getValueChangeCondition() );

555
    m_notifierConnection.disconnect();
556 557

    // lock, unlocked if l looses focus
558
    typename WPropertyVariable< T >::ConstraintContainerType::WriteTicket l = m_constraints->getWriteTicket();
559
    l->get().clear();
560 561
}

562 563 564 565 566 567
template < typename T >
boost::shared_ptr< WPropertyBase > WPropertyVariable< T >::clone()
{
    return boost::shared_ptr< WPropertyBase >( new WPropertyVariable< T >( *this ) );
}

568 569 570 571 572 573 574
template < typename T >
void WPropertyVariable< T >::propertyChangeNotifier()
{
    // propagate change, include pointer to property
    signal_PropertyChange( shared_from_this() );
}

575
template < typename T >
576
bool WPropertyVariable< T >::accept( const T& newValue )
577
{
578
    // lock, lock vanishes if l looses focus
579
    typename WPropertyVariable< T >::ConstraintContainerType::ReadTicket l = m_constraints->getReadTicket();
580 581

    // iterate through the set
582
    bool acceptable = WFlag< T >::accept( newValue );
583
    for( typename ConstraintContainerType::ConstIterator it = l->get().begin(); it !=  l->get().end(); ++it )
584
    {
585
        acceptable &= ( *it )->accept( boost::static_pointer_cast< WPropertyVariable< T > >( shared_from_this() ), newValue );
586 587 588
    }

    return acceptable;
589 590
}

591 592 593 594 595
template < typename T >
bool WPropertyVariable< T >::setAsString( std::string value )
{
    try
    {
596
        // use the helper class which can handle different kinds of properties for us
597
        PROPERTY_TYPE_HELPER::WStringConversion< T > h = PROPERTY_TYPE_HELPER::WStringConversion< T >();
598
        return set( h.create( WFlag< T >::get(), value ) );
599
    }
600
    catch( const std::exception &e )
601 602 603 604 605
    {
        return false;
    }
}

606 607 608 609
template < typename T >
std::string WPropertyVariable< T >::getAsString()
{
    std::string val;
610 611 612
    // use the helper class which can handle different kinds of properties for us
    PROPERTY_TYPE_HELPER::WStringConversion< T > h = PROPERTY_TYPE_HELPER::WStringConversion< T >();
    return h.asString( WFlag< T >::get() );
613 614 615 616

    return val;
}

617
template < typename T >
618
bool WPropertyVariable< T >::set( boost::shared_ptr< WPropertyBase > value, bool recommendedOnly )
619 620
{
    // try to cast the given property to a WPropertyVariable of right type:
621
    boost::shared_ptr< WPropertyVariable< T > > v = boost::dynamic_pointer_cast< WPropertyVariable< T > >( value );
622
    if( v )
623
    {
624 625 626 627 628 629 630 631
        if( recommendedOnly )
        {
            return setRecommendedValue( v->get() );
        }
        else
        {
            return set( v->get() );
        }
632 633 634 635 636 637 638 639
    }
    else
    {
        return false;
    }
}

template < typename T >
640
bool WPropertyVariable< T >::set( const T& value, bool suppressNotification )
641
{
642
    m_notYetSet = false;
643 644 645
    return WFlag< T >::set( value, suppressNotification );
}

646
template < typename T >
647
bool WPropertyVariable< T >::setRecommendedValue( const T& value )
648 649 650 651 652 653 654 655 656 657 658 659 660 661
{
    // NOTE: well this is quite problematic when used multi-threaded ...
    if( m_notYetSet )
    {
        bool ret = set( value );
        m_notYetSet = true;
        return ret;
    }
    else
    {
        return false;
    }
}

662
template < typename T >
663
bool WPropertyVariable< T >::ensureValidity( const T& newValidValue, bool suppressNotification )
664
{
665
    if( !accept( WFlag< T >::get() ) )
666 667 668 669 670 671 672 673 674
    {
        // the currently set constraints forbid the current value.
        // reset it to the new value
        return WFlag< T >::set( newValidValue, suppressNotification );
    }

    return true;
}

675 676 677
template < typename T >
void WPropertyVariable< T >::addConstraint( boost::shared_ptr< PropertyConstraint > constraint )
{
678
    // lock, unlocked if l looses focus
679
    typename WPropertyVariable< T >::ConstraintContainerType::WriteTicket l = m_constraints->getWriteTicket();
680 681 682 683
    l->get().insert( constraint );

    // unlock by hand
    l.reset();
684
}
685

686 687 688
template < typename T >
boost::shared_ptr< WCondition > WPropertyVariable< T >::getContraintsChangedCondition()
{
689
    return m_constraints->getChangeCondition();
690 691
}

692
template < typename T >
693
void WPropertyVariable< T >::updateType()
694
{
695 696
    PROPERTY_TYPE_HELPER::WTypeIdentifier< T > tid;
    m_type = tid.getType();
697 698
}

699
template < typename T >
700
boost::shared_ptr< WPropertyConstraintMin< T > > WPropertyVariable< T >::minConstraint( const T& min )
701 702 703 704 705
{
    return boost::shared_ptr< WPropertyConstraintMin< T > >( new WPropertyConstraintMin< T >( min ) );
}

template < typename T >
706
boost::shared_ptr< WPropertyConstraintMax< T > > WPropertyVariable< T >::maxConstraint( const T& max )
707 708 709 710 711
{
    return boost::shared_ptr< WPropertyConstraintMax< T > >( new WPropertyConstraintMax< T >( max ) );
}

template < typename T >
712
boost::shared_ptr< WPropertyConstraintMin< T > > WPropertyVariable< T >::setMin( const T& min )
713
{
714
    boost::shared_ptr< WPropertyConstraintMin< T > > c = minConstraint( min );
715
    replaceConstraint( c, PC_MIN );
716
    return c;
717 718 719
}

template < typename T >
720
boost::shared_ptr< WPropertyConstraintMax< T > > WPropertyVariable< T >::setMax( const T& max )
721
{
722
    boost::shared_ptr< WPropertyConstraintMax< T > > c = maxConstraint( max );
723 724 725 726 727 728 729
    replaceConstraint( c, PC_MAX );
    return c;
}

template < typename T >
void WPropertyVariable< T >::replaceConstraint( boost::shared_ptr< PropertyConstraint > constraint, PROPERTYCONSTRAINT_TYPE type )
{
730
    // lock, unlocked if l looses focus
731
    typename WPropertyVariable< T >::ConstraintContainerType::WriteTicket l = m_constraints->getWriteTicket();
732 733 734

    removeConstraints( type, l );
    l->get().insert( constraint );
735 736 737 738 739 740 741 742
}

template < typename T >
boost::shared_ptr< typename WPropertyVariable< T >::PropertyConstraint >
WPropertyVariable< T >::replaceConstraint( PROPERTYCONSTRAINT_TYPE constraint, PROPERTYCONSTRAINT_TYPE type )
{
    boost::shared_ptr< typename WPropertyVariable< T >::PropertyConstraint > c = PropertyConstraint::create( constraint );
    replaceConstraint( c, type );
743 744 745 746 747 748 749
    return c;
}

template < typename T >
boost::shared_ptr< typename WPropertyVariable< T >::PropertyConstraint >
WPropertyVariable< T >::getFirstConstraint( PROPERTYCONSTRAINT_TYPE type )
{
750
    // lock, unlocked if l looses focus
751
    typename WPropertyVariable< T >::ConstraintContainerType::ReadTicket l = m_constraints->getReadTicket();
752 753

    // search first appearance of a constraint of the specified type
754
    for( typename ConstraintContainerType::ConstIterator it = l->get().begin(); it != l->get().end(); ++it )
755
    {
756
        if( ( *it )->getType() == type )
757 758 759 760 761 762
        {
            return ( *it );
        }
    }

    return boost::shared_ptr< PropertyConstraint >();
763 764
}

765 766 767
template < typename T >
int WPropertyVariable< T >::countConstraint( PROPERTYCONSTRAINT_TYPE type )
{
768
    // lock, unlocked if l looses focus
769
    typename WPropertyVariable< T >::ConstraintContainerType::ReadTicket l = m_constraints->getReadTicket();
770 771 772

    int i = 0;
    // search first appearance of a constraint of the specified type
773
    for( typename ConstraintContainerType::ConstIterator it =  l->get().begin(); it != l->get().end(); ++it )
774
    {
775
        if( ( *it )->getType() == type )
776 777 778 779 780 781 782 783
        {
            i++;
        }
    }

    return i;
}

784 785 786
template < typename T >
boost::shared_ptr< WPropertyConstraintMin< T > > WPropertyVariable< T >::getMin()
{
787 788
    // get min
    boost::shared_ptr< PropertyConstraint > c = getFirstConstraint( PC_MIN );
789
    if( !c.get() )
790 791 792 793 794 795
    {
        // return NULL if not found
        return boost::shared_ptr< WPropertyConstraintMin< T > >();
    }

    // cast to proper type
796
    return boost::static_pointer_cast< WPropertyConstraintMin< T > >( c );
797 798 799 800 801
}

template < typename T >
boost::shared_ptr< WPropertyConstraintMax< T > > WPropertyVariable< T >::getMax()
{
802 803
    // get min
    boost::shared_ptr< PropertyConstraint > c = getFirstConstraint( PC_MAX );
804
    if( !c.get() )
805 806 807 808 809 810
    {
        // return NULL if not found
        return boost::shared_ptr< WPropertyConstraintMax< T > >();
    }

    // cast to proper type
811
    return boost::static_pointer_cast< WPropertyConstraintMax< T > >( c );
812 813
}

814
template< typename T >
815
typename WPropertyVariable<T>::ConstraintContainerType WPropertyVariable<T>::getConstraints()
816
{
817
    return m_constraints;
818 819
}

820
template < typename T >
821
void WPropertyVariable< T >::removeConstraints( PROPERTYCONSTRAINT_TYPE type,
822
                                                typename WPropertyVariable< T >::ConstraintContainerType::WriteTicket ticket )
823
{
824
    typename WPropertyVariable< T >::ConstraintContainerType::WriteTicket l = ticket;
825 826 827

    bool useLock = !ticket;

828
    // lock the constraints set
829
    if( useLock )
830
    {
831
        // lock, unlocked if l looses focus
832
        l = m_constraints->getWriteTicket();
833 834
    }

835
    size_t nbErased = 0;    // count how much items have been removed
836
    for( typename ConstraintContainerType::ConstIterator it = l->get().begin(); it != l->get().end(); )
837
    {
838
        if( ( *it )->getType() == type )
839
        {
840
            l->get().erase( it++ );
841
            ++nbErased;
842 843 844 845
        }
        else
        {
            ++it;
846 847
        }
    }
848 849

    // only notify and unlock if locked earlier.
850
    if( useLock )
851
    {
852
        // no operations done? No condition fired
853
        if( nbErased == 0 )
854 855 856 857
        {
            l->suppressUnlockCondition();
        }

858 859
        // unlock by hand
        l.reset();
860 861
    }
}
862

863 864 865 866
template < typename T >
void WPropertyVariable< T >::removeConstraint( PROPERTYCONSTRAINT_TYPE type )
{
    // simply forward the call
867
    removeConstraints( type, typename WPropertyVariable< T >::ConstraintContainerType::WriteTicket() );
868 869 870 871 872 873
}

template < typename T >
void WPropertyVariable< T >::removeConstraint( boost::shared_ptr< PropertyConstraint > constraint )
{
    // lock released automatically
874
    typename WPropertyVariable< T >::ConstraintContainerType::WriteTicket l = m_constraints->getWriteTicket();
875

876
    if( l->get().erase( constraint ) == 0 )
877 878 879
    {
        // nothing changed. Suppress update condition to fire
        l->suppressUnlockCondition();
880
    }
881 882 883 884 885 886 887 888 889 890 891 892
}

template < typename T >
WPropertyVariable< T >::PropertyConstraint::PropertyConstraint()
{
}

template < typename T >
WPropertyVariable< T >::PropertyConstraint::~PropertyConstraint()
{
}

893 894 895 896 897 898
template < typename T >
PROPERTYCONSTRAINT_TYPE WPropertyVariable< T >::PropertyConstraint::getType()
{
    return PC_UNKNOWN;
}

899
#endif  // WPROPERTYVARIABLE_H
900