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