source: src/Actions/Action.hpp

Candidate_v1.6.1
Last change on this file was e7ad08, checked in by Frederik Heber <frederik.heber@…>, 7 years ago

Python interface now converts dashes in tokens to underscores, store-session used keyword arguments.

  • MoleCuilder's python functions (i.e. commands) typically have quite a number of arguments and therefore can be easily confused. We circumvent this by using keyword (or named) arguments that are also independent of position. Moreover, in that case only the non-default arguments need to be given.
  • TESTS: Marked failing python tests as XFAIL for the moment.
  • Property mode set to 100644
File size: 11.7 KB
Line 
1/*
2 * Action.hpp
3 *
4 * Created on: Dec 8, 2009
5 * Author: crueger
6 */
7
8#ifndef ACTION_HPP_
9#define ACTION_HPP_
10
11// include config.h
12#ifdef HAVE_CONFIG_H
13#include <config.h>
14#endif
15
16#include <algorithm>
17#include <iosfwd>
18#include <string>
19
20#include <boost/preprocessor/list/adt.hpp>
21
22/** Used in .def files in paramdefaults define to set that no default value exists.
23 * We define NOPARAM_DEFAULT here, as it is used in .def files and needs to be present
24 * before these are included.
25 */
26#define NOPARAM_DEFAULT BOOST_PP_NIL
27
28namespace MoleCuilder {
29 //!> helps normalizing Action's tokens for use as Python parameter names
30#ifdef HAVE_INLINE
31 inline
32#endif
33 std::string normalizeToken(std::string _token) {
34 std::replace(_token.begin(), _token.end(), '-', '_');
35 return _token;
36 }
37} /* namespace MoleCuilder */
38
39/** Nicely visible short-hand for push a status message
40 *
41 */
42#ifndef STATUS
43#define STATUS(msg) \
44 pushStatus(msg); \
45 LOG(0, "STATUS: " << msg)
46#endif
47
48// forward declaration
49template <typename T> class Registry;
50
51namespace MoleCuilder {
52 class ActionHistory;
53 class ActionQueue;
54 class ActionRegistry;
55 class ActionSequence;
56}
57class ActionSequenceTest;
58class Dialog;
59
60#include "Actions/ActionParameters.hpp"
61#include "Actions/ActionState.hpp"
62#include "Actions/ActionTrait.hpp"
63
64
65namespace MoleCuilder {
66
67/** Actions are Command patterns to allow for undoing and redoing.
68 *
69 * Each specific Action derives from this class to implement a certain functionality.
70 *
71 * Actions describe something that has to be done.
72 * Actions can be passed around, stored, performed and undone (Command-Pattern:
73 * http://en.wikipedia.org/wiki/Command_pattern).
74 *
75 * Unique to each Action is its ActionTrait, i.e. the options it requires
76 * to perform a certain function. E.g. in order to execute a "add atom" Action
77 * we need to know a position and an element. These options have certain
78 * properties, see \ref OptionTrait and \ref ActionTrait wherein these are stored.
79 * Essentially, each option is stored as an \ref OptionTrait instance and
80 * contains the token, default value, a description, the type, ...
81 *
82 * ActionTrait itself is also an OptionTrait because the command token may actually
83 * coincide with an option-token. E.g. this allows "...--add-atom 3" to mean
84 * both execute the action under token "add-atom" and that the option "add-atom"
85 * (the new atom's \ref element number) should contain 3.
86 *
87 * \ref ActionTrait contains a map of all associated options. With this in the cstor
88 * we register not only the Action with the \ref ActionRegistry but also each of
89 * its \link options OptionTrait \endlink with the \ref OptionRegistry.
90 *
91 * The token of the option is unique, but two Action's may share the same token if:
92 * -# they have the same default value
93 * -# they have the same type
94 *
95 * This requirement is easy because if you need to store some option of another
96 * type, simply think of a new suitable name for it.
97 *
98 * The actual value, i.e. "3" in the "add-atom" example, is taken from the
99 * ValueStorage, see \ref Dialog for how this is possible.
100 *
101 * \note There is a unit test that checks on the consistency of all registered
102 * options, also in "--enable-debug"-mode assertions will check that an option
103 * has not been registered before under another type.
104 *
105 */
106class Action
107{
108 //!> grant ActionQueue access to undo() and redo()
109 friend class ActionHistory;
110 //!> grant ActionQueue access to call()
111 friend class ActionQueue;
112 //!> grant ActionRegistry access to cstors (for ActionRegistry::fillRegistry())
113 friend class ActionRegistry;
114 //!> grant ActionSequence access to Action's private stuff
115 friend class ActionSequence;
116 //!> grant all Registry templates access to cstor and dstor (for Registry<T>::cleanup())
117 template <typename T> friend class ::Registry;
118 //!> TextMenu needs to instantiate some specific Actions, grant access to cstor
119 friend class TextMenu;
120
121 // some unit tests on Actions
122 friend class ::ActionSequenceTest;
123public:
124
125 enum QueryOptions {Interactive, NonInteractive};
126
127 /** Destructor for class Action.
128 *
129 * Needs to be public as clone() is a public function.
130 *
131 */
132 virtual ~Action();
133
134protected:
135 /**
136 * Standard constructor of Action Base class
137 *
138 * All Actions need to have a name. The second flag indicates, whether the action should
139 * be registered with the ActionRegistry. If the Action is registered the name of the
140 * Action needs to be unique for all Actions that are registered.
141 *
142 * \note NO reference for \a _Traits as we do have to copy it, otherwise _Traits would have
143 * to be present throughout the program's run.
144 *
145 * \param Traits information class to this action
146 */
147 Action(const ActionTrait &_Traits);
148
149 /**
150 * This method is used to call an action. The basic operations for the Action
151 * are carried out and if necessary/possible the Action is added to the History
152 * to allow for undo of this action.
153 *
154 * If the call needs to undone you have to use the History, to avoid destroying
155 * invariants used by the History.
156 *
157 * Note that this call can be Interactive (i.e. a dialog will ask the user for
158 * necessary information) and NonInteractive (i.e. the information will have to
159 * be present already within the ValueStorage class or else a MissingArgumentException
160 * is thrown)
161 */
162 void call();
163
164public:
165 /**
166 * This method provides a flag that indicates if an undo mechanism is implemented
167 * for this Action. If this is true, and this action was called last, you can
168 * use the History to undo this action.
169 */
170 virtual bool canUndo()=0;
171
172 /**
173 * This method provides a flag, that indicates if the Action changes the state of
174 * the application in a way that needs to be undone for the History to work.
175 *
176 * If this is false the Action will not be added to the History upon calling. However
177 * Actions called before this one will still be available for undo.
178 */
179 virtual bool shouldUndo()=0;
180
181 /**
182 * Indicates whether the Action can do it's work at the moment. If this
183 * is false calling the action will result in a no-op.
184 */
185 virtual bool isActive() const;
186
187 /**
188 * Returns the name of the Action.
189 */
190 const std::string getName() const;
191
192 /**
193 * returns a detailed help message.
194 */
195 const std::string help() const;
196
197 /** Clones the Action.
198 *
199 */
200 virtual Action* clone(enum QueryOptions flag = Interactive) const=0;
201
202 /** Prepares the Action's parameters.
203 *
204 */
205 virtual void prepare(enum QueryOptions flag = Interactive);
206
207 /** Prints what would be necessary to add the Action from the Command Line Interface.
208 *
209 * \param ost output stream to print to
210 */
211 virtual void outputAsCLI(std::ostream &ost) const=0;
212
213 /** Prints what would be necessary to add the Action from a Python script
214 *
215 * \param ost output stream to print to
216 * \param prefix package prefix to be used
217 */
218 virtual void outputAsPython(std::ostream &ost, const std::string &prefix) const=0;
219
220 /** Sets the option defined by \a _token to \a _value for this action.
221 *
222 * This is needed when constructing MakroActions.
223 *
224 * \param _token token of the option
225 * \param _value new value
226 */
227 virtual void setOptionValue(const std::string &_token, const std::string &_value)=0;
228
229 /**
230 * Traits resemble all necessary information that "surrounds" an action, such as
231 * its name (for ActionRegistry and as ref from string to instance and vice versa),
232 * which menu, which position, what parameters, their types, if it is itself a
233 * parameter and so on ...
234 *
235 * Note that is important that we do not use a reference here. We want to copy the
236 * information in the Action's constructor and have it contained herein. Hence, we
237 * also have our own copy constructor for ActionTrait. Information should be
238 * encapsulated in the Action, no more references to the outside than absolutely
239 * necessary.
240 */
241 const ActionTrait Traits;
242
243protected:
244 /** Removes the static entities Action::success and Action::failure.
245 * This is only to be called on the program's exit, i.e. in cleanUp(),
246 * as these static entities are used throughout all Actions.
247 */
248 static void removeStaticStateEntities();
249
250 /** Creates the static entities Action::success and Action::failure.
251 * This is only to be called by ActionHistory.
252 */
253 static void createStaticStateEntities();
254
255 /**
256 * This method is called by the History, when an undo is performed. It is
257 * provided with the corresponding state produced by the performCall or
258 * performRedo method and needs to provide a state that can be used for redo.
259 */
260 ActionState::ptr undo(ActionState::ptr);
261
262 /**
263 * This method is called by the History, when a redo is performed. It is
264 * provided with the corresponding state produced by the undo method and
265 * needs to produce a State that can then be used for another undo.
266 */
267 ActionState::ptr redo(ActionState::ptr);
268
269 /**
270 * This special state can be used to indicate that the Action was successful
271 * without providing a special state. Use this if your Action does not need
272 * a specialized state.
273 */
274 static ActionState::ptr success;
275
276 /**
277 * This special state can be returned, to indicate that the action could not do it's
278 * work, was aborted by the user etc. If you return this state make sure to transactionize
279 * your Actions and unroll the complete transaction before this is returned.
280 */
281 static ActionState::ptr failure;
282
283 /**
284 * This creates the dialog requesting the information needed for this action from the user
285 * via means of the user interface.
286 */
287 Dialog * createDialog();
288
289 /** Virtual function that starts the timer.
290 *
291 */
292 virtual void startTimer() const {};
293
294 /** Virtual function that ends the timer.
295 *
296 */
297 virtual void endTimer() const {};
298
299 /** Function pass-through for ActionQueue::insertAction().
300 *
301 * This pass-through is present to allow each derived Action access to private
302 * ActionQueue::insertAction() which is not possible otherwise as friendship
303 * is not inherited.
304 *
305 */
306 static void insertAction(Action *_action, enum Action::QueryOptions state);
307
308 /** Proxy function to grant all derived Actions access to
309 * ActionQueue::pushStatus().
310 *
311 * \param _msg status message to push
312 */
313 void pushStatus(const std::string& _msg);
314
315private:
316
317 /**
318 * This is called internally before the action is processed. This adds necessary queries
319 * to a given dialog to obtain parameters for the user for processing the action accordingly.
320 * The dialog will be given to the user before Action::performCall() is initiated, values
321 * are transfered via ValueStorage.
322 */
323 virtual Dialog * fillDialog(Dialog*)=0;
324
325 /**
326 * This is called internally when the call is being done. Implement this method to do the actual
327 * work of the Action. Implement this in your Derived classes. Needs to return a state that can be
328 * used to undo the action.
329 */
330 virtual ActionState::ptr performCall()=0;
331
332 /**
333 * This is called internally when the undo process is chosen. This Method should use the state
334 * produced by the performCall method to return the state of the application to the state
335 * it had before the Action.
336 */
337 virtual ActionState::ptr performUndo(ActionState::ptr)=0;
338
339 /**
340 * This is called internally when the redo process is chosen. This method shoudl use the state
341 * produced by the performUndo method to return the application to the state it should have after
342 * the action.
343 *
344 * Often this method can be implement to re-use the performCall method. However if user interaction
345 * or further parameters are needed, those should be taken from the state and not query the user
346 * again.
347 */
348 virtual ActionState::ptr performRedo(ActionState::ptr)=0;
349};
350
351}
352
353#endif /* ACTION_HPP_ */
Note: See TracBrowser for help on using the repository browser.