source: src/Actions/ActionQueue.hpp@ 0ec9f5

Candidate_v1.7.0 stable
Last change on this file since 0ec9f5 was 0ec9f5, checked in by Frederik Heber <frederik.heber@…>, 5 years ago

Added UndoMarkAction.

NOTE: This action is necessary as not all actions are actually recorded
in the history. For example, the UndoAction is an action that is not
pushed into the history deque and also must not as further undos would
then become impossible. There are other actions that just do output
or similar things that do not change the state.
This makes it impossible to undo back to a certain state by blindly
counting actions as one cannot know from the outside whether an action
is stateless or not.

undoing till the set mark.

  • TESTS: added regression test case on undo-mark.
  • Property mode set to 100644
File size: 9.9 KB
Line 
1/*
2 * ActionQueue.hpp
3 *
4 * Created on: Aug 16, 2013
5 * Author: heber
6 */
7
8#ifndef ACTIONQUEUE_HPP_
9#define ACTIONQUEUE_HPP_
10
11// include config.h
12#ifdef HAVE_CONFIG_H
13#include <config.h>
14#endif
15
16#include "CodePatterns/Singleton.hpp"
17
18#include "CodePatterns/Observer/Channels.hpp"
19#include "CodePatterns/Observer/Observable.hpp"
20
21#ifdef HAVE_ACTION_THREAD
22#include <boost/thread.hpp>
23#endif
24#include <vector>
25
26#include "Actions/Action.hpp"
27#include "Actions/ActionState.hpp"
28#include "Actions/ActionStatusList.hpp"
29
30#ifdef HAVE_ACTION_THREAD
31void stopQueue();
32void waitQueue();
33#endif
34
35class CommandLineParser;
36
37namespace MoleCuilder {
38
39class ActionHistory;
40class ActionRegistry;
41class ActionTrait;
42class DryRunAdvocate;
43
44namespace Queuedetail {
45 template <class T> const T* lastChanged()
46 {
47 ASSERT(0, "Queuedetail::lastChanged() - only specializations may be used.");
48 return NULL;
49 }
50}
51
52/** This class combines the whole handling of Actions into a single class.
53 *
54 * It spawns new Actions by its internal ActionRegistry. Spawned Actions are
55 * automatically queued and placed into a History after execution.
56 */
57class ActionQueue : public Singleton<ActionQueue>, public Observable
58{
59 friend class Singleton<ActionQueue>;
60public:
61 typedef std::vector<std::string> ActionTokens_t;
62 typedef std::vector< Action * > ActionQueue_t;
63
64 //!> channels for this observable
65 enum NotificationType {
66 ActionQueued, // new action was queued
67 NotificationType_MAX // denotes the maximum of available notification types
68 };
69
70 //>! access to last changed element (atom or molecule)
71 template <class T> const T* lastChanged() const
72 { return Queuedetail::lastChanged<T>(); }
73
74 /** Queues the Action with \a name to be called.
75 *
76 * \param name token of Action to actionqueue
77 * \param state whether Actions needs to be filled via a Dialog or not
78 */
79 void queueAction(const std::string &name, enum Action::QueryOptions state = Action::Interactive);
80
81 /** Returns the spawned action by token \a name.
82 *
83 * Action is checked into internal actionqueue.
84 *
85 * \return ref to newly spawned action
86 */
87 const Action& getActionByName(const std::string &name);
88
89 /** Checks whether the Action is known by the given \a name.
90 *
91 * \param name token of action to check
92 * \return true - token is known, false - else
93 */
94 bool isActionKnownByName(const std::string &name) const;
95
96 /** Register an Action with the ActionRegistry.
97 *
98 * \param _action action to add
99 */
100 void registerAction(Action *_action);
101
102 /** Returns the vector with the tokens of all currently known Actions.
103 *
104 * \return list of all tokens
105 */
106 const ActionTokens_t getListOfActions() const;
107
108 /** Returns the trait to an Action.
109 *
110 * \param name name of Action
111 * \return const ref to its default Trait.
112 */
113 const ActionTrait& getActionsTrait(const std::string &name) const;
114
115 /** Print the current contents of the actionqueue as CLI instantiated list of Actions.
116 *
117 * This is useful for storing the current session.
118 *
119 * \param output output stream to print to
120 */
121 void outputAsCLI(std::ostream &output) const;
122
123 /** Print the current contents of the actionqueue as Python instantiated list of Actions.
124 *
125 * This is useful for storing the current session.
126 *
127 * \param output output stream to print to
128 */
129 void outputAsPython(std::ostream &output) const;
130
131 /** Undoes last called Action.
132 *
133 */
134 void undoLast();
135
136 /** Redoes last undone Action.
137 *
138 */
139 void redoLast();
140
141 /**
142 * Marks the current item of the action history to allow returning to that state lateron.
143 */
144 void setMark();
145
146 /**
147 * Resets any currently marked item in the action history.
148 */
149 void unsetMark();
150
151 /** Undoes actions till a set mark in the ActionHistory.
152 *
153 */
154 void undoTillMark();
155
156 /** Checks whether there is one completed Action stored in ActionHistory in the past.
157 *
158 * @return true - at least one Action to undo present, false - else
159 */
160 bool canUndo() const;
161
162 /** Checks whether there is one completed Action stored in ActionHistory in the future.
163 *
164 * @return true - at least one Action to redo present, false - else
165 */
166 bool canRedo() const;
167
168 /** Return status of last executed action.
169 *
170 * \return true - action executed correctly, false - else
171 */
172 bool getLastActionOk() const
173 { return lastActionOk; }
174
175 /** Getter to ref to list of status messages.
176 *
177 * This is meant for UIs to registers as Observables.
178 *
179 * \return ref to StatusList variable
180 */
181 ActionStatusList& getStatusList()
182 { return StatusList; }
183
184 /** Getter for isDryRun state flag.
185 *
186 * \return true - ActionQueue does not execute Actions but skips, false - else
187 */
188 bool getDryRun() const
189 { return dryrun_flag; }
190
191 /** States whether the ActionQueue is currently executing Actions or done executing.
192 *
193 * \return true - ActionQueue is done executing Actions.
194 */
195 bool isIdle() const;
196
197 /** States whether the current Action in the ActionQueue is a Process.
198 *
199 * \return true - ActionQueue is currently executing a process.
200 */
201 bool isProcess() const;
202
203 /** States whether the current Action in the ActionQueue is a MakroAction.
204 *
205 * \return true - ActionQueue is currently executing a MakroAction.
206 */
207 bool isMakroAction() const;
208
209 /** Getter to the current Action.
210 *
211 * \note Using this ref is only useful during the execution of the Action, e.g.
212 * when an Action inside the ActionSequence of a MakroAction needs access to the
213 * MakroAction itself (to signal stop). \sa MoleCuilder::ForceAnnealingAction::performCall()
214 *
215 * \warning Due to the multi-threaded nature of the ActionQueue this is very
216 * dangerous to use in other circumstances.
217 *
218 * \return const ref to the currently executed action
219 */
220 const Action& getCurrentAction() const;
221
222private:
223 //!> grant Action access to internal history functions.
224 friend class Action;
225 //!> grant CommandLineParser access to stop and clearQueue()
226 friend class ::CommandLineParser;
227 //!> grant Advocate access to setting dryrun
228 friend class DryRunAdvocate;
229
230 /** Queues the Action with \a name to be called.
231 *
232 * \param _action action to add
233 * \param state whether Actions needs to be filled via a Dialog or not
234 */
235 void queueAction(const Action * const _action, enum Action::QueryOptions state = Action::Interactive);
236
237 /** Wrapper function to add state to ActionHistory.
238 *
239 * \param _Action Action whose state to add
240 * \param _state state to add
241 */
242 void addElement(Action* _Action, ActionState::ptr _state);
243
244 /** Advocate function to add status message to the list.
245 *
246 */
247 void pushStatus(const std::string &_msg)
248 { StatusList.pushMessage(_msg); }
249
250 /** Wrapper function to clear ActionHistory.
251 *
252 */
253 void clear();
254
255 /** Clears all actions present in the actionqueues from \a _fromAction.
256 *
257 * @param _fromAction 0 if all Actions to clear or else
258 */
259 void clearQueue(const size_t _fromAction = 0);
260
261#ifdef HAVE_ACTION_THREAD
262 boost::thread &getRunThread()
263 { return run_thread; }
264
265 /** Clears the temporary queue.
266 *
267 */
268 void clearTempQueue();
269
270 /** Sets the run_thread_isIdle flag.
271 *
272 * @param _flag state to set to
273 */
274 void setRunThreadIdle(const bool _flag);
275
276 /** Runs the ActionQueue.
277 *
278 */
279 void run();
280
281 friend void ::stopQueue();
282
283 /** Stops the internal thread.
284 *
285 */
286 void stop();
287
288 friend void ::waitQueue();
289
290 /** Wait till all currently queued actions are processed.
291 *
292 */
293 void wait();
294
295 /** Moves all action from tempqueue into real queue.
296 *
297 */
298 void insertTempQueue();
299
300#endif
301
302 /** Insert an action after CurrentAction.
303 *
304 * This is implemented only to allow action's COMMAND to work. If we
305 * were to use queueAction, actions would come after all other already
306 * present actions.
307 */
308 void insertAction(Action *_action, enum Action::QueryOptions state);
309
310 /** Sets the current state of the \a isDryRun flag.
311 *
312 * \param _dryrun true - Actions will not get executed anymore, false - else
313 */
314 void setDryRun(const bool _dryrun)
315 { dryrun_flag = _dryrun; }
316
317 /** Checks whether next Action should be skipped or not.
318 *
319 * \param _nextaction next action to execute to inspect whether it unsets dryrun_flag
320 * \return true - dryrun_flag set and \a _nextaction is not unsetting dry run
321 */
322 bool isDryRun(const Action *_nextaction) const;
323
324private:
325 /** Private cstor for ActionQueue.
326 *
327 * Must be private as is singleton.
328 *
329 */
330 ActionQueue();
331
332 /** Dstor for ActionQueue.
333 *
334 */
335 ~ActionQueue();
336
337private:
338 friend const Action *Queuedetail::lastChanged<Action>();
339 static const Action *_lastchangedaction;
340
341 //!> ActionRegistry to spawn new actions
342 ActionRegistry *AR;
343
344 //!> ActionHistory is for undoing and redoing actions, requires ActionRegistry fully initialized
345 ActionHistory *history;
346
347 //!> internal actionqueue of actions
348 ActionQueue_t actionqueue;
349
350 //!> indicates that the last action has failed
351 bool lastActionOk;
352
353 //!> point to current action in actionqueue
354 size_t CurrentAction;
355
356#ifdef HAVE_ACTION_THREAD
357 //!> internal temporary actionqueue of actions used by insertAction()
358 ActionQueue_t tempqueue;
359
360 //!> internal thread to call Actions
361 boost::thread run_thread;
362
363 //!> internal mutex to synchronize access to queue
364 mutable boost::mutex mtx_queue;
365
366 //!> conditional variable notifying when run_thread is idling
367 boost::condition_variable cond_idle;
368
369 //!> flag indicating whether run_thread is idle or not
370 bool run_thread_isIdle;
371
372 //!> internal mutex to synchronize access to run_thread_isIdle
373 mutable boost::mutex mtx_idle;
374#endif
375
376 //!> internal list of status messages from Actions for UIs to display
377 ActionStatusList StatusList;
378
379 //!> internal flag whether to call or skip actions (i.e. do a dry run)
380 bool dryrun_flag;
381};
382namespace Queuedetail {
383 template <> inline const Action* lastChanged<Action>() { return ActionQueue::_lastchangedaction; }
384}
385
386};
387
388#endif /* ACTIONQUEUE_HPP_ */
Note: See TracBrowser for help on using the repository browser.