Commit 40288d01 authored by Sebastian Eichelbaum's avatar Sebastian Eichelbaum
Browse files

[ADD] - refactored WProperties. Now, we have a group base class...

[ADD] - refactored WProperties. Now, we have a group base class WPropertyGroupBase. WPropertyGroup and WPropertyStruct derive from this and can, therefore, reuse all the thread-safe property-list management. WProperties is now an alias to WPropertyGroup.
parent 3d3c64f9
This diff is collapsed.
This diff is collapsed.
......@@ -27,7 +27,7 @@
#include <boost/shared_ptr.hpp>
// This class contains forward declarations for every thing which is needed to use WProperties in all their variations. Simply include this file
// This class contains forward declarations for every thing which is needed to use WPropertyGroup in all their variations. Simply include this file
// in your headers if your somehow need properties or related classes.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
......@@ -37,7 +37,7 @@
// WPropertyTypes.h does not include any other property header. So we can include it directly here.
// Provides:
// * class WPropertyVariable< T >
// * class WProperties
// * class WPropertyGroup
// * enum PROPERTY_TYPE
// * enum PROPERTY_PURPOSE
// * typedefs WPVPropXYZ
......@@ -49,6 +49,9 @@
// From WPropertyBase.h
class WPropertyBase;
// From WPropertyGroupBase.h
class WPropertyGroupBase;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Utilities
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
......
......@@ -34,6 +34,7 @@
#include "exceptions/WPropertyNameMalformed.h"
#include "WProperties.h"
#include "WPropertyBase.h"
#include "WPropertyGroupBase.h"
#include "WPropertyVariable.h"
#include "WTransferFunction.h"
......@@ -161,6 +162,11 @@ WPropGroup WPropertyBase::toPropGroup()
return boost::shared_static_cast< WPVGroup >( shared_from_this() );
}
WPropertyGroupBase::SPtr WPropertyBase::toPropGroupBase()
{
return boost::shared_static_cast< WPropertyGroupBase >( shared_from_this() );
}
WPropMatrix4X4 WPropertyBase::toPropMatrix4X4()
{
return boost::shared_static_cast< WPVMatrix4X4 >( shared_from_this() );
......
......@@ -268,7 +268,6 @@ public:
*/
WPropTransferFunction toPropTransferFunction();
/**
* Helper converts this instance to its native type.
*
......@@ -276,6 +275,13 @@ public:
*/
WPropGroup toPropGroup();
/**
* Convert the property to a WPropertyGroupBase. This can be done with property structs and groups-
*
* \return the property as base group.
*/
boost::shared_ptr< WPropertyGroupBase > toPropGroupBase();
/**
* Helper converts this instance to an arbitrary type.
*
......
This diff is collapsed.
This diff is collapsed.
//---------------------------------------------------------------------------
//
// 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/>.
//
//---------------------------------------------------------------------------
#include <iostream>
#include <map>
#include <string>
#include <vector>
#include <algorithm>
#include <boost/lexical_cast.hpp>
#include <boost/tokenizer.hpp>
#include "WLogger.h"
#include "exceptions/WPropertyUnknown.h"
#include "exceptions/WPropertyNotUnique.h"
#include "WPropertyHelper.h"
#include "WPropertyGroupBase.h"
WPropertyGroupBase::WPropertyGroupBase( std::string name, std::string description ):
WPropertyBase( name, description ),
m_properties(),
m_childUpdateCondition( new WConditionSet() )
{
m_updateCondition->add( m_properties.getChangeCondition() );
}
WPropertyGroupBase::~WPropertyGroupBase()
{
}
WPropertyGroupBase::WPropertyGroupBase( const WPropertyGroupBase& from ):
WPropertyBase( from ),
m_properties(),
m_childUpdateCondition( new WConditionSet() )
{
// copy the properties inside
// lock, unlocked if l looses focus
PropertySharedContainerType::ReadTicket l = from.m_properties.getReadTicket();
// we need to make a deep copy here.
for( PropertyConstIterator iter = l->get().begin(); iter != l->get().end(); ++iter )
{
// clone them to keep dynamic type
addArbitraryProperty( ( *iter )->clone() );
}
// unlock explicitly
l.reset();
// add the change condition of the prop list
m_updateCondition->add( m_properties.getChangeCondition() );
}
boost::shared_ptr< WCondition > WPropertyGroupBase::getChildUpdateCondition() const
{
return m_childUpdateCondition;
}
bool WPropertyGroupBase::propNamePredicate( boost::shared_ptr< WPropertyBase > prop1, boost::shared_ptr< WPropertyBase > prop2 ) const
{
return ( prop1->getName() == prop2->getName() );
}
boost::shared_ptr< WPropertyBase > WPropertyGroupBase::findProperty( const WPropertyGroupBase* const props, std::string name ) const
{
boost::shared_ptr< WPropertyBase > result = boost::shared_ptr< WPropertyBase >();
// lock, unlocked if l looses focus
PropertySharedContainerType::ReadTicket l = props->m_properties.getReadTicket();
// iterate over the items
for( PropertyContainerType::const_iterator it = l->get().begin(); it != l->get().end(); ++it )
{
if( ( *it )->getName() == name )
{
result = ( *it );
break;
}
}
// done. Unlocked after l looses focus.
return result;
}
boost::shared_ptr< WPropertyBase > WPropertyGroupBase::findProperty( std::string name ) const
{
boost::shared_ptr< WPropertyBase > result = boost::shared_ptr< WPropertyBase >();
// tokenize the name -> contains any paths?
typedef boost::tokenizer<boost::char_separator< char > > tokenizer;
boost::char_separator< char > sep( "/" ); // separate by /
tokenizer tok( name, sep );
// iterate along the path
const WPropertyGroupBase* curProps = this; // the group currently in while traversing the path
for( tokenizer::iterator it = tok.begin(); it != tok.end(); ++it )
{
// was the last token not a group?
if( result && !WPVBaseTypes::isPropertyGroup( result->getType() ) )
{
// no it wasn't. This means that one token inside the path is no group, but it needs to be one
return boost::shared_ptr< WPropertyBase >();
}
// get the properties along the path
result = findProperty( curProps, boost::lexical_cast< std::string >( *it ) );
if( !result )
{
// not found? Return NULL.
return boost::shared_ptr< WPropertyBase >();
}
else if( result && WPVBaseTypes::isPropertyGroup( result->getType() ) )
{
// it is a group. Go down
curProps = result->toPropGroupBase().get();
}
}
return result;
}
bool WPropertyGroupBase::existsProperty( std::string name )
{
return ( findProperty( name ) != boost::shared_ptr< WPropertyBase >() );
}
boost::shared_ptr< WPropertyBase > WPropertyGroupBase::getProperty( std::string name )
{
boost::shared_ptr< WPropertyBase > p = findProperty( name );
if( p == boost::shared_ptr< WPropertyBase >() )
{
throw WPropertyUnknown( std::string( "Property \"" + name + "\" can't be found." ) );
}
return p;
}
void WPropertyGroupBase::addArbitraryProperty( WPropertyBase::SPtr prop )
{
// lock, unlocked if l looses focus
PropertySharedContainerType::WriteTicket l = m_properties.getWriteTicket();
// NOTE: WPropertyBase already prohibits invalid property names -> no check needed here
// check uniqueness:
if( std::count_if( l->get().begin(), l->get().end(),
boost::bind( boost::mem_fn( &WPropertyGroupBase::propNamePredicate ), this, prop, _1 ) ) )
{
// unlock explicitly
l.reset();
// oh oh, this property name is not unique in this group
if( !getName().empty() )
{
throw WPropertyNotUnique( std::string( "Property \"" + prop->getName() + "\" is not unique in this group (\"" + getName() + "\")." ) );
}
else
{
throw WPropertyNotUnique( std::string( "Property \"" + prop->getName() + "\" is not unique in this group (unnamed root)." ) );
}
}
// PV_PURPOSE_INFORMATION groups do not allow PV_PURPOSE_PARAMETER properties but vice versa.
if( getPurpose() == PV_PURPOSE_INFORMATION )
{
prop->setPurpose( PV_PURPOSE_INFORMATION );
}
// INFORMATION properties are allowed inside PARAMETER groups -> do not set the properties purpose.
l->get().push_back( prop );
// add the child's update condition to the list
m_childUpdateCondition->add( prop->getUpdateCondition() );
}
WPropertyGroupBase::PropertySharedContainerType::ReadTicket WPropertyGroupBase::getProperties() const
{
return m_properties.getReadTicket();
}
WPropertyGroupBase::PropertySharedContainerType::ReadTicket WPropertyGroupBase::getReadTicket() const
{
return m_properties.getReadTicket();
}
//---------------------------------------------------------------------------
//
// 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 WPROPERTYGROUPBASE_H
#define WPROPERTYGROUPBASE_H
#include <map>
#include <string>
#include <vector>
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread.hpp>
#include "WConditionSet.h"
#include "WPropertyBase.h"
#include "WPropertyTypes.h"
#include "WPropertyVariable.h"
#include "WSharedSequenceContainer.h"
#include "WExportCommon.h"
/**
* This is the base class and interface for property groups. This class itself is abstract and derived from WPropertyBase. So if you create a
* group of properties, this ensures that your group is a property itself. This interface defines no way to add, remove or edit the property list
* itself. This allows the deriving class to prohibit modifications and to provide a custom interface, or even model-controller like
* implementations.
*
* Another advantage is, that the GUI implementations which support WPropertyGroupBase can display your custom properties directly.
*/
class OWCOMMON_EXPORT WPropertyGroupBase: public WPropertyBase
{
public:
/**
* For shortening: a type defining a shared vector of WSubject pointers.
*/
typedef std::vector< boost::shared_ptr< WPropertyBase > > PropertyContainerType;
/**
* The alias for a shared container.
*/
typedef WSharedSequenceContainer< PropertyContainerType > PropertySharedContainerType;
/**
* The const iterator type of the container.
*/
typedef PropertyContainerType::const_iterator PropertyConstIterator;
/**
* The iterator type of the container.
*/
typedef PropertyContainerType::iterator PropertyIterator;
/**
* Convenience typedef for a boost::shared_ptr< WPropertyGroupBase >.
*/
typedef boost::shared_ptr< WPropertyGroupBase > SPtr;
/**
* Convenience typedef for a boost::shared_ptr< const WPropertyGroupBase >.
*/
typedef boost::shared_ptr< const WPropertyGroupBase > ConstSPtr;
///////////////////////////////////////////////////////////////////////////////////////////////////
// Construction
///////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Constructor. Creates an empty list of properties.
*
* \param name the name of the property group. The GUI is using this name for naming the tabs/group boxes
* \param description the description of the group.
*/
WPropertyGroupBase( std::string name, std::string description );
/**
* 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.
* 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 flag is changed
* (which after cloning is completely decoupled from the clone).
*
* \note the properties inside this list are also copied deep
*
* \param from the instance to copy.
*/
explicit WPropertyGroupBase( const WPropertyGroupBase& from );
/**
* Destructor.
*/
virtual ~WPropertyGroupBase();
///////////////////////////////////////////////////////////////////////////////////////////////////
// The WPropertyGroupBase interface
///////////////////////////////////////////////////////////////////////////////////////////////////
/**
* This returns the condition fired whenever one children fires its update condition. Useful to get notified about all changes that happen.
*
* \return the condition fired if a child fires its update condition.
*/
virtual boost::shared_ptr< WCondition > getChildUpdateCondition() const;
/**
* Helper function that finds a property by its name. Use this method to find out whether the property exists or not, since
* findProperty throws an exception.
*
* \param name name of searched property.
*
* \return Answer to the question whether the property exists.
*/
virtual bool existsProperty( std::string name );
/**
* Function searches the property. If it does not exists, it throws an exception.
*
* \param name the name of the property
*
* \return a WProperty object
*/
virtual boost::shared_ptr< WPropertyBase > getProperty( std::string name );
/**
* Returns a read ticket for read-access to the list of properties.
*
* \return the read ticket.
*/
virtual PropertySharedContainerType::ReadTicket getProperties() const;
/**
* Returns an read ticket for the properties. This, and only this, has to be used for external iteration of properties.
*
* \see WSharedObjectTicketRead
* \return the read ticket.
*/
virtual PropertySharedContainerType::ReadTicket getReadTicket() const;
/**
* Searches the property with a given name. It does not throw any exception. It simply returns NULL if it can't be found.
*
* \param name the name of the property to search
*
* \return the property or NULL if not found.
*/
virtual boost::shared_ptr< WPropertyBase > findProperty( std::string name ) const;
protected:
/**
* Helping function to find a property inside a specific group. It does not recursively find properties nested inside other property groups.
*
* \param props the group to search in. This is not a shared pointer since it is not needed. It simply can't happen that it is freed during
* findProperty as it is contained in this or a nested properties instance.
* \param name the name of the property inside THIS group.
*
* \return the property if found, else NULL.
*/
virtual boost::shared_ptr< WPropertyBase > findProperty( const WPropertyGroupBase* const props, std::string name ) const;
/**
* The set of proerties. This uses the operators ==,<,> WProperty to determine equalness.
*/
PropertySharedContainerType m_properties;
/**
* Condition notified whenever a property inside this group fires its WPropertyBase::m_updateCondition. This is especially useful to get a
* notification if something updates without further knowledge what changed. Useful if you want to listen for updates in modules for example.
*
* \see getChildUpdateCondition
*/
boost::shared_ptr< WConditionSet > m_childUpdateCondition;
/**
* Compares the names of two properties and returns true if they are equal.
*
* \param prop1 the first prop.
* \param prop2 the second prop.
*
* \return Are the names of the two properties equal?
*/
bool propNamePredicate( boost::shared_ptr< WPropertyBase > prop1, boost::shared_ptr< WPropertyBase > prop2 ) const;
/**
* Insert the specified property into the list. This method is protected. It is a convenience method for deriving classes to add properties
* without the need to update several conditions and similar.
*
* \param prop the property to add
*/
void addArbitraryProperty( WPropertyBase::SPtr prop );
private:
};
#endif // WPROPERTYGROUPBASE_H
......@@ -35,7 +35,9 @@
#include <boost/mpl/copy.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include "WStringUtils.h"
#include "WCondition.h"
#include "WPropertyGroupBase.h"
#include "WPropertyBase.h"
#include "exceptions/WPropertyUnknown.h"
......@@ -161,19 +163,19 @@ template<
typename T8 = WPropertyStructHelper::NOTYPE,
typename T9 = WPropertyStructHelper::NOTYPE
>
class WPropertyStruct: public WPropertyBase
class WPropertyStruct: public WPropertyGroupBase
{
public:
typedef WPropertyStruct< BOOST_PP_ENUM_PARAMS( 10, T ) > WPropertyStructType;
/**
* Convenience typedef for a boost::shared_ptr< WPropertyBase >
* Convenience typedef for a boost::shared_ptr< WPropertyStructType >
*/
typedef boost::shared_ptr< WPropertyStructType > SPtr;
/**
* Convenience typedef for a boost::shared_ptr< const WPropertyBase >
* Convenience typedef for a boost::shared_ptr< const WPropertyStructType >
*/
typedef boost::shared_ptr< const WPropertyStructType > ConstSPtr;
......@@ -194,7 +196,7 @@ public:
* \param description the description of the property
*/
WPropertyStruct( std::string name, std::string description ):
WPropertyBase( name, description )
WPropertyGroupBase( name, description )
{
}
......@@ -205,7 +207,7 @@ public:
* \param from the instance to copy.
*/
explicit WPropertyStruct( const WPropertyStructType& from ):
WPropertyBase( from )
WPropertyGroupBase( from )
{
// this created a NEW update condition and NEW property instances (clones)
}
......@@ -215,6 +217,7 @@ public:
*/
virtual ~WPropertyStruct()
{
// the storing tuple is destroyed automatically and the properties if not used anymore
}
/**
......@@ -225,9 +228,10 @@ public:
* \return the property.
*/
template< int N >
typename boost::mpl::at< TypeVector, boost::mpl::size_t< N > >::type& getProperty()
typename boost::mpl::at< TypeVector, boost::mpl::size_t< N > >::type getProperty()
{
return m_properties.template get< N >();
typedef typename boost::mpl::at< TypeVector, boost::mpl::size_t< N > >::type::element_type TargetType;
return boost::shared_dynamic_cast< TargetType >( getProperty( N ) );
}
/**
......@@ -238,9 +242,10 @@ public:
* \return the property.
*/
template< int N >
const typename boost::mpl::at< TypeVector, boost::mpl::size_t< N > >::type& getProperty() const
typename boost::mpl::at< TypeVector, boost::mpl::size_t< N > >::type::element_type::ConstSPtr getProperty() const
{
return m_properties.template get< N >();
typedef typename boost::mpl::at< TypeVector, boost::mpl::size_t< N > >::type::element_type TargetType;
return boost::shared_dynamic_cast< const TargetType >( getProperty( N ) );
}
/**
......@@ -267,31 +272,9 @@ public:
*/
WPropertyBase::SPtr getProperty( size_t n )
{
switch( n )
{
case 0:
return getProperty< 0 >();
case 1:
return getProperty< 1 >();
case 2:
return getProperty< 2 >();
case 3:
return getProperty< 3 >();
case 4:
return getProperty< 4 >();
case 5:
return getProperty< 5 >();
case 6:
return getProperty< 6 >();
case 7:
return getProperty< 7 >();
case 8:
return getProperty< 8 >();
case 9:
return getProperty< 9 >();
default:
throw WPropertyUnknown( "The property with this ID is not known" );
};
// lock, unlocked if l looses focus
PropertySharedContainerType::ReadTicket l = m_properties.getReadTicket();