Forráskód Böngészése

Update workflowStep API

* Step are "registered" within the workflow when a transition is added

* A step can be registered/added to only one workflow

* A method workflow:steps() return all steps registered within a workflow

* Added method "bool workflowstep::widgetType()" indicating if a step is a QWidget

* Only non QWidget steps will be explicitly deleted by a workflow.
Jean-Christophe Fillion-Robin 13 éve
szülő
commit
3b1b1d3162

+ 1 - 1
Libs/Core/Testing/Cpp/ctkBranchingWorkflowStep.h

@@ -32,7 +32,7 @@ class ctkBranchingWorkflowStep : public ctkWorkflowStep
 public:
 
   typedef ctkWorkflowStep Superclass;
-  explicit ctkBranchingWorkflowStep(ctkWorkflow* newWorkflow, const QString& newId) : Superclass(newWorkflow, newId){};
+  explicit ctkBranchingWorkflowStep(const QString& newId) : Superclass(newId){};
 
   void setBranchId(const QString& newId)
   {

+ 2 - 2
Libs/Core/Testing/Cpp/ctkExampleDerivedWorkflowStep.cpp

@@ -47,8 +47,8 @@ ctkExampleDerivedWorkflowStepPrivate::ctkExampleDerivedWorkflowStepPrivate()
 // ctkExampleDerivedWorkflowStep methods
 
 //-----------------------------------------------------------------------------
-ctkExampleDerivedWorkflowStep::ctkExampleDerivedWorkflowStep(ctkWorkflow* newWorkflow, const QString& newId) :
-  Superclass(newWorkflow, newId)
+ctkExampleDerivedWorkflowStep::ctkExampleDerivedWorkflowStep(const QString& newId) :
+  Superclass(newId)
   , d_ptr(new ctkExampleDerivedWorkflowStepPrivate)
 {
 }

+ 1 - 1
Libs/Core/Testing/Cpp/ctkExampleDerivedWorkflowStep.h

@@ -39,7 +39,7 @@ class ctkExampleDerivedWorkflowStep : public ctkWorkflowStep
 public:
 
   typedef ctkWorkflowStep Superclass;
-  explicit ctkExampleDerivedWorkflowStep(ctkWorkflow* newWorkflow, const QString& newId);
+  explicit ctkExampleDerivedWorkflowStep(const QString& newId);
   virtual ~ctkExampleDerivedWorkflowStep();
 
   /// Get the values for the counters of the number of times we have

+ 10 - 10
Libs/Core/Testing/Cpp/ctkWorkflowTest1.cpp

@@ -62,7 +62,7 @@ int numberOfTimesEntryExitTest(ctkExampleDerivedWorkflowStep* step1=0, int step1
     if (step4->numberOfTimesRanOnEntry() != step4Entry || step4->numberOfTimesRanOnExit() != step4Exit)
       {
       return 0;
-      }    
+      }
     }
 
   return 1;
@@ -123,16 +123,16 @@ int ctkWorkflowTest1(int argc, char * argv [] )
 
   // create two steps and the workflow
   ctkWorkflow *workflow = new ctkWorkflow();
-  ctkExampleDerivedWorkflowStep *step1 = new ctkExampleDerivedWorkflowStep(workflow, "Step 1");
+  ctkExampleDerivedWorkflowStep *step1 = new ctkExampleDerivedWorkflowStep("Step 1");
   step1->setName("Step 1");
   step1->setDescription("Description for step 1");
-  ctkExampleDerivedWorkflowStep *step2 = new ctkExampleDerivedWorkflowStep(workflow, "Step 2");
+  ctkExampleDerivedWorkflowStep *step2 = new ctkExampleDerivedWorkflowStep("Step 2");
   step2->setName("Step 2");
   step2->setDescription("Description for step 2");
 
   // --------------------------------------------------------------------------
   // try to add a transition for a step with the same id
-  ctkExampleDerivedWorkflowStep *step1Duplicated = new ctkExampleDerivedWorkflowStep(workflow, "Step 1");
+  ctkExampleDerivedWorkflowStep *step1Duplicated = new ctkExampleDerivedWorkflowStep("Step 1");
   if (workflow->addTransition(step1, step1Duplicated))
     {
     std::cerr << "workflow connected two steps with the same id";
@@ -172,7 +172,7 @@ int ctkWorkflowTest1(int argc, char * argv [] )
 
   // --------------------------------------------------------------------------
   // workflow with one step
-  
+
   // set the initial step (which sets the initial state)
   workflow->setInitialStep(step1);
 
@@ -236,7 +236,7 @@ int ctkWorkflowTest1(int argc, char * argv [] )
     std::cerr << "Step2 not added to workflow";
     return EXIT_FAILURE;
     }
-  
+
   // if (workflow->numberOfSteps() != 2)
   //   {
   //   std::cerr << "workflow has " << workflow->numberOfSteps() << " steps, not 2";
@@ -269,7 +269,7 @@ int ctkWorkflowTest1(int argc, char * argv [] )
   // --------------------------------------------------------------------------
   // Step3
 
-  ctkExampleDerivedWorkflowStep *step3 = new ctkExampleDerivedWorkflowStep(workflow, "Step 3");
+  ctkExampleDerivedWorkflowStep *step3 = new ctkExampleDerivedWorkflowStep("Step 3");
   step3->setName("Step 3");
   step3->setDescription("Description for step 3");
 
@@ -416,7 +416,7 @@ int ctkWorkflowTest1(int argc, char * argv [] )
 
   // --------------------------------------------------------------------------
   // workflow with two finishing steps (step3 and step4)
-  ctkExampleDerivedWorkflowStep *step4 = new ctkExampleDerivedWorkflowStep(workflow, "Step 4");
+  ctkExampleDerivedWorkflowStep *step4 = new ctkExampleDerivedWorkflowStep("Step 4");
   step4->setName("Step 4");
   step4->setDescription("Description for step 4");
   workflow->addTransition(step3, step4);
@@ -480,7 +480,7 @@ int ctkWorkflowTest1(int argc, char * argv [] )
     {
     std::cerr << "error looping from step 4 to step 4";
     return EXIT_FAILURE;
-    }  
+    }
 
   // go back to step 3, and then go from step 3 to step 3 (should loop without hitting step4)
   workflow->goBackward();
@@ -491,7 +491,7 @@ int ctkWorkflowTest1(int argc, char * argv [] )
     {
     std::cerr << "error looping from step 3 to step 3";
     return EXIT_FAILURE;
-    }  
+    }
 
   // try to go automatically to step 4 and stay there by setting the property goBackToOriginStepUponSuccess to false
   workflow->setGoBackToOriginStepUponSuccess(false);

+ 7 - 7
Libs/Core/Testing/Cpp/ctkWorkflowTest2.cpp

@@ -63,7 +63,7 @@ int numberOfTimesEntryExitTest(ctkExampleWorkflowStepUsingSignalsAndSlots* step1
     if (step4->numberOfTimesRanOnEntry() != step4Entry || step4->numberOfTimesRanOnExit() != step4Exit)
       {
       return 0;
-      }    
+      }
     }
 
   return 1;
@@ -124,17 +124,17 @@ int ctkWorkflowTest2(int argc, char * argv [] )
 
   // create the steps and the workflow
   ctkWorkflow *workflow = new ctkWorkflow();
-  ctkWorkflowStep *step1 = new ctkWorkflowStep(workflow, "Step 1");
+  ctkWorkflowStep *step1 = new ctkWorkflowStep("Step 1");
   step1->setName("Step 1");
   step1->setId("FirstStep");
   step1->setDescription("Description for step 1");
-  ctkWorkflowStep *step2 = new ctkWorkflowStep(workflow, "Step 2");
+  ctkWorkflowStep *step2 = new ctkWorkflowStep("Step 2");
   step2->setName("Step 2");
   step2->setDescription("Description for step 2");
