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 #ifndef WSTRATEGYHELPER_H 00026 #define WSTRATEGYHELPER_H 00027 00028 #include <string> 00029 #include <vector> 00030 00031 #include <boost/shared_ptr.hpp> 00032 #include <boost/thread.hpp> 00033 00034 #include "WLogger.h" 00035 #include "WItemSelection.h" 00036 #include "WItemSelector.h" 00037 #include "WSharedSequenceContainer.h" 00038 #include "WProperties.h" 00039 #include "WPropertyHelper.h" 00040 00041 /** 00042 * This class allows for an easy strategy pattern-based switching between properties and strategy instances using a WPropSelection. The idea of 00043 * this class is that you specify the type of some class you want to serve as the base class of several strategies. Each of these strategies has 00044 * a name, description and several properties. An instance of this class automatically provides a WPropSelection containing an item for each strategy 00045 * instance you add. A switch in this property causes to automatically hide all properties not belonging to this strategy. This class will ease 00046 * the writing of modules that provide multiple "ways of doing it". If you utilize this class in your module, you should add ALL your strategies 00047 * before you add this WStrategyHelper's properties to your module's properties. 00048 * 00049 * \tparam StrategyType the base class type of your strategies. 00050 * 00051 * The type in StrategyType needs to comply to the following rules: 00052 * <ul> 00053 * <li> provide a typedef SPtr, representing the pointer type of this class. Usually, this is a boost::shared_ptr 00054 * <li> provide a typedef ConstSPtr, representing the pointer type of this class. Usually, this is a boost::shared_ptr< const > 00055 * <li> provide a method std::string getName() const 00056 * <li> provide a method std::string getDescription() const 00057 * <li> provide a method const char** getXPMIcon() const 00058 * <li> provide a method WProperties::SPtr getProperties() const; 00059 * </ul> 00060 * The cool thing is, this class complies to its own requirements on strategy base classes. This allows you to nest strategy selections. 00061 * 00062 * \note the class is thread-safe, although it might not be a nice idea to modify the strategy list while the user tries to select some. He will 00063 * probably be very annoyed. 00064 * 00065 * \note you should use \ref WObjectNDIP which complies to this rules. This furthermore eases the task of writing strategies. 00066 */ 00067 template< class StrategyType > 00068 class WStrategyHelper 00069 { 00070 public: 00071 /** 00072 * Convenience typedef for a boost::shared_ptr< WStrategyHelper >. 00073 */ 00074 typedef boost::shared_ptr< WStrategyHelper > SPtr; 00075 00076 /** 00077 * Convenience typedef for a boost::shared_ptr< const WStrategyHelper >. 00078 */ 00079 typedef boost::shared_ptr< const WStrategyHelper > ConstSPtr; 00080 00081 /** 00082 * Constructs an empty strategy selector. Use one of the addStrategy methods to register strategies. 00083 * 00084 * \param name name of this strategy selector 00085 * \param description a description for this selection 00086 * \param icon an icon for this selection. Can be NULL. 00087 * \param selectorName the name of the selection property used to switch. If empty, the name of the WStrategyHelper will be used. 00088 * \param selectorDescription the description of the selection property used to switch. If empty, description of the WStrategyHelper is used. 00089 */ 00090 WStrategyHelper( std::string name, std::string description, const char** icon = NULL, std::string selectorName = std::string(), 00091 std::string selectorDescription = std::string() ); 00092 00093 /** 00094 * Destructor. 00095 */ 00096 ~WStrategyHelper(); 00097 00098 /** 00099 * Gets the name of this strategy selector. 00100 * 00101 * \return the name. 00102 */ 00103 std::string getName() const; 00104 00105 /** 00106 * Gets the description for this strategy selector. 00107 * 00108 * \return the description 00109 */ 00110 std::string getDescription() const; 00111 00112 /** 00113 * Get the icon for this strategy selectior in XPM format. 00114 * 00115 * \return The icon. 00116 */ 00117 const char** getXPMIcon() const; 00118 00119 /** 00120 * Get this strategy selectors properties. This group contains the WPropSelection property to switch the strategy as well as groups for all 00121 * registered strategies. 00122 * 00123 * \return properties 00124 */ 00125 WProperties::SPtr getProperties() const; 00126 00127 /** 00128 * Adds the given strategy to the list of all strategies. 00129 * 00130 * \param strategy the strategy to add. 00131 */ 00132 void addStrategy( typename StrategyType::SPtr strategy ); 00133 00134 /** 00135 * Return the currently active strategy. 00136 * 00137 * \return the active strategy 00138 */ 00139 typename StrategyType::ConstSPtr operator()() const; 00140 00141 /** 00142 * Return the currently active strategy. 00143 * 00144 * \return the active strategy 00145 */ 00146 typename StrategyType::SPtr operator()(); 00147 00148 protected: 00149 private: 00150 const char** m_icon; //!< the icon pointer 00151 WProperties::SPtr m_properties; //!< stores the selection property and the strategy property groups 00152 00153 /** 00154 * A list of items that can be selected. Will be extended for each added strategy. 00155 */ 00156 WItemSelection::SPtr m_possibleSelections; 00157 00158 /** 00159 * The property allowing the user to switch the strategy. Will be extended for each added strategy. 00160 */ 00161 WPropSelection m_possibleSelectionProp; 00162 00163 /** 00164 * The type used to securely manage the strategies 00165 */ 00166 typedef WSharedSequenceContainer< std::vector< typename StrategyType::SPtr > > ContainerType; 00167 00168 /** 00169 * This is the list of all strategies 00170 */ 00171 ContainerType m_strategies; 00172 00173 /** 00174 * This lock is needed to protect the addStrategy function. Although the m_strategies member is protected due to the use of a WSharedObject, 00175 * an update in the selection (m_possibleSelectionProp) causes an update of the hide status of all property groups in m_strategies. This 00176 * would cause a deadlock if m_strategies is still locked. This lock is only locked if addStrategy is called. 00177 */ 00178 boost::mutex m_addLock; 00179 00180 /** 00181 * Connection between \ref update and the update condition of \ref m_possibleSelectionProp. 00182 */ 00183 boost::signals2::connection m_updateConnection; 00184 00185 /** 00186 * Update strategy's property hide status on updates in \ref m_possibleSelectionProp. 00187 */ 00188 void update(); 00189 }; 00190 00191 template< typename StrategyType > 00192 WStrategyHelper< StrategyType >::WStrategyHelper( std::string name, std::string description, const char** icon, 00193 std::string selectorName, std::string selectorDescription ): 00194 m_icon( icon ), 00195 m_properties( new WProperties( name, description ) ), 00196 m_possibleSelections( new WItemSelection() ) 00197 { 00198 // Create the main selector property: 00199 selectorName = selectorName.empty() ? name : selectorName; 00200 selectorDescription = selectorDescription.empty() ? name : selectorDescription; 00201 m_possibleSelectionProp = m_properties->addProperty( selectorName, selectorDescription, m_possibleSelections->getSelectorNone() ); 00202 WPropertyHelper::PC_SELECTONLYONE::addTo( m_possibleSelectionProp ); 00203 WPropertyHelper::PC_NOTEMPTY::addTo( m_possibleSelectionProp ); 00204 00205 // if the selection changes, we want to hide all not selected strategy groups. So we register a change callback 00206 m_updateConnection = m_possibleSelectionProp->getUpdateCondition()->subscribeSignal( 00207 boost::bind( &WStrategyHelper< StrategyType >::update, this ) 00208 ); 00209 } 00210 00211 template< typename StrategyType > 00212 WStrategyHelper< StrategyType >::~WStrategyHelper() 00213 { 00214 // cleanup 00215 } 00216 00217 template< typename StrategyType > 00218 void WStrategyHelper< StrategyType >::update() 00219 { 00220 // get lock 00221 typename ContainerType::WriteTicket w = m_strategies.getWriteTicket(); 00222 00223 // update each hide state 00224 size_t currentID = 0; 00225 size_t selectedID = m_possibleSelectionProp->get(); 00226 00227 for( typename ContainerType::Iterator i = w->get().begin(); i != w->get().end(); ++i ) 00228 { 00229 ( *i )->getProperties()->setHidden( currentID != selectedID ); 00230 currentID++; 00231 } 00232 // w unlocks automatically 00233 } 00234 00235 template< typename StrategyType > 00236 std::string WStrategyHelper< StrategyType >::getName() const 00237 { 00238 return m_properties->getName(); 00239 } 00240 00241 template< typename StrategyType > 00242 std::string WStrategyHelper< StrategyType >::getDescription() const 00243 { 00244 return m_properties->getDescription(); 00245 } 00246 00247 template< typename StrategyType > 00248 const char** WStrategyHelper< StrategyType >::getXPMIcon() const 00249 { 00250 return m_icon; 00251 } 00252 00253 template< typename StrategyType > 00254 WProperties::SPtr WStrategyHelper< StrategyType >::getProperties() const 00255 { 00256 return m_properties; 00257 } 00258 00259 template< typename StrategyType > 00260 void WStrategyHelper< StrategyType >::addStrategy( typename StrategyType::SPtr strategy ) 00261 { 00262 // lock this method. 00263 boost::lock_guard< boost::mutex > lock( m_addLock ); 00264 00265 // add strategy to list of strategies 00266 typename ContainerType::WriteTicket w = m_strategies.getWriteTicket(); 00267 w->get().push_back( strategy ); 00268 size_t size = w->get().size(); 00269 00270 // add strategy to selector: 00271 m_possibleSelections->addItem( strategy->getName(), strategy->getDescription(), strategy->getIcon() ); 00272 m_properties->addProperty( strategy->getProperties() ); 00273 00274 // we can safely unlock m_strategies now. This is needed since an update in m_possibleSelectionProp requests a read lock and will deadlock if 00275 // w was not unlocked. 00276 w.reset(); 00277 00278 // the first strategy. Select it. If this somehow changes the selection, the update mechanism ensures proper hide/unhide on all property 00279 // groups. 00280 if( size == 1 ) 00281 { 00282 m_possibleSelectionProp->set( m_possibleSelections->getSelectorFirst() ); 00283 } 00284 else 00285 { 00286 m_possibleSelectionProp->set( m_possibleSelectionProp->get().newSelector() ); 00287 } 00288 00289 // lock unlocked automatically 00290 } 00291 00292 template< typename StrategyType > 00293 typename StrategyType::ConstSPtr WStrategyHelper< StrategyType >::operator()() const 00294 { 00295 // get lock 00296 typename ContainerType::ReadTicket r = m_strategies.getReadTicket(); 00297 return r->get()[ m_possibleSelectionProp->get() ]; 00298 // r unlocks automatically 00299 } 00300 00301 template< typename StrategyType > 00302 typename StrategyType::SPtr WStrategyHelper< StrategyType >::operator()() 00303 { 00304 // get lock 00305 typename ContainerType::WriteTicket w = m_strategies.getWriteTicket(); 00306 return w->get()[ m_possibleSelectionProp->get() ]; 00307 // w unlocks automatically 00308 } 00309 00310 #endif // WSTRATEGYHELPER_H 00311