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