OpenWalnut  1.4.0
WStrategyHelper.h
1 //---------------------------------------------------------------------------
2 //
3 // Project: OpenWalnut ( http://www.openwalnut.org )
4 //
5 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
6 // For more information see http://www.openwalnut.org/copying
7 //
8 // This file is part of OpenWalnut.
9 //
10 // OpenWalnut is free software: you can redistribute it and/or modify
11 // it under the terms of the GNU Lesser General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // OpenWalnut is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public License
21 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
22 //
23 //---------------------------------------------------------------------------
24 
25 #ifndef WSTRATEGYHELPER_H
26 #define WSTRATEGYHELPER_H
27 
28 #include <string>
29 #include <vector>
30 
31 #ifndef Q_MOC_RUN
32 #include <boost/shared_ptr.hpp>
33 #endif
34 #ifndef Q_MOC_RUN
35 #include <boost/thread.hpp>
36 #endif
37 
38 #include "WLogger.h"
39 #include "WItemSelection.h"
40 #include "WItemSelector.h"
41 #include "WSharedSequenceContainer.h"
42 #include "WProperties.h"
43 #include "WPropertyHelper.h"
44 
45 /**
46  * This class allows for an easy strategy pattern-based switching between properties and strategy instances using a WPropSelection. The idea of
47  * 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
48  * a name, description and several properties. An instance of this class automatically provides a WPropSelection containing an item for each strategy
49  * instance you add. A switch in this property causes to automatically hide all properties not belonging to this strategy. This class will ease
50  * 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
51  * before you add this WStrategyHelper's properties to your module's properties.
52  *
53  * \tparam StrategyType the base class type of your strategies.
54  *
55  * The type in StrategyType needs to comply to the following rules:
56  * <ul>
57  * <li> provide a typedef SPtr, representing the pointer type of this class. Usually, this is a boost::shared_ptr
58  * <li> provide a typedef ConstSPtr, representing the pointer type of this class. Usually, this is a boost::shared_ptr< const >
59  * <li> provide a method std::string getName() const
60  * <li> provide a method std::string getDescription() const
61  * <li> provide a method const char** getXPMIcon() const
62  * <li> provide a method WProperties::SPtr getProperties() const;
63  * </ul>
64  * The cool thing is, this class complies to its own requirements on strategy base classes. This allows you to nest strategy selections.
65  *
66  * \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
67  * probably be very annoyed.
68  *
69  * \note you should use \ref WObjectNDIP which complies to this rules. This furthermore eases the task of writing strategies.
70  */
71 template< class StrategyType >
73 {
74 public:
75  /**
76  * Convenience typedef for a boost::shared_ptr< WStrategyHelper >.
77  */
78  typedef boost::shared_ptr< WStrategyHelper > SPtr;
79 
80  /**
81  * Convenience typedef for a boost::shared_ptr< const WStrategyHelper >.
82  */
83  typedef boost::shared_ptr< const WStrategyHelper > ConstSPtr;
84 
85  /**
86  * Constructs an empty strategy selector. Use one of the addStrategy methods to register strategies.
87  *
88  * \param name name of this strategy selector
89  * \param description a description for this selection
90  * \param icon an icon for this selection. Can be NULL.
91  * \param selectorName the name of the selection property used to switch. If empty, the name of the WStrategyHelper will be used.
92  * \param selectorDescription the description of the selection property used to switch. If empty, description of the WStrategyHelper is used.
93  */
94  WStrategyHelper( std::string name, std::string description, const char** icon = NULL, std::string selectorName = std::string(),
95  std::string selectorDescription = std::string() );
96 
97  /**
98  * Destructor.
99  */
101 
102  /**
103  * Gets the name of this strategy selector.
104  *
105  * \return the name.
106  */
107  std::string getName() const;
108 
109  /**
110  * Gets the description for this strategy selector.
111  *
112  * \return the description
113  */
114  std::string getDescription() const;
115 
116  /**
117  * Get the icon for this strategy selectior in XPM format.
118  *
119  * \return The icon.
120  */
121  const char** getXPMIcon() const;
122 
123  /**
124  * Get this strategy selectors properties. This group contains the WPropSelection property to switch the strategy as well as groups for all
125  * registered strategies.
126  *
127  * \return properties
128  */
130 
131  /**
132  * Adds the given strategy to the list of all strategies.
133  *
134  * \param strategy the strategy to add.
135  */
136  void addStrategy( typename StrategyType::SPtr strategy );
137 
138  /**
139  * Return the currently active strategy.
140  *
141  * \return the active strategy
142  */
143  typename StrategyType::ConstSPtr operator()() const;
144 
145  /**
146  * Return the currently active strategy.
147  *
148  * \return the active strategy
149  */
150  typename StrategyType::SPtr operator()();
151 
152 protected:
153 private:
154  const char** m_icon; //!< the icon pointer
155  WProperties::SPtr m_properties; //!< stores the selection property and the strategy property groups
156 
157  /**
158  * A list of items that can be selected. Will be extended for each added strategy.
159  */
161 
162  /**
163  * The property allowing the user to switch the strategy. Will be extended for each added strategy.
164  */
165  WPropSelection m_possibleSelectionProp;
166 
167  /**
168  * The type used to securely manage the strategies
169  */
171 
172  /**
173  * This is the list of all strategies
174  */
175  ContainerType m_strategies;
176 
177  /**
178  * This lock is needed to protect the addStrategy function. Although the m_strategies member is protected due to the use of a WSharedObject,
179  * an update in the selection (m_possibleSelectionProp) causes an update of the hide status of all property groups in m_strategies. This
180  * would cause a deadlock if m_strategies is still locked. This lock is only locked if addStrategy is called.
181  */
182  boost::mutex m_addLock;
183 
184  /**
185  * Connection between \ref update and the update condition of \ref m_possibleSelectionProp.
186  */
187  boost::signals2::connection m_updateConnection;
188 
189  /**
190  * Update strategy's property hide status on updates in \ref m_possibleSelectionProp.
191  */
192  void update();
193 };
194 
195 template< typename StrategyType >
196 WStrategyHelper< StrategyType >::WStrategyHelper( std::string name, std::string description, const char** icon,
197  std::string selectorName, std::string selectorDescription ):
198  m_icon( icon ),
199  m_properties( new WProperties( name, description ) ),
200  m_possibleSelections( new WItemSelection() )
201 {
202  // Create the main selector property:
203  selectorName = selectorName.empty() ? name : selectorName;
204  selectorDescription = selectorDescription.empty() ? name : selectorDescription;
205  m_possibleSelectionProp = m_properties->addProperty( selectorName, selectorDescription, m_possibleSelections->getSelectorNone() );
208 
209  // if the selection changes, we want to hide all not selected strategy groups. So we register a change callback
210  m_updateConnection = m_possibleSelectionProp->getUpdateCondition()->subscribeSignal(
211  boost::bind( &WStrategyHelper< StrategyType >::update, this )
212  );
213 }
214 
215 template< typename StrategyType >
217 {
218  // cleanup
219 }
220 
221 template< typename StrategyType >
223 {
224  // get lock
225  typename ContainerType::WriteTicket w = m_strategies.getWriteTicket();
226 
227  // update each hide state
228  size_t currentID = 0;
229  size_t selectedID = m_possibleSelectionProp->get();
230 
231  for( typename ContainerType::Iterator i = w->get().begin(); i != w->get().end(); ++i )
232  {
233  ( *i )->getProperties()->setHidden( currentID != selectedID );
234  currentID++;
235  }
236  // w unlocks automatically
237 }
238 
239 template< typename StrategyType >
241 {
242  return m_properties->getName();
243 }
244 
245 template< typename StrategyType >
247 {
248  return m_properties->getDescription();
249 }
250 
251 template< typename StrategyType >
253 {
254  return m_icon;
255 }
256 
257 template< typename StrategyType >
259 {
260  return m_properties;
261 }
262 
263 template< typename StrategyType >
264 void WStrategyHelper< StrategyType >::addStrategy( typename StrategyType::SPtr strategy )
265 {
266  // lock this method.
267  boost::lock_guard< boost::mutex > lock( m_addLock );
268 
269  // add strategy to list of strategies
270  typename ContainerType::WriteTicket w = m_strategies.getWriteTicket();
271  w->get().push_back( strategy );
272  size_t size = w->get().size();
273 
274  // add strategy to selector:
275  m_possibleSelections->addItem( strategy->getName(), strategy->getDescription(), strategy->getIcon() );
276  m_properties->addProperty( strategy->getProperties() );
277 
278  // we can safely unlock m_strategies now. This is needed since an update in m_possibleSelectionProp requests a read lock and will deadlock if
279  // w was not unlocked.
280  w.reset();
281 
282  // the first strategy. Select it. If this somehow changes the selection, the update mechanism ensures proper hide/unhide on all property
283  // groups.
284  if( size == 1 )
285  {
286  m_possibleSelectionProp->set( m_possibleSelections->getSelectorFirst() );
287  }
288  else
289  {
290  m_possibleSelectionProp->set( m_possibleSelectionProp->get().newSelector() );
291  }
292 
293  // lock unlocked automatically
294 }
295 
296 template< typename StrategyType >
297 typename StrategyType::ConstSPtr WStrategyHelper< StrategyType >::operator()() const
298 {
299  // get lock
300  typename ContainerType::ReadTicket r = m_strategies.getReadTicket();
301  return r->get()[ m_possibleSelectionProp->get() ];
302  // r unlocks automatically
303 }
304 
305 template< typename StrategyType >
306 typename StrategyType::SPtr WStrategyHelper< StrategyType >::operator()()
307 {
308  // get lock
309  typename ContainerType::WriteTicket w = m_strategies.getWriteTicket();
310  return w->get()[ m_possibleSelectionProp->get() ];
311  // w unlocks automatically
312 }
313 
314 #endif // WSTRATEGYHELPER_H
315 
boost::shared_ptr< WSharedObjectTicketWrite< std::vector< typename StrategyType::SPtr > > > WriteTicket
Type for write tickets.
Definition: WSharedObject.h:69
boost::shared_ptr< WItemSelection > SPtr
Convenience typedef for a boost::shared_ptr< WItemSelection >
boost::mutex m_addLock
This lock is needed to protect the addStrategy function.
WProperties::SPtr getProperties() const
Get this strategy selectors properties.
boost::signals2::connection m_updateConnection
Connection between update and the update condition of m_possibleSelectionProp.
const char ** m_icon
the icon pointer
StrategyType::ConstSPtr operator()() const
Return the currently active strategy.
This class provides a common interface for thread-safe access to sequence containers (list...
std::string getName() const
Gets the name of this strategy selector.
WItemSelection::SPtr m_possibleSelections
A list of items that can be selected.
~WStrategyHelper()
Destructor.
void update()
Update strategy's property hide status on updates in m_possibleSelectionProp.
std::string getDescription() const
Gets the description for this strategy selector.
const char ** getXPMIcon() const
Get the icon for this strategy selectior in XPM format.
Class to manage properties of an object and to provide convenience methods for easy access and manipu...
A class containing a list of named items.
WPropSelection m_possibleSelectionProp
The property allowing the user to switch the strategy.
void addTo(WPropSelection prop)
Add the PC_NOTEMPTY constraint to the property.
This class allows for an easy strategy pattern-based switching between properties and strategy instan...
boost::shared_ptr< WPropertyGroup > SPtr
shared pointer to object of this type
void addStrategy(typename StrategyType::SPtr strategy)
Adds the given strategy to the list of all strategies.
boost::shared_ptr< const WStrategyHelper > ConstSPtr
Convenience typedef for a boost::shared_ptr< const WStrategyHelper >.
ContainerType m_strategies
This is the list of all strategies.
boost::shared_ptr< WStrategyHelper > SPtr
Convenience typedef for a boost::shared_ptr< WStrategyHelper >.
WStrategyHelper(std::string name, std::string description, const char **icon=NULL, std::string selectorName=std::string(), std::string selectorDescription=std::string())
Constructs an empty strategy selector.
WSharedSequenceContainer< std::vector< typename StrategyType::SPtr > > ContainerType
The type used to securely manage the strategies.
std::vector< typename StrategyType::SPtr >::iterator Iterator
A typedef for the correct iterator to traverse this sequence container.
boost::shared_ptr< WSharedObjectTicketRead< std::vector< typename StrategyType::SPtr > > > ReadTicket
Type for read tickets.
Definition: WSharedObject.h:64
WProperties::SPtr m_properties
stores the selection property and the strategy property groups
void addTo(WPropSelection prop)
Add the PC_SELECTONLYONE constraint to the property.