ctkWorkflow.h 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. /*=========================================================================
  2. Library: CTK
  3. Copyright (c) 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.apache.org/licenses/LICENSE-2.0.txt
  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. /// \ingroup Core
  25. /// \brief ctkWorkflow is the basis for a workflow engine, i.e. a state
  26. /// machine with enhancements to support ctkWorkflowStep.
  27. class CTK_CORE_EXPORT ctkWorkflow : public QObject
  28. {
  29. Q_OBJECT
  30. Q_ENUMS(TransitionDirectionality)
  31. Q_PROPERTY(bool isRunning READ isRunning DESIGNABLE false)
  32. Q_PROPERTY(bool goBackToOriginStepUponSuccess READ goBackToOriginStepUponSuccess WRITE setGoBackToOriginStepUponSuccess)
  33. public:
  34. typedef QObject Superclass;
  35. explicit ctkWorkflow(QObject* parent = 0);
  36. virtual ~ctkWorkflow();
  37. /// \brief Start the workflow.
  38. /// The workflow will always start in the initial step, even if it is stopped and restarted).
  39. /// \note Calls onEntry() for the initial step.
  40. Q_INVOKABLE virtual void start();
  41. /// \brief Returns whether the workflow is currently running
  42. bool isRunning()const;
  43. /// \brief Stops the workflow.
  44. /// \note Calls onExit() for the current step.
  45. Q_INVOKABLE virtual void stop();
  46. /// \brief Transition directionalities.
  47. ///
  48. /// The direction of transitions between an origin step and a destination step can be either:
  49. /// <ul>
  50. /// <li>\a Bidirectional: A transition from the origin to the destination, and a transition from
  51. /// the destination to the origin</li>
  52. /// <li>\a Forward: A transition from the origin to the destination only</li>
  53. /// <li>\a Backward: A transition from the destination to the origin only</li>
  54. /// </ul>
  55. enum TransitionDirectionality
  56. {
  57. Bidirectional = 0,
  58. Forward,
  59. Backward
  60. };
  61. /// \brief Creates a transition between two steps, and adds the two steps to the workflow if they
  62. /// have not been previously added. (Cannot add two steps with the same id).
  63. ///
  64. /// The destination step should semantically be a next step, i.e. from a workflow perspective, the
  65. /// \a destination step is meant to appear after the \a origin step.
  66. ///
  67. /// To add a single step, \a destination can be set to 0.
  68. ///
  69. /// Returns true/false indicating whether the method was successful.
  70. Q_INVOKABLE virtual bool addTransition(ctkWorkflowStep* origin, ctkWorkflowStep* destination,
  71. const QString& branchId = QString(),
  72. const ctkWorkflow::TransitionDirectionality directionality
  73. = ctkWorkflow::Bidirectional);
  74. /// \brief Determine whether a transition has already been added
  75. /// <ul>
  76. /// <li>If a branch id is not given or is empty: a transition exists if a transition has been
  77. /// previously added with the same origin, destination and directionality</li>
  78. /// <li>If a non-empty branch id is given: a transition exists if the transition has been previously
  79. /// added with the same origin, destination and directionality, OR if a transition has been
  80. /// previously added with the same origin and branch id (for forward transitions) or
  81. /// with the same destination and branch id (for backward transitions)</li>
  82. /// </ul>
  83. Q_INVOKABLE bool hasTransition(ctkWorkflowStep* origin, ctkWorkflowStep* destination,
  84. const QString& branchId = QString(),
  85. const ctkWorkflow::TransitionDirectionality directionality
  86. = ctkWorkflow::Bidirectional);
  87. /// \brief Set/get the initial step.
  88. /// \note In not specified, the first step added will be considered as the initialStep
  89. Q_INVOKABLE ctkWorkflowStep* initialStep()const;
  90. Q_INVOKABLE virtual void setInitialStep(ctkWorkflowStep* step);
  91. /// \brief Register ctkWorkflowStep so that ctkWorkflow keeps track of the associated steps
  92. /// and clean the memory when appropriate.
  93. /// \note This function is declared public for convenience and shouldn't be directly used.
  94. /// The step will register itself when instantiated.
  95. /// \note Since ctkWorkflowStep are neither QObject nor QWidget, they will be registered. On
  96. /// on the othen hand, ctkWorkflowWidgetStep will be managed by their parent QWidget and
  97. /// won't be registered.
  98. void registerWorkflowStep(ctkWorkflowStep* step);
  99. /// Get the current step of the state machine
  100. Q_INVOKABLE ctkWorkflowStep* currentStep()const;
  101. /// Check to see if there is a step with a given id in the workflow.
  102. Q_INVOKABLE bool hasStep(const QString& id)const;
  103. /// Returns whether or not we can go forward: i.e. there exists a step that directly follows the
  104. /// given step.
  105. ///
  106. /// If no step is given, then the workflow's current step will be used.
  107. Q_INVOKABLE bool canGoForward(ctkWorkflowStep* step=0)const;
  108. /// Returns whether or not we can go backward: i.e. there exists a step that directly preceeds the
  109. /// given step.
  110. ///
  111. /// If no step is given, then the workflow's current step will be used.
  112. Q_INVOKABLE bool canGoBackward(ctkWorkflowStep* step=0)const;
  113. /// Returns whether or not we can go to the goal step from the origin step: i.e. there is a path
  114. /// in the workflow from the current step to the given step.
  115. ///
  116. /// If no step is designated as the 'origin', then the workflow's current step will be used
  117. /// Note: does not currently work in branching workflows if the origin and target steps are not on
  118. /// the same branch
  119. Q_INVOKABLE bool canGoToStep(const QString& targetId, ctkWorkflowStep* step=0)const;
  120. /// Get the steps that directly follow the given step.
  121. ///
  122. /// More specifically, the returned list of steps will be the destination steps for which
  123. /// addTransition() has been called with the given step as the origin step and directionality set
  124. /// to ctkWorkflow::Bidirectional or ctkWorkflow::Forward.
  125. ///
  126. /// If no step is given, then the workflow's current step will be used.
  127. Q_INVOKABLE QList<ctkWorkflowStep*> forwardSteps(ctkWorkflowStep* step=0)const;
  128. /// Get the steps that directly preceed the given step.
  129. ///
  130. /// More specifically, the returned list of steps will be the origin steps for which
  131. /// addTransition() has been called with the given step as the destination step and directionality
  132. /// set to ctkWorkflow::Bidirectional or ctkWorkflow::Backward.
  133. ///
  134. /// If no step is given, then the workflow's current step will be used.
  135. Q_INVOKABLE QList<ctkWorkflowStep*> backwardSteps(ctkWorkflowStep* step=0)const;
  136. /// Get the steps that are 'finish' steps (i.e. have no step following them)
  137. Q_INVOKABLE QList<ctkWorkflowStep*> finishSteps()const;
  138. /// Configures the behavior of goToStep(targetId).
  139. ///
  140. /// If set to true, goToStep(targetId) goes back to the origin step after
  141. /// the attempt of going to the target step succeeded.
  142. /// If set to false, goToStep(targetId) stays at the target step when the attempt
  143. /// succeeded.
  144. bool goBackToOriginStepUponSuccess()const;
  145. void setGoBackToOriginStepUponSuccess(bool flag);
  146. public slots:
  147. /// Use this to trigger evaluation of the processing state of the current step, and subsequent
  148. /// conditional transition to the next step.
  149. virtual void goForward(const QString& desiredBranchId = QString());
  150. /// Use this to trigger transition to the previous step (does not require validation)
  151. virtual void goBackward(const QString& desiredBranchId = QString());
  152. /// Go to the given step by iteratively calling goForward() until we reach it.
  153. virtual void goToStep(const QString& targetId);
  154. /// \brief Receives the result of a step's validate(const QString&) function.
  155. ///
  156. /// If the validation is successful, then this slot begins the transition to the next step.
  157. virtual void evaluateValidationResults(bool validationSucceeded, const QString& branchId);
  158. protected:
  159. void goToNextStepAfterSuccessfulValidation(const QString& branchId);
  160. void goToProcessingStateAfterValidationFailed();
  161. /// \brief Processing that occurs after the attempt to go to a 'goTo' step succeeds
  162. virtual void goToStepSucceeded();
  163. /// \brief Processing that occurs after the attempt to go to a 'goTo' step fails
  164. virtual void goToStepFailed();
  165. /// \brief Goes to the step from which the attempt to go to the 'goTo' step was initiated
  166. void goFromGoToStepToStartingStep();
  167. protected slots:
  168. /// On an attempt to go to the next step, calls the current step's
  169. /// validate(const QString&) function to validate the processing step.
  170. void attemptToGoToNextStep();
  171. /// \brief Called when transitioning to the next step upon successful validation, or
  172. /// when transitioning to the previous step.
  173. /// Calls onExit() of the transition's origin step and then onEntry() of
  174. /// the transition's destination step.
  175. /// \note Must be sent by a ctkWorkflowTransition.
  176. void performTransitionBetweenSteps();
  177. signals:
  178. /// Emitted when the current step has changed, after the step's onEntry() has completed.
  179. /// \note This signal is not emitted in the process of going to a goToStep
  180. void currentStepChanged(ctkWorkflowStep* currentStep);
  181. protected:
  182. QScopedPointer<ctkWorkflowPrivate> d_ptr;
  183. private:
  184. Q_DECLARE_PRIVATE(ctkWorkflow);
  185. Q_DISABLE_COPY(ctkWorkflow);
  186. };
  187. #endif