Browse Source

Merge branches 'ctkWorkflow-python-wrapping', 'ctkWorkflowGroupBox-resize-issue' and 'ctkWorkflow-backward-forwads-crash'

* ctkWorkflow-python-wrapping:
  Combines ctkWorkflowAbstractWidgetStep and ctkWorkflowWidgetStep classes
  ctkWorkflowStep - setId() and id() are public and exposed in python
  ctkWorkflowWidgetStep - Renamed property 'id' into 'stepid'
  ctkWorkflow - In not set, InitialStep default to the first added step
  ctk/__init__.py.in - Decorates ctkWorkflowStep and ctkWorkflowWidgetStep
  ctkWorkflowAbstractWidgetStepPrivate derives from ctkWorkflowStepPrivate
  ctkWorkflowTransition - Use Q_ENUMS to expose InterstepTransitionType to python
  ctkWorkflow - Use Q_INVOKABLE to expose method to python
  ctkWorkflow - Added associated PythonQt decorator
  ctkWorkflowAbstractWidgetStep - has{Show, Create}UICommand are boolean
  ctkWorkflow - evaluateValidationResults and processingAfterOnEntry connected by default
  ctkWorkflowWidget - Use Q_PROPERTY and Q_INVOKABLE to expose method to python

* ctkWorkflowGroupBox-resize-issue:
  ctkWorkflowGroupBox - Use ctkDynamicSpacer::setActive

* ctkWorkflow-backward-forwads-crash:
  ctkWorkflow - No backward/forward steps are associated with step not added in workflow
  Combines ctkWorkflowAbstractWidgetStep and ctkWorkflowWidgetStep classes
  ctkWorkflowStep - setId() and id() are public and exposed in python
  ctkWorkflowWidgetStep - Renamed property 'id' into 'stepid'
  ctkWorkflow - In not set, InitialStep default to the first added step
  ctk/__init__.py.in - Decorates ctkWorkflowStep and ctkWorkflowWidgetStep
  ctkWorkflowAbstractWidgetStepPrivate derives from ctkWorkflowStepPrivate
  ctkWorkflowTransition - Use Q_ENUMS to expose InterstepTransitionType to python
  ctkWorkflow - Use Q_INVOKABLE to expose method to python
  ctkWorkflow - Added associated PythonQt decorator
  ctkWorkflowAbstractWidgetStep - has{Show, Create}UICommand are boolean
  ctkWorkflow - evaluateValidationResults and processingAfterOnEntry connected by default
  ctkWorkflowWidget - Use Q_PROPERTY and Q_INVOKABLE to expose method to python
Jean-Christophe Fillion-Robin 14 years ago
parent
commit
88b78b8447
31 changed files with 1286 additions and 978 deletions
  1. 5 5
      Applications/ctkSimplePythonShell/ctkSimplePythonQtDecorators.h
  2. 19 0
      Libs/Core/CMakeLists.txt
  3. 21 5
      Libs/Core/Testing/Cpp/ctkExampleWorkflowStepUsingSignalsAndSlots.cpp
  4. 2 1
      Libs/Core/Testing/Cpp/ctkExampleWorkflowStepUsingSignalsAndSlots.h
  5. 20 2
      Libs/Core/Testing/Cpp/ctkWorkflowTest1.cpp
  6. 37 28
      Libs/Core/Testing/Cpp/ctkWorkflowTest2.cpp
  7. 161 0
      Libs/Core/ctkCorePythonQtDecorators.h
  8. 112 347
      Libs/Core/ctkWorkflow.cpp
  9. 23 34
      Libs/Core/ctkWorkflow.h
  10. 32 9
      Libs/Core/ctkWorkflowStep.cpp
  11. 16 10
      Libs/Core/ctkWorkflowStep.h
  12. 4 1
      Libs/Core/ctkWorkflowStep_p.h
  13. 1 0
      Libs/Core/ctkWorkflowTransitions.h
  14. 291 0
      Libs/Core/ctkWorkflow_p.h
  15. 89 2
      Libs/Scripting/Python/Core/Python/ctk/__init__.py.in
  16. 21 4
      Libs/Widgets/CMakeLists.txt
  17. 4 1
      Libs/Widgets/Resources/UI/ctkWorkflowGroupBox.ui
  18. 12 18
      Libs/Widgets/Testing/Cpp/ctkExampleUseOfWorkflowWidgetUsingSignalsAndSlots.cpp
  19. 16 4
      Libs/Widgets/Testing/Cpp/ctkExampleWorkflowWidgetStepUsingSignalsAndSlots.cpp
  20. 2 1
      Libs/Widgets/Testing/Cpp/ctkExampleWorkflowWidgetStepUsingSignalsAndSlots.h
  21. 1 1
      Libs/Widgets/Testing/Cpp/ctkWorkflowWidgetTest1.cpp
  22. 39 28
      Libs/Widgets/Testing/Cpp/ctkWorkflowWidgetTest2.cpp
  23. 70 0
      Libs/Widgets/ctkWidgetsPythonQtDecorators.h
  24. 0 223
      Libs/Widgets/ctkWorkflowAbstractWidgetStep.cpp
  25. 0 155
      Libs/Widgets/ctkWorkflowAbstractWidgetStep.h
  26. 10 10
      Libs/Widgets/ctkWorkflowButtonBoxWidget.cpp
  27. 3 3
      Libs/Widgets/ctkWorkflowGroupBox.cpp
  28. 4 4
      Libs/Widgets/ctkWorkflowWidget.h
  29. 155 24
      Libs/Widgets/ctkWorkflowWidgetStep.cpp
  30. 104 45
      Libs/Widgets/ctkWorkflowWidgetStep.h
  31. 12 13
      Libs/Widgets/ctkWorkflowAbstractWidgetStep_p.h

+ 5 - 5
Applications/ctkSimplePythonShell/ctkSimplePythonQtDecorators.h

@@ -4,6 +4,9 @@
 
 // CTK includes
 #include <ctkAbstractPythonManager.h>
+#include <ctkCorePythonQtDecorators.h>
+#include <ctkWidgetsPythonQtDecorators.h>
+#include <PythonQt.h>
 
 // NOTE:
 //
@@ -21,11 +24,8 @@ public:
   ctkSimplePythonQtDecorators(ctkAbstractPythonManager* pythonManager)
     {
     Q_ASSERT(pythonManager);
-    //pythonManager->registerClassForPythonQt(&qSlicerCoreApplication::staticMetaObject);
-    //pythonManager->registerClassForPythonQt(&qSlicerModuleManager::staticMetaObject);
-    //pythonManager->registerClassForPythonQt(&qSlicerAbstractModule::staticMetaObject);
-    //pythonManager->registerClassForPythonQt(&qSlicerAbstractModuleWidget::staticMetaObject);
-    //pythonManager->registerCPPClassForPythonQt("qSlicerModuleFactoryManager");
+    pythonManager->registerPythonQtDecorator(new ctkCorePythonQtDecorators);
+    pythonManager->registerPythonQtDecorator(new ctkWidgetsPythonQtDecorators);
     }
 
 public slots:

+ 19 - 0
Libs/Core/CMakeLists.txt

@@ -46,6 +46,7 @@ SET(KIT_SRCS
   ctkUtils.h
   ctkWorkflow.h
   ctkWorkflow.cpp
+  ctkWorkflow_p.h
   ctkWorkflowStep.h
   ctkWorkflowStep.cpp
   ctkWorkflowStep_p.h
@@ -59,6 +60,17 @@ IF(CTK_HAVE_BFD)
     )
 ENDIF()
 
+IF(CTK_WRAP_PYTHONQT_LIGHT)
+  LIST(APPEND KIT_SRCS
+    ctkCorePythonQtDecorators.h
+    )
+  # Let's make sure the decorator are not wrapped !
+  SET_SOURCE_FILES_PROPERTIES(
+    ctkCorePythonQtDecorators.h
+    WRAP_EXCLUDE
+    )
+ENDIF()
+
 # Headers that should run through moc
 SET(KIT_MOC_SRCS
   ctkCommandLineParser.h
@@ -68,10 +80,17 @@ SET(KIT_MOC_SRCS
   ctkTransferFunction.h
   ctkTransferFunctionRepresentation.h
   ctkWorkflow.h
+  ctkWorkflow_p.h
   ctkWorkflowStep_p.h
   ctkWorkflowTransitions.h
   )
 
+IF(CTK_WRAP_PYTHONQT_LIGHT)
+  LIST(APPEND KIT_MOC_SRCS
+    ctkCorePythonQtDecorators.h
+    )
+ENDIF()
+
 # UI files
 SET(KIT_UI_FORMS
 )

+ 21 - 5
Libs/Core/Testing/Cpp/ctkExampleWorkflowStepUsingSignalsAndSlots.cpp

@@ -37,6 +37,8 @@ public:
   // and onExit() functions
   int numberOfTimesRanOnEntry;
   int numberOfTimesRanOnExit;
+
+  ctkWorkflowStep * Step;
 };
 
 //-----------------------------------------------------------------------------
@@ -47,15 +49,19 @@ ctkExampleWorkflowStepUsingSignalsAndSlotsPrivate::ctkExampleWorkflowStepUsingSi
 {
   this->numberOfTimesRanOnEntry = 0;
   this->numberOfTimesRanOnExit = 0;
+  this->Step = 0;
 }
 
 //-----------------------------------------------------------------------------
 // ctkExampleWorkflowStepUsingSignalsAndSlots methods
 
 //-----------------------------------------------------------------------------
-ctkExampleWorkflowStepUsingSignalsAndSlots::ctkExampleWorkflowStepUsingSignalsAndSlots(QObject* _parent) : Superclass(_parent)
+ctkExampleWorkflowStepUsingSignalsAndSlots::ctkExampleWorkflowStepUsingSignalsAndSlots(
+    ctkWorkflowStep * newStep, QObject* newParent) : Superclass(newParent)
   , d_ptr(new ctkExampleWorkflowStepUsingSignalsAndSlotsPrivate)
 {
+  Q_D(ctkExampleWorkflowStepUsingSignalsAndSlots);
+  d->Step = newStep;
 }
 
 //-----------------------------------------------------------------------------
@@ -66,15 +72,23 @@ ctkExampleWorkflowStepUsingSignalsAndSlots::~ctkExampleWorkflowStepUsingSignalsA
 //-----------------------------------------------------------------------------
 void ctkExampleWorkflowStepUsingSignalsAndSlots::validate(const QString& desiredBranchId)const
 {
+  Q_D(const ctkExampleWorkflowStepUsingSignalsAndSlots);
   // Always returns true in this simple example
-  emit validationComplete(true, desiredBranchId);
+
+  QObject::staticMetaObject.invokeMethod(
+      d->Step->ctkWorkflowStepQObject(), "validationComplete",
+      Q_ARG(bool, true), Q_ARG(QString, desiredBranchId));
 }
 
 //-----------------------------------------------------------------------------
 void ctkExampleWorkflowStepUsingSignalsAndSlots::validateFails()const
 {
+  Q_D(const ctkExampleWorkflowStepUsingSignalsAndSlots);
+
   // Always returns false in this simple example
-  emit validationComplete(false);
+  QObject::staticMetaObject.invokeMethod(
+      d->Step->ctkWorkflowStepQObject(), "validationComplete",
+      Q_ARG(bool, false));
 }
 
 //-----------------------------------------------------------------------------
@@ -89,7 +103,8 @@ void ctkExampleWorkflowStepUsingSignalsAndSlots::onEntry(const ctkWorkflowStep*
   d->numberOfTimesRanOnEntry++;
 
   // signals that we are finished
-  emit onEntryComplete();
+  QObject::staticMetaObject.invokeMethod(
+      d->Step->ctkWorkflowStepQObject(), "onEntryComplete");
 }
 
 //-----------------------------------------------------------------------------
@@ -104,7 +119,8 @@ void ctkExampleWorkflowStepUsingSignalsAndSlots::onExit(const ctkWorkflowStep* g
   d->numberOfTimesRanOnExit++;
 
   // signals that we are finished
-  emit onExitComplete();
+  QObject::staticMetaObject.invokeMethod(
+      d->Step->ctkWorkflowStepQObject(), "onExitComplete");
 }
 
 //-----------------------------------------------------------------------------

+ 2 - 1
Libs/Core/Testing/Cpp/ctkExampleWorkflowStepUsingSignalsAndSlots.h

@@ -74,7 +74,8 @@ class ctkExampleWorkflowStepUsingSignalsAndSlots : public QObject
 
 public:
   typedef QObject Superclass;
-  explicit ctkExampleWorkflowStepUsingSignalsAndSlots(QObject* parent = 0);
+  explicit ctkExampleWorkflowStepUsingSignalsAndSlots(ctkWorkflowStep * newStep,
+                                                      QObject* newParent = 0);
   virtual ~ctkExampleWorkflowStepUsingSignalsAndSlots();
 
   /// Get the values for the counters of the number of times we have

+ 20 - 2
Libs/Core/Testing/Cpp/ctkWorkflowTest1.cpp

@@ -267,13 +267,31 @@ int ctkWorkflowTest1(int argc, char * argv [] )
     }
 
   // --------------------------------------------------------------------------
-  // workflow with three steps
+  // Step3
 
-  // add a third step manually
   ctkExampleDerivedWorkflowStep *step3 = new ctkExampleDerivedWorkflowStep(workflow, "Step 3");
   step3->setName("Step 3");
   step3->setDescription("Description for step 3");
 