-  ctkWorkflowStep *step3 = new ctkWorkflowStep(workflow, "Step 3");
+  ctkWorkflowStep *step3 = new ctkWorkflowStep("Step 3");
   step3->setName("Step 3");
   step3->setDescription("Description for step 3");
-  ctkWorkflowStep *step4 = new ctkWorkflowStep(workflow, "Step 4");
+  ctkWorkflowStep *step4 = new ctkWorkflowStep("Step 4");
   step4->setName("Step 4");
   step4->setDescription("Description for step 4");
 
@@ -200,10 +200,10 @@ int ctkWorkflowTest2(int argc, char * argv [] )
   step2->setHasOnExitCommand(1);
   step3->setHasOnExitCommand(1);
   step4->setHasOnExitCommand(1);
-  
+
   // set the initial step (which sets the initial state)
   workflow->setInitialStep(step1);
-  
+
   // add the first and second steps
   if (!workflow->addTransition(step1, step2))
     {

+ 10 - 10
Libs/Core/Testing/Cpp/ctkWorkflowTest3.cpp

@@ -47,15 +47,15 @@ int ctkWorkflowTest3(int argc, char * argv [] )
 
   // create two steps and the workflow
   ctkWorkflow *workflow = new ctkWorkflow();
-  ctkExampleDerivedWorkflowStep* s0 = new ctkExampleDerivedWorkflowStep(workflow, "Step 0");
-  ctkExampleDerivedWorkflowStep* s1 = new ctkExampleDerivedWorkflowStep(workflow, "Step 1");
-  ctkBranchingWorkflowStep* s2 = new ctkBranchingWorkflowStep(workflow, "Step 2");
-  ctkExampleDerivedWorkflowStep* s3 = new ctkExampleDerivedWorkflowStep(workflow, "Step 3");
-  ctkExampleDerivedWorkflowStep* s4 = new ctkExampleDerivedWorkflowStep(workflow, "Step 4");
-  ctkExampleDerivedWorkflowStep* s5 = new ctkExampleDerivedWorkflowStep(workflow, "Step 5");
-  ctkExampleDerivedWorkflowStep* s6 = new ctkExampleDerivedWorkflowStep(workflow, "Step 6");
-  ctkExampleDerivedWorkflowStep* s7 = new ctkExampleDerivedWorkflowStep(workflow, "Step 7");
-  ctkExampleDerivedWorkflowStep* s8 = new ctkExampleDerivedWorkflowStep(workflow, "Step 8");
+  ctkExampleDerivedWorkflowStep* s0 = new ctkExampleDerivedWorkflowStep("Step 0");
+  ctkExampleDerivedWorkflowStep* s1 = new ctkExampleDerivedWorkflowStep("Step 1");
+  ctkBranchingWorkflowStep* s2 = new ctkBranchingWorkflowStep("Step 2");
+  ctkExampleDerivedWorkflowStep* s3 = new ctkExampleDerivedWorkflowStep("Step 3");
+  ctkExampleDerivedWorkflowStep* s4 = new ctkExampleDerivedWorkflowStep("Step 4");
+  ctkExampleDerivedWorkflowStep* s5 = new ctkExampleDerivedWorkflowStep("Step 5");
+  ctkExampleDerivedWorkflowStep* s6 = new ctkExampleDerivedWorkflowStep("Step 6");
+  ctkExampleDerivedWorkflowStep* s7 = new ctkExampleDerivedWorkflowStep("Step 7");
+  ctkExampleDerivedWorkflowStep* s8 = new ctkExampleDerivedWorkflowStep("Step 8");
 
   workflow->addTransition(s0, s1);
   workflow->addTransition(s1, s2);
@@ -192,7 +192,7 @@ int ctkWorkflowTest3(int argc, char * argv [] )
     std::cerr << "error transitioning s3->s2" << std::endl;
     return EXIT_FAILURE;
     }
- 
+
   // transition to s5
   s2->setBranchId("advanced");
   workflow->goForward();

+ 2 - 2
Libs/Core/ctkCorePythonQtDecorators.h

@@ -58,9 +58,9 @@ public slots:
     return new ctkWorkflowStep();
     }
 
-  ctkWorkflowStep* new_ctkWorkflowStep(ctkWorkflow* newWorkflow, const QString& newId = QString())
+  ctkWorkflowStep* new_ctkWorkflowStep(const QString& newId)
     {
-    return new ctkWorkflowStep(newWorkflow, newId);
+    return new ctkWorkflowStep(newId);
     }
 
   void delete_ctkWorkflowStep(ctkWorkflowStep * step)

+ 56 - 27
Libs/Core/ctkWorkflow.cpp

@@ -62,11 +62,11 @@ ctkWorkflowPrivate::ctkWorkflowPrivate(ctkWorkflow& object)
 
 // --------------------------------------------------------------------------
 ctkWorkflowPrivate::~ctkWorkflowPrivate()
-{ 
+{
 }
 
 // --------------------------------------------------------------------------
-void ctkWorkflowPrivate::addStep(ctkWorkflowStep* step)
+bool ctkWorkflowPrivate::addStep(ctkWorkflowStep* step)
 {
   Q_Q(ctkWorkflow);
 
@@ -74,6 +74,23 @@ void ctkWorkflowPrivate::addStep(ctkWorkflowStep* step)
   Q_ASSERT(!q->hasStep(step->id()));
   Q_ASSERT(!this->StateMachine->isRunning());
 
+  if (!step->workflow())
+    {
+    step->setWorkflow(q);
+    }
+  if (step->workflow() != q)
+    {
+    // Check if steps are not already associated with a different workflow
+    QString msg("addStep - step [%1] already associated with a different workfow !");
+    logger.error(msg.arg(step->id()));
+    return false;
+    }
+  if (!this->RegisteredSteps.contains(step))
+    {
+    this->RegisteredSteps << step;
+    emit q->stepRegistered(step);
+    }
+
   // Add the states, creating them if necessary
   this->StateMachine->addState(step->processingState());
   this->StateMachine->addState(step->validationState());
@@ -101,6 +118,8 @@ void ctkWorkflowPrivate::addStep(ctkWorkflowStep* step)
   this->connect(
       step->ctkWorkflowStepQObject(), SIGNAL(onExitComplete()),
       SLOT(processingAfterOnExit()));
+
+  return true;
 }
 
 // --------------------------------------------------------------------------
@@ -259,7 +278,7 @@ void ctkWorkflowPrivate::createTransitionToPreviousStartingStep(ctkWorkflowStep*
 
     this->TransitionToPreviousStartingStep = transition;
     }
-  
+
   QState* currentState;
   // looping on the finish step
   if (startingStep == currentStep)
@@ -541,9 +560,14 @@ ctkWorkflow::~ctkWorkflow()
     }
 
   // Clean registered step
-  while (!d->registeredSteps.isEmpty())
+  while (!d->RegisteredSteps.isEmpty())
     {
-    delete d->registeredSteps.takeFirst();
+    ctkWorkflowStep * step = d->RegisteredSteps.takeFirst();
+    if (!step->isWidgetType())
+      {
+      delete step;
+      }
+
     }
 }
 
@@ -578,7 +602,11 @@ bool ctkWorkflow::addTransition(ctkWorkflowStep* origin, ctkWorkflowStep* destin
   // add the origin step if it doesn't exist in the workflow yet
   if (origin && !this->hasStep(origin->id()))
     {
-    d->addStep(origin);
+    bool ok = d->addStep(origin);
+    if (!ok)
+      {
+      return false;
+      }
     }
 
   // Set destination id if empty
@@ -590,7 +618,11 @@ bool ctkWorkflow::addTransition(ctkWorkflowStep* origin, ctkWorkflowStep* destin
   // add the destination step if it doesn't exist in the workflow yet
   if (destination && !this->hasStep(destination->id()))
     {
-    d->addStep(destination);
+    bool ok = d->addStep(destination);
+    if (!ok)
+      {
+      return false;
+      }
     }
 
   if (origin && destination)
@@ -599,7 +631,7 @@ bool ctkWorkflow::addTransition(ctkWorkflowStep* origin, ctkWorkflowStep* destin
     if (this->hasTransition(origin, destination, branchId, directionality))
       {
       logger.warn("addTransition - Cannot create a transition that matches a "
-                  "previously created transtiion");
+                  "previously created transition");
       return false;
       }
 
@@ -607,6 +639,7 @@ bool ctkWorkflow::addTransition(ctkWorkflowStep* origin, ctkWorkflowStep* destin
     if (directionality == ctkWorkflow::Forward
         || directionality == ctkWorkflow::Bidirectional)
       {
+      //qDebug() << "addTransition" << origin->id() << "->" << destination->id();
       d->createTransitionToNextStep(origin, destination, branchId);
       }
 
@@ -614,6 +647,7 @@ bool ctkWorkflow::addTransition(ctkWorkflowStep* origin, ctkWorkflowStep* destin
     if (directionality == ctkWorkflow::Backward
         || directionality == ctkWorkflow::Bidirectional)
       {
+      //qDebug() << "addTransition" << origin->id() << "<-" << destination->id();
       d->createTransitionToPreviousStep(origin, destination, branchId);
       }
     }
@@ -628,18 +662,6 @@ bool ctkWorkflow::addTransition(ctkWorkflowStep* origin, ctkWorkflowStep* destin
 }
 
 // --------------------------------------------------------------------------
-void ctkWorkflow::registerWorkflowStep(ctkWorkflowStep* step)
-{
-  Q_D(ctkWorkflow);
-  if (!step)
-    {
-    qCritical() << "ctkWorkflow::registerWorkflowStep - Failed to register Null step !";
-    return;
-    }
-  d->registeredSteps << step;
-}
-
-// --------------------------------------------------------------------------
 bool ctkWorkflow::hasTransition(ctkWorkflowStep* origin, ctkWorkflowStep* destination,
                                 const QString& branchId,
                                 const ctkWorkflow::TransitionDirectionality directionality)
@@ -722,6 +744,13 @@ QList<ctkWorkflowStep*> ctkWorkflow::finishSteps()const
 }
 
 // --------------------------------------------------------------------------
+QList<ctkWorkflowStep*> ctkWorkflow::steps()const
+{
+  Q_D(const ctkWorkflow);
+  return d->RegisteredSteps;
+}
+
+// --------------------------------------------------------------------------
 bool ctkWorkflow::canGoForward(ctkWorkflowStep* step)const
 {
   return (!this->forwardSteps(step).isEmpty());
@@ -765,7 +794,7 @@ void ctkWorkflow::start()
     logger.warn("start - Cannot start workflow without an initial step");
     return;
     }
-  
+
   // Setup to do the entry processing for the initial setp
   d->StateMachine->setInitialState(d->InitialStep->processingState());
   d->OriginStep = 0;
@@ -856,7 +885,7 @@ void ctkWorkflow::goBackward(const QString& desiredBranchId)
   Q_ASSERT(!branchId.isEmpty());
 
   d->DesiredBranchId = desiredBranchId;
-  
+
   logger.info("goBackward - posting TransitionToPreviousStep");
   d->StateMachine->postEvent(
                              new ctkWorkflowInterstepTransitionEvent(ctkWorkflowInterstepTransition::TransitionToPreviousStep, branchId));
@@ -906,7 +935,7 @@ void ctkWorkflow::goToStep(const QString& targetId)
 void ctkWorkflow::attemptToGoToNextStep()
 {
   logger.info("attemptToGoToNextStep - Attempting to go to the next step ");
- 
+
   Q_D(ctkWorkflow);
   Q_ASSERT(d->CurrentStep);
   //Q_ASSERT(this->canGoForward(d->CurrentStep));
@@ -1024,7 +1053,7 @@ void ctkWorkflow::performTransitionBetweenSteps()
 
   ctkWorkflowInterstepTransition* transition = qobject_cast<ctkWorkflowInterstepTransition*>(QObject::sender());
   Q_ASSERT(transition);
-    
+
   d->OriginStep = d->stepFromState(transition->sourceState());
   d->DestinationStep = d->stepFromState(transition->targetState());
   d->TransitionType = transition->transitionType();
@@ -1035,9 +1064,9 @@ void ctkWorkflow::performTransitionBetweenSteps()
   // update the map from the step to the previous step if we are going forward
   if (d->TransitionType == ctkWorkflowInterstepTransition::TransitionToNextStep)
     {
-    d->StepToPreviousStepMap.insert(d->DestinationStep, d->OriginStep);        
+    d->StepToPreviousStepMap.insert(d->DestinationStep, d->OriginStep);
     }
- 
+
   // exit the destination step
   d->onExitInternal(d->OriginStep, d->DestinationStep, d->TransitionType);
 }
@@ -1081,7 +1110,7 @@ void ctkWorkflow::goToStepFailed()
 {
   // Abort attempt to get to the finish step
   Q_D(ctkWorkflow);
- 
+
   d->GoToStep = 0;
   d->StartingStep = 0;
 

+ 10 - 12
Libs/Core/ctkWorkflow.h

@@ -17,7 +17,7 @@
   limitations under the License.
 
 =========================================================================*/
- 
+
 #ifndef __ctkWorkflow_h
 #define __ctkWorkflow_h
 
@@ -110,15 +110,6 @@ public:
   Q_INVOKABLE ctkWorkflowStep* initialStep()const;
   Q_INVOKABLE virtual void setInitialStep(ctkWorkflowStep* step);
 
-  /// \brief Register ctkWorkflowStep so that ctkWorkflow keeps track of the associated steps
-  /// and clean the memory when appropriate.
-  /// \note This function is declared public for convenience and shouldn't be directly used.
-  /// The step will register itself when instantiated.
-  /// \note Since ctkWorkflowStep are neither QObject nor QWidget, they will be registered. On
-  /// on the othen hand, ctkWorkflowWidgetStep will be managed by their parent QWidget and
-  /// won't be registered.
-  void registerWorkflowStep(ctkWorkflowStep* step);
-
   /// Get the current step of the state machine
   Q_INVOKABLE ctkWorkflowStep* currentStep()const;
 
@@ -166,6 +157,9 @@ public:
   /// Get the steps that are 'finish' steps (i.e. have no step following them)
   Q_INVOKABLE QList<ctkWorkflowStep*> finishSteps()const;
 
+  /// Returns list of steps managed by the workflow
+  Q_INVOKABLE QList<ctkWorkflowStep*> steps()const;
+
   /// Configures the behavior of goToStep(targetId).
   ///
   /// If set to true, goToStep(targetId) goes back to the origin step after
@@ -203,10 +197,10 @@ protected:
 
   /// \brief Processing that occurs after the attempt to go to a 'goTo' step fails
   virtual void goToStepFailed();
- 
+
   /// \brief Goes to the step from which the attempt to go to the 'goTo' step was initiated
   void goFromGoToStepToStartingStep();
- 
+
 protected slots:
 
   /// On an attempt to go to the next step, calls the current step's
@@ -225,6 +219,10 @@ signals:
   /// \note This signal is not emitted in the process of going to a goToStep
   void currentStepChanged(ctkWorkflowStep* currentStep);
 
+  /// Emitted when a step is registered with this workflow
+  /// \sa addTransition
+  void stepRegistered(ctkWorkflowStep* step);
+
 protected:
   QScopedPointer<ctkWorkflowPrivate> d_ptr;
 

+ 21 - 18
Libs/Core/ctkWorkflowStep.cpp

@@ -19,6 +19,8 @@
   =========================================================================*/
 
 // Qt includes
+#include <QDebug>
+#include <QMetaType>
 #include <QObject>
 #include <QState>
 
@@ -42,8 +44,11 @@ static ctkLogger logger("org.commontk.core.ctkWorkflowStep");
 ctkWorkflowStepPrivate::ctkWorkflowStepPrivate(ctkWorkflowStep& object)
   :q_ptr(&object)
 {
+  qRegisterMetaType<ctkWorkflowStep*>("ctkWorkflowStep*");
   this->Workflow = 0;
 
+  this->WidgetType = false;
+
   this->HasValidateCommand = false;
   this->HasOnEntryCommand = false;
   this->HasOnExitCommand = false;
@@ -69,8 +74,14 @@ ctkWorkflowStepPrivate::ctkWorkflowStepPrivate(ctkWorkflowStep& object)
 // --------------------------------------------------------------------------
 ctkWorkflowStepPrivate::~ctkWorkflowStepPrivate()
 {
-  delete this->ValidationState;
-  delete this->ProcessingState;
+  if (!this->ValidationState.isNull())
+    {
+    delete this->ValidationState;
+    }
+  if (!this->ProcessingState.isNull())
+    {
+    delete this->ProcessingState;
+    }
 
   // If we delete the states, then Qt will handle deleting the transitions
 }
@@ -95,7 +106,7 @@ void ctkWorkflowStepPrivate::onExitCompleteInternal()const
 
 // --------------------------------------------------------------------------
 void ctkWorkflowStepPrivate::invokeValidateCommandInternal(const QString& desiredBranchId)const
-{  
+{
   emit invokeValidateCommand(desiredBranchId);
 }
 
@@ -117,34 +128,22 @@ void ctkWorkflowStepPrivate::invokeOnExitCommandInternal(const ctkWorkflowStep*
 // --------------------------------------------------------------------------
 ctkWorkflowStep::ctkWorkflowStep(): d_ptr(new ctkWorkflowStepPrivate(*this))
 {
-  Q_D(ctkWorkflowStep);
-  d->Workflow->registerWorkflowStep(this);
 }
 
 // --------------------------------------------------------------------------
-ctkWorkflowStep::ctkWorkflowStep(ctkWorkflow* newWorkflow, const QString& newId)
+ctkWorkflowStep::ctkWorkflowStep(const QString& newId)
   : d_ptr(new ctkWorkflowStepPrivate(*this))
 {
   Q_D(ctkWorkflowStep);
-
   d->Id = newId;
-  d->Workflow = newWorkflow;
-
-  d->Workflow->registerWorkflowStep(this);
-}
-
-// --------------------------------------------------------------------------
-ctkWorkflowStep::ctkWorkflowStep(ctkWorkflowStepPrivate * pimpl):d_ptr(pimpl)
-{
 }
 
 // --------------------------------------------------------------------------
 ctkWorkflowStep::ctkWorkflowStep(ctkWorkflowStepPrivate * pimpl,
-                                 ctkWorkflow* newWorkflow, const QString& newId):d_ptr(pimpl)
+                                 const QString& newId):d_ptr(pimpl)
 {
   Q_D(ctkWorkflowStep);
   d->Id = newId;
-  d->Workflow = newWorkflow;
 }
 
 // --------------------------------------------------------------------------
@@ -154,6 +153,7 @@ ctkWorkflowStep::~ctkWorkflowStep()
 
 // --------------------------------------------------------------------------
 CTK_GET_CPP(ctkWorkflowStep, ctkWorkflow*, workflow, Workflow);
+CTK_SET_CPP(ctkWorkflowStep, ctkWorkflow*, setWorkflow, Workflow);
 
 // --------------------------------------------------------------------------
 CTK_GET_CPP(ctkWorkflowStep, QString, id, Id);
@@ -205,6 +205,9 @@ CTK_GET_CPP(ctkWorkflowStep, ctkWorkflowIntrastepTransition*,
             validationFailedTransition, ValidationFailedTransition);
 
 // --------------------------------------------------------------------------
+CTK_GET_CPP(ctkWorkflowStep, bool, isWidgetType, WidgetType);
+
+// --------------------------------------------------------------------------
 QObject* ctkWorkflowStep::ctkWorkflowStepQObject()
 {
   Q_D(ctkWorkflowStep);
@@ -234,7 +237,7 @@ void ctkWorkflowStep::onExitComplete()const
 
 // --------------------------------------------------------------------------
 void ctkWorkflowStep::invokeValidateCommand(const QString& desiredBranchId)const
-{  
+{
   Q_D(const ctkWorkflowStep);
   d->invokeValidateCommandInternal(desiredBranchId);
 }

+ 5 - 4
Libs/Core/ctkWorkflowStep.h

@@ -47,7 +47,7 @@ class CTK_CORE_EXPORT ctkWorkflowStep
 
 public:
   explicit ctkWorkflowStep();
-  explicit ctkWorkflowStep(ctkWorkflow* newWorkflow, const QString& newId);
+  explicit ctkWorkflowStep(const QString& newId);
   virtual ~ctkWorkflowStep();
 
   /// Get the \a workflow associated with this step
@@ -90,14 +90,15 @@ public:
   bool hasOnExitCommand()const;
   void setHasOnExitCommand(bool newHasOnExitCommand);
 
+  /// Returns true if the object is a widget; otherwise returns false
+  bool isWidgetType()const;
+
   /// Get QObject associated with this step, to connect signals/slots
   QObject* ctkWorkflowStepQObject();
 
 protected:
 
-  explicit ctkWorkflowStep(ctkWorkflowStepPrivate * pimpl);
-  explicit ctkWorkflowStep(ctkWorkflowStepPrivate * pimpl,
-                           ctkWorkflow* newWorkflow, const QString& newId);
+  explicit ctkWorkflowStep(ctkWorkflowStepPrivate * pimpl, const QString& newId);
 
   /// Set workflow
   void setWorkflow(ctkWorkflow* newWorkflow);

+ 5 - 2
Libs/Core/ctkWorkflowStep_p.h

@@ -23,6 +23,7 @@
 
 // Qt includes
 #include <QObject>
+#include <QPointer>
 
 class QString;
 class QState;
@@ -53,13 +54,15 @@ public:
 protected:
   ctkWorkflow* Workflow;
 
+  bool WidgetType;
+
   QString      Id;
   QString      Name;
   QString      Description;
   QString      StatusText;
 
-  QState* ProcessingState;
-  QState* ValidationState;
+  QPointer<QState> ProcessingState;
+  QPointer<QState> ValidationState;
 
   ctkWorkflowIntrastepTransition* ValidationTransition;
   ctkWorkflowIntrastepTransition* ValidationFailedTransition;

+ 4 - 4
Libs/Core/ctkWorkflow_p.h

@@ -17,7 +17,7 @@
   limitations under the License.
 
 =========================================================================*/
- 
+
 #ifndef __ctkWorkflow_p_h
 #define __ctkWorkflow_p_h
 
@@ -155,7 +155,7 @@ public:
   /// and validationFailedtransition transition.
   ///
   /// \return True or False indicating whether the method was successful.
-  void addStep(ctkWorkflowStep* step);
+  bool addStep(ctkWorkflowStep* step);
 
   /// \brief Returns whether a transition has been previously added with the same origin,
   /// destination and directionality
@@ -250,7 +250,7 @@ public slots:
 
   /// \brief Workflow processing executed after a step's onEntry function is run.
   void processingAfterOnEntry();
-  
+
   /// \brief Workflow processing executed after a step's onExit function is run.
   void processingAfterOnExit();
 
@@ -267,7 +267,7 @@ public:
   typedef QList<ctkWorkflowStep*>                          StepListType;
 
   // Register a list of pointers to the steps in the worflow for cleaning purpose
-  StepListType registeredSteps;
+  StepListType RegisteredSteps;
 
   // Maintain a map of <state, step> key/value pairs, to find the step
   // that a given state belongs to

+ 3 - 3
Libs/Widgets/Testing/Cpp/ctkExampleDerivedWorkflowWidgetStep.cpp

@@ -68,8 +68,8 @@ ctkExampleDerivedWorkflowWidgetStepPrivate::ctkExampleDerivedWorkflowWidgetStepP
 // ctkExampleDerivedWorkflowWidgetStep methods
 
 //-----------------------------------------------------------------------------
-ctkExampleDerivedWorkflowWidgetStep::ctkExampleDerivedWorkflowWidgetStep(ctkWorkflow* newWorkflow, const QString& newId) :
-  Superclass(newWorkflow, newId)
+ctkExampleDerivedWorkflowWidgetStep::ctkExampleDerivedWorkflowWidgetStep(const QString& newId) :
+  Superclass(newId)
   , d_ptr(new ctkExampleDerivedWorkflowWidgetStepPrivate)
 {
 }
@@ -183,7 +183,7 @@ void ctkExampleDerivedWorkflowWidgetStep::validate(const QString& desiredBranchI
     this->setStatusText("");
     retVal = true;
     }
- 
+
   // return the validation results
   this->validationComplete(retVal, desiredBranchId);
 }

+ 2 - 2
Libs/Widgets/Testing/Cpp/ctkExampleDerivedWorkflowWidgetStep.h

@@ -42,9 +42,9 @@ class ctkExampleDerivedWorkflowWidgetStep : public ctkWorkflowWidgetStep
   Q_OBJECT
 public:
   typedef ctkWorkflowWidgetStep Superclass;
-  explicit ctkExampleDerivedWorkflowWidgetStep(ctkWorkflow* newWorkflow, const QString& newId);
+  explicit ctkExampleDerivedWorkflowWidgetStep(const QString& newId);
   virtual ~ctkExampleDerivedWorkflowWidgetStep();
- 
+
   ///
   /// Set/get the label on this step's user interface
   QLabel* label()const;

+ 4 - 4
Libs/Widgets/Testing/Cpp/ctkExampleUseOfWorkflowWidgetUsingDerivedSteps.cpp

@@ -62,21 +62,21 @@ int ctkExampleUseOfWorkflowWidgetUsingDerivedSteps ( int argc, char * argv [] )
   groupBox->setHideWidgetsOfNonCurrentSteps(hideWidgets);
 
   // create and add the first workflow step
-  ctkExampleDerivedWorkflowWidgetStep* testStep1 = new ctkExampleDerivedWorkflowWidgetStep(workflow, "Step 1");
+  ctkExampleDerivedWorkflowWidgetStep* testStep1 = new ctkExampleDerivedWorkflowWidgetStep("Step 1");
   testStep1->setName("Step 1");
   testStep1->setDescription("I am in step 1");
   // can specify the name of the tab
   workflowWidget->associateStepWithLabel(testStep1, "name 1");
 
   // create and add the second workflow step
-  ctkExampleDerivedWorkflowWidgetStep* testStep2 = new ctkExampleDerivedWorkflowWidgetStep(workflow, "Step 2");
+  ctkExampleDerivedWorkflowWidgetStep* testStep2 = new ctkExampleDerivedWorkflowWidgetStep("Step 2");
   testStep2->setName("Step 2");
   testStep2->setDescription("I am in step 2");
   // a new tab is automatically created
   workflowWidget->associateStepWithLabel(testStep2, "name 2");
 
   // create and add a third workflow step
-  ctkExampleDerivedWorkflowWidgetStep* testStep3 = new ctkExampleDerivedWorkflowWidgetStep(workflow, "Step 3");
+  ctkExampleDerivedWorkflowWidgetStep* testStep3 = new ctkExampleDerivedWorkflowWidgetStep("Step 3");
   testStep3->setName("Step 3");
   testStep3->setDescription("I am in step 3");
   // can place a step on a tab that was previously created by
@@ -116,7 +116,7 @@ int ctkExampleUseOfWorkflowWidgetUsingDerivedSteps ( int argc, char * argv [] )
   workflow->stop();
   QTimer::singleShot(100, &app, SLOT(quit()));
   app.exec();
-  
+
   // handles deletion of the workflowWidget, workflow, steps, states
   // and transitions
   delete workflowWidget;

+ 5 - 5
Libs/Widgets/Testing/Cpp/ctkExampleUseOfWorkflowWidgetUsingSignalsAndSlots.cpp

@@ -65,21 +65,21 @@ int ctkExampleUseOfWorkflowWidgetUsingSignalsAndSlots(int argc, char * argv [] )
   groupBox->setHideWidgetsOfNonCurrentSteps(hideWidgets);
 
   // create and add the first workflow step
-  ctkWorkflowWidgetStep* testStep1 = new ctkWorkflowWidgetStep(workflow, "Step 1");
+  ctkWorkflowWidgetStep* testStep1 = new ctkWorkflowWidgetStep("Step 1");
   testStep1->setName("Step 1");
   testStep1->setDescription("I am in step 1");
   // can specify the name of the tab
   workflowWidget->associateStepWithLabel(testStep1, "name 1");
 
   // create and add the second workflow step
-  ctkWorkflowWidgetStep* testStep2 = new ctkWorkflowWidgetStep(workflow, "Step 2");
+  ctkWorkflowWidgetStep* testStep2 = new ctkWorkflowWidgetStep("Step 2");
   testStep2->setName("Step 2");
   testStep2->setDescription("I am in step 2");
   // a new tab is automatically created
   workflowWidget->associateStepWithLabel(testStep2, "name 2");
 
   // create and add a third workflow step
-  ctkWorkflowWidgetStep* testStep3 = new ctkWorkflowWidgetStep(workflow, "Step 3");
+  ctkWorkflowWidgetStep* testStep3 = new ctkWorkflowWidgetStep("Step 3");
   testStep3->setName("Step 3");
   testStep3->setDescription("I am in step 3");
   // can place a step on a tab that was previously created by
@@ -158,7 +158,7 @@ int ctkExampleUseOfWorkflowWidgetUsingSignalsAndSlots(int argc, char * argv [] )
   // 2) change step 2's value to something invalid (ex. 0)
   // 3) "Back" to step 1
   // 4) "finish" - attempts to go to step 3, but leaves you in step 2
-  
+
   // start the workflow
   workflow->start();
   workflowWidget->show();
@@ -171,7 +171,7 @@ int ctkExampleUseOfWorkflowWidgetUsingSignalsAndSlots(int argc, char * argv [] )
   workflow->stop();
   QTimer::singleShot(100, &app, SLOT(quit()));
   app.exec();
-  
+
   // handles deletion of the workflowWidget, workflow, steps, states
   // and transitions
   delete workflowWidget;

+ 63 - 16
Libs/Widgets/Testing/Cpp/ctkWorkflowWidgetTest1.cpp

@@ -20,14 +20,15 @@
 
 // QT includes
 #include <QApplication>
-#include <QTimer>
-#include <QPushButton>
+#include <QDebug>
+#include <QIcon>
 #include <QLabel>
 #include <QLineEdit>
 #include <QList>
-#include <QIcon>
+#include <QPushButton>
+#include <QSignalSpy>
 #include <QStyle>
-#include <QDebug>
+#include <QTimer>
 
 // CTK includes
 #include "ctkWorkflow.h"
@@ -72,7 +73,7 @@ bool buttonClickTest(QApplication& app, int defaultTime, ctkWorkflowWidgetStep*
   // TODO finish buttons
   if ((workflow->canGoBackward() != backButton->isEnabled()) || (workflow->canGoForward() != nextButton->isEnabled()) || (shownLineEdit && !shownLineEdit->isEnabled()))
     {
-    std::cerr << "Incorrect widget visibility - the buttons are incorrectly enabled" << std::endl;    
+    std::cerr << "Incorrect widget visibility - the buttons are incorrectly enabled" << std::endl;
     return false;
     }
 
@@ -226,7 +227,7 @@ int userInteractionSimulator1(QApplication& app, ctkExampleDerivedWorkflowWidget
   // step2        back         *             step1
   // step1        next         * (empty)     step1
   // step1        next                       step2
-  
+
   tests << new derivedTestData(nextButton, step1, step2, step1, "1")
         << new derivedTestData(nextButton, step2, step1, step1, "100")
         << new derivedTestData(backButton, step1, step2)
@@ -421,7 +422,7 @@ int userInteractionSimulator2(QApplication& app, ctkExampleDerivedWorkflowWidget
 //   //   return EXIT_FAILURE;
 //   //   }
 
-//   // we should be in the first step     
+//   // we should be in the first step
 //   if (!buttonClickTest(app, defaultTime, step1, step2, workflow, workflowWidget, backButton, nextButton, finishButton1, finishButton2)) {return EXIT_FAILURE;}
 
 //   // tests with good input, so that we can get all of the buttons
@@ -458,7 +459,7 @@ int userInteractionSimulator2(QApplication& app, ctkExampleDerivedWorkflowWidget
 //   //   return EXIT_FAILURE;
 //   //   }
 //   if (!buttonClickTest(app, defaultTime, step2, step1, workflow, workflowWidget, backButton, nextButton, finishButton1, finishButton2)) {return EXIT_FAILURE;}
-  
+
 //   nextButton->click();
 //   QTimer::singleShot(defaultTime, &app, SLOT(quit()));
 //   app.exec();
@@ -520,7 +521,7 @@ int userInteractionSimulator2(QApplication& app, ctkExampleDerivedWorkflowWidget
 
 //   finishButton2->click();
 //   if (!buttonClickTest(app, defaultTime, step1, step2, workflow, workflowWidget, backButton, nextButton, finishButton1, finishButton2)) {return EXIT_FAILURE;}
-  
+
 //   nextButton->click();
 //   if (!buttonClickTest(app, defaultTime, step2, step1, workflow, workflowWidget, backButton, nextButton, finishButton1, finishButton2)) {return EXIT_FAILURE;}
 
@@ -540,7 +541,7 @@ int runWorkflowWidgetTest(ctkWorkflowWidget* workflowWidget, QApplication& app,
 
   // create and add the first workflow step (depends on workflowWidget
   // type)
-  ctkExampleDerivedWorkflowWidgetStep* step1 = new ctkExampleDerivedWorkflowWidgetStep(workflow, "Step 1");
+  ctkExampleDerivedWorkflowWidgetStep* step1 = new ctkExampleDerivedWorkflowWidgetStep("Step 1");
   step1->setName("Step 1");
   step1->setDescription("I am in step 1");
   if (ctkWorkflowTabWidget* tabWidget = qobject_cast<ctkWorkflowTabWidget*>(workflowWidget))
@@ -553,7 +554,7 @@ int runWorkflowWidgetTest(ctkWorkflowWidget* workflowWidget, QApplication& app,
 
   // create and add the second workflow step (depends on
   // workflowWidget type)
-  ctkExampleDerivedWorkflowWidgetStep* step2 = new ctkExampleDerivedWorkflowWidgetStep(workflow, "Step 2");
+  ctkExampleDerivedWorkflowWidgetStep* step2 = new ctkExampleDerivedWorkflowWidgetStep("Step 2");
   step2->setName("Step 2");
   step2->setDescription("I am in step 2");
   if (ctkWorkflowTabWidget* tabWidget = qobject_cast<ctkWorkflowTabWidget*>(workflowWidget))
@@ -561,13 +562,59 @@ int runWorkflowWidgetTest(ctkWorkflowWidget* workflowWidget, QApplication& app,
     tabWidget->associateStepWithLabel(step2, "tab2");
     }
 
+  int expectedStepCount = 0;
+  int currentStepCount = workflow->steps().count();
+  if (currentStepCount != expectedStepCount)
+    {
+    std::cerr << "Line " << __LINE__ << " - Problem with steps()\n"
+              << "\tcurrentStepCount: " << currentStepCount << "\n"
+              << "\texpectedStepCount:" << expectedStepCount << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  QSignalSpy signalSpyStepRegistered(workflow, SIGNAL(stepRegistered(ctkWorkflowStep*)));
+
   // add the steps to the workflow
   workflow->addTransition(step1, step2);
 
+  expectedStepCount = 2;
+  currentStepCount = workflow->steps().count();
+  if (currentStepCount != expectedStepCount)
+    {
+    std::cerr << "Line " << __LINE__ << " - Problem with steps()\n"
+              << "\tcurrentStepCount: " << currentStepCount << "\n"
+              << "\texpectedStepCount:" << expectedStepCount << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  int expectedSignalStepRegisteredCount = 2;
+  int currentSignalStepRegisteredCount = signalSpyStepRegistered.count();
+  if (currentSignalStepRegisteredCount != expectedSignalStepRegisteredCount)
+    {
+    std::cerr << "Line " << __LINE__ << " - Problem with 'stepRegistered' signal\n"
+              << "\tcurrentSignalStepRegisteredCount: " << currentSignalStepRegisteredCount << "\n"
+              << "\texpectedSignalStepRegisteredCount:" << expectedSignalStepRegisteredCount << std::endl;
+    return EXIT_FAILURE;
+    }
+
   // start the workflow
   workflow->start();
   workflowWidget->show();
 
+  // Attempt to add step to a different workflow
+  ctkWorkflow* workflow2 = new ctkWorkflow;
+  workflow2->addTransition(step1, step2);
+
+  expectedStepCount = 0;
+  currentStepCount = workflow2->steps().count();
+  if (currentStepCount != expectedStepCount)
+    {
+    std::cerr << "Line " << __LINE__ << " - Problem with steps()\n"
+              << "\tcurrentStepCount: " << currentStepCount << "\n"
+              << "\texpectedStepCount:" << expectedStepCount << std::endl;
+    return EXIT_FAILURE;
+    }
+
   // first user interaction test
   if (userInteractionSimulator1(app, step1, step2, workflow, workflowWidget, defaultTime) == EXIT_FAILURE)
     {
@@ -581,7 +628,7 @@ int runWorkflowWidgetTest(ctkWorkflowWidget* workflowWidget, QApplication& app,
 
   // create and add a third workflow step (depends on workflowWidget
   // type)
-  ctkExampleDerivedWorkflowWidgetStep* step3 = new ctkExampleDerivedWorkflowWidgetStep(workflow, "Step 3");
+  ctkExampleDerivedWorkflowWidgetStep* step3 = new ctkExampleDerivedWorkflowWidgetStep("Step 3");
   step3->setName("Step 3");
   step3->setDescription("I am in step 3");
   if (ctkWorkflowStackedWidget* stackedWidget = qobject_cast<ctkWorkflowStackedWidget*>(workflowWidget))
@@ -597,7 +644,7 @@ int runWorkflowWidgetTest(ctkWorkflowWidget* workflowWidget, QApplication& app,
   step3->setIcon(step3->stepArea()->style()->standardIcon(QStyle::SP_ArrowUp));
 
   workflow->addTransition(step2, step3);
-  
+
   // restart the workflow
   workflow->start();
 
@@ -620,7 +667,7 @@ int runWorkflowWidgetTest(ctkWorkflowWidget* workflowWidget, QApplication& app,
 //   step2->setFinishStepsToHaveButtonsInStepArea(finishSteps);
 //   step3->setFinishStepsToHaveButtonsInStepArea(finishSteps);
 // //  workflow->addFinishStep(step2);
-  
+
   // // restart the workflow
   // workflow->start();
   // QTimer::singleShot(defaultTime, &app, SLOT(quit()));
@@ -658,7 +705,7 @@ int ctkWorkflowWidgetTest1(int argc, char * argv [] )
   if (runWorkflowWidgetTest(new ctkWorkflowStackedWidget, app, hideWidgets, defaultTime) == EXIT_FAILURE)
     {
     return EXIT_FAILURE;
-    }                                                                   
+    }
   if (runWorkflowWidgetTest(new ctkWorkflowTabWidget, app, hideWidgets, defaultTime) == EXIT_FAILURE)
     {
     return EXIT_FAILURE;
@@ -672,7 +719,7 @@ int ctkWorkflowWidgetTest1(int argc, char * argv [] )
   if (runWorkflowWidgetTest(new ctkWorkflowStackedWidget, app, hideWidgets, defaultTime) == EXIT_FAILURE)
     {
     return EXIT_FAILURE;
-    }                                                                   
+    }
   if (runWorkflowWidgetTest(new ctkWorkflowTabWidget, app, hideWidgets, defaultTime) == EXIT_FAILURE)
     {
     return EXIT_FAILURE;

+ 11 - 11
Libs/Widgets/Testing/Cpp/ctkWorkflowWidgetTest2.cpp

@@ -67,12 +67,12 @@ bool buttonClickTestSignalSlot(QApplication& app, int defaultTime, ctkWorkflowWi
     std::cerr << "Incorrect widget visibility - the current step's widgets are invisible" << std::endl;
     return false;
     }
- 
+
   // ensure that buttons are appropriately enabled
   // TODO finish buttons
   if ((workflow->canGoBackward() != backButton->isEnabled()) || (workflow->canGoForward() != nextButton->isEnabled()) || (shownLineEdit && !shownLineEdit->isEnabled()))
     {
-    std::cerr << "Incorrect widget visibility - the buttons are incorrectly enabled" << std::endl;    
+    std::cerr << "Incorrect widget visibility - the buttons are incorrectly enabled" << std::endl;
     return false;
     }
 
@@ -442,7 +442,7 @@ int userInteractionSimulator2(QApplication& app, ctkWorkflowWidgetStep* step1, c
 //     return EXIT_FAILURE;
 //     }
 
-//   // we should be in the first step     
+//   // we should be in the first step
 //   if (!buttonClickTestSignalSlot(app, defaultTime, step1, qObject1, step2, qObject2, workflow, workflowWidget, step1BackButton, step1NextButton, step2BackButton, step2NextButton, step1FinishButton1, step2FinishButton1, step1FinishButton2, step2FinishButton2)) {return EXIT_FAILURE;}
 
 //   // tests with good input, so that we can get all of the buttons
@@ -475,7 +475,7 @@ int userInteractionSimulator2(QApplication& app, ctkWorkflowWidgetStep* step1, c
 //     return EXIT_FAILURE;
 //     }
 //   if (!buttonClickTestSignalSlot(app, defaultTime, step2, qObject2, step1, qObject1, workflow, workflowWidget, step2BackButton, step2NextButton, step1BackButton, step1NextButton, step2FinishButton1, step1FinishButton1, step2FinishButton2, step1FinishButton2)) {return EXIT_FAILURE;}
-  
+
 //   step2NextButton->click();
 //   QTimer::singleShot(defaultTime, &app, SLOT(quit()));
 //   app.exec();
@@ -534,7 +534,7 @@ int userInteractionSimulator2(QApplication& app, ctkWorkflowWidgetStep* step1, c
 
 //   step1FinishButton2->click();
 //   if (!buttonClickTestSignalSlot(app, defaultTime, step1, qObject1, step2, qObject2, workflow, workflowWidget, step1BackButton, step1NextButton, step2BackButton, step2BackButton, step1FinishButton1, step2FinishButton1, step1FinishButton2, step2FinishButton2)) {return EXIT_FAILURE;}
-  
+
 //   step1NextButton->click();
 //   if (!buttonClickTestSignalSlot(app, defaultTime, step2, qObject2, step1, qObject1, workflow, workflowWidget, step2BackButton, step2NextButton, step1BackButton, step1BackButton, step2FinishButton1, step1FinishButton1, step2FinishButton2, step1FinishButton2)) {return EXIT_FAILURE;}
 
@@ -559,20 +559,20 @@ int ctkWorkflowWidgetTest2(int argc, char * argv [] )
 
   // create and add the first workflow step (depends on workflowWidget
   // type)
-  ctkWorkflowWidgetStep* step1 = new ctkWorkflowWidgetStep(workflow, "Step 1");
+  ctkWorkflowWidgetStep* step1 = new ctkWorkflowWidgetStep("Step 1");
   step1->setName("Step 1");
   step1->setDescription("I am in step 1");
   if (ctkWorkflowTabWidget* tabWidget = qobject_cast<ctkWorkflowTabWidget*>(workflowWidget))
     {
     tabWidget->associateStepWithLabel(step1, "tab1");
     }
-  
+
   // step1 is the initial step
   workflow->setInitialStep(step1);
 
   // create and add the second workflow step (depends on
   // workflowWidget type)
-  ctkWorkflowWidgetStep* step2 = new ctkWorkflowWidgetStep(workflow, "Step 2");
+  ctkWorkflowWidgetStep* step2 = new ctkWorkflowWidgetStep("Step 2");
   step2->setName("Step 2");
   step2->setDescription("I am in step 2");
   if (ctkWorkflowTabWidget* tabWidget = qobject_cast<ctkWorkflowTabWidget*>(workflowWidget))
@@ -655,7 +655,7 @@ int ctkWorkflowWidgetTest2(int argc, char * argv [] )
 
   // create and add a third workflow step (depends on workflowWidget
   // type)
-  ctkWorkflowWidgetStep* step3 = new ctkWorkflowWidgetStep(workflow, "Step 3");
+  ctkWorkflowWidgetStep* step3 = new ctkWorkflowWidgetStep("Step 3");
   step3->setName("Step 3");
   step3->setDescription("I am in step 3");
   if (ctkWorkflowStackedWidget* stackedWidget = qobject_cast<ctkWorkflowStackedWidget*>(workflowWidget))
@@ -722,7 +722,7 @@ int ctkWorkflowWidgetTest2(int argc, char * argv [] )
 //   step2->setFinishStepsToHaveButtonsInStepArea(finishSteps);
 //   step3->setFinishStepsToHaveButtonsInStepArea(finishSteps);
 // //  workflow->addFinishStep(step2);
-  
+
   // // restart the workflow
   // workflow->start();
   // QTimer::singleShot(defaultTime, &app, SLOT(quit()));
@@ -738,7 +738,7 @@ int ctkWorkflowWidgetTest2(int argc, char * argv [] )
   // workflow->stop();
   // QTimer::singleShot(defaultTime, &app, SLOT(quit()));
   // app.exec();
-  
+
   // handles deletion of the workflowWidget, workflow, steps, states
   // and transitions
   delete workflowWidget;

+ 25 - 3
Libs/Widgets/ctkWorkflowWidget.cpp

@@ -79,7 +79,7 @@ ctkWorkflowWidgetPrivate::~ctkWorkflowWidgetPrivate()
 ctkWorkflowWidget::ctkWorkflowWidget(QWidget* _parent) : Superclass(_parent)
   , d_ptr(new ctkWorkflowWidgetPrivate)
 {
-  Q_D(ctkWorkflowWidget); 
+  Q_D(ctkWorkflowWidget);
   d->WorkflowGroupBox = new ctkWorkflowGroupBox(this);
   d->ButtonBoxWidget = new ctkWorkflowButtonBoxWidget();
 }
@@ -110,11 +110,21 @@ void ctkWorkflowWidget::setWorkflow(ctkWorkflow* newWorkflow)
   if (d->Workflow)
     {
     QObject::disconnect(d->Workflow, SIGNAL(currentStepChanged(ctkWorkflowStep*)), this, SLOT(onCurrentStepChanged(ctkWorkflowStep)));
+    QObject::disconnect(d->Workflow, SIGNAL(stepRegistered(ctkWorkflowStep*)), this, SLOT(onStepRegistered(ctkWorkflowStep)));
     }
 
   d->Workflow = newWorkflow;
 
+  if (d->Workflow)
+    {
+    foreach(ctkWorkflowStep* step, d->Workflow->steps())
+      {
+      this->onStepRegistered(step);
+      }
+    }
+
   QObject::connect(newWorkflow, SIGNAL(currentStepChanged(ctkWorkflowStep*)), this, SLOT(onCurrentStepChanged(ctkWorkflowStep*)));
+  QObject::connect(newWorkflow, SIGNAL(stepRegistered(ctkWorkflowStep*)), this, SLOT(onStepRegistered(ctkWorkflowStep*)));
 
   d->ButtonBoxWidget->setWorkflow(newWorkflow);
 }
@@ -130,6 +140,18 @@ void ctkWorkflowWidget::onCurrentStepChanged(ctkWorkflowStep* currentStep)
 }
 
 // --------------------------------------------------------------------------
+void ctkWorkflowWidget::onStepRegistered(ctkWorkflowStep* step)
+{
+  if (step->isWidgetType())
+    {
+    QWidget * widget = dynamic_cast<QWidget*>(step);
+    Q_ASSERT(widget);
+    widget->setParent(this);
+    widget->setVisible(false);
+    }
+}
+
+// --------------------------------------------------------------------------
 void ctkWorkflowWidget::updateStepUI(ctkWorkflowStep* currentStep)
 {
   Q_D(ctkWorkflowWidget);
@@ -147,7 +169,7 @@ void ctkWorkflowWidget::updateStepUI(ctkWorkflowStep* currentStep)
       {
       layout->addWidget(d->ButtonBoxWidget);
       }
-      
+
     layout->setContentsMargins(0,0,0,0);
     }
 
@@ -159,7 +181,7 @@ void ctkWorkflowWidget::updateButtonBoxUI(ctkWorkflowStep* currentStep)
 {
   Q_D(ctkWorkflowWidget);
   Q_ASSERT(currentStep);
-  
+
   // Update the button box widget if we want to show it
   if (d->ShowButtonBoxWidget)
     {

+ 5 - 2
Libs/Widgets/ctkWorkflowWidget.h

@@ -23,7 +23,7 @@
 
 // Qt includes
 #include <QWidget>
-class QPushButton; 
+class QPushButton;
 class QGroupBox;
 #include <QBoxLayout>
 
@@ -70,6 +70,9 @@ public slots:
   /// step has changed.
   virtual void onCurrentStepChanged(ctkWorkflowStep* currentStep);
 
+protected slots:
+  void onStepRegistered(ctkWorkflowStep* step);
+
 protected:
 
   // Triggers updates of the workflowGroupBox when the current workflow step has changed.
@@ -77,7 +80,7 @@ protected:
 
   // Triggers updates of the buttonBoxWidget when the current workflow step has changed.
   void updateButtonBoxUI(ctkWorkflowStep* currentStep);
- 
+
 protected:
   QScopedPointer<ctkWorkflowWidgetPrivate> d_ptr;
 

+ 9 - 5
Libs/Widgets/ctkWorkflowWidgetStep.cpp

@@ -43,6 +43,7 @@ static ctkLogger logger("org.commontk.libs.widgets.ctkWorkflowWidgetStep");
 ctkWorkflowWidgetStepPrivate::ctkWorkflowWidgetStepPrivate(ctkWorkflowWidgetStep& object)
   :Superclass(object), q_ptr(&object)
 {
+  this->WidgetType = true;
 //  this->buttonBoxWidget = 0;
 //  this->hasButtonBoxWidget = false;
 
@@ -51,6 +52,11 @@ ctkWorkflowWidgetStepPrivate::ctkWorkflowWidgetStepPrivate(ctkWorkflowWidgetStep
 }
 
 //-----------------------------------------------------------------------------
+ctkWorkflowWidgetStepPrivate::~ctkWorkflowWidgetStepPrivate()
+{
+}
+
+//-----------------------------------------------------------------------------
 void ctkWorkflowWidgetStepPrivate::invokeShowUserInterfaceCommandInternal()const
 {
   emit invokeShowUserInterfaceCommand();
@@ -87,7 +93,7 @@ void ctkWorkflowWidgetStepPrivate::createUserInterfaceCompleteInternal()const
 //-----------------------------------------------------------------------------
 ctkWorkflowWidgetStep::ctkWorkflowWidgetStep(QWidget* newParent) :
   QWidget(newParent),
-  ctkWorkflowStep(new ctkWorkflowWidgetStepPrivate(*this), 0, QString())
+  ctkWorkflowStep(new ctkWorkflowWidgetStepPrivate(*this), QString())
 {
   Q_D(ctkWorkflowWidgetStep);
   d->hasShowUserInterfaceCommand = false;
@@ -96,11 +102,9 @@ ctkWorkflowWidgetStep::ctkWorkflowWidgetStep(QWidget* newParent) :
 }
 
 //-----------------------------------------------------------------------------
-ctkWorkflowWidgetStep::ctkWorkflowWidgetStep(ctkWorkflow* newWorkflow,
-                                                             const QString& newId,
-                                                             QWidget* newParent) :
+ctkWorkflowWidgetStep::ctkWorkflowWidgetStep(const QString& newId, QWidget* newParent) :
   QWidget(newParent),
-  ctkWorkflowStep(new ctkWorkflowWidgetStepPrivate(*this), newWorkflow, newId)
+  ctkWorkflowStep(new ctkWorkflowWidgetStepPrivate(*this), newId)
 {
   Q_D(ctkWorkflowWidgetStep);
   d->hasShowUserInterfaceCommand = false;

+ 1 - 2
Libs/Widgets/ctkWorkflowWidgetStep.h

@@ -78,8 +78,7 @@ public:
   Q_DECLARE_FLAGS(ButtonBoxHints, ButtonBoxHint)
 
   explicit ctkWorkflowWidgetStep(QWidget* newParent = 0);
-  explicit ctkWorkflowWidgetStep(ctkWorkflow* newWorkflow, const QString& newId,
-                                 QWidget* newParent = 0);
+  explicit ctkWorkflowWidgetStep(const QString& newId, QWidget* newParent = 0);
   virtual ~ctkWorkflowWidgetStep();
 
   /// \brief Override the back button text of any ctkWorkflowButtonBox when this step

+ 2 - 2
Libs/Widgets/ctkWorkflowWidgetStep_p.h

@@ -37,10 +37,10 @@ class ctkWorkflowWidgetStepPrivate : public ctkWorkflowStepPrivate
   Q_DECLARE_PUBLIC(ctkWorkflowWidgetStep);
 protected:
   ctkWorkflowWidgetStep* q_ptr;
-  
+
 public:
   ctkWorkflowWidgetStepPrivate(ctkWorkflowWidgetStep& object);
-  ~ctkWorkflowWidgetStepPrivate(){}
+  ~ctkWorkflowWidgetStepPrivate();
   typedef ctkWorkflowStepPrivate Superclass;
 
 protected: