ctkWorkflow.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. /*=========================================================================
  2. Library: CTK
  3. Copyright (c) 2010 Kitware Inc.
  4. Licensed under the Apache License, Version 2.0 (the "License");
  5. you may not use this file except in compliance with the License.
  6. You may obtain a copy of the License at
  7. http://www.commontk.org/LICENSE
  8. Unless required by applicable law or agreed to in writing, software
  9. distributed under the License is distributed on an "AS IS" BASIS,
  10. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. See the License for the specific language governing permissions and
  12. limitations under the License.
  13. =========================================================================*/
  14. #ifndef __ctkWorkflow_h
  15. #define __ctkWorkflow_h
  16. // Qt includes
  17. #include <QObject>
  18. // CTK includes
  19. #include "ctkPimpl.h"
  20. #include "CTKCoreExport.h"
  21. class ctkWorkflowStep;
  22. class ctkWorkflowPrivate;
  23. class QAbstractState;
  24. /// \brief ctkWorkflow is the basis for a workflow engine, i.e. a state
  25. /// machine with enhancements to support ctkWorkflowStep.
  26. class CTK_CORE_EXPORT ctkWorkflow : public QObject
  27. {
  28. Q_OBJECT
  29. public:
  30. typedef QObject Superclass;
  31. explicit ctkWorkflow(QObject* parent = 0);
  32. virtual ~ctkWorkflow();
  33. /// \brief Start the workflow.
  34. /// The workflow will always start in the initial step, even if it is stopped and restarted).
  35. /// \note Calls onEntry() for the initial step.
  36. virtual void start();
  37. /// \brief Returns whether the workflow is currently running
  38. bool isRunning()const;
  39. /// \brief Stops the workflow.
  40. /// \note Calls onExit() for the current step.
  41. virtual void stop();
  42. /// \brief Transition directionalities.
  43. ///
  44. /// The direction of transitions between an origin step and a destination step can be either:
  45. /// <ul>
  46. /// <li>\a Bidirectional: A transition from the origin to the destination, and a transition from
  47. /// the destination to the origin</li>
  48. /// <li>\a Forward: A transition from the origin to the destination only</li>
  49. /// <li>\a Backward: A transition from the destination to the origin only</li>
  50. enum TransitionDirectionality
  51. {
  52. Bidirectional = 0,
  53. Forward,
  54. Backward
  55. };
  56. /// \brief Creates a transition between two steps, and adds the two steps to the workflow if they
  57. /// have not been previously added. (Cannot add two steps with the same id).
  58. ///
  59. /// The destination step should semantically be a next step, i.e. from a workflow perspective, the
  60. /// \a destination step is meant to appear after the \a origin step.
  61. /// Tthis method will:
  62. /// <ul>
  63. /// <li>Call addStep()</li> to add the origin and destination steps, if they have not been
  64. /// previously added to the workflow</li>
  65. /// <li>If \a directionality is ctkWorkflow::Bidirectional or ctkWorkflow::Forward, creates a
  66. /// transition from the origin to the destination (more specifically, the transition is from the
  67. /// \a origin's validation state to the \a destination's processing state, and is of type ctkWorkflowTransition::TransitionToNextStep</li>
  68. /// <li>If \a directionality is ctkWorkflow::Bidirectional or ctkWorkflow::Backward, creates a
  69. /// transition from the destination to the origin (more specifically, the transition is from the
  70. /// \a destination's processing state to the \a origin's processing state, and is of type
  71. /// ctkWorkflowTransition::TransitionToPreviousStep</li>
  72. ///
  73. /// The default value of directionality is ctkWorkflow::Bidirectional.
  74. ///
  75. /// To add a single step, \a destination can be set to 0.
  76. ///
  77. /// Returns true/false indicating whether the method was successful.
  78. virtual bool addTransition(ctkWorkflowStep* origin, ctkWorkflowStep* destination,
  79. const QString& branchId = QString(),
  80. const ctkWorkflow::TransitionDirectionality directionality
  81. = ctkWorkflow::Bidirectional);
  82. // /// \Determine whether a transition has already been added
  83. // bool hasTransition(ctkWorkflowStep* origin, ctkWorkflowStep* destination,
  84. // const ctkWorkflow::TransitionDirectionality directionality/*,
  85. // const QString& branchId = QString()*/);
  86. /// \Determine whether a transition has already been added
  87. /// If a branch id is not given or is empty: a transition exists if the transition has been
  88. /// previously added with the same origin, destination and directionality
  89. /// if a non-empty branch id is given: a transition exists if the transition has been previously
  90. /// added with the same origin, destination and directionality, OR if a transition has been
  91. /// previously added wtih the same origin and branch id (for forward transitions) or
  92. /// with the same destination and branch id (for backward transitions)
  93. bool hasTransition(ctkWorkflowStep* origin, ctkWorkflowStep* destination,
  94. const QString& branchId = QString(),
  95. const ctkWorkflow::TransitionDirectionality directionality = ctkWorkflow::Bidirectional);
  96. /// \brief Set/get the initial step.
  97. ///
  98. /// Convenience method to set the QStateMachine's initialState to a specific step's
  99. /// processing state.
  100. ///
  101. /// \note The initialStep() function *must* be called to set the state machine's initial state
  102. /// correctly
  103. ctkWorkflowStep* initialStep()const;
  104. virtual void setInitialStep(ctkWorkflowStep* step);
  105. /// Get the current step of the state machine
  106. ctkWorkflowStep* currentStep()const;
  107. /// Check to see if there is a step with a given id in the workflow.
  108. bool hasStep(const QString& id)const;
  109. /// Returns whether or not we can go forward: i.e. the workflow is running and there exists a step
  110. /// that directly follows the given step.
  111. ///
  112. /// If no step is given, then the workflow's current step will be used.
  113. bool canGoForward(ctkWorkflowStep* step=0)const;
  114. /// Returns whether or not we can go backward: i.e. the workflow is running and there exists a
  115. /// step that directly preceeds the given step.
  116. ///
  117. /// If no step is given, then the workflow's current step will be used.
  118. bool canGoBackward(ctkWorkflowStep* step=0)const;
  119. /// Returns whether or not we can go to the goal step from the origin step: i.e. there is a path
  120. /// in the workflow from the current step to the given step.
  121. ///
  122. /// If no step is designated as the 'origin', then the workflow's current step will be used
  123. bool canGoToStep(const QString& targetId, ctkWorkflowStep* step=0)const;
  124. /// Get the steps that directly follow the given step.
  125. ///
  126. /// More specifically, the returned list of steps will be the destination steps for which
  127. /// addTransition() has been called with the given step as the origin step and directionality set
  128. /// to ctkWorkflow::Bidirectional or ctkWorkflow::Forward.
  129. ///
  130. /// If no step is given, then the workflow's current step will be used.
  131. QList<ctkWorkflowStep*> forwardSteps(ctkWorkflowStep* step=0)const;
  132. /// Get the steps that directly preceed the given step.
  133. ///
  134. /// More specifically, the returned list of steps will be the origin steps for which
  135. /// addTransition() has been called with the given step as the destination step and directionality
  136. /// set to ctkWorkflow::Bidirectional or ctkWorkflow::Backward.
  137. ///
  138. /// If no step is given, then the workflow's current step will be used.
  139. QList<ctkWorkflowStep*> backwardSteps(ctkWorkflowStep* step=0)const;
  140. /// Get the steps that are 'finish' steps (i.e. have no step following them)
  141. QList<ctkWorkflowStep*> finishSteps()const;
  142. public slots:
  143. /// Use this to trigger evaluation of the processing state of the current step, and subsequent
  144. /// conditional transition to the next step.
  145. virtual void goForward(const QString& desiredBranchId = QString());
  146. /// Use this to trigger transition to the previous step (does not require validation)
  147. virtual void goBackward(const QString& desiredBranchId = QString());
  148. /// Go to the given step by iteratively calling goForward() until we reach it.
  149. virtual void goToStep(const QString& targetId);
  150. /// \brief Receives the result of a step's validate(const QString&) function.
  151. ///
  152. /// If the validation is successful, then this slot begins the transition to the next step.
  153. ///
  154. /// This slot should be connected to each ctkWorkflowStep's validationComplete() signal.
  155. virtual void evaluateValidationResults(bool validationSucceeded, const QString& branchId);
  156. /// \brief Workflow processing executed after a step's onEntry function is run.
  157. ///
  158. /// This slot should be connected to each ctkWorkflowStep's onEntryComplete() signal.
  159. virtual void processingAfterOnEntry();
  160. /// \brief Workflow processing executed after a step's onExit function is run.
  161. ///
  162. /// This slot should be connected to each ctkWorkflowStep's onExitComplete() signal.
  163. virtual void processingAfterOnExit();
  164. protected:
  165. /// \brief Triggers the start of a ctkWorkflowTransition of type
  166. /// ctkWorkflowTransitionType::TransitionToNextStep()
  167. void goToNextStepAfterSuccessfulValidation(const QString& branchId);
  168. /// \brief Triggers the start of a ctkWorkflowTransition of type
  169. /// ctkWorkflowTransitionType::ValidationFailedTransition
  170. void goToProcessingStateAfterValidationFailed();
  171. /// \brief Processing that occurs after the attempt to go to a 'goTo' step succeeds
  172. virtual void goToStepSucceeded();
  173. /// \brief Processing that occurs after the attempt to go to a 'goTo' step fails
  174. virtual void goToStepFailed();
  175. /// \brief Goes to the step from which the attempt to go to the 'goTo' step was initiated
  176. void goFromGoToStepToStartingStep();
  177. /// \brief Performs required connections between the step and this
  178. /// workflow, if the user is deriving a custom step as a subclasses of ctkWorkflowStep
  179. virtual void connectStep(ctkWorkflowStep* step);
  180. protected slots:
  181. /// On an attempt to go to the next step, calls the current step's
  182. /// validate(const QString&) function to validate the processing step. The
  183. /// validate(const QString&) function emits a signal that is connected to the
  184. /// workflow's evaluateValidationResults slot. If the validation is
  185. /// successful, then the slot triggers the start of a
  186. /// ctkWorkflowTransition of type
  187. /// ctkWorkflowTransitionType::TransitionToNextStep, otherwise it
  188. /// triggers the start of a ctkWorkflowTransition of type
  189. /// ctkWorkflowTransitionType::ValidationFailedTransition.
  190. void attemptToGoToNextStep();
  191. /// \brief May be called when transitioning to the next step upon successful validation, or
  192. /// when transitioning to the previous step.
  193. /// Calls onExit() of the transition's origin step and then onEntry() of
  194. /// the transition's destination step.
  195. /// \note Must be sent by a ctkWorkflowTransition.
  196. void performTransitionBetweenSteps();
  197. signals:
  198. /// Emitted when the current step has changed, after the step's onEntry() has completed.
  199. /// \note This signal is not emitted in the process of going to a goToStep
  200. void currentStepChanged(ctkWorkflowStep* currentStep);
  201. private:
  202. CTK_DECLARE_PRIVATE(ctkWorkflow);
  203. };
  204. #endif