+  // --------------------------------------------------------------------------
+  // Attempt to retrieve the forward or backward steps of step not yet added to the workflow
+
+  if (workflow->forwardSteps(step3).count() != 0)
+    {
+    std::cerr << "No forward steps should be associated with step3";
+    return EXIT_FAILURE;
+    }
+
+  if (workflow->backwardSteps(step3).count() != 0)
+    {
+    std::cerr << "No backward steps should be associated with step3";
+    return EXIT_FAILURE;
+    }
+
+  // --------------------------------------------------------------------------
+  // workflow with three steps
+
+  // add a third step manually
   if (!workflow->addTransition(step2, step3, "", ctkWorkflow::Forward))
     {
     std::cerr << "could not add step 3 with forward transition";

+ 37 - 28
Libs/Core/Testing/Cpp/ctkWorkflowTest2.cpp

@@ -139,42 +139,51 @@ int ctkWorkflowTest2(int argc, char * argv [] )
 
   // create the qObjects that implement the required functions, and
   // communicate with the workflow using signals and slots
-  ctkExampleWorkflowStepUsingSignalsAndSlots* qObject1 = new ctkExampleWorkflowStepUsingSignalsAndSlots;
-  ctkExampleWorkflowStepUsingSignalsAndSlots* qObject2 = new ctkExampleWorkflowStepUsingSignalsAndSlots;
-  ctkExampleWorkflowStepUsingSignalsAndSlots* qObject3 = new ctkExampleWorkflowStepUsingSignalsAndSlots;
-  ctkExampleWorkflowStepUsingSignalsAndSlots* qObject4 = new ctkExampleWorkflowStepUsingSignalsAndSlots;
+  ctkExampleWorkflowStepUsingSignalsAndSlots* qObject1 = new ctkExampleWorkflowStepUsingSignalsAndSlots(step1);
+  ctkExampleWorkflowStepUsingSignalsAndSlots* qObject2 = new ctkExampleWorkflowStepUsingSignalsAndSlots(step2);
+  ctkExampleWorkflowStepUsingSignalsAndSlots* qObject3 = new ctkExampleWorkflowStepUsingSignalsAndSlots(step3);
+  ctkExampleWorkflowStepUsingSignalsAndSlots* qObject4 = new ctkExampleWorkflowStepUsingSignalsAndSlots(step4);
 
   // use the qObjects for validation
-  QObject::connect(step1->ctkWorkflowStepQObject(), SIGNAL(invokeValidateCommand(const QString&)), qObject1, SLOT(validate(const QString&)));
-  QObject::connect(qObject1, SIGNAL(validationComplete(bool, const QString&)), workflow, SLOT(evaluateValidationResults(bool, const QString&)));
-  QObject::connect(step2->ctkWorkflowStepQObject(), SIGNAL(invokeValidateCommand(const QString&)), qObject2, SLOT(validate(const QString&)));
-  QObject::connect(qObject2, SIGNAL(validationComplete(bool, const QString&)), workflow, SLOT(evaluateValidationResults(bool, const QString&)));
+  QObject::connect(step1->ctkWorkflowStepQObject(), SIGNAL(invokeValidateCommand(const QString&)),
+                   qObject1, SLOT(validate(const QString&)));
+  QObject::connect(step2->ctkWorkflowStepQObject(), SIGNAL(invokeValidateCommand(const QString&)),
+                   qObject2, SLOT(validate(const QString&)));
   // step 3's validation will always fail
-  QObject::connect(step3->ctkWorkflowStepQObject(), SIGNAL(invokeValidateCommand(const QString&)), qObject3, SLOT(validateFails()));
-  QObject::connect(qObject3, SIGNAL(validationComplete(bool, const QString&)), workflow, SLOT(evaluateValidationResults(bool, const QString&)));
+  QObject::connect(step3->ctkWorkflowStepQObject(), SIGNAL(invokeValidateCommand(const QString&)),
+                   qObject3, SLOT(validateFails()));
 
-  QObject::connect(step4->ctkWorkflowStepQObject(), SIGNAL(invokeValidateCommand(const QString&)), qObject4, SLOT(validate(const QString&)));
-  QObject::connect(qObject4, SIGNAL(validationComplete(bool, const QString&)), workflow, SLOT(evaluateValidationResults(bool, const QString&)));
+  QObject::connect(step4->ctkWorkflowStepQObject(), SIGNAL(invokeValidateCommand(const QString&)),
+                   qObject4, SLOT(validate(const QString&)));
 
   // use the qObjects for entry processing
-  QObject::connect(step1->ctkWorkflowStepQObject(), SIGNAL(invokeOnEntryCommand(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)), qObject1, SLOT(onEntry(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)));
-  QObject::connect(qObject1, SIGNAL(onEntryComplete()), workflow, SLOT(processingAfterOnEntry()));
-  QObject::connect(step2->ctkWorkflowStepQObject(), SIGNAL(invokeOnEntryCommand(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)), qObject2, SLOT(onEntry(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)));
-  QObject::connect(qObject2, SIGNAL(onEntryComplete()), workflow, SLOT(processingAfterOnEntry()));
-  QObject::connect(step3->ctkWorkflowStepQObject(), SIGNAL(invokeOnEntryCommand(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)), qObject3, SLOT(onEntry(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)));
-  QObject::connect(qObject3, SIGNAL(onEntryComplete()), workflow, SLOT(processingAfterOnEntry()));
-  QObject::connect(step4->ctkWorkflowStepQObject(), SIGNAL(invokeOnEntryCommand(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)), qObject4, SLOT(onEntry(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)));
-  QObject::connect(qObject4, SIGNAL(onEntryComplete()), workflow, SLOT(processingAfterOnEntry()));
+  QObject::connect(
+      step1->ctkWorkflowStepQObject(), SIGNAL(invokeOnEntryCommand(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)),
+      qObject1, SLOT(onEntry(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)));
+  QObject::connect(
+      step2->ctkWorkflowStepQObject(), SIGNAL(invokeOnEntryCommand(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)),
+      qObject2, SLOT(onEntry(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)));
+  QObject::connect(
+      step3->ctkWorkflowStepQObject(), SIGNAL(invokeOnEntryCommand(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)),
+      qObject3, SLOT(onEntry(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)));
+  QObject::connect(
+      step4->ctkWorkflowStepQObject(), SIGNAL(invokeOnEntryCommand(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)),
+      qObject4, SLOT(onEntry(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)));
+
 
   // use the qObjects for exit processing
-  QObject::connect(step1->ctkWorkflowStepQObject(), SIGNAL(invokeOnExitCommand(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)), qObject1, SLOT(onExit(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)));
-  QObject::connect(qObject1, SIGNAL(onExitComplete()), workflow, SLOT(processingAfterOnExit()));
-  QObject::connect(step2->ctkWorkflowStepQObject(), SIGNAL(invokeOnExitCommand(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)), qObject2, SLOT(onExit(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)));
-  QObject::connect(qObject2, SIGNAL(onExitComplete()), workflow, SLOT(processingAfterOnExit()));
-  QObject::connect(step3->ctkWorkflowStepQObject(), SIGNAL(invokeOnExitCommand(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)), qObject3, SLOT(onExit(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)));
-  QObject::connect(qObject3, SIGNAL(onExitComplete()), workflow, SLOT(processingAfterOnExit()));
-  QObject::connect(step4->ctkWorkflowStepQObject(), SIGNAL(invokeOnExitCommand(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)), qObject4, SLOT(onExit(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)));
-  QObject::connect(qObject4, SIGNAL(onExitComplete()), workflow, SLOT(processingAfterOnExit()));
+  QObject::connect(
+      step1->ctkWorkflowStepQObject(), SIGNAL(invokeOnExitCommand(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)),
+      qObject1, SLOT(onExit(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)));
+  QObject::connect(
+      step2->ctkWorkflowStepQObject(), SIGNAL(invokeOnExitCommand(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)),
+      qObject2, SLOT(onExit(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)));
+  QObject::connect(
+      step3->ctkWorkflowStepQObject(), SIGNAL(invokeOnExitCommand(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)),
+      qObject3, SLOT(onExit(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)));
+  QObject::connect(
+      step4->ctkWorkflowStepQObject(), SIGNAL(invokeOnExitCommand(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)),
+      qObject4, SLOT(onExit(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)));
 
   step1->setHasValidateCommand(1);
   step2->setHasValidateCommand(1);

+ 161 - 0
Libs/Core/ctkCorePythonQtDecorators.h

@@ -0,0 +1,161 @@
+/*=auto=========================================================================
+
+ Portions (c) Copyright 2005 Brigham and Women's Hospital (BWH) 
+ All Rights Reserved.
+
+ See Doc/copyright/copyright.txt
+ or http://www.slicer.org/copyright/copyright.txt for details.
+
+ Program:   3D Slicer
+
+=========================================================================auto=*/
+
+#ifndef __ctkCorePythonQtDecorators_h
+#define __ctkCorePythonQtDecorators_h
+
+// Qt includes
+#include <QObject>
+
+// PythonQt includes
+#include <PythonQt.h>
+
+// CTK includes
+#include <ctkWorkflowStep.h>
+#include <ctkWorkflowTransitions.h>
+
+#include "ctkCoreExport.h"
+
+// NOTE:
+//
+// For decorators it is assumed that the methods will never be called
+// with the self argument as NULL.  The self argument is the first argument
+// for non-static methods.
+//
+
+class CTK_CORE_EXPORT ctkCorePythonQtDecorators : public QObject
+{
+  Q_OBJECT
+public:
+
+  ctkCorePythonQtDecorators()
+    {
+    PythonQt::self()->registerCPPClass("ctkWorkflowStep", 0, "CTKCore");
+    PythonQt::self()->registerClass(&ctkWorkflowInterstepTransition::staticMetaObject, "CTKCore");
+    }
+
+public slots:
+
+  //
+  // ctkWorkflowStep
+  //
+
+  ctkWorkflowStep* new_ctkWorkflowStep()
+    {
+    return new ctkWorkflowStep();
+    }
+
+  ctkWorkflowStep* new_ctkWorkflowStep(ctkWorkflow* newWorkflow, const QString& newId = QString())
+    {
+    return new ctkWorkflowStep(newWorkflow, newId);
+    }
+
+  void delete_ctkWorkflowStep(ctkWorkflowStep * step)
+    {
+    delete step;
+    }
+    
+  ctkWorkflow* workflow(ctkWorkflowStep* step)const
+    {
+    return step->workflow();
+    }
+
+  QString id(ctkWorkflowStep* step)const
+    {
+    return step->id();
+    }
+
+  void setId(ctkWorkflowStep* step, const QString& newId)const
+    {
+    step->setId(newId);
+    }
+
+  QString name(ctkWorkflowStep* step)const
+    {
+    return step->name();
+    }
+    
+  void setName(ctkWorkflowStep* step, const QString& newName)
+    {
+    step->setName(newName);
+    }
+
+  QString description(ctkWorkflowStep* step)const
+    {
+    return step->description();
+    }
+    
+  void setDescription(ctkWorkflowStep* step, const QString& newDescription)
+    {
+    step->setDescription(newDescription);
+    }
+
+  QString statusText(ctkWorkflowStep* step)const
+    {
+    return step->statusText();
+    }
+
+  bool hasValidateCommand(ctkWorkflowStep* step)const
+    {
+    return step->hasValidateCommand();
+    }
+    
+  void setHasValidateCommand(ctkWorkflowStep* step, bool newHasValidateCommand)
+    {
+    step->setHasValidateCommand(newHasValidateCommand);
+    }
+
+  bool hasOnEntryCommand(ctkWorkflowStep* step)const
+    {
+    return step->hasOnEntryCommand();
+    }
+    
+  void setHasOnEntryCommand(ctkWorkflowStep* step, bool newHasOnEntryCommand)
+    {
+    step->setHasOnEntryCommand(newHasOnEntryCommand);
+    }
+
+  bool hasOnExitCommand(ctkWorkflowStep* step)const
+    {
+    return step->hasOnExitCommand();
+    }
+    
+  void setHasOnExitCommand(ctkWorkflowStep* step, bool newHasOnExitCommand)
+    {
+    step->setHasOnExitCommand(newHasOnExitCommand);
+    }
+  
+  QObject* ctkWorkflowStepQObject(ctkWorkflowStep* step)
+    {
+    return step->ctkWorkflowStepQObject();
+    }
+
+  //
+  // ctkWorkflowInterstepTransition
+  //
+  ctkWorkflowInterstepTransition* new_ctkWorkflowInterstepTransition(ctkWorkflowInterstepTransition::InterstepTransitionType newTransitionType)
+    {
+    return new ctkWorkflowInterstepTransition(newTransitionType);
+    }
+  
+  ctkWorkflowInterstepTransition* new_ctkWorkflowInterstepTransition(ctkWorkflowInterstepTransition::InterstepTransitionType newTransitionType, const QString& newId)
+    {
+    return new ctkWorkflowInterstepTransition(newTransitionType, newId);
+    }
+    
+  void delete_ctkWorkflowInterstepTransition(ctkWorkflowInterstepTransition * transition)
+    {
+    delete transition;
+    }
+};
+
+#endif

+ 112 - 347
Libs/Core/ctkWorkflow.cpp

@@ -36,250 +36,6 @@
 static ctkLogger logger("org.commontk.libs.core.ctkWorkflow");
 //--------------------------------------------------------------------------
 
-namespace
-{
-//-----------------------------------------------------------------------------
-struct forwardAndBackwardSteps
-{
-  QList<ctkWorkflowStep*> forwardSteps()
-  {
-    return this->ForwardSteps;
-  }
-
-  QList<ctkWorkflowStep*> backwardSteps()
-  {
-    return this->BackwardSteps;
-  }
-
-  QList<QString> forwardBranchIds()
-  {
-    return this->ForwardBranchIds;
-  }
-
-  QList<QString> backwardBranchIds()
-  {
-    return this->BackwardBranchIds;
-  }
-
-  void appendForwardStep(ctkWorkflowStep* step, QString id)
-  {
-    this->ForwardSteps.append(step);
-    this->ForwardBranchIds.append(id);
-  }
-
-  void appendBackwardStep(ctkWorkflowStep* step, QString id)
-  {
-    this->BackwardSteps.append(step);
-    this->BackwardBranchIds.append(id);
-  }
-
-  QString firstForwardBranchId()
-  {
-    if (this->ForwardBranchIds.isEmpty())
-      {
-      return QString();
-      }
-    else
-      {
-    return this->ForwardBranchIds.first();
-      }
-  }
-
-  ctkWorkflowStep* forwardStep(QString branchId)
-  {
-    int index = this->ForwardBranchIds.indexOf(branchId);
-    if (index != -1)
-      {
-      return ForwardSteps.at(index);
-      }
-    else
-      {
-      return 0;
-      }
-  }
-
-  QString backwardBranchId(ctkWorkflowStep* step)
-  {
-    int index = this->BackwardSteps.indexOf(step);
-    if (index != -1)
-      {
-      return BackwardBranchIds.at(index);
-      }
-    else
-      {
-      return QString();
-      }
-  }
-
-  QString forwardBranchId(ctkWorkflowStep* step)
-  {
-    int index = this->ForwardSteps.indexOf(step);
-    if (index != -1)
-      {
-      return ForwardBranchIds.at(index);
-      }
-    else
-      {
-      return QString();
-      }
-  }
-
-private:
-  QList<ctkWorkflowStep*> ForwardSteps;
-  QList<ctkWorkflowStep*> BackwardSteps;
-
-  QList<QString> ForwardBranchIds;
-  QList<QString> BackwardBranchIds;
-
-};
-}
-
-//-----------------------------------------------------------------------------
-class ctkWorkflowPrivate
-{
-  Q_DECLARE_PUBLIC(ctkWorkflow);
-protected:
-  ctkWorkflow* const q_ptr;
-public:
-  ctkWorkflowPrivate(ctkWorkflow& object);
-  ~ctkWorkflowPrivate();
-
-  /// \brief Add a step to the workflow
-  ///
-  /// \note The step's components will be automatically be added to the state machine
-  /// (i.e. the processingState state, validationState state, validationTransition transition
-  /// and validationFailedtransition transition.
-  ///
-  /// \return True or False indicating whether the method was successful.
-  void addStep(ctkWorkflowStep* step);
-
-  /// \brief Returns whether a transition has been previously added with the same origin,
-  /// destination and directionality
-  bool hasDuplicateTransition(ctkWorkflowStep* origin, ctkWorkflowStep* destination,
-                              const ctkWorkflow::TransitionDirectionality directionality);
-
-  /// \brief Returns whether a transition has been previously added with the same origin and branch
-  /// id (for forward transitions) or with the same destination and branch id (for backward transitions
-  bool hasTransitionWithSameBranchId(ctkWorkflowStep* origin, ctkWorkflowStep* destination,
-                                     const QString& branchId,
-                                     const ctkWorkflow::TransitionDirectionality directionality);
-
-  /// \brief Creates a transition from the origin to the destinatio.
-  ///
-  /// More specifically, the transition is from the \a origin's validation state to the \a
-  /// destination's processing state, and is of type ctkWorkflowTransition::TransitionToNextStep
-  ///
-  /// The destination step should semantically be a next step, i.e. from a workflow perspective, the
-  /// \a destination step is meant to appear after the \a origin step.
-  ///
-  /// Returns true/false indicating whether the method was successful.
-  void createTransitionToNextStep(ctkWorkflowStep* origin,
-                                  ctkWorkflowStep* destination,
-                                  const QString& branchId = "");
-
-  /// \brief Creates a transition from the destination to the origin
-  ///
-  /// More specifically, the transition is from the \a destination's processing state to the \a
-  /// origin's processing state, and is of type ctkWorkflowTransition::TransitionToPreviousStep
-  ///
-  /// The destination step should semantically be a next step, i.e. from a workflow perspective, the
-  /// \a destination step is meant to appear after the \a origin step.
-  ///
-  /// Returns true/false indicating whether the method was successful.
-  void createTransitionToPreviousStep(ctkWorkflowStep* origin,
-                                      ctkWorkflowStep* destination,
-                                      const QString& branchId = "");
-
-  /// \brief Creates a transition from the goTo step to the step from which the attempt to go to the
-  /// goTo step was initiated.
-  ///
-  /// More specifically, the transition is from the \a goTo step's processing state to the \a
-  /// starting step's processing state, and is of type ctkWorkflowTransition::TransitionToPreviousStartingStep
-  ///
-  /// Returns true/false indicating whether the method was successful.
-  void createTransitionToPreviousStartingStep(ctkWorkflowStep* startingStep,
-                                              ctkWorkflowStep* currentStep);
-  ///
-  void validateInternal(ctkWorkflowStep* step);
-
-  /// \brief Performs computation required when entering this step.
-  ///
-  /// Does some sanity checks and then either calls onEntry() or emits the invokeOnEntryCommand(),
-  /// depending on whether the user indicates that there is an onEntryCommand.
-  void onEntryInternal(ctkWorkflowStep* step, ctkWorkflowStep* comingFrom,
-                       const ctkWorkflowInterstepTransition::InterstepTransitionType& transitionType);
-
-  /// \brief Performs computation required when exiting this step.
-  ///
-  /// Does some sanity checks and then either calls onExit() or emits the invokeOnExitCommand(),
-  /// depending on whether the user indicates that there is an onExitCommand.
-  void onExitInternal(ctkWorkflowStep* step, ctkWorkflowStep* goingTo,
-                      const ctkWorkflowInterstepTransition::InterstepTransitionType& transitionType);
-
-  /// Get the step in the workflow with a given id.
-  ctkWorkflowStep* stepFromId(const QString& id)const;
-
-  /// Get the step that a state belongs to (if any)
-  ctkWorkflowStep* stepFromState(const QAbstractState* state);
-
-  /// Get the number of forward steps from the given step
-  int numberOfForwardSteps(ctkWorkflowStep* step);
-
-  /// Get the number of backward steps from the given step
-  int numberOfBackwardSteps(ctkWorkflowStep* step);
-
-  /// Get the ids of the steps that directly follow the given step.
-  QList<QString> forwardBranchIds(ctkWorkflowStep* step)const;
-
-  /// Get the ids of the steps that directly preceed the given step.
-  QList<QString> backwardBranchIds(ctkWorkflowStep* step)const;
-
-  /// Determines whether there exists a path from the origin step (the current step by default) to
-  /// the step with the given goalId
-  bool pathExists(const QString& goalId, ctkWorkflowStep* origin = 0)const;
-
-  /// Determines whether there exists a path from the current step's next step (as given by the
-  /// branchId) to the step with the given goalId
-  bool pathExistsFromNextStep(const QString& goalId, const QString& branchId)const;
-
-  QStateMachine* StateMachine;
-
-  // Maintain a list of pointers to the steps in the workflow,
-  // along with their forward and backward transitions
-  QMap<ctkWorkflowStep*, forwardAndBackwardSteps*>         StepToForwardAndBackwardStepMap;
-
-  // ... and its associated convenient typedef
-  typedef QMap<ctkWorkflowStep*, forwardAndBackwardSteps*> StepToForwardAndBackwardStepMapType;
-  typedef QList<ctkWorkflowStep*>                          StepListType;
-
-  // Maintain a map of <state, step> key/value pairs, to find the step
-  // that a given state belongs to
-  typedef QMap<const QAbstractState*, ctkWorkflowStep*>           StateToStepMapType;
-  typedef QMap<const QAbstractState*, ctkWorkflowStep*>::iterator StateToStepMapIterator;
-  StateToStepMapType                                              StateToStepMap;
-
-  ctkWorkflowStep*                         InitialStep;
-  ctkWorkflowStep*                         CurrentStep;
-  QMap<ctkWorkflowStep*, ctkWorkflowStep*> StepToPreviousStepMap;
-
-  // Used when performing a transition
-  ctkWorkflowStep*                                        OriginStep;
-  ctkWorkflowStep*                                        DestinationStep;
-  ctkWorkflowInterstepTransition::InterstepTransitionType TransitionType;
-
-  QString          DesiredBranchId; // Desired branchId specified when invoking goForward
-
-  ctkWorkflowStep* GoToStep;   // Desired step when attempting to go to a finish step
-
-  ctkWorkflowStep* StartingStep; // Current step when we began the attempt to go to the desired finish step
-
-  // Temporary transition after successfully going to finish step, to get us back to the starting step
-  ctkWorkflowInterstepTransition* TransitionToPreviousStartingStep;
-
-  QString ARTIFICIAL_BRANCH_ID_PREFIX;
-
-};
-
 // --------------------------------------------------------------------------
 // ctkWorkflowPrivate methods
 
@@ -330,7 +86,17 @@ void ctkWorkflowPrivate::addStep(ctkWorkflowStep* step)
 
   // Setup the signal/slot that triggers the evaluation of the validation results
   // after validate(const QString&) is called
-  q->connectStep(step);
+  this->connect(
+      step->ctkWorkflowStepQObject(), SIGNAL(validationComplete(bool, const QString&)),
+      q, SLOT(evaluateValidationResults(bool, const QString&)));
+
+  this->connect(
+      step->ctkWorkflowStepQObject(), SIGNAL(onEntryComplete()),
+      SLOT(processingAfterOnEntry()));
+
+  this->connect(
+      step->ctkWorkflowStepQObject(), SIGNAL(onExitComplete()),
+      SLOT(processingAfterOnExit()));
 }
 
 // --------------------------------------------------------------------------
@@ -577,6 +343,62 @@ void ctkWorkflowPrivate::onEntryInternal(
 }
 
 // --------------------------------------------------------------------------
