OpenWalnut 1.3.1
WPropertyGroupBase.cpp
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 #include <iostream>
00026 #include <map>
00027 #include <string>
00028 #include <vector>
00029 #include <algorithm>
00030 
00031 #include <boost/tokenizer.hpp>
00032 
00033 #include "WStringUtils.h"
00034 #include "WLogger.h"
00035 #include "exceptions/WPropertyUnknown.h"
00036 #include "exceptions/WPropertyNotUnique.h"
00037 
00038 #include "WPropertyHelper.h"
00039 
00040 #include "WPropertyGroupBase.h"
00041 
00042 WPropertyGroupBase::WPropertyGroupBase( std::string name, std::string description ):
00043     WPropertyBase( name, description ),
00044     m_properties()
00045 {
00046     // this groups update condition also fires upon group modification -> add WSharedObject condition
00047     m_updateCondition->add( m_properties.getChangeCondition() );
00048 }
00049 
00050 WPropertyGroupBase::~WPropertyGroupBase()
00051 {
00052 }
00053 
00054 WPropertyGroupBase::WPropertyGroupBase( const WPropertyGroupBase& from ):
00055     WPropertyBase( from ),
00056     m_properties()
00057 {
00058     // copy the properties inside
00059 
00060     // lock, unlocked if l looses focus
00061     PropertySharedContainerType::ReadTicket l = from.m_properties.getReadTicket();
00062 
00063     // we need to make a deep copy here.
00064     for( PropertyConstIterator iter = l->get().begin(); iter != l->get().end(); ++iter )
00065     {
00066         // clone them to keep dynamic type
00067         addArbitraryProperty( ( *iter )->clone() );
00068     }
00069 
00070     // unlock explicitly
00071     l.reset();
00072 
00073     // this groups update condition also fires upon group modification -> add WSharedObject condition
00074     m_updateCondition->add( m_properties.getChangeCondition() );
00075 }
00076 
00077 bool WPropertyGroupBase::propNamePredicate( boost::shared_ptr< WPropertyBase > prop1, boost::shared_ptr< WPropertyBase > prop2 ) const
00078 {
00079     return ( prop1->getName() == prop2->getName() );
00080 }
00081 
00082 boost::shared_ptr< WPropertyBase > WPropertyGroupBase::findProperty( const WPropertyGroupBase* const props, std::string name ) const
00083 {
00084     boost::shared_ptr< WPropertyBase > result = boost::shared_ptr< WPropertyBase >();
00085 
00086     // lock, unlocked if l looses focus
00087     PropertySharedContainerType::ReadTicket l = props->m_properties.getReadTicket();
00088 
00089     // iterate over the items
00090     for( PropertyContainerType::const_iterator it = l->get().begin(); it != l->get().end(); ++it )
00091     {
00092         if( ( *it )->getName() == name )
00093         {
00094             result = ( *it );
00095             break;
00096         }
00097     }
00098 
00099     // done. Unlocked after l looses focus.
00100     return result;
00101 }
00102 
00103 boost::shared_ptr< WPropertyBase > WPropertyGroupBase::findProperty( std::string name ) const
00104 {
00105     boost::shared_ptr< WPropertyBase > result = boost::shared_ptr< WPropertyBase >();
00106 
00107     // tokenize the name -> contains any paths?
00108     typedef boost::tokenizer<boost::char_separator< char > > tokenizer;
00109     boost::char_separator< char > sep( "/" );   // separate by /
00110     tokenizer tok( name, sep );
00111 
00112     // iterate along the path
00113     const WPropertyGroupBase* curProps = this;       // the group currently in while traversing the path
00114     for( tokenizer::iterator it = tok.begin(); it != tok.end(); ++it )
00115     {
00116         // was the last token not a group?
00117         if( result && !WPVBaseTypes::isPropertyGroup( result->getType() ) )
00118         {
00119             // no it wasn't. This means that one token inside the path is no group, but it needs to be one
00120             return boost::shared_ptr< WPropertyBase >();
00121         }
00122 
00123         // get the properties along the path
00124         result = findProperty( curProps, string_utils::toString( *it ) );
00125         if( !result )
00126         {
00127             // not found? Return NULL.
00128             return boost::shared_ptr< WPropertyBase >();
00129         }
00130         else if( result && WPVBaseTypes::isPropertyGroup( result->getType() ) )
00131         {
00132             // it is a group. Go down
00133             curProps = result->toPropGroupBase().get();
00134         }
00135     }
00136 
00137     return result;
00138 }
00139 
00140 bool WPropertyGroupBase::existsProperty( std::string name )
00141 {
00142     return ( findProperty( name ) != boost::shared_ptr< WPropertyBase >() );
00143 }
00144 
00145 boost::shared_ptr< WPropertyBase > WPropertyGroupBase::getProperty( std::string name )
00146 {
00147     boost::shared_ptr< WPropertyBase > p = findProperty( name );
00148     if( p == boost::shared_ptr< WPropertyBase >() )
00149     {
00150         throw WPropertyUnknown( std::string( "Property \"" + name + "\" can't be found." ) );
00151     }
00152 
00153     return p;
00154 }
00155 
00156 void WPropertyGroupBase::addArbitraryProperty( WPropertyBase::SPtr prop )
00157 {
00158     // lock, unlocked if l looses focus
00159     PropertySharedContainerType::WriteTicket l = m_properties.getWriteTicket();
00160 
00161     // NOTE: WPropertyBase already prohibits invalid property names -> no check needed here
00162 
00163     // check uniqueness:
00164     if( std::count_if( l->get().begin(), l->get().end(),
00165             boost::bind( boost::mem_fn( &WPropertyGroupBase::propNamePredicate ), this, prop, _1 ) ) )
00166     {
00167         // unlock explicitly
00168         l.reset();
00169 
00170         // oh oh, this property name is not unique in this group
00171         if( !getName().empty() )
00172         {
00173             throw WPropertyNotUnique( std::string( "Property \"" + prop->getName() + "\" is not unique in this group (\"" + getName() + "\")." ) );
00174         }
00175         else
00176         {
00177             throw WPropertyNotUnique( std::string( "Property \"" + prop->getName() + "\" is not unique in this group (unnamed root)." ) );
00178         }
00179     }
00180 
00181     // PV_PURPOSE_INFORMATION groups do not allow PV_PURPOSE_PARAMETER properties but vice versa.
00182     if( getPurpose() == PV_PURPOSE_INFORMATION )
00183     {
00184         prop->setPurpose( PV_PURPOSE_INFORMATION );
00185     }
00186     // INFORMATION properties are allowed inside PARAMETER groups -> do not set the properties purpose.
00187 
00188     l->get().push_back( prop );
00189 
00190     // add the child's update condition to the list
00191     m_updateCondition->add( prop->getUpdateCondition() );
00192 }
00193 
00194 WPropertyGroupBase::PropertySharedContainerType::ReadTicket WPropertyGroupBase::getProperties() const
00195 {
00196     return m_properties.getReadTicket();
00197 }
00198 
00199 WPropertyGroupBase::PropertySharedContainerType::ReadTicket WPropertyGroupBase::getReadTicket() const
00200 {
00201     return m_properties.getReadTicket();
00202 }
00203