+void ctkWorkflowPrivate::processingAfterOnEntry()
+{
+  Q_Q(ctkWorkflow);
+
+  logger.debug("processingAfterOnEntry");
+
+  if (!this->DestinationStep)
+    {
+    logger.error("processingAfterOnEntry - Called processingAfterOnEntry without "
+                 "having set a destination step");
+    return;
+    }
+
+  // Update the currentStep and previous step
+  this->CurrentStep = this->DestinationStep;
+
+  // Reset the pointers used internally for performing a transition
+  this->OriginStep = 0;
+  this->DestinationStep = 0;
+
+  // // Reset the pointers used internally for performing a transition
+  // // back to the starting step
+  // if (d->TransitionToPreviousStartingStep)
+  //   {
+
+  //   std::cout << "TRANSITION TO PREVIOUS STARTING STEP EXISTS" << std::endl;
+  //   //d->TransitionToPreviousStartingStep->sourceState()->removeTransition(d->TransitionToPreviousStartingStep);
+  //   //std::cout << "removed" << std::endl;
+  //   // d->TransitionToPreviousStartingStep = 0;
+  //   //destination->processingState()->removeTransition(d->TransitionToPreviousStartingStep);
+  //   //delete d->TransitionToPreviousStartingStep;
+  //   // d->TransitionToPreviousStartingStep = 0;
+  //   std::cout << "here" << std::endl;
+  //   }
+
+  // If we are trying to get to the finish step, then check if we are
+  // finished.
+  if (this->GoToStep)
+    {
+    if (this->CurrentStep == this->GoToStep)
+      {
+      q->goToStepSucceeded();
+      }
+    // if we're not finished, continue transitioning to the next step
+    else
+      {
+      q->goForward();
+      }
+    }
+  else
+    {
+    emit q->currentStepChanged(this->CurrentStep);
+    }
+}
+
+// --------------------------------------------------------------------------
 void ctkWorkflowPrivate::onExitInternal(
     ctkWorkflowStep* step,
     ctkWorkflowStep* goingTo,
@@ -603,6 +425,25 @@ void ctkWorkflowPrivate::onExitInternal(
 }
 
 // --------------------------------------------------------------------------
+void ctkWorkflowPrivate::processingAfterOnExit()
+{
+  // enter the destination step if we have one
+  if (this->DestinationStep)
+    {
+    this->onEntryInternal(this->DestinationStep, this->OriginStep, this->TransitionType);
+    }
+  // reset the pointers used internally for performing a transition if we're done
+  else
+    {
+    this->OriginStep = 0;
+    this->DestinationStep = 0;
+    // we've exited the CurrentStep and haven't gone into another step, so we no longer have a
+    // currentStep.
+    this->CurrentStep = 0;
+    }
+}
+
+// --------------------------------------------------------------------------
 ctkWorkflowStep* ctkWorkflowPrivate::stepFromState(const QAbstractState* state)
 {
   if (state)
@@ -709,6 +550,12 @@ bool ctkWorkflow::addTransition(ctkWorkflowStep* origin, ctkWorkflowStep* destin
     return false;
     }
 
+  // Set origin id if empty
+  if (origin && origin->id().isEmpty())
+    {
+    origin->setId(QString("step%1").arg(d->StepToForwardAndBackwardStepMap.count()));
+    }
+
   // cannot currently create a transition between two steps of the same id, which is equivalent to
   // adding a transition from a step to itself
   if (origin && destination && (QString::compare(origin->id(), destination->id(), Qt::CaseInsensitive) == 0))
@@ -724,6 +571,12 @@ bool ctkWorkflow::addTransition(ctkWorkflowStep* origin, ctkWorkflowStep* destin
     d->addStep(origin);
     }
 
+  // Set destination id if empty
+  if (destination && destination->id().isEmpty())
+    {
+    destination->setId(QString("step%1").arg(d->StepToForwardAndBackwardStepMap.count()));
+    }
+
   // add the destination step if it doesn't exist in the workflow yet
   if (destination && !this->hasStep(destination->id()))
     {
@@ -755,6 +608,12 @@ bool ctkWorkflow::addTransition(ctkWorkflowStep* origin, ctkWorkflowStep* destin
       }
     }
 
+  // Set initialStep if needed
+  if (origin && d->StepToForwardAndBackwardStepMap.count() == 2 && !this->initialStep())
+    {
+    this->setInitialStep(origin);
+    }
+
   return true;
 }
 
@@ -786,36 +645,15 @@ bool ctkWorkflow::hasTransition(ctkWorkflowStep* origin, ctkWorkflowStep* destin
 }
 
 // --------------------------------------------------------------------------
-void ctkWorkflow::connectStep(ctkWorkflowStep* step)
-{
-  Q_ASSERT(step);
-
-  if (!step->hasValidateCommand())
-    {
-    QObject::connect(step->ctkWorkflowStepQObject(), SIGNAL(validationComplete(bool, const QString&)), this, SLOT(evaluateValidationResults(bool, const QString&)));
-    }
-
-  if (!step->hasOnEntryCommand())
-    {
-    QObject::connect(step->ctkWorkflowStepQObject(), SIGNAL(onEntryComplete()), this, SLOT(processingAfterOnEntry()));
-    }
-
-  if (!step->hasOnExitCommand())
-    {
-    QObject::connect(step->ctkWorkflowStepQObject(), SIGNAL(onExitComplete()), this, SLOT(processingAfterOnExit()));
-    }
-}
-
-// --------------------------------------------------------------------------
 QList<ctkWorkflowStep*> ctkWorkflow::forwardSteps(ctkWorkflowStep* step)const
 {
   Q_D(const ctkWorkflow);
   // use the given step if provided, otherwise use the workflow's current step
-  if (step)
+  if (step && d->StepToForwardAndBackwardStepMap.contains(step))
     {
     return d->StepToForwardAndBackwardStepMap.value(step)->forwardSteps();
     }
-  else if (d->CurrentStep)
+  else if (d->CurrentStep && d->StepToForwardAndBackwardStepMap.contains(d->CurrentStep))
     {
     return d->StepToForwardAndBackwardStepMap.value(d->CurrentStep)->forwardSteps();
     }
@@ -830,11 +668,11 @@ QList<ctkWorkflowStep*> ctkWorkflow::backwardSteps(ctkWorkflowStep* step)const
 {
   Q_D(const ctkWorkflow);
   // use the current step if provided, otherwise use the workflow's current step
-  if (step)
+  if (step && d->StepToForwardAndBackwardStepMap.contains(step))
     {
     return d->StepToForwardAndBackwardStepMap.value(step)->backwardSteps();
     }
-  else if (d->CurrentStep)
+  else if (d->CurrentStep && d->StepToForwardAndBackwardStepMap.contains(d->CurrentStep))
     {
     return d->StepToForwardAndBackwardStepMap.value(d->CurrentStep)->backwardSteps();
     }
@@ -888,8 +726,12 @@ bool ctkWorkflow::hasStep(const QString& id)const
 }
 
 // --------------------------------------------------------------------------
+// Convenience method to set the QStateMachine's initialState to a
+// specific step's processing state.
 CTK_GET_CPP(ctkWorkflow, ctkWorkflowStep*, initialStep, InitialStep);
 CTK_SET_CPP(ctkWorkflow, ctkWorkflowStep*, setInitialStep, InitialStep);
+
+// --------------------------------------------------------------------------
 CTK_GET_CPP(ctkWorkflow, ctkWorkflowStep*, currentStep, CurrentStep);
 
 // --------------------------------------------------------------------------
@@ -1175,83 +1017,6 @@ void ctkWorkflow::performTransitionBetweenSteps()
 }
 
 // --------------------------------------------------------------------------
-void ctkWorkflow::processingAfterOnExit()
-{
-  Q_D(ctkWorkflow);
-
-  // enter the destination step if we have one
-  if (d->DestinationStep)
-    {
-    d->onEntryInternal(d->DestinationStep, d->OriginStep, d->TransitionType);
-    }
-  // reset the pointers used internally for performing a transition if we're done
-  else
-    {
-    d->OriginStep = 0;
-    d->DestinationStep = 0;
-    // we've exited the CurrentStep and haven't gone into another step, so we no longer have a
-    // currentStep.
-    d->CurrentStep = 0;
-    }
-}
-
-// --------------------------------------------------------------------------
-void ctkWorkflow::processingAfterOnEntry()
-{
-  logger.debug("processingAfterOnEntry");
-
-  Q_D(ctkWorkflow);
-
-  if (!d->DestinationStep)
-    {
-    logger.error("processingAfterOnEntry - Called processingAfterOnEntry without "
-                 "having set a destination step");
-    return;
-    }
-
-  // Update the currentStep and previous step
-  d->CurrentStep = d->DestinationStep;
-
-  // Reset the pointers used internally for performing a transition
-  d->OriginStep = 0;
-  d->DestinationStep = 0;
-
-  // // Reset the pointers used internally for performing a transition
-  // // back to the starting step
-  // if (d->TransitionToPreviousStartingStep)
-  //   {
-
-  //   std::cout << "TRANSITION TO PREVIOUS STARTING STEP EXISTS" << std::endl;
-  //   //d->TransitionToPreviousStartingStep->sourceState()->removeTransition(d->TransitionToPreviousStartingStep);
-  //   //std::cout << "removed" << std::endl;
-  //   // d->TransitionToPreviousStartingStep = 0;
-  //   //destination->processingState()->removeTransition(d->TransitionToPreviousStartingStep);
-  //   //delete d->TransitionToPreviousStartingStep;
-  //   // d->TransitionToPreviousStartingStep = 0;
-  //   std::cout << "here" << std::endl;
-  //   }
-
-  // If we are trying to get to the finish step, then check if we are
-  // finished.
-  if (d->GoToStep)
-    {
-    if (d->CurrentStep == d->GoToStep)
-      {
-      this->goToStepSucceeded();
-      }
-    // if we're not finished, continue transitioning to the next step
-    else
-      {
-      this->goForward();
-      }
-    }
-  else
-    {
-    emit this->currentStepChanged(d->CurrentStep);
-    }
-}
-
-// --------------------------------------------------------------------------
 void ctkWorkflow::goToStepSucceeded()
 {
   Q_D(ctkWorkflow);

+ 23 - 34
Libs/Core/ctkWorkflow.h

@@ -38,6 +38,8 @@ class QAbstractState;
 class CTK_CORE_EXPORT ctkWorkflow : public QObject
 {
   Q_OBJECT
+  Q_ENUMS(TransitionDirectionality)
+  Q_PROPERTY(bool isRunning READ isRunning DESIGNABLE false)
 
 public:
 
@@ -48,14 +50,14 @@ public:
   /// \brief Start the workflow.
   /// The workflow will always start in the initial step, even if it is stopped and restarted).
   /// \note Calls onEntry() for the initial step.
-  virtual void start();
+  Q_INVOKABLE virtual void start();
 
   /// \brief Returns whether the workflow is currently running
   bool isRunning()const;
 
   /// \brief Stops the workflow.
   /// \note Calls onExit() for the current step.
-  virtual void stop();
+  Q_INVOKABLE virtual void stop();
 
   /// \brief Transition directionalities.
   ///
@@ -82,10 +84,10 @@ public:
   /// To add a single step, \a destination can be set to 0.
   ///
   /// Returns true/false indicating whether the method was successful.
-  virtual bool addTransition(ctkWorkflowStep* origin, ctkWorkflowStep* destination,
-                             const QString& branchId = QString(),
-                             const ctkWorkflow::TransitionDirectionality directionality
-                               = ctkWorkflow::Bidirectional);
+  Q_INVOKABLE virtual bool addTransition(ctkWorkflowStep* origin, ctkWorkflowStep* destination,
+                                         const QString& branchId = QString(),
+                                         const ctkWorkflow::TransitionDirectionality directionality
+                                         = ctkWorkflow::Bidirectional);
 
   /// \brief Determine whether a transition has already been added
   /// <ul>
@@ -96,37 +98,33 @@ public:
   /// previously added with the same origin and branch id (for forward transitions) or
   /// with the same destination and branch id (for backward transitions)</li>
   /// </ul>
-  bool hasTransition(ctkWorkflowStep* origin, ctkWorkflowStep* destination,
-                     const QString& branchId = QString(),
-                     const ctkWorkflow::TransitionDirectionality directionality = ctkWorkflow::Bidirectional);
+  Q_INVOKABLE bool hasTransition(ctkWorkflowStep* origin, ctkWorkflowStep* destination,
+                                 const QString& branchId = QString(),
+                                 const ctkWorkflow::TransitionDirectionality directionality
+                                 = ctkWorkflow::Bidirectional);
 
   /// \brief Set/get the initial step.
-  ///
-  /// Convenience method to set the QStateMachine's initialState to a specific step's
-  /// processing state.
-  ///
-  /// \note The initialStep() function *must* be called to set the state machine's initial state
-  /// correctly
-  ctkWorkflowStep* initialStep()const;
-  virtual void setInitialStep(ctkWorkflowStep* step);
+  /// \note In not specified, the first step added will be considered as the initialStep
+  Q_INVOKABLE ctkWorkflowStep* initialStep()const;
+  Q_INVOKABLE virtual void setInitialStep(ctkWorkflowStep* step);
 
   /// Get the current step of the state machine
-  ctkWorkflowStep* currentStep()const;
+  Q_INVOKABLE ctkWorkflowStep* currentStep()const;
 
   /// Check to see if there is a step with a given id in the workflow.
-  bool hasStep(const QString& id)const;
+  Q_INVOKABLE bool hasStep(const QString& id)const;
 
   /// Returns whether or not we can go forward: i.e. there exists a step that directly follows the
   /// given step.
   ///
   /// If no step is given, then the workflow's current step will be used.
-  bool canGoForward(ctkWorkflowStep* step=0)const;
+  Q_INVOKABLE bool canGoForward(ctkWorkflowStep* step=0)const;
 
   /// Returns whether or not we can go backward: i.e. there exists a step that directly preceeds the
   /// given step.
   ///
   /// If no step is given, then the workflow's current step will be used.
-  bool canGoBackward(ctkWorkflowStep* step=0)const;
+  Q_INVOKABLE bool canGoBackward(ctkWorkflowStep* step=0)const;
 
   /// Returns whether or not we can go to the goal step from the origin step: i.e. there is a path
   /// in the workflow from the current step to the given step.
@@ -134,7 +132,7 @@ public:
   /// If no step is designated as the 'origin', then the workflow's current step will be used
   /// Note: does not currently work in branching workflows if the origin and target steps are not on
   /// the same branch
-  bool canGoToStep(const QString& targetId, ctkWorkflowStep* step=0)const;
+  Q_INVOKABLE bool canGoToStep(const QString& targetId, ctkWorkflowStep* step=0)const;
 
   /// Get the steps that directly follow the given step.
   ///
@@ -143,7 +141,7 @@ public:
   /// to ctkWorkflow::Bidirectional or ctkWorkflow::Forward.
   ///
   /// If no step is given, then the workflow's current step will be used.
-  QList<ctkWorkflowStep*> forwardSteps(ctkWorkflowStep* step=0)const;
+  Q_INVOKABLE QList<ctkWorkflowStep*> forwardSteps(ctkWorkflowStep* step=0)const;
 
   /// Get the steps that directly preceed the given step.
   ///
@@ -152,10 +150,10 @@ public:
   /// set to ctkWorkflow::Bidirectional or ctkWorkflow::Backward.
   ///
   /// If no step is given, then the workflow's current step will be used.
-  QList<ctkWorkflowStep*> backwardSteps(ctkWorkflowStep* step=0)const;
+  Q_INVOKABLE QList<ctkWorkflowStep*> backwardSteps(ctkWorkflowStep* step=0)const;
 
   /// Get the steps that are 'finish' steps (i.e. have no step following them)
-  QList<ctkWorkflowStep*> finishSteps()const;
+  Q_INVOKABLE QList<ctkWorkflowStep*> finishSteps()const;
 
 public slots:
 
@@ -174,12 +172,6 @@ public slots:
   /// If the validation is successful, then this slot begins the transition to the next step.
   virtual void evaluateValidationResults(bool validationSucceeded, const QString& branchId);
 
-  /// \brief Workflow processing executed after a step's onEntry function is run.
-  virtual void processingAfterOnEntry();
-
-  /// \brief Workflow processing executed after a step's onExit function is run.
-  virtual void processingAfterOnExit();
-
 protected:
 
   void goToNextStepAfterSuccessfulValidation(const QString& branchId);
@@ -194,9 +186,6 @@ protected:
  
   /// \brief Goes to the step from which the attempt to go to the 'goTo' step was initiated
   void goFromGoToStepToStartingStep();
-
-  /// \brief Performs required connections between the step and this workflow
-  virtual void connectStep(ctkWorkflowStep* step);
  
 protected slots:
 

+ 32 - 9
Libs/Core/ctkWorkflowStep.cpp

@@ -115,20 +115,31 @@ void ctkWorkflowStepPrivate::invokeOnExitCommandInternal(const ctkWorkflowStep*
 // ctkWorkflowStep methods
 
 // --------------------------------------------------------------------------
+ctkWorkflowStep::ctkWorkflowStep(): d_ptr(new ctkWorkflowStepPrivate(*this))
+{
+}
+
+// --------------------------------------------------------------------------
 ctkWorkflowStep::ctkWorkflowStep(ctkWorkflow* newWorkflow, const QString& newId)
   : d_ptr(new ctkWorkflowStepPrivate(*this))
 {
   Q_D(ctkWorkflowStep);
 
-  if (newId.isEmpty())
-    {
-     d->Id = d->metaObject()->className();
-    }
-  else
-    {
-    d->Id = newId;
-    }
+  d->Id = newId;
+  d->Workflow = newWorkflow;
+}
+
+// --------------------------------------------------------------------------
+ctkWorkflowStep::ctkWorkflowStep(ctkWorkflowStepPrivate * pimpl):d_ptr(pimpl)
+{
+}
 
+// --------------------------------------------------------------------------
+ctkWorkflowStep::ctkWorkflowStep(ctkWorkflowStepPrivate * pimpl,
+                                 ctkWorkflow* newWorkflow, const QString& newId):d_ptr(pimpl)
+{
+  Q_D(ctkWorkflowStep);
+  d->Id = newId;
   d->Workflow = newWorkflow;
 }
 
@@ -143,7 +154,19 @@ CTK_SET_CPP(ctkWorkflowStep, ctkWorkflow*, setWorkflow, Workflow);
 
 // --------------------------------------------------------------------------
 CTK_GET_CPP(ctkWorkflowStep, QString, id, Id);
-CTK_SET_CPP(ctkWorkflowStep, const QString&, setId, Id);
+
+// --------------------------------------------------------------------------
+void ctkWorkflowStep::setId(const QString& newId)
+{
+  Q_D(ctkWorkflowStep);
+  if (d->Workflow && d->Workflow->hasStep(newId) && !this->id().isEmpty())
+    {
+    logger.error(QString("ctkWorkflowStep - Failed to change id from '%1' to '%2' - "
+                         "Step already added to a workflow !").arg(this->id()).arg(newId));
+    return;
+    }
+  d->Id = newId;
+}
 
 // --------------------------------------------------------------------------
 CTK_GET_CPP(ctkWorkflowStep, QString, name, Name);

+ 16 - 10
Libs/Core/ctkWorkflowStep.h

@@ -27,8 +27,11 @@ class QState;
 
 // CTK includes
 #include "ctkPimpl.h"
-#include "ctkCoreExport.h"
+#include "ctkWorkflow_p.h"
 #include "ctkWorkflowTransitions.h"
+
+#include "ctkCoreExport.h"
+
 class ctkWorkflow;
 
 class ctkWorkflowStepPrivate;
@@ -42,6 +45,7 @@ class CTK_CORE_EXPORT ctkWorkflowStep
 {
 
 public:
+  explicit ctkWorkflowStep();
   explicit ctkWorkflowStep(ctkWorkflow* newWorkflow, const QString& newId);
   virtual ~ctkWorkflowStep();
 
@@ -51,6 +55,10 @@ public:
   /// Get id
   QString id()const;
 
+  /// Set step Id
+  /// \note Setting the Id after the step had been added to a workflow is a no-op
+  void setId(const QString& newStepId);
+
   /// Set/get \a name
   QString name()const;
   void setName(const QString& newName);
@@ -86,8 +94,9 @@ public:
 
 protected:
 
-  /// Set step Id
-  void setId(const QString& newStepId);
+  explicit ctkWorkflowStep(ctkWorkflowStepPrivate * pimpl);
+  explicit ctkWorkflowStep(ctkWorkflowStepPrivate * pimpl,
+                           ctkWorkflow* newWorkflow, const QString& newId);
 
   /// Set workflow
   void setWorkflow(ctkWorkflow* newWorkflow);
@@ -172,8 +181,9 @@ protected:
   /// 1) Reimplement the validate(const QString&) method in a subclass of
   /// ctkWorkflowStep, following these instructions:
   /// <ul>
-  ///   <li>emit the signal ctkWorkflowStep::validateComplete(bool, const QString&) (true on successful validation,
-  /// false on failure; the QString is the desired branchId to use with branching workflows)</li>
+  ///   <li>invoke the superclass method ctkWorkflowStep::validateComplete(bool, const QString&)
+  /// (true on successful validation, false on failure; the QString is the desired branchId to use
+  /// with branching workflows)</li>
   /// </ul>
   //
   /// OR:
@@ -183,14 +193,10 @@ protected:
   ///  <li>Call setHasValidateCommand(1) on the step
   ///  <li>Create a slot foo() associated with any QObject*, following these instructions:</li>
   ///  <ul>
-  ///     <li>Emit a signal bar(int, const QString&) (true on successful validation, false on
-  /// failure)</li>
-  ///     <li>Set the following two connections:</li>
+  ///     <li>Set the following connection:</li>
   ///     <ul>
   ///       <li>QObject::connect(step, SIGNAL(invokeValidateCommand(const QString&)), object,
   /// SLOT(foo(const QString&)))</li>
-  ///       <li>QObject::connect(object, SIGNAl(bar(bool, const QString&)), workflow,
-  /// SLOT(evaluateValidationResults(bool, const QString&)))</li>
   ///      </ul>
   ///    </ul>
   ///  </ul>

+ 4 - 1
Libs/Core/ctkWorkflowStep_p.h

@@ -23,6 +23,7 @@
 
 // Qt includes
 #include <QObject>
+
 class QString;
 class QState;
 
@@ -31,10 +32,12 @@ class QState;
 #include "ctkWorkflow.h"
 #include "ctkWorkflowStep.h"
 #include "ctkWorkflowTransitions.h"
+#include "ctkCoreExport.h"
+
 class ctkWorkflow;
 
 //-----------------------------------------------------------------------------
-class ctkWorkflowStepPrivate: public QObject
+class CTK_CORE_EXPORT ctkWorkflowStepPrivate: public QObject
 {
   Q_OBJECT
   Q_DECLARE_PUBLIC(ctkWorkflowStep);

+ 1 - 0
Libs/Core/ctkWorkflowTransitions.h

@@ -128,6 +128,7 @@ struct CTK_CORE_EXPORT ctkWorkflowInterstepTransitionEvent : public QEvent
 class CTK_CORE_EXPORT ctkWorkflowInterstepTransition : public QAbstractTransition
 {
   Q_OBJECT
+  Q_ENUMS(InterstepTransitionType)
 
 public:
 

+ 291 - 0
Libs/Core/ctkWorkflow_p.h

@@ -0,0 +1,291 @@
+/*=========================================================================
+
+  Library:   CTK
+
+  Copyright (c) Kitware Inc.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.commontk.org/LICENSE
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+=========================================================================*/
+ 
+#ifndef __ctkWorkflow_p_h
+#define __ctkWorkflow_p_h
+
+// Qt includes
+#include <QObject>
+#include <QString>
+#include <QList>
+#include <QMap>
+
+// CTK includes
+#include "ctkWorkflow.h"
+#include "ctkWorkflowTransitions.h"
+
+class QStateMachine;
+class ctkWorkflowStep;
+//class ctkWorkflow;
+//enum ctkWorkflow::TransitionDirectionality;
+
+//-----------------------------------------------------------------------------
+struct forwardAndBackwardSteps
+{
+  QList<ctkWorkflowStep*> forwardSteps()
+  {
+    return this->ForwardSteps;
+  }
+
+  QList<ctkWorkflowStep*> backwardSteps()
+  {
+    return this->BackwardSteps;
+  }
+
+  QList<QString> forwardBranchIds()
+  {
+    return this->ForwardBranchIds;
+  }
+
+  QList<QString> backwardBranchIds()
+  {
+    return this->BackwardBranchIds;
+  }
+
+  void appendForwardStep(ctkWorkflowStep* step, QString id)
+  {
+    this->ForwardSteps.append(step);
+    this->ForwardBranchIds.append(id);
+  }
+
+  void appendBackwardStep(ctkWorkflowStep* step, QString id)
+  {
+    this->BackwardSteps.append(step);
+    this->BackwardBranchIds.append(id);
+  }
+
+  QString firstForwardBranchId()
+  {
+    if (this->ForwardBranchIds.isEmpty())
+      {
+      return QString();
+      }
+    else
+      {
+    return this->ForwardBranchIds.first();
+      }
+  }
+
+  ctkWorkflowStep* forwardStep(QString branchId)
+  {
+    int index = this->ForwardBranchIds.indexOf(branchId);
+    if (index != -1)
+      {
+      return ForwardSteps.at(index);
+      }
+    else
+      {
+      return 0;
+      }
+  }
+
+  QString backwardBranchId(ctkWorkflowStep* step)
+  {
+    int index = this->BackwardSteps.indexOf(step);
+    if (index != -1)
+      {
+      return BackwardBranchIds.at(index);
+      }
+    else
+      {
+      return QString();
+      }
+  }
+
+  QString forwardBranchId(ctkWorkflowStep* step)
+  {
+    int index = this->ForwardSteps.indexOf(step);
+    if (index != -1)
+      {
+      return ForwardBranchIds.at(index);
+      }
+    else
+      {
+      return QString();
+      }
+  }
+
+private:
+  QList<ctkWorkflowStep*> ForwardSteps;
+  QList<ctkWorkflowStep*> BackwardSteps;
+
+  QList<QString> ForwardBranchIds;
+  QList<QString> BackwardBranchIds;
+
+};
+
+// --------------------------------------------------------------------------
+class ctkWorkflowPrivate : public QObject
+{
+  Q_OBJECT
+  Q_DECLARE_PUBLIC(ctkWorkflow);
+protected:
+  ctkWorkflow* const q_ptr;
+public:
+  ctkWorkflowPrivate(ctkWorkflow& object);
+  ~ctkWorkflowPrivate();
+
+  /// \brief Add a step to the workflow
+  ///
+  /// \note The step's components will be automatically be added to the state machine
+  /// (i.e. the processingState state, validationState state, validationTransition transition
+  /// and validationFailedtransition transition.
+  ///
+  /// \return True or False indicating whether the method was successful.
+  void addStep(ctkWorkflowStep* step);
+
+  /// \brief Returns whether a transition has been previously added with the same origin,
+  /// destination and directionality
+  bool hasDuplicateTransition(ctkWorkflowStep* origin, ctkWorkflowStep* destination,
+                              const ctkWorkflow::TransitionDirectionality directionality);
+
+  /// \brief Returns whether a transition has been previously added with the same origin and branch
+  /// id (for forward transitions) or with the same destination and branch id (for backward transitions
+  bool hasTransitionWithSameBranchId(ctkWorkflowStep* origin, ctkWorkflowStep* destination,
+                                     const QString& branchId,
+                                     const ctkWorkflow::TransitionDirectionality directionality);
+
+  /// \brief Creates a transition from the origin to the destinatio.
+  ///
+  /// More specifically, the transition is from the \a origin's validation state to the \a
+  /// destination's processing state, and is of type ctkWorkflowTransition::TransitionToNextStep
+  ///
+  /// The destination step should semantically be a next step, i.e. from a workflow perspective, the
+  /// \a destination step is meant to appear after the \a origin step.
+  ///
+  /// Returns true/false indicating whether the method was successful.
+  void createTransitionToNextStep(ctkWorkflowStep* origin,
+                                  ctkWorkflowStep* destination,
+                                  const QString& branchId = "");
+
+  /// \brief Creates a transition from the destination to the origin
+  ///
+  /// More specifically, the transition is from the \a destination's processing state to the \a
+  /// origin's processing state, and is of type ctkWorkflowTransition::TransitionToPreviousStep
+  ///
+  /// The destination step should semantically be a next step, i.e. from a workflow perspective, the
+  /// \a destination step is meant to appear after the \a origin step.
+  ///
+  /// Returns true/false indicating whether the method was successful.
+  void createTransitionToPreviousStep(ctkWorkflowStep* origin,
+                                      ctkWorkflowStep* destination,
+                                      const QString& branchId = "");
+
+  /// \brief Creates a transition from the goTo step to the step from which the attempt to go to the
+  /// goTo step was initiated.
+  ///
+  /// More specifically, the transition is from the \a goTo step's processing state to the \a
+  /// starting step's processing state, and is of type ctkWorkflowTransition::TransitionToPreviousStartingStep
+  ///
+  /// Returns true/false indicating whether the method was successful.
+  void createTransitionToPreviousStartingStep(ctkWorkflowStep* startingStep,
+                                              ctkWorkflowStep* currentStep);
+  ///
+  void validateInternal(ctkWorkflowStep* step);
+
+  /// \brief Performs computation required when entering this step.
+  ///
+  /// Does some sanity checks and then either calls onEntry() or emits the invokeOnEntryCommand(),
+  /// depending on whether the user indicates that there is an onEntryCommand.
+  void onEntryInternal(ctkWorkflowStep* step, ctkWorkflowStep* comingFrom,
+                       const ctkWorkflowInterstepTransition::InterstepTransitionType& transitionType);
+
+  /// \brief Performs computation required when exiting this step.
+  ///
+  /// Does some sanity checks and then either calls onExit() or emits the invokeOnExitCommand(),
+  /// depending on whether the user indicates that there is an onExitCommand.
+  void onExitInternal(ctkWorkflowStep* step, ctkWorkflowStep* goingTo,
+                      const ctkWorkflowInterstepTransition::InterstepTransitionType& transitionType);
+
+  /// Get the step in the workflow with a given id.
+  ctkWorkflowStep* stepFromId(const QString& id)const;
+
+  /// Get the step that a state belongs to (if any)
+  ctkWorkflowStep* stepFromState(const QAbstractState* state);
+
+  /// Get the number of forward steps from the given step
+  int numberOfForwardSteps(ctkWorkflowStep* step);
+
+  /// Get the number of backward steps from the given step
+  int numberOfBackwardSteps(ctkWorkflowStep* step);
+
+  /// Get the ids of the steps that directly follow the given step.
+  QList<QString> forwardBranchIds(ctkWorkflowStep* step)const;
+
+  /// Get the ids of the steps that directly preceed the given step.
+  QList<QString> backwardBranchIds(ctkWorkflowStep* step)const;
+
+  /// Determines whether there exists a path from the origin step (the current step by default) to
+  /// the step with the given goalId
+  bool pathExists(const QString& goalId, ctkWorkflowStep* origin = 0)const;
+
+  /// Determines whether there exists a path from the current step's next step (as given by the
+  /// branchId) to the step with the given goalId
+  bool pathExistsFromNextStep(const QString& goalId, const QString& branchId)const;
+
+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();
+
+public:
+
+  QStateMachine* StateMachine;
+
+  // Maintain a list of pointers to the steps in the workflow,
+  // along with their forward and backward transitions
+  QMap<ctkWorkflowStep*, forwardAndBackwardSteps*>         StepToForwardAndBackwardStepMap;
+
+  // ... and its associated convenient typedef
+  typedef QMap<ctkWorkflowStep*, forwardAndBackwardSteps*> StepToForwardAndBackwardStepMapType;
+  typedef QList<ctkWorkflowStep*>                          StepListType;
+
+  // Maintain a map of <state, step> key/value pairs, to find the step
+  // that a given state belongs to
+  typedef QMap<const QAbstractState*, ctkWorkflowStep*>           StateToStepMapType;
+  typedef QMap<const QAbstractState*, ctkWorkflowStep*>::iterator StateToStepMapIterator;
+  StateToStepMapType                                              StateToStepMap;
+
+  ctkWorkflowStep*                         InitialStep;
+  ctkWorkflowStep*                         CurrentStep;
+  QMap<ctkWorkflowStep*, ctkWorkflowStep*> StepToPreviousStepMap;
+
+  // Used when performing a transition
+  ctkWorkflowStep*                                        OriginStep;
+  ctkWorkflowStep*                                        DestinationStep;
+  ctkWorkflowInterstepTransition::InterstepTransitionType TransitionType;
+
+  QString          DesiredBranchId; // Desired branchId specified when invoking goForward
+
+  ctkWorkflowStep* GoToStep;   // Desired step when attempting to go to a finish step
+
+  ctkWorkflowStep* StartingStep; // Current step when we began the attempt to go to the desired finish step
+
+  // Temporary transition after successfully going to finish step, to get us back to the starting step
+  ctkWorkflowInterstepTransition* TransitionToPreviousStartingStep;
+
+  QString ARTIFICIAL_BRANCH_ID_PREFIX;
+
+};
+
+#endif

+ 89 - 2
Libs/Scripting/Python/Core/Python/ctk/__init__.py.in

@@ -12,6 +12,93 @@ for kit in __kits_to_load:
   except ImportError as detail:
     if CTK_VERBOSE_IMPORT: 
       print detail
-   
+
+def add_methodclass_to_ctkWorkflowStep_or_ctkWorkflowWidgetStep(workflowstep_class):
+  
+  def validate(self, validationSucceed, desiredBranchId):
+    """Validates the computation performed in this step's processing state."""
+    self.ctkWorkflowStepQObject().validationComplete(validationSucceed, desiredBranchId)
+    
+  def onEntry(self, comingFrom, transitionType):
+    """Reimplement this function for step-specific processing when entering a step."""
+    self.ctkWorkflowStepQObject().onEntryComplete()
+
+  def onExit(self, comingFrom, transitionType):
+    """Reimplement this function for step-specific processing when exiting a step."""
+    self.ctkWorkflowStepQObject().onExitComplete()
+    
+  def initialize(self, stepid):
+    workflowstep_class.__init__(self)
+    self.setId(stepid)
+    self.setHasValidateCommand(True)
+    self.setHasOnEntryCommand(True)
+    self.setHasOnExitCommand(True)
+    
+    qobj = self.ctkWorkflowStepQObject()
+    
+    qobj.connect('invokeValidateCommand(const QString&)', self.validate)
+    
+    qobj.connect('invokeOnEntryCommand(const ctkWorkflowStep*, \
+      ctkWorkflowInterstepTransition::InterstepTransitionType)', self.onEntry)
+      
+    qobj.connect('invokeOnExitCommand(const ctkWorkflowStep*, \
+      ctkWorkflowInterstepTransition::InterstepTransitionType)', self.onExit)    
+    
+  workflowstep_class.validate = validate
+  workflowstep_class.onEntry = onEntry
+  workflowstep_class.onExit = onExit
+  workflowstep_class.initialize = initialize
+
+def add_methodclass_to_ctkWorkflowWidgetStep():
+  
+  def createUserInterface(self):
+    self.ctkWorkflowStepQObject().createUserInterfaceComplete()
+    
+  #def showUserInterface(self):
+  #  self.ctkWorkflowStepQObject().showUserInterfaceComplete()
+    
+  ctkWorkflowWidgetStep.createUserInterface = createUserInterface;
+  #ctkWorkflowWidgetStep.showUserInterface = showUserInterface;
+    
+def decorates_ctkWorkflowWidgetStep_initialize_method():
+  """Decorates ctkWorkflowWidgetStep::initialize() method.
+  The properties 'hasCreateUserInterfaceCommand' and 'hasShowUserInterfaceCommand'
+  are set to True.
+  Signals 'invokeCreateUserInterfaceCommand' and 'invokeShowUserInterfaceCommand'
+  are respectively connected to the slots 'createUserInterface' and 'showUserInterface'.
+  """
+  
+  f = ctkWorkflowWidgetStep.initialize
+  
+  from functools import wraps
+  @wraps(f)
+  def decorated(self, *args, **kwargs):
+    f(self, *args, **kwargs)
+    self.setHasCreateUserInterfaceCommand(True)
+    #self.setHasShowUserInterfaceCommand(True)
+    
+    qobj = self.ctkWorkflowStepQObject()
+    
+    qobj.connect('invokeCreateUserInterfaceCommand()', self.createUserInterface)
+    #qobj.connect('invokeShowUserInterfaceCommand()', self.showUserInterface)
+  
+  ctkWorkflowWidgetStep.initialize = decorated
+
+#
+# Decorators
+#
+
+_lib = next((_lib for _lib in __kits_to_load if _lib == 'Core'), None)
+if _lib == 'Core':
+  add_methodclass_to_ctkWorkflowStep_or_ctkWorkflowWidgetStep(ctkWorkflowStep)
+  
+_lib = next((_lib for _lib in __kits_to_load if _lib == 'Widgets'), None)
+if _lib == 'Widgets':
+  add_methodclass_to_ctkWorkflowStep_or_ctkWorkflowWidgetStep(ctkWorkflowWidgetStep)
+  add_methodclass_to_ctkWorkflowWidgetStep()
+  decorates_ctkWorkflowWidgetStep_initialize_method()
+
 # Removing things the user shouldn't have to see.
-del __kits_to_load
+del __kits_to_load, _lib
+del add_methodclass_to_ctkWorkflowStep_or_ctkWorkflowWidgetStep
+del add_methodclass_to_ctkWorkflowWidgetStep, decorates_ctkWorkflowWidgetStep_initialize_method

+ 21 - 4
Libs/Widgets/CMakeLists.txt

@@ -9,9 +9,6 @@ SET(KIT_export_directive "CTK_WIDGETS_EXPORT")
 
 # Source files
 SET(KIT_SRCS
-  ctkWorkflowAbstractWidgetStep.cpp
-  ctkWorkflowAbstractWidgetStep.h
-  ctkWorkflowAbstractWidgetStep_p.h
   ctkActionsWidget.cpp
   ctkActionsWidget.h
   ctkAddRemoveComboBox.cpp
@@ -116,14 +113,26 @@ SET(KIT_SRCS
   ctkWorkflowWidget.cpp
   ctkWorkflowWidget.h
   ctkWorkflowWidgetStep.cpp
+  ctkWorkflowWidgetStep_p.h
   ctkWorkflowWidgetStep.h
   ctkDateRangeWidget.cpp
   ctkDateRangeWidget.h
   )
 
+IF(CTK_WRAP_PYTHONQT_LIGHT)
+  LIST(APPEND KIT_SRCS
+    ctkWidgetsPythonQtDecorators.h
+    )
+  # Let's make sure the decorator are not wrapped !
+  SET_SOURCE_FILES_PROPERTIES(
+    ctkWidgetsPythonQtDecorators.h
+    WRAP_EXCLUDE
+    )
+ENDIF()
+
 # Headers that should run through moc
 SET(KIT_MOC_SRCS
-  ctkWorkflowAbstractWidgetStep_p.h
+  ctkWorkflowAbstractPagedWidget.h
   ctkActionsWidget.h
   ctkAxesWidget.h
   ctkAddRemoveComboBox.h
@@ -176,9 +185,17 @@ SET(KIT_MOC_SRCS
   ctkWorkflowTabWidget.h
   ctkWorkflowWidget.h
   ctkWorkflowWidgetStep.h
+  ctkWorkflowWidgetStep_p.h
   ctkDateRangeWidget.h
   )
 
+
+IF(CTK_WRAP_PYTHONQT_LIGHT)
+  LIST(APPEND KIT_MOC_SRCS
+    ctkWidgetsPythonQtDecorators.h
+    )
+ENDIF()
+
 # UI files
 SET(KIT_UI_FORMS
   Resources/UI/ctkAddRemoveComboBox.ui

+ 4 - 1
Libs/Widgets/Resources/UI/ctkWorkflowGroupBox.ui

@@ -188,6 +188,9 @@
        <verstretch>0</verstretch>
       </sizepolicy>
      </property>
+     <property name="active">
+      <bool>true</bool>
+     </property>
      <property name="activate" stdset="0">
       <bool>true</bool>
      </property>
@@ -219,7 +222,7 @@
    <sender>CollapsibleButton</sender>
    <signal>toggled(bool)</signal>
    <receiver>DynamicSpacer</receiver>
-   <slot>activate(bool)</slot>
+   <slot>setActive(bool)</slot>
    <hints>
     <hint type="sourcelabel">
      <x>260</x>

+ 12 - 18
Libs/Widgets/Testing/Cpp/ctkExampleUseOfWorkflowWidgetUsingSignalsAndSlots.cpp

@@ -92,9 +92,12 @@ int ctkExampleUseOfWorkflowWidgetUsingSignalsAndSlots(int argc, char * argv [] )
 
   // create the qObjects that implement the required functions for
   // each step, and communicate with the workflow using signals and slots
-  ctkExampleWorkflowWidgetStepUsingSignalsAndSlots* qObject1 = new ctkExampleWorkflowWidgetStepUsingSignalsAndSlots;
-  ctkExampleWorkflowWidgetStepUsingSignalsAndSlots* qObject2 = new ctkExampleWorkflowWidgetStepUsingSignalsAndSlots;
-  ctkExampleWorkflowWidgetStepUsingSignalsAndSlots* qObject3 = new ctkExampleWorkflowWidgetStepUsingSignalsAndSlots;
+  ctkExampleWorkflowWidgetStepUsingSignalsAndSlots* qObject1 =
+      new ctkExampleWorkflowWidgetStepUsingSignalsAndSlots(testStep1);
+  ctkExampleWorkflowWidgetStepUsingSignalsAndSlots* qObject2 =
+      new ctkExampleWorkflowWidgetStepUsingSignalsAndSlots(testStep2);
+  ctkExampleWorkflowWidgetStepUsingSignalsAndSlots* qObject3 =
+      new ctkExampleWorkflowWidgetStepUsingSignalsAndSlots(testStep3);
 
   // set the widget for each qObject
   qObject1->setWidget(testStep1->stepArea());
@@ -103,35 +106,26 @@ int ctkExampleUseOfWorkflowWidgetUsingSignalsAndSlots(int argc, char * argv [] )
 
   // use the qObjects for validation
   QObject::connect(testStep1->ctkWorkflowStepQObject(), SIGNAL(invokeValidateCommand(const QString&)), qObject1, SLOT(validate(const QString&)));
-  QObject::connect(qObject1, SIGNAL(validationComplete(bool, const QString&)), workflow, SLOT(evaluateValidationResults(bool, const QString&)));
   QObject::connect(testStep2->ctkWorkflowStepQObject(), SIGNAL(invokeValidateCommand(const QString&)), qObject2, SLOT(validate(const QString&)));
-  QObject::connect(qObject2, SIGNAL(validationComplete(bool, const QString&)), workflow, SLOT(evaluateValidationResults(bool, const QString&)));
   QObject::connect(testStep3->ctkWorkflowStepQObject(), SIGNAL(invokeValidateCommand(const QString&)), qObject3, SLOT(validate(const QString&)));
-  QObject::connect(qObject3, SIGNAL(validationComplete(bool, const QString&)), workflow, SLOT(evaluateValidationResults(bool, const QString&)));
 
   // use the qObjects for entry processing
   QObject::connect(testStep1->ctkWorkflowStepQObject(), SIGNAL(invokeOnEntryCommand(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)), qObject1, SLOT(onEntry(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)));
-  QObject::connect(qObject1, SIGNAL(onEntryComplete()), workflow, SLOT(processingAfterOnEntry()));
   QObject::connect(testStep2->ctkWorkflowStepQObject(), SIGNAL(invokeOnEntryCommand(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)), qObject2, SLOT(onEntry(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)));
-  QObject::connect(qObject2, SIGNAL(onEntryComplete()), workflow, SLOT(processingAfterOnEntry()));
   QObject::connect(testStep3->ctkWorkflowStepQObject(), SIGNAL(invokeOnEntryCommand(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)), qObject3, SLOT(onEntry(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)));
-  QObject::connect(qObject3, SIGNAL(onEntryComplete()), workflow, SLOT(processingAfterOnEntry()));
 
   // use the qObjects for exit processing
   QObject::connect(testStep1->ctkWorkflowStepQObject(), SIGNAL(invokeOnExitCommand(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)), qObject1, SLOT(onExit(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)));
-  QObject::connect(qObject1, SIGNAL(onExitComplete()), workflow, SLOT(processingAfterOnExit()));
   QObject::connect(testStep2->ctkWorkflowStepQObject(), SIGNAL(invokeOnExitCommand(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)), qObject2, SLOT(onExit(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)));
-  QObject::connect(qObject2, SIGNAL(onExitComplete()), workflow, SLOT(processingAfterOnExit()));
   QObject::connect(testStep3->ctkWorkflowStepQObject(), SIGNAL(invokeOnExitCommand(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)), qObject3, SLOT(onExit(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)));
-  QObject::connect(qObject3, SIGNAL(onExitComplete()), workflow, SLOT(processingAfterOnExit()));
 
   // use the qObjects for populating the stepWidgetsList
-  QObject::connect(testStep1->ctkWorkflowAbstractWidgetStepQObject(), SIGNAL(invokeCreateUserInterfaceCommand()), qObject1, SLOT(createUserInterface()));
-  QObject::connect(qObject1, SIGNAL(createUserInterfaceComplete()), testStep1->ctkWorkflowAbstractWidgetStepQObject(), SIGNAL(showUserInterfaceComplete()));
-  QObject::connect(testStep2->ctkWorkflowAbstractWidgetStepQObject(), SIGNAL(invokeCreateUserInterfaceCommand()), qObject2, SLOT(createUserInterface()));
-  QObject::connect(qObject2, SIGNAL(createUserInterfaceComplete()), testStep2->ctkWorkflowAbstractWidgetStepQObject(), SIGNAL(showUserInterfaceComplete()));
-  QObject::connect(testStep3->ctkWorkflowAbstractWidgetStepQObject(), SIGNAL(invokeCreateUserInterfaceCommand()), qObject3, SLOT(createUserInterface()));
-  QObject::connect(qObject3, SIGNAL(createUserInterfaceComplete()), testStep3->ctkWorkflowAbstractWidgetStepQObject(), SIGNAL(showUserInterfaceComplete()));
+  QObject::connect(testStep1->ctkWorkflowStepQObject(), SIGNAL(invokeCreateUserInterfaceCommand()), qObject1, SLOT(createUserInterface()));
+  QObject::connect(qObject1, SIGNAL(createUserInterfaceComplete()), testStep1->ctkWorkflowStepQObject(), SIGNAL(showUserInterfaceComplete()));
+  QObject::connect(testStep2->ctkWorkflowStepQObject(), SIGNAL(invokeCreateUserInterfaceCommand()), qObject2, SLOT(createUserInterface()));
+  QObject::connect(qObject2, SIGNAL(createUserInterfaceComplete()), testStep2->ctkWorkflowStepQObject(), SIGNAL(showUserInterfaceComplete()));
+  QObject::connect(testStep3->ctkWorkflowStepQObject(), SIGNAL(invokeCreateUserInterfaceCommand()), qObject3, SLOT(createUserInterface()));
+  QObject::connect(qObject3, SIGNAL(createUserInterfaceComplete()), testStep3->ctkWorkflowStepQObject(), SIGNAL(showUserInterfaceComplete()));
 
   testStep1->setHasValidateCommand(1);
   testStep1->setHasOnEntryCommand(1);

+ 16 - 4
Libs/Widgets/Testing/Cpp/ctkExampleWorkflowWidgetStepUsingSignalsAndSlots.cpp

@@ -50,6 +50,8 @@ public:
   int numberOfTimesRanOnEntry;
   int numberOfTimesRanOnExit;
 
+  ctkWorkflowStep * Step;
+
 };
 
 //-----------------------------------------------------------------------------
@@ -66,15 +68,21 @@ ctkExampleWorkflowWidgetStepUsingSignalsAndSlotsPrivate::ctkExampleWorkflowWidge
 
   this->numberOfTimesRanOnEntry = 0;
   this->numberOfTimesRanOnExit = 0;
+
+  this->Step = 0;
 }
 
 //-----------------------------------------------------------------------------
 // ctkExampleWorkflowWidgetStepUsingSignalsAndSlots methods
 
 //-----------------------------------------------------------------------------
-ctkExampleWorkflowWidgetStepUsingSignalsAndSlots::ctkExampleWorkflowWidgetStepUsingSignalsAndSlots(QObject* _parent) : Superclass(_parent)
+ctkExampleWorkflowWidgetStepUsingSignalsAndSlots::
+    ctkExampleWorkflowWidgetStepUsingSignalsAndSlots(ctkWorkflowStep* newStep, QObject* newParent) :
+    Superclass(newParent)
   , d_ptr(new ctkExampleWorkflowWidgetStepUsingSignalsAndSlotsPrivate)
 {
+  Q_D(ctkExampleWorkflowWidgetStepUsingSignalsAndSlots);
+  d->Step = newStep;
 }
 
 //-----------------------------------------------------------------------------
@@ -106,7 +114,8 @@ void ctkExampleWorkflowWidgetStepUsingSignalsAndSlots::onEntry(
   d->numberOfTimesRanOnEntry++;
 
   // signals that we are finished
-  emit onEntryComplete();
+  QObject::staticMetaObject.invokeMethod(
+      d->Step->ctkWorkflowStepQObject(), "onEntryComplete");
 }
 
 //-----------------------------------------------------------------------------
@@ -123,7 +132,8 @@ void ctkExampleWorkflowWidgetStepUsingSignalsAndSlots::onExit(
   d->numberOfTimesRanOnExit++;
 
   // signals that we are finished
-  emit onExitComplete();
+  QObject::staticMetaObject.invokeMethod(
+      d->Step->ctkWorkflowStepQObject(), "onExitComplete");
 }
 
 //-----------------------------------------------------------------------------
@@ -197,6 +207,8 @@ void ctkExampleWorkflowWidgetStepUsingSignalsAndSlots::validate(const QString& d
     }
 
   // return the validation results
-  emit validationComplete(retVal, desiredBranchId);
+  QObject::staticMetaObject.invokeMethod(
+      d->Step->ctkWorkflowStepQObject(), "validationComplete",
+      Q_ARG(bool, retVal), Q_ARG(QString, desiredBranchId));
 }
 

+ 2 - 1
Libs/Widgets/Testing/Cpp/ctkExampleWorkflowWidgetStepUsingSignalsAndSlots.h

@@ -80,7 +80,8 @@ class ctkExampleWorkflowWidgetStepUsingSignalsAndSlots : public QObject
 public:
 
   typedef QObject Superclass;
-  explicit ctkExampleWorkflowWidgetStepUsingSignalsAndSlots(QObject* parent = 0);
+  explicit ctkExampleWorkflowWidgetStepUsingSignalsAndSlots(ctkWorkflowStep* newStep,
+                                                            QObject* newParent = 0);
   virtual ~ctkExampleWorkflowWidgetStepUsingSignalsAndSlots();
 
   // Set/get the widget onto which this step's user interface will be placed

+ 1 - 1
Libs/Widgets/Testing/Cpp/ctkWorkflowWidgetTest1.cpp

@@ -43,7 +43,7 @@
 #include <iostream>
 
 //-----------------------------------------------------------------------------
-bool buttonClickTest(QApplication& app, int defaultTime, ctkWorkflowAbstractWidgetStep* currentStep, QWidget* shownStepArea, QLineEdit* shownLineEdit, QLabel* shownLabel, QWidget* hiddenStepArea, QLineEdit* hiddenLineEdit, QLabel* hiddenLabel, ctkWorkflow* workflow, ctkWorkflowWidget* workflowWidget, QPushButton* backButton, QPushButton* nextButton, QPushButton* finishButton1=0, QPushButton* finishButton2=0)
+bool buttonClickTest(QApplication& app, int defaultTime, ctkWorkflowWidgetStep* currentStep, QWidget* shownStepArea, QLineEdit* shownLineEdit, QLabel* shownLabel, QWidget* hiddenStepArea, QLineEdit* hiddenLineEdit, QLabel* hiddenLabel, ctkWorkflow* workflow, ctkWorkflowWidget* workflowWidget, QPushButton* backButton, QPushButton* nextButton, QPushButton* finishButton1=0, QPushButton* finishButton2=0)
 {
   QTimer::singleShot(defaultTime, &app, SLOT(quit()));
   app.exec();

+ 39 - 28
Libs/Widgets/Testing/Cpp/ctkWorkflowWidgetTest2.cpp

@@ -43,7 +43,7 @@
 #include <iostream>
 
 //-----------------------------------------------------------------------------
-bool buttonClickTestSignalSlot(QApplication& app, int defaultTime, ctkWorkflowAbstractWidgetStep* currentStep, QWidget* shownStepArea, QLineEdit* shownLineEdit, QLabel* shownLabel, QWidget* hiddenStepArea, QLineEdit* hiddenLineEdit, QLabel* hiddenLabel, ctkWorkflow* workflow, ctkWorkflowWidget* workflowWidget, QPushButton* backButton, QPushButton* nextButton, QPushButton* finishButton1=0, QPushButton* finishButton2=0)
+bool buttonClickTestSignalSlot(QApplication& app, int defaultTime, ctkWorkflowWidgetStep* currentStep, QWidget* shownStepArea, QLineEdit* shownLineEdit, QLabel* shownLabel, QWidget* hiddenStepArea, QLineEdit* hiddenLineEdit, QLabel* hiddenLabel, ctkWorkflow* workflow, ctkWorkflowWidget* workflowWidget, QPushButton* backButton, QPushButton* nextButton, QPushButton* finishButton1=0, QPushButton* finishButton2=0)
 {
   QTimer::singleShot(defaultTime, &app, SLOT(quit()));
   app.exec();
@@ -585,36 +585,46 @@ int ctkWorkflowWidgetTest2(int argc, char * argv [] )
 
   // create the qObjects that implement the required functions, and
   // communicate with the workflow using signals and slots
-  ctkExampleWorkflowWidgetStepUsingSignalsAndSlots* qObject1 = new ctkExampleWorkflowWidgetStepUsingSignalsAndSlots;
-  ctkExampleWorkflowWidgetStepUsingSignalsAndSlots* qObject2 = new ctkExampleWorkflowWidgetStepUsingSignalsAndSlots;
+  ctkExampleWorkflowWidgetStepUsingSignalsAndSlots* qObject1 =
+      new ctkExampleWorkflowWidgetStepUsingSignalsAndSlots(step1);
+  ctkExampleWorkflowWidgetStepUsingSignalsAndSlots* qObject2 =
+      new ctkExampleWorkflowWidgetStepUsingSignalsAndSlots(step2);
 
   // set the widget for each qObject
   qObject1->setWidget(step1->stepArea());
   qObject2->setWidget(step2->stepArea());
 
   // use the qObjects for validation
-  QObject::connect(step1->ctkWorkflowStepQObject(), SIGNAL(invokeValidateCommand(const QString&)), qObject1, SLOT(validate(const QString&)));
-  QObject::connect(qObject1, SIGNAL(validationComplete(bool, const QString&)), workflow, SLOT(evaluateValidationResults(bool, const QString&)));
-  QObject::connect(step2->ctkWorkflowStepQObject(), SIGNAL(invokeValidateCommand(const QString&)), qObject2, SLOT(validate(const QString&)));
-  QObject::connect(qObject2, SIGNAL(validationComplete(bool, const QString&)), workflow, SLOT(evaluateValidationResults(bool, const QString&)));
+  QObject::connect(step1->ctkWorkflowStepQObject(),
+                   SIGNAL(invokeValidateCommand(const QString&)),
+                   qObject1, SLOT(validate(const QString&)));
+  QObject::connect(step2->ctkWorkflowStepQObject(),
+                   SIGNAL(invokeValidateCommand(const QString&)),
+                   qObject2, SLOT(validate(const QString&)));
 
   // use the qObjects for entry processing
-  QObject::connect(step1->ctkWorkflowStepQObject(), SIGNAL(invokeOnEntryCommand(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)), qObject1, SLOT(onEntry(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)));
-  QObject::connect(qObject1, SIGNAL(onEntryComplete()), workflow, SLOT(processingAfterOnEntry()));
-  QObject::connect(step2->ctkWorkflowStepQObject(), SIGNAL(invokeOnEntryCommand(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)), qObject2, SLOT(onEntry(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)));
-  QObject::connect(qObject2, SIGNAL(onEntryComplete()), workflow, SLOT(processingAfterOnEntry()));
+  QObject::connect(step1->ctkWorkflowStepQObject(),
+                   SIGNAL(invokeOnEntryCommand(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)),
+                   qObject1, SLOT(onEntry(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)));
+  QObject::connect(step2->ctkWorkflowStepQObject(),
+                   SIGNAL(invokeOnEntryCommand(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)),
+                   qObject2, SLOT(onEntry(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)));
 
   // use the qObjects for exit processing
-  QObject::connect(step1->ctkWorkflowStepQObject(), SIGNAL(invokeOnExitCommand(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)), qObject1, SLOT(onExit(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)));
-  QObject::connect(qObject1, SIGNAL(onExitComplete()), workflow, SLOT(processingAfterOnExit()));
-  QObject::connect(step2->ctkWorkflowStepQObject(), SIGNAL(invokeOnExitCommand(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)), qObject2, SLOT(onExit(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)));
-  QObject::connect(qObject2, SIGNAL(onExitComplete()), workflow, SLOT(processingAfterOnExit()));
+  QObject::connect(step1->ctkWorkflowStepQObject(),
+                   SIGNAL(invokeOnExitCommand(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)),
+                   qObject1, SLOT(onExit(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)));
+  QObject::connect(step2->ctkWorkflowStepQObject(),
+                   SIGNAL(invokeOnExitCommand(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)),
+                   qObject2, SLOT(onExit(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)));
 
   // use the qObjects for populating the stepWidgetsList
-  QObject::connect(step1->ctkWorkflowAbstractWidgetStepQObject(), SIGNAL(invokeCreateUserInterfaceCommand()), qObject1, SLOT(createUserInterface()));
-  QObject::connect(qObject1, SIGNAL(createUserInterfaceComplete()), step1->ctkWorkflowAbstractWidgetStepQObject(), SIGNAL(showUserInterfaceComplete()));
-  QObject::connect(step2->ctkWorkflowAbstractWidgetStepQObject(), SIGNAL(invokeCreateUserInterfaceCommand()), qObject2, SLOT(createUserInterface()));
-  QObject::connect(qObject2, SIGNAL(createUserInterfaceComplete()), step2->ctkWorkflowAbstractWidgetStepQObject(), SIGNAL(showUserInterfaceComplete()));
+  QObject::connect(step1->ctkWorkflowStepQObject(),
+                   SIGNAL(invokeCreateUserInterfaceCommand()),
+                   qObject1, SLOT(createUserInterface()));
+  QObject::connect(step2->ctkWorkflowStepQObject(),
+                   SIGNAL(invokeCreateUserInterfaceCommand()),
+                   qObject2, SLOT(createUserInterface()));
 
   step1->setHasValidateCommand(1);
   step2->setHasValidateCommand(1);
@@ -665,25 +675,26 @@ int ctkWorkflowWidgetTest2(int argc, char * argv [] )
 
   // create the qObjects that implement the required functions, and
   // communicate with the workflow using signals and slots
-  ctkExampleWorkflowWidgetStepUsingSignalsAndSlots* qObject3 = new ctkExampleWorkflowWidgetStepUsingSignalsAndSlots;
+  ctkExampleWorkflowWidgetStepUsingSignalsAndSlots* qObject3 =
+      new ctkExampleWorkflowWidgetStepUsingSignalsAndSlots(step3);
 
   qObject3->setWidget(step3->stepArea());
 
   // use the qObjects for validation
-  QObject::connect(step3->ctkWorkflowStepQObject(), SIGNAL(invokeValidateCommand(const QString&)), qObject3, SLOT(validate(const QString&)));
-  QObject::connect(qObject3, SIGNAL(validationComplete(bool, const QString&)), workflow, SLOT(evaluateValidationResults(bool, const QString&)));
+  QObject::connect(step3->ctkWorkflowStepQObject(), SIGNAL(invokeValidateCommand(const QString&)),
+                   qObject3, SLOT(validate(const QString&)));
 
   // use the qObjects for entry processing
-  QObject::connect(step3->ctkWorkflowStepQObject(), SIGNAL(invokeOnEntryCommand(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)), qObject3, SLOT(onEntry(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)));
-  QObject::connect(qObject3, SIGNAL(onEntryComplete()), workflow, SLOT(processingAfterOnEntry()));
+  QObject::connect(step3->ctkWorkflowStepQObject(), SIGNAL(invokeOnEntryCommand(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)),
+                   qObject3, SLOT(onEntry(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)));
 
   // use the qObjects for exit processing
-  QObject::connect(step3->ctkWorkflowStepQObject(), SIGNAL(invokeOnExitCommand(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)), qObject3, SLOT(onExit(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)));
-  QObject::connect(qObject3, SIGNAL(onExitComplete()), workflow, SLOT(processingAfterOnExit()));
+  QObject::connect(step3->ctkWorkflowStepQObject(), SIGNAL(invokeOnExitCommand(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)),
+                   qObject3, SLOT(onExit(const ctkWorkflowStep*, const ctkWorkflowInterstepTransition::InterstepTransitionType)));
 
   // use the qObjects for populating the stepWidgetsList
-  QObject::connect(step3->ctkWorkflowAbstractWidgetStepQObject(), SIGNAL(invokeCreateUserInterfaceCommand()), qObject3, SLOT(createUserInterface()));
-  QObject::connect(qObject3, SIGNAL(createUserInterfaceComplete()), step3->ctkWorkflowAbstractWidgetStepQObject(), SIGNAL(createUserInterfaceComplete()));
+  QObject::connect(step3->ctkWorkflowStepQObject(), SIGNAL(invokeCreateUserInterfaceCommand()), qObject3, SLOT(createUserInterface()));
+  QObject::connect(qObject3, SIGNAL(createUserInterfaceComplete()), step3->ctkWorkflowStepQObject(), SIGNAL(createUserInterfaceComplete()));
 
   step3->setHasValidateCommand(1);
   step3->setHasOnEntryCommand(1);

+ 70 - 0
Libs/Widgets/ctkWidgetsPythonQtDecorators.h

@@ -0,0 +1,70 @@
+/*=auto=========================================================================
+
+ Portions (c) Copyright 2005 Brigham and Women's Hospital (BWH) 
+ All Rights Reserved.
+
+ See Doc/copyright/copyright.txt
+ or http://www.slicer.org/copyright/copyright.txt for details.
+
+ Program:   3D Slicer
+
+=========================================================================auto=*/
+
+#ifndef __ctkWidgetsPythonQtDecorators_h
+#define __ctkWidgetsPythonQtDecorators_h
+
+// Qt includes
+#include <QObject>
+
+// PythonQt includes
+#include <PythonQt.h>
+
+// CTK includes
+#include <ctkWorkflowWidgetStep.h>
+
+#include "ctkWidgetsExport.h"
+
+// NOTE:
+//
+// For decorators it is assumed that the methods will never be called
+// with the self argument as NULL.  The self argument is the first argument
+// for non-static methods.
+//
+
+class CTK_WIDGETS_EXPORT ctkWidgetsPythonQtDecorators : public QObject
+{
+  Q_OBJECT
+public:
+
+  ctkWidgetsPythonQtDecorators()
+    {
+    PythonQt::self()->addParentClass("ctkWorkflowWidgetStep", "ctkWorkflowStep",
+                                     PythonQtUpcastingOffset<ctkWorkflowWidgetStep,ctkWorkflowStep>());
+    }
+
+public slots:
+
+  bool hasCreateUserInterfaceCommand(ctkWorkflowWidgetStep* step)const
+    {
+    return step->hasCreateUserInterfaceCommand();
+    }
+
+  void setHasCreateUserInterfaceCommand(
+    ctkWorkflowWidgetStep* step, bool newHasCreateUserInterfaceCommand)
+    {
+    step->setHasCreateUserInterfaceCommand(newHasCreateUserInterfaceCommand);
+    }
+
+  bool hasShowUserInterfaceCommand(ctkWorkflowWidgetStep* step)const
+    {
+    return step->hasShowUserInterfaceCommand();
+    }
+
+  void setHasShowUserInterfaceCommand(
+    ctkWorkflowWidgetStep* step, bool newHasShowUserInterfaceCommand)
+    {
+    step->setHasShowUserInterfaceCommand(newHasShowUserInterfaceCommand);
+    }
+};
+
+#endif

+ 0 - 223
Libs/Widgets/ctkWorkflowAbstractWidgetStep.cpp

@@ -1,223 +0,0 @@
-/*=========================================================================
-
-  Library:   CTK
-
-  Copyright (c) Kitware Inc.
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-  http://www.commontk.org/LICENSE
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-
-  =========================================================================*/
-
-// Qt includes
-#include <QObject>
-#include <QWidget>
-#include <QList>
-#include <QDebug>
-#include <QIcon>
-
-// CTK includes
-#include "ctkWorkflowAbstractWidgetStep.h"
-#include "ctkWorkflowAbstractWidgetStep_p.h"
-#include "ctkWorkflowWidget.h"
-#include "ctkWorkflow.h"
-//#include "ctkWorkflowButtonBoxWidget.h"
-#include "ctkLogger.h"
-
-// STD includes
-#include <iostream>
-
-//-----------------------------------------------------------------------------
-static ctkLogger logger("org.commontk.libs.widgets.ctkWorkflowAbstractWidgetStep");
-//-----------------------------------------------------------------------------
-
-//-----------------------------------------------------------------------------
-// ctkWorkflowAbstractWidgetStepPrivate methods
-
-//-----------------------------------------------------------------------------
-ctkWorkflowAbstractWidgetStepPrivate::ctkWorkflowAbstractWidgetStepPrivate(ctkWorkflowAbstractWidgetStep& object)
-  :q_ptr(&object)
-{
-//  this->buttonBoxWidget = 0;
-//  this->hasButtonBoxWidget = false;
-
-  this->icon = QIcon();
-  this->created = false;
-}
-
-//-----------------------------------------------------------------------------
-void ctkWorkflowAbstractWidgetStepPrivate::invokeShowUserInterfaceCommandInternal()const
-{
-  emit invokeShowUserInterfaceCommand();
-}
-
-//-----------------------------------------------------------------------------
-void ctkWorkflowAbstractWidgetStepPrivate::showUserInterfaceCompleteInternal()const
-{
-  emit showUserInterfaceComplete();
-}
-
-//-----------------------------------------------------------------------------
-void ctkWorkflowAbstractWidgetStepPrivate::showUserInterface()
-{
-  Q_Q(ctkWorkflowAbstractWidgetStep);
-  q->showUserInterface();
-}
-
-//-----------------------------------------------------------------------------
-void ctkWorkflowAbstractWidgetStepPrivate::invokeCreateUserInterfaceCommandInternal()const
-{
-  emit invokeCreateUserInterfaceCommand();
-}
-
-//-----------------------------------------------------------------------------
-void ctkWorkflowAbstractWidgetStepPrivate::createUserInterfaceCompleteInternal()const
-{
-  emit createUserInterfaceComplete();
-}
-
-//-----------------------------------------------------------------------------
-// ctkWorkflowAbstractWidgetStep methods
-
-//-----------------------------------------------------------------------------
-ctkWorkflowAbstractWidgetStep::ctkWorkflowAbstractWidgetStep(ctkWorkflow* newWorkflow, const QString& newId) : Superclass(newWorkflow, newId)
-  , d_ptr(new ctkWorkflowAbstractWidgetStepPrivate(*this))
-{
-  Q_D(ctkWorkflowAbstractWidgetStep);
-  d->hasShowUserInterfaceCommand = 0;
-  d->hasCreateUserInterfaceCommand = 0;
-  d->ButtonBoxHints = ctkWorkflowAbstractWidgetStep::NoHints;
-}
-
-//-----------------------------------------------------------------------------
-ctkWorkflowAbstractWidgetStep::~ctkWorkflowAbstractWidgetStep()
-{
-}
-
-//-----------------------------------------------------------------------------
-CTK_GET_CPP(ctkWorkflowAbstractWidgetStep, int, hasShowUserInterfaceCommand, hasShowUserInterfaceCommand);
-CTK_SET_CPP(ctkWorkflowAbstractWidgetStep, int, setHasShowUserInterfaceCommand, hasShowUserInterfaceCommand);
-CTK_GET_CPP(ctkWorkflowAbstractWidgetStep, int, hasCreateUserInterfaceCommand, hasCreateUserInterfaceCommand);
-CTK_SET_CPP(ctkWorkflowAbstractWidgetStep, int, setHasCreateUserInterfaceCommand, hasCreateUserInterfaceCommand);
-CTK_GET_CPP(ctkWorkflowAbstractWidgetStep, QString, backButtonText, backButtonText);
-CTK_SET_CPP(ctkWorkflowAbstractWidgetStep, const QString&, setBackButtonText, backButtonText);
-CTK_GET_CPP(ctkWorkflowAbstractWidgetStep, QString, nextButtonText, nextButtonText);
-CTK_SET_CPP(ctkWorkflowAbstractWidgetStep, const QString&, setNextButtonText, nextButtonText);
-// CTK_GET_CPP(ctkWorkflowAbstractWidgetStep, QList<QString>, finishButtonTexts, finishButtonTexts);
-// CTK_SET_CPP(ctkWorkflowAbstractWidgetStep, QList<QString>, setFinishButtonTexts, finishButtonTexts);
-//CTK_GET_CPP(ctkWorkflowAbstractWidgetStep, bool, hasButtonBoxWidget, hasButtonBoxWidget);
-//CTK_SET_CPP(ctkWorkflowAbstractWidgetStep, bool, setHasButtonBoxWidget, hasButtonBoxWidget);
-CTK_GET_CPP(ctkWorkflowAbstractWidgetStep, QIcon, icon, icon);
-CTK_SET_CPP(ctkWorkflowAbstractWidgetStep, const QIcon&, setIcon, icon);
-
-//-----------------------------------------------------------------------------
-CTK_GET_CPP(ctkWorkflowAbstractWidgetStep, ctkWorkflowAbstractWidgetStep::ButtonBoxHints,
-            buttonBoxHints, ButtonBoxHints);
-CTK_SET_CPP(ctkWorkflowAbstractWidgetStep, ctkWorkflowAbstractWidgetStep::ButtonBoxHints,
-            setButtonBoxHints, ButtonBoxHints);
-
-//-----------------------------------------------------------------------------
-// void ctkWorkflowAbstractWidgetStep::setFinishButtonText(const QString& name)
-// {
-//   QList<QString> names;
-//   names << name;
-//   this->setFinishButtonTexts(names);
-// }
-
-// //-----------------------------------------------------------------------------
-// ctkWorkflowButtonBoxWidget* ctkWorkflowAbstractWidgetStep::buttonBoxWidget()
-// {
-//   Q_D(ctkWorkflowAbstractWidgetStep);
-
-//   if (!d->hasButtonBoxWidget)
-//     {
-//     return 0;
-//     }
-
-//   if (!d->buttonBoxWidget)
-//     {
-//     if (!this->workflow())
-//       {
-//       logger.error("buttonBoxWidget - Cannot create buttonBoxWidget without a workflow");
-//       return 0;
-//       }
-//     d->buttonBoxWidget = new ctkWorkflowButtonBoxWidget(this->workflow());
-//     }
-//   return d->buttonBoxWidget;
-// }
-
-//-----------------------------------------------------------------------------
-void ctkWorkflowAbstractWidgetStep::showUserInterface()
-{
-  Q_D(ctkWorkflowAbstractWidgetStep);
-
-  // use the user's showUserInterfaceCommand if given
-  if (d->hasShowUserInterfaceCommand)
-    {
-    this->invokeShowUserInterfaceCommand();
-    return;
-    }
-
-  // otherwise we provide an implementation here
-  logger.debug(QString("showUserInterface - showing %1").arg(this->name()));
-
-  // create the user interface if this is the first time we're showing this step
-  if (!d->created)
-    {
-    if (d->hasCreateUserInterfaceCommand)
-      {
-      this->invokeCreateUserInterfaceCommand();
-      }
-    else
-      {
-      this->createUserInterface();
-      }
-    d->created = true;
-    }
-
-  emit showUserInterfaceComplete();
-}
-
-// --------------------------------------------------------------------------
-QObject* ctkWorkflowAbstractWidgetStep::ctkWorkflowAbstractWidgetStepQObject()
-{
-  Q_D(ctkWorkflowAbstractWidgetStep);
-  return d;
-}
-
-//-----------------------------------------------------------------------------
-void ctkWorkflowAbstractWidgetStep::invokeShowUserInterfaceCommand()const
-{
-  Q_D(const ctkWorkflowAbstractWidgetStep);
-  d->invokeShowUserInterfaceCommandInternal();
-}
-
-//-----------------------------------------------------------------------------
-void ctkWorkflowAbstractWidgetStep::showUserInterfaceComplete()const
-{
-  Q_D(const ctkWorkflowAbstractWidgetStep);
-  d->showUserInterfaceCompleteInternal();
-}
-
-//-----------------------------------------------------------------------------
-void ctkWorkflowAbstractWidgetStep::invokeCreateUserInterfaceCommand()const
-{
-  Q_D(const ctkWorkflowAbstractWidgetStep);
-  d->invokeCreateUserInterfaceCommandInternal();
-}
-
-//-----------------------------------------------------------------------------
-void ctkWorkflowAbstractWidgetStep::createUserInterfaceComplete()const
-{
-  Q_D(const ctkWorkflowAbstractWidgetStep);
-  d->createUserInterfaceCompleteInternal();
-}

+ 0 - 155
Libs/Widgets/ctkWorkflowAbstractWidgetStep.h

@@ -1,155 +0,0 @@
-/*=========================================================================
-
-  Library:   CTK
-
-  Copyright (c) Kitware Inc.
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-      http://www.commontk.org/LICENSE
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-
-=========================================================================*/
-
-#ifndef __ctkWorkflowAbstractWidgetStep_h
-#define __ctkWorkflowAbstractWidgetStep_h 
-
-// QT includes
-class QObject;
-class QWidget;
-class QIcon;
-#include <QBoxLayout>
-#include <QFlags>
-
-// CTK includes
-#include "ctkPimpl.h"
-#include "ctkWidgetsExport.h"
-#include "ctkWorkflowStep.h"
-#include "ctkWorkflowTransitions.h"
-//class ctkWorkflowButtonBoxWidget;
-class ctkWorkflowGroupBox;
-
-class ctkWorkflowAbstractWidgetStepPrivate;
-
-///
-/// \brief ctkWorkflowAbstractWidgetStep is a convienience class to quickly
-/// construct a ctkWorkflowStep with a user interface.
-///
-/// It embeds a QWidget* stepArea, onto which step-specific widgets can be placed.
-/// The showUserInterface() and hideUserInterface() commands of ctkWorkflowStep are
-/// written for you, and, if you desire, the step's "Next" and/or "Back" buttons are
-/// added with the appropriate signals and slots.
-/// To create a custom step, you can derive from this class and
-/// implement only two functions:
-/// 1) ctkWorkflowAbstractWidgetStep::populateStepWidgetsList(), to define the
-/// step-specific widgets;
-/// 2) ctkWorkflowAbstractWidgetStep::validate(const QString&), to validate the processing
-/// state associated with this step.
-/// For additional customization, you can reimplement
-/// showUserInterface() and hideUserInterface() in derived classes.
-/// \sa showUserInterface() hideUserInterface()
-
-class CTK_WIDGETS_EXPORT ctkWorkflowAbstractWidgetStep : public ctkWorkflowStep
-{
-public:
-
-  enum ButtonBoxHint {
-    NoHints = 0x0,
-    BackButtonHidden = 0x1,
-    BackButtonDisabled = 0x2,
-    NextButtonHidden = 0x4,
-    NextButtonDisabled = 0x8,
-    ButtonBoxHidden = 0x10
-  };
-  Q_DECLARE_FLAGS(ButtonBoxHints, ButtonBoxHint)
-
-  typedef ctkWorkflowStep Superclass;
-  explicit ctkWorkflowAbstractWidgetStep(ctkWorkflow* newWorkflow, const QString& newId);
-  virtual ~ctkWorkflowAbstractWidgetStep();
-
-  /// \brief Override the back button text of any ctkWorkflowButtonBox when this step
-  /// is the current step
-  virtual QString backButtonText()const;
-  virtual void setBackButtonText(const QString& name);
-
-  /// \brief Override the next button text of any ctkWorkflowButtonBox when this step
-  /// is the current step
-  virtual QString nextButtonText()const;
-  virtual void setNextButtonText(const QString& name);
-
-  /// \brief Override the button visibility of any ctkWorkflowButtonBox when this step is the
-  /// current step
-  void setButtonBoxHints(ButtonBoxHints buttonBoxHints);
-  ButtonBoxHints buttonBoxHints()const;
-
-  /// \brief Associate an icon with this step (ex. used by ctkWorkflowButtonBox to display an icon
-  /// on 'goTo' buttons).
-  QIcon icon()const;
-  void setIcon(const QIcon& newIcon);
-
-  /// Get the QObject associated with this step, to connect signals/slots
-  QObject* ctkWorkflowAbstractWidgetStepQObject();
-
-  /// Returns the QWidget onto which this step's user interface elements are placed.
-  virtual QWidget* stepArea() = 0;
-
-  /// Set/get whether a showUserInterfaceCommand has been provided in
-  /// a separate QObject (see method 2 described for
-  /// showUserInterface())
-  virtual int hasShowUserInterfaceCommand()const;
-  virtual void setHasShowUserInterfaceCommand(int flag);
-
-  /// Set/get whether a createUserInterfaceCommand has been provided in
-  /// a separate QObject (see method 2 described for
-  /// createUserInterface())
-  virtual int hasCreateUserInterfaceCommand()const;
-  virtual void setHasCreateUserInterfaceCommand(int flag);
-
-protected:
-
-  /// Creates the user interface associated with this step.
-  virtual void createUserInterface() = 0;
-
-  /// Prepares the step to be shown.
-  virtual void showUserInterface();
-
-  /// \brief Signal (emitted by the private implementation) indicating that the step's
-  /// createUserInterface() method should be called.
-  /// \sa createUserInterface()
-  void invokeCreateUserInterfaceCommand()const;
-
-  /// \brief Signal (emitted by the private implementation) indicating that the step's
-  /// createUserInterface() method has completed.
-  /// \sa createUserInterface()
-  void createUserInterfaceComplete()const;
-
-  /// \brief Signal (emitted by the private implementation) indicating that the step's
-  /// 'showUserInterface() method should be called.
-  /// \sa showUserInterface()
-  void invokeShowUserInterfaceCommand()const;
-
-  /// \brief Signal (emitted by the private implementation) indicating that the step's
-  /// showUserInterface() method has completed.
-  /// \sa showUserInterface()
-  void showUserInterfaceComplete()const;
-
-protected:
-  QScopedPointer<ctkWorkflowAbstractWidgetStepPrivate> d_ptr;
-
-private:
-  Q_DECLARE_PRIVATE(ctkWorkflowAbstractWidgetStep);
-  Q_DISABLE_COPY(ctkWorkflowAbstractWidgetStep);
-  friend class ctkWorkflowGroupBox; // For access to showUserInterface()
-};
-
- Q_DECLARE_OPERATORS_FOR_FLAGS(ctkWorkflowAbstractWidgetStep::ButtonBoxHints)
-
-#endif
-

+ 10 - 10
Libs/Widgets/ctkWorkflowButtonBoxWidget.cpp

@@ -30,7 +30,7 @@
 // CTK includes
 #include "ctkWorkflowButtonBoxWidget.h"
 #include "ctkWorkflowStep.h"
-#include "ctkWorkflowAbstractWidgetStep.h"
+#include "ctkWorkflowWidgetStep.h"
 #include "ctkWorkflow.h"
 
 // STD includes
@@ -118,7 +118,7 @@ void ctkWorkflowButtonBoxWidgetPrivate::updateBackButton(ctkWorkflowStep* curren
   Q_ASSERT(q->layout());
 #endif
 
-  ctkWorkflowAbstractWidgetStep* step = dynamic_cast<ctkWorkflowAbstractWidgetStep*>(currentStep);
+  ctkWorkflowWidgetStep* step = dynamic_cast<ctkWorkflowWidgetStep*>(currentStep);
 
   // Set the back button text
   QString backButtonText = this->BackButtonDefaultText;
@@ -138,9 +138,9 @@ void ctkWorkflowButtonBoxWidgetPrivate::updateBackButton(ctkWorkflowStep* curren
     if (step)
       {
       this->BackButton->setDisabled(
-          step->buttonBoxHints() & ctkWorkflowAbstractWidgetStep::BackButtonDisabled);
+          step->buttonBoxHints() & ctkWorkflowWidgetStep::BackButtonDisabled);
       this->BackButton->setHidden(
-          step->buttonBoxHints() & ctkWorkflowAbstractWidgetStep::BackButtonHidden);
+          step->buttonBoxHints() & ctkWorkflowWidgetStep::BackButtonHidden);
       }
     }
   // Disable the back button if we can't go backward, and optionally hide it
@@ -162,7 +162,7 @@ void ctkWorkflowButtonBoxWidgetPrivate::updateNextButton(ctkWorkflowStep* curren
   Q_ASSERT(q->layout());
 #endif
 
-  ctkWorkflowAbstractWidgetStep* step = dynamic_cast<ctkWorkflowAbstractWidgetStep*>(currentStep);
+  ctkWorkflowWidgetStep* step = dynamic_cast<ctkWorkflowWidgetStep*>(currentStep);
 
   // Set the next button text
   QString nextButtonText = this->NextButtonDefaultText;
@@ -182,9 +182,9 @@ void ctkWorkflowButtonBoxWidgetPrivate::updateNextButton(ctkWorkflowStep* curren
     if (step)
       {
       this->NextButton->setDisabled(
-          step->buttonBoxHints() & ctkWorkflowAbstractWidgetStep::NextButtonDisabled);
+          step->buttonBoxHints() & ctkWorkflowWidgetStep::NextButtonDisabled);
       this->NextButton->setHidden(
-          step->buttonBoxHints() & ctkWorkflowAbstractWidgetStep::NextButtonHidden);
+          step->buttonBoxHints() & ctkWorkflowWidgetStep::NextButtonHidden);
       }
     }
   // Disable the next button if we can't go forward, and optionally hide it
@@ -230,7 +230,7 @@ void ctkWorkflowButtonBoxWidgetPrivate::updateGoToButtons(ctkWorkflowStep* curre
       QObject::connect(goToButton, SIGNAL(clicked()), q, SLOT(prepareGoToStep()));
       this->GoToButtonToStepMap[goToButton] = step;
       // if the goTo step has an icon associated with it, then add it to the button
-      if (ctkWorkflowAbstractWidgetStep* wwStep = dynamic_cast<ctkWorkflowAbstractWidgetStep*>(step))
+      if (ctkWorkflowWidgetStep* wwStep = dynamic_cast<ctkWorkflowWidgetStep*>(step))
         {
         goToButton->setIcon(wwStep->icon());
         }
@@ -393,9 +393,9 @@ void ctkWorkflowButtonBoxWidget::updateButtons(ctkWorkflowStep* currentStep)
   Q_D(ctkWorkflowButtonBoxWidget);
 
   // hide aspects of the button bar if specified by the current step
-  if(ctkWorkflowAbstractWidgetStep* currentWidgetStep = dynamic_cast<ctkWorkflowAbstractWidgetStep*>(currentStep))
+  if(ctkWorkflowWidgetStep* currentWidgetStep = dynamic_cast<ctkWorkflowWidgetStep*>(currentStep))
     {
-    bool hideButtonBar = currentWidgetStep->buttonBoxHints() & ctkWorkflowAbstractWidgetStep::ButtonBoxHidden;
+    bool hideButtonBar = currentWidgetStep->buttonBoxHints() & ctkWorkflowWidgetStep::ButtonBoxHidden;
     this->setHidden(hideButtonBar);
     }
 

+ 3 - 3
Libs/Widgets/ctkWorkflowGroupBox.cpp

@@ -26,7 +26,7 @@
 
 // CTK includes
 #include "ctkWorkflowGroupBox.h"
-#include "ctkWorkflowAbstractWidgetStep.h"
+#include "ctkWorkflowWidgetStep.h"
 #include "ctkFittedTextBrowser.h"
 #include "ui_ctkWorkflowGroupBox.h"
 #include "ctkLogger.h"
@@ -117,7 +117,7 @@ void ctkWorkflowGroupBox::updateGroupBox(ctkWorkflowStep* currentStep)
     }
 
   // disable/hide the previously shown step
-  if (ctkWorkflowAbstractWidgetStep* prevStep = dynamic_cast<ctkWorkflowAbstractWidgetStep*>(d->StepShownPreviously))
+  if (ctkWorkflowWidgetStep* prevStep = dynamic_cast<ctkWorkflowWidgetStep*>(d->StepShownPreviously))
     {
     logger.debug(QString("updateClientArea - hiding %1").arg(prevStep->name()));
     if (QWidget* stepArea = prevStep->stepArea())
@@ -130,7 +130,7 @@ void ctkWorkflowGroupBox::updateGroupBox(ctkWorkflowStep* currentStep)
       }
     }
   
-  ctkWorkflowAbstractWidgetStep* currentWidgetStep = dynamic_cast<ctkWorkflowAbstractWidgetStep*>(currentStep);
+  ctkWorkflowWidgetStep* currentWidgetStep = dynamic_cast<ctkWorkflowWidgetStep*>(currentStep);
   // show/enable the current step
   if (currentWidgetStep)
     {

+ 4 - 4
Libs/Widgets/ctkWorkflowWidget.h

@@ -43,7 +43,7 @@ class ctkWorkflowWidgetPrivate;
 class CTK_WIDGETS_EXPORT ctkWorkflowWidget : public QWidget
 {
   Q_OBJECT
-
+  Q_PROPERTY(bool showButtonBoxWidget READ showButtonBoxWidget WRITE setShowButtonBoxWidget)
 public:
 
   typedef QWidget Superclass;
@@ -51,8 +51,8 @@ public:
   virtual ~ctkWorkflowWidget();
 
   /// Set/get the workflow associated with this widget.
-  virtual ctkWorkflow* workflow()const;
-  virtual void setWorkflow(ctkWorkflow* newWorkflow);
+  Q_INVOKABLE virtual ctkWorkflow* workflow()const;
+  Q_INVOKABLE virtual void setWorkflow(ctkWorkflow* newWorkflow);
 
   /// Get the widget constaining the title, subtitle, pre-text, post-text, error-text and client area
   /// layout.
@@ -63,7 +63,7 @@ public:
   void setShowButtonBoxWidget(bool newShowButtonBoxWidget);
 
   /// Get the widget with the 'next', 'back' and 'goTo' buttons
-  ctkWorkflowButtonBoxWidget* buttonBoxWidget()const;
+  Q_INVOKABLE ctkWorkflowButtonBoxWidget* buttonBoxWidget()const;
 
 public slots:
   /// Triggers updates of the the workflowGroupBox and the buttonBoxWidget when the current workflow

+ 155 - 24
Libs/Widgets/ctkWorkflowWidgetStep.cpp

@@ -19,17 +19,14 @@
   =========================================================================*/
 
 // Qt includes
-#include <QObject>
-#include <QWidget>
 #include <QList>
 #include <QDebug>
-#include <QIcon>
 
 // CTK includes
 #include "ctkWorkflowWidgetStep.h"
+#include "ctkWorkflowWidgetStep_p.h"
 #include "ctkWorkflowWidget.h"
 #include "ctkWorkflow.h"
-#include "ctkWorkflowButtonBoxWidget.h"
 #include "ctkLogger.h"
 
 // STD includes
@@ -40,40 +37,75 @@ static ctkLogger logger("org.commontk.libs.widgets.ctkWorkflowWidgetStep");
 //-----------------------------------------------------------------------------
 
 //-----------------------------------------------------------------------------
-class ctkWorkflowWidgetStepPrivate
+// ctkWorkflowWidgetStepPrivate methods
+
+//-----------------------------------------------------------------------------
+ctkWorkflowWidgetStepPrivate::ctkWorkflowWidgetStepPrivate(ctkWorkflowWidgetStep& object)
+  :Superclass(object), q_ptr(&object)
+{
+//  this->buttonBoxWidget = 0;
+//  this->hasButtonBoxWidget = false;
+
+  this->icon = QIcon();
+  this->created = false;
+}
+
+//-----------------------------------------------------------------------------
+void ctkWorkflowWidgetStepPrivate::invokeShowUserInterfaceCommandInternal()const
 {
-public:
-  ctkWorkflowWidgetStepPrivate();
-  ~ctkWorkflowWidgetStepPrivate(){};
-  ctkWorkflowWidgetStep::ButtonBoxHintForPlugin ButtonBoxHintsForPlugin;
-};
+  emit invokeShowUserInterfaceCommand();
+}
 
 //-----------------------------------------------------------------------------
-// ctkWorkflowWidgetStepPrivate methods
+void ctkWorkflowWidgetStepPrivate::showUserInterfaceCompleteInternal()const
+{
+  emit showUserInterfaceComplete();
+}
+
+//-----------------------------------------------------------------------------
+void ctkWorkflowWidgetStepPrivate::showUserInterface()
+{
+  Q_Q(ctkWorkflowWidgetStep);
+  q->showUserInterface();
+}
+
+//-----------------------------------------------------------------------------
+void ctkWorkflowWidgetStepPrivate::invokeCreateUserInterfaceCommandInternal()const
+{
+  emit invokeCreateUserInterfaceCommand();
+}
 
 //-----------------------------------------------------------------------------
-ctkWorkflowWidgetStepPrivate::ctkWorkflowWidgetStepPrivate()
+void ctkWorkflowWidgetStepPrivate::createUserInterfaceCompleteInternal()const
 {
+  emit createUserInterfaceComplete();
 }
 
 //-----------------------------------------------------------------------------
 // ctkWorkflowWidgetStep methods
 
 //-----------------------------------------------------------------------------
-ctkWorkflowWidgetStep::ctkWorkflowWidgetStep(ctkWorkflow* newWorkflow, 
-  const QString& newId, QWidget* newParent) : QWidget(newParent), ctkWorkflowAbstractWidgetStep(newWorkflow, newId)
-  , d_ptr(new ctkWorkflowWidgetStepPrivate)
+ctkWorkflowWidgetStep::ctkWorkflowWidgetStep(QWidget* newParent) :
+  QWidget(newParent),
+  ctkWorkflowStep(new ctkWorkflowWidgetStepPrivate(*this), 0, QString())
 {
   Q_D(ctkWorkflowWidgetStep);
-  d->ButtonBoxHintsForPlugin = ctkWorkflowWidgetStep::qNoHints;
+  d->hasShowUserInterfaceCommand = false;
+  d->hasCreateUserInterfaceCommand = false;
+  d->ButtonBoxHints = ctkWorkflowWidgetStep::NoHints;
 }
 
 //-----------------------------------------------------------------------------
-ctkWorkflowWidgetStep::ctkWorkflowWidgetStep(QWidget* newParent) : QWidget(newParent), ctkWorkflowAbstractWidgetStep(0, QString())
-  , d_ptr(new ctkWorkflowWidgetStepPrivate)
+ctkWorkflowWidgetStep::ctkWorkflowWidgetStep(ctkWorkflow* newWorkflow,
+                                                             const QString& newId,
+                                                             QWidget* newParent) :
+  QWidget(newParent),
+  ctkWorkflowStep(new ctkWorkflowWidgetStepPrivate(*this), newWorkflow, newId)
 {
   Q_D(ctkWorkflowWidgetStep);
-  d->ButtonBoxHintsForPlugin = ctkWorkflowWidgetStep::qNoHints;
+  d->hasShowUserInterfaceCommand = false;
+  d->hasCreateUserInterfaceCommand = false;
+  d->ButtonBoxHints = ctkWorkflowWidgetStep::NoHints;
 }
 
 //-----------------------------------------------------------------------------
@@ -82,20 +114,119 @@ ctkWorkflowWidgetStep::~ctkWorkflowWidgetStep()
 }
 
 //-----------------------------------------------------------------------------
+CTK_GET_CPP(ctkWorkflowWidgetStep, bool, hasShowUserInterfaceCommand, hasShowUserInterfaceCommand);
+CTK_SET_CPP(ctkWorkflowWidgetStep, bool, setHasShowUserInterfaceCommand, hasShowUserInterfaceCommand);
+CTK_GET_CPP(ctkWorkflowWidgetStep, bool, hasCreateUserInterfaceCommand, hasCreateUserInterfaceCommand);
+CTK_SET_CPP(ctkWorkflowWidgetStep, bool, setHasCreateUserInterfaceCommand, hasCreateUserInterfaceCommand);
+CTK_GET_CPP(ctkWorkflowWidgetStep, QString, backButtonText, backButtonText);
+CTK_SET_CPP(ctkWorkflowWidgetStep, const QString&, setBackButtonText, backButtonText);
+CTK_GET_CPP(ctkWorkflowWidgetStep, QString, nextButtonText, nextButtonText);
+CTK_SET_CPP(ctkWorkflowWidgetStep, const QString&, setNextButtonText, nextButtonText);
+// CTK_GET_CPP(ctkWorkflowWidgetStep, QList<QString>, finishButtonTexts, finishButtonTexts);
+// CTK_SET_CPP(ctkWorkflowWidgetStep, QList<QString>, setFinishButtonTexts, finishButtonTexts);
+//CTK_GET_CPP(ctkWorkflowWidgetStep, bool, hasButtonBoxWidget, hasButtonBoxWidget);
+//CTK_SET_CPP(ctkWorkflowWidgetStep, bool, setHasButtonBoxWidget, hasButtonBoxWidget);
+CTK_GET_CPP(ctkWorkflowWidgetStep, QIcon, icon, icon);
+CTK_SET_CPP(ctkWorkflowWidgetStep, const QIcon&, setIcon, icon);
+
+//-----------------------------------------------------------------------------
 QWidget* ctkWorkflowWidgetStep::stepArea()
 {
   return this;
 }
 
 //-----------------------------------------------------------------------------
-ctkWorkflowWidgetStep::ButtonBoxHintsForPlugin ctkWorkflowWidgetStep::buttonBoxHintsForPlugin() const
+CTK_GET_CPP(ctkWorkflowWidgetStep, ctkWorkflowWidgetStep::ButtonBoxHints,
+            buttonBoxHints, ButtonBoxHints);
+CTK_SET_CPP(ctkWorkflowWidgetStep, ctkWorkflowWidgetStep::ButtonBoxHints,
+            setButtonBoxHints, ButtonBoxHints);
+
+//-----------------------------------------------------------------------------
+// void ctkWorkflowWidgetStep::setFinishButtonText(const QString& name)
+// {
+//   QList<QString> names;
+//   names << name;
+//   this->setFinishButtonTexts(names);
+// }
+
+// //-----------------------------------------------------------------------------
+// ctkWorkflowButtonBoxWidget* ctkWorkflowWidgetStep::buttonBoxWidget()
+// {
+//   Q_D(ctkWorkflowWidgetStep);
+
+//   if (!d->hasButtonBoxWidget)
+//     {
+//     return 0;
+//     }
+
+//   if (!d->buttonBoxWidget)
+//     {
+//     if (!this->workflow())
+//       {
+//       logger.error("buttonBoxWidget - Cannot create buttonBoxWidget without a workflow");
+//       return 0;
+//       }
+//     d->buttonBoxWidget = new ctkWorkflowButtonBoxWidget(this->workflow());
+//     }
+//   return d->buttonBoxWidget;
+// }
+
+//-----------------------------------------------------------------------------
+void ctkWorkflowWidgetStep::showUserInterface()
+{
+  Q_D(ctkWorkflowWidgetStep);
+
+  // use the user's showUserInterfaceCommand if given
+  if (d->hasShowUserInterfaceCommand)
+    {
+    this->invokeShowUserInterfaceCommand();
+    return;
+    }
+
+  // otherwise we provide an implementation here
+  logger.debug(QString("showUserInterface - showing %1").arg(this->name()));
+
+  // create the user interface if this is the first time we're showing this step
+  if (!d->created)
+    {
+    if (d->hasCreateUserInterfaceCommand)
+      {
+      this->invokeCreateUserInterfaceCommand();
+      }
+    else
+      {
+      this->createUserInterface();
+      }
+    d->created = true;
+    }
+
+  emit showUserInterfaceComplete();
+}
+
+//-----------------------------------------------------------------------------
+void ctkWorkflowWidgetStep::invokeShowUserInterfaceCommand()const
+{
+  Q_D(const ctkWorkflowWidgetStep);
+  d->invokeShowUserInterfaceCommandInternal();
+}
+
+//-----------------------------------------------------------------------------
+void ctkWorkflowWidgetStep::showUserInterfaceComplete()const
+{
+  Q_D(const ctkWorkflowWidgetStep);
+  d->showUserInterfaceCompleteInternal();
+}
+
+//-----------------------------------------------------------------------------
+void ctkWorkflowWidgetStep::invokeCreateUserInterfaceCommand()const
 {
-  return ctkWorkflowWidgetStep::ButtonBoxHintsForPlugin(QFlag(this->Superclass::buttonBoxHints()));
+  Q_D(const ctkWorkflowWidgetStep);
+  d->invokeCreateUserInterfaceCommandInternal();
 }
 
 //-----------------------------------------------------------------------------
-void ctkWorkflowWidgetStep::setButtonBoxHintsForPlugin(
-  ctkWorkflowWidgetStep::ButtonBoxHintsForPlugin newButtonBoxHints)
+void ctkWorkflowWidgetStep::createUserInterfaceComplete()const
 {
-  this->Superclass::setButtonBoxHints(QFlag(newButtonBoxHints));
+  Q_D(const ctkWorkflowWidgetStep);
+  d->createUserInterfaceCompleteInternal();
 }

+ 104 - 45
Libs/Widgets/ctkWorkflowWidgetStep.h

@@ -19,85 +19,144 @@
 =========================================================================*/
 
 #ifndef __ctkWorkflowWidgetStep_h
-#define __ctkWorkflowWidgetStep_h 
+#define __ctkWorkflowWidgetStep_h
 
-// QT includes
+// Qt includes
 #include <QWidget>
-#include <QIcon>
 #include <QBoxLayout>
 #include <QFlags>
+#include <QIcon>
 
 // CTK includes
 #include "ctkPimpl.h"
+#include "ctkWidgetsExport.h"
 #include "ctkWorkflowStep.h"
 #include "ctkWorkflowTransitions.h"
-#include "ctkWorkflowAbstractWidgetStep.h"
-#include "ctkWidgetsExport.h"
 
-class ctkWorkflowWidgetStepPrivate;
-class ctkWorkflowButtonBoxWidget;
 class ctkWorkflowGroupBox;
-class ctkWorkflow;
-
-///
-/// \brief A concrete implementation of ctkWorkflowAbstractWidgetStep that derives from QWidget.
 
-class ctkWorkflowWidgetStepPlugin;
+class ctkWorkflowWidgetStepPrivate;
 
-class CTK_WIDGETS_EXPORT ctkWorkflowWidgetStep : public QWidget,
-                                                 public ctkWorkflowAbstractWidgetStep
-{ 
+///
+/// \brief ctkWorkflowWidgetStep is a convienience class to quickly
+/// construct a ctkWorkflowStep with a user interface.
+///
+/// It embeds a QWidget* stepArea, onto which step-specific widgets can be placed.
+/// The showUserInterface() and hideUserInterface() commands of ctkWorkflowStep are
+/// written for you, and, if you desire, the step's "Next" and/or "Back" buttons are
+/// added with the appropriate signals and slots.
+/// To create a custom step, you can derive from this class and
+/// implement only two functions:
+/// 1) ctkWorkflowWidgetStep::populateStepWidgetsList(), to define the
+/// step-specific widgets;
+/// 2) ctkWorkflowWidgetStep::validate(const QString&), to validate the processing
+/// state associated with this step.
+/// For additional customization, you can reimplement
+/// showUserInterface() and hideUserInterface() in derived classes.
+/// \sa showUserInterface() hideUserInterface()
+
+class CTK_WIDGETS_EXPORT ctkWorkflowWidgetStep : public QWidget, public ctkWorkflowStep
+{
   Q_OBJECT
-  Q_PROPERTY(QString id READ id WRITE setId)
+  Q_PROPERTY(QString stepid READ id WRITE setId)
   Q_PROPERTY(QIcon icon READ icon WRITE setIcon)
   Q_PROPERTY(QString backButtonText READ backButtonText WRITE setBackButtonText)
   Q_PROPERTY(QString nextButtonText READ nextButtonText WRITE setNextButtonText)
-  Q_FLAGS(ButtonBoxHintForPlugin)
-  Q_PROPERTY(ButtonBoxHintForPlugin buttonBoxHints READ buttonBoxHintsForPlugin WRITE setButtonBoxHintsForPlugin)
-
+  Q_ENUMS(ButtonBoxHint)
 public:
 
-  typedef ctkWorkflowAbstractWidgetStep Superclass;
-  explicit ctkWorkflowWidgetStep(ctkWorkflow* newWorkflow, const QString& newId, QWidget* newParent = 0);
+  enum ButtonBoxHint {
+    NoHints = 0x0,
+    BackButtonHidden = 0x1,
+    BackButtonDisabled = 0x2,
+    NextButtonHidden = 0x4,
+    NextButtonDisabled = 0x8,
+    ButtonBoxHidden = 0x10
+  };
+  Q_DECLARE_FLAGS(ButtonBoxHints, ButtonBoxHint)
+
   explicit ctkWorkflowWidgetStep(QWidget* newParent = 0);
+  explicit ctkWorkflowWidgetStep(ctkWorkflow* newWorkflow, const QString& newId,
+                                 QWidget* newParent = 0);
   virtual ~ctkWorkflowWidgetStep();
 
+  /// \brief Override the back button text of any ctkWorkflowButtonBox when this step
+  /// is the current step
+  virtual QString backButtonText()const;
+  virtual void setBackButtonText(const QString& name);
+
+  /// \brief Override the next button text of any ctkWorkflowButtonBox when this step
+  /// is the current step
+  virtual QString nextButtonText()const;
+  virtual void setNextButtonText(const QString& name);
+
+  /// \brief Override the button visibility of any ctkWorkflowButtonBox when this step is the
+  /// current step
+  void setButtonBoxHints(ButtonBoxHints buttonBoxHints);
+  ButtonBoxHints buttonBoxHints()const;
+
+  /// \brief Associate an icon with this step (ex. used by ctkWorkflowButtonBox to display an icon
+  /// on 'goTo' buttons).
+  QIcon icon()const;
+  void setIcon(const QIcon& newIcon);
+
+  /// Returns the QWidget onto which this step's user interface elements are placed.
   virtual QWidget* stepArea();
 
-  //-----------------------------------------------------------------------------
-  // To have ButtonBoxHints displayed as a propery in QtDesigner ... 
-  // Since ctkWorkflowAbstractWidgetStep is not a QObject, there is no way to 
-  // add ctkWorkflowAbstractWidgetStep::ButtonBoxHints to the meta object system using 
-  // the QFLAGS(ctkWorkflowAbstractWidgetStep::ButtonBoxHints)
-  // The following enums, setter and getter serve as proxy for qtdesigner plugin
-  // TODO Ideally, the following code should be private ..
-  enum ButtonBoxHintForPlugin {
-    qNoHints = 0x0,
-    qBackButtonHidden = 0x1,
-    qBackButtonDisabled = 0x2,
-    qNextButtonHidden = 0x4,
-    qNextButtonDisabled = 0x8,
-    qButtonBoxHidden = 0x10
-  };
-  Q_DECLARE_FLAGS(ButtonBoxHintsForPlugin, ButtonBoxHintForPlugin)
-  void setButtonBoxHintsForPlugin(ButtonBoxHintsForPlugin buttonBoxHints);
-  ButtonBoxHintsForPlugin buttonBoxHintsForPlugin()const;
-  //-----------------------------------------------------------------------------
+  /// Set/get whether a showUserInterfaceCommand has been provided in
+  /// a separate QObject (see method 2 described for
+  /// showUserInterface())
+  virtual bool hasShowUserInterfaceCommand()const;
+  virtual void setHasShowUserInterfaceCommand(bool flag);
+
+  /// Set/get whether a createUserInterfaceCommand has been provided in
+  /// a separate QObject (see method 2 described for
+  /// createUserInterface())
+  virtual bool hasCreateUserInterfaceCommand()const;
+  virtual void setHasCreateUserInterfaceCommand(bool flag);
 
 protected:
 
+  /// Creates the user interface associated with this step.
   virtual void createUserInterface(){}
 
-protected:
-  QScopedPointer<ctkWorkflowWidgetStepPrivate> d_ptr;
+  /// Prepares the step to be shown.
+  virtual void showUserInterface();
+
+  /// \brief Signal (emitted by the private implementation) indicating that the step's
+  /// createUserInterface() method should be called.
+  /// \sa createUserInterface()
+  void invokeCreateUserInterfaceCommand()const;
+
+  /// \brief Signal (emitted by the private implementation) indicating that the step's
+  /// createUserInterface() method has completed.
+  /// \sa createUserInterface()
+  void createUserInterfaceComplete()const;
+
+  /// \brief Signal (emitted by the private implementation) indicating that the step's
+  /// 'showUserInterface() method should be called.
+  /// \sa showUserInterface()
+  void invokeShowUserInterfaceCommand()const;
+
+  /// \brief Signal (emitted by the private implementation) indicating that the step's
+  /// showUserInterface() method has completed.
+  /// \sa showUserInterface()
+  void showUserInterfaceComplete()const;
 
 private:
-  Q_DECLARE_PRIVATE(ctkWorkflowWidgetStep);
-  Q_DISABLE_COPY(ctkWorkflowWidgetStep);
 
+  //Q_DECLARE_PRIVATE(ctkWorkflowWidgetStep);
+  // Since this class derives from both QWidget and ctkWorkflowStep,
+  // let's specify which 'd_ptr' to use to avoid ambiguous reference
+  inline ctkWorkflowWidgetStepPrivate* d_func() { return reinterpret_cast<ctkWorkflowWidgetStepPrivate *>(qGetPtrHelper(ctkWorkflowStep::d_ptr)); }
+  inline const ctkWorkflowWidgetStepPrivate* d_func() const { return reinterpret_cast<const ctkWorkflowWidgetStepPrivate *>(qGetPtrHelper(ctkWorkflowStep::d_ptr)); }
+  friend class ctkWorkflowWidgetStepPrivate;
+
+  Q_DISABLE_COPY(ctkWorkflowWidgetStep);
+  friend class ctkWorkflowGroupBox; // For access to showUserInterface()
 };
 
-Q_DECLARE_OPERATORS_FOR_FLAGS(ctkWorkflowWidgetStep::ButtonBoxHintsForPlugin)
+ Q_DECLARE_OPERATORS_FOR_FLAGS(ctkWorkflowWidgetStep::ButtonBoxHints)
 
 #endif
 

+ 12 - 13
Libs/Widgets/ctkWorkflowAbstractWidgetStep_p.h

@@ -18,45 +18,44 @@
 
   =========================================================================*/
 
-#ifndef __ctkWorkflowAbstractWidgetStep_p_h
-#define __ctkWorkflowAbstractWidgetStep_p_h
+#ifndef __ctkWorkflowWidgetStep_p_h
+#define __ctkWorkflowWidgetStep_p_h
 
 // Qt includes
 #include <QObject>
 #include <QList>
 #include <QIcon>
-class QWidget;
 
 // CTK includes
-#include "ctkWorkflowAbstractWidgetStep.h"
+#include "ctkWorkflowWidgetStep.h"
 #include "ctkWorkflowStep_p.h"
-//class ctkWorkflowButtonBoxWidget;
 
 //-----------------------------------------------------------------------------
-class ctkWorkflowAbstractWidgetStepPrivate : public QObject
+class ctkWorkflowWidgetStepPrivate : public ctkWorkflowStepPrivate
 {
   Q_OBJECT
-  Q_DECLARE_PUBLIC(ctkWorkflowAbstractWidgetStep);
+  Q_DECLARE_PUBLIC(ctkWorkflowWidgetStep);
 protected:
-  ctkWorkflowAbstractWidgetStep* q_ptr;
+  ctkWorkflowWidgetStep* q_ptr;
   
 public:
-  ctkWorkflowAbstractWidgetStepPrivate(ctkWorkflowAbstractWidgetStep& object);
-  ~ctkWorkflowAbstractWidgetStepPrivate(){}
+  ctkWorkflowWidgetStepPrivate(ctkWorkflowWidgetStep& object);
+  ~ctkWorkflowWidgetStepPrivate(){}
+  typedef ctkWorkflowStepPrivate Superclass;
 
 protected:
 
   QList<ctkWorkflowStep*> finishStepsToHaveButtonsInStepArea;
 
   // int hasPopulateStepWidgetsListCommand;
-  int hasShowUserInterfaceCommand;
-  int hasCreateUserInterfaceCommand;
+  bool hasShowUserInterfaceCommand;
+  bool hasCreateUserInterfaceCommand;
 
   // names for the buttons
   QString backButtonText;
   QString nextButtonText;
 
-  ctkWorkflowAbstractWidgetStep::ButtonBoxHints  ButtonBoxHints;
+  ctkWorkflowWidgetStep::ButtonBoxHints  ButtonBoxHints;
 
   QIcon icon;