Parcourir la source

State machine and example hosted app and hosting system done

Benoit Bleuze il y a 14 ans
Parent
commit
c5fcf137ed

+ 16 - 54
Applications/ctkExampleHost/ctkHostAppExampleWidget.cpp

@@ -85,7 +85,7 @@ void ctkHostAppExampleWidget::runButtonClicked()
 void ctkHostAppExampleWidget::stopButtonClicked()
 {
   qDebug() << "stop button clicked";
-  this->Host->getDicomAppService ()->setState (ctkDicomAppHosting::CANCELED);
+  this->Host->exitApplication();
 }
 
 //----------------------------------------------------------------------------
@@ -156,66 +156,28 @@ void ctkHostAppExampleWidget::placeholderResized()
   //ui->placeholderFrame->printPosition();
 }
 
-//----------------------------------------------------------------------------
+
+
 void ctkHostAppExampleWidget::appStateChanged(ctkDicomAppHosting::State state)
 {
   ui->statusLabel->setText(ctkDicomSoapState::toStringValue(state));
-
-  bool reply;
-  ctkDicomAppHosting::ObjectDescriptor ourObjectDescriptor;
-  QList<ctkDicomAppHosting::Study> studies;
-  ctkDicomAppHosting::AvailableData data;
-  ctkDicomAppHosting::Patient patient;
-
-  //TODO put the state changed routine back in notifyStateChanged for the state machine part.
-  switch (state)
-  {
-  case ctkDicomAppHosting::IDLE:
-    if (this->Host->getApplicationState() != ctkDicomAppHosting::IDLE)
-    {
-      qDebug()<<"state was not IDLE before -> setState EXIT ";
-      this->Host->getDicomAppService()->setState(ctkDicomAppHosting::EXIT);
-    }
-    break;
-  case ctkDicomAppHosting::INPROGRESS:
-    patient.name = "John Doe";
-    patient.id = "0000";
-    patient.assigningAuthority = "authority";
-    patient.sex = "male";
-    patient.birthDate = "today";
-    patient.objectDescriptors = QList<ctkDicomAppHosting::ObjectDescriptor>();
-
-    patient.studies = studies;
-
-    ourObjectDescriptor.descriptorUUID = QUuid("{11111111-1111-1111-1111-111111111111}");
-    ourObjectDescriptor.mimeType = "text/plain";
-    ourObjectDescriptor.classUID = "lovelyClass";
-    ourObjectDescriptor.transferSyntaxUID = "transSyntaxUId";
-    ourObjectDescriptor.modality = "modMod";
-
-    data.objectDescriptors =  QList<ctkDicomAppHosting::ObjectDescriptor>();
-    data.objectDescriptors.append (ourObjectDescriptor);
-    data.patients = QList<ctkDicomAppHosting::Patient>();
-    data.patients.append (patient);
-
-    qDebug()<<"send dataDescriptors";
-    reply = this->Host->getDicomAppService()->notifyDataAvailable (data,true);
-    qDebug() << "  notifyDataAvailable(1111) returned: " << reply;
-    break;
-  case ctkDicomAppHosting::COMPLETED:
-  case ctkDicomAppHosting::SUSPENDED:
-  case ctkDicomAppHosting::CANCELED:
-  case ctkDicomAppHosting::EXIT:
-    //shouldn't happen, when exiting the application just dies
-  default:
-    //do nothing
-    break;
-  }
-  this->Host->setApplicationState(state);
 }
 
+
 //----------------------------------------------------------------------------
 void ctkHostAppExampleWidget::outputMessage ()
 {
   ui->messageOutput->append (this->Host->processReadAll ());
 }
+
+//----------------------------------------------------------------------------
+void ctkHostAppExampleWidget::suspendButtonClicked()
+{
+  this->Host->getDicomAppService()->setState(ctkDicomAppHosting::SUSPENDED);
+}
+
+void ctkHostAppExampleWidget::cancelButtonClicked()
+{
+  this->Host->getDicomAppService()->setState(ctkDicomAppHosting::CANCELED);
+}
+

+ 2 - 0
Applications/ctkExampleHost/ctkHostAppExampleWidget.h

@@ -50,6 +50,8 @@ public slots:
   void startButtonClicked();
   void runButtonClicked();
   void stopButtonClicked();
+  void suspendButtonClicked();
+  void cancelButtonClicked();
   void appProcessError(QProcess::ProcessError error);
   void appProcessStateChanged(QProcess::ProcessState state);
   void appStateChanged(ctkDicomAppHosting::State state);

+ 72 - 7
Applications/ctkExampleHost/ctkHostAppExampleWidget.ui

@@ -16,8 +16,8 @@
     <verstretch>0</verstretch>
    </sizepolicy>
   </property>
-  <layout class="QVBoxLayout" name="verticalLayout">
-   <item>
+  <layout class="QGridLayout" name="gridLayout">
+   <item row="0" column="0">
     <layout class="QHBoxLayout" name="horizontalLayout_3">
      <item>
       <widget class="QPushButton" name="loadButton">
@@ -55,7 +55,7 @@
      </item>
     </layout>
    </item>
-   <item>
+   <item row="1" column="0">
     <layout class="QHBoxLayout" name="horizontalLayout_2">
      <item>
       <widget class="QPushButton" name="startButton">
@@ -133,14 +133,45 @@
      </item>
     </layout>
    </item>
-   <item>
+   <item row="2" column="0">
+    <layout class="QHBoxLayout" name="horizontalLayout_5">
+     <item>
+      <widget class="QPushButton" name="SuspendButton">
+       <property name="text">
+        <string>Suspend</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="CancelButton">
+       <property name="text">
+        <string>Cancel</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <spacer name="horizontalSpacer_6">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+    </layout>
+   </item>
+   <item row="3" column="0">
     <widget class="Line" name="line">
      <property name="orientation">
       <enum>Qt::Horizontal</enum>
      </property>
     </widget>
    </item>
-   <item>
+   <item row="4" column="0">
     <layout class="QHBoxLayout" name="horizontalLayout">
      <item>
       <widget class="QCheckBox" name="checkBox">
@@ -167,7 +198,7 @@
      </item>
     </layout>
    </item>
-   <item>
+   <item row="5" column="0">
     <widget class="QTextEdit" name="messageOutput">
      <property name="sizePolicy">
       <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
@@ -183,7 +214,7 @@
      </property>
     </widget>
    </item>
-   <item>
+   <item row="6" column="0">
     <widget class="ctkHostedAppPlaceholderWidget" name="placeholderFrame">
      <property name="sizePolicy">
       <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
@@ -338,11 +369,45 @@
     </hint>
    </hints>
   </connection>
+  <connection>
+   <sender>SuspendButton</sender>
+   <signal>clicked()</signal>
+   <receiver>ctkHostAppExampleWidget</receiver>
+   <slot>suspendButtonClicked()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>47</x>
+     <y>83</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>291</x>
+     <y>296</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>CancelButton</sender>
+   <signal>clicked()</signal>
+   <receiver>ctkHostAppExampleWidget</receiver>
+   <slot>cancelButtonClicked()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>132</x>
+     <y>83</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>291</x>
+     <y>296</y>
+    </hint>
+   </hints>
+  </connection>
  </connections>
  <slots>
   <slot>startButtonClicked()</slot>
   <slot>stopButtonClicked()</slot>
   <slot>loadButtonClicked()</slot>
   <slot>runButtonClicked()</slot>
+  <slot>suspendButtonClicked()</slot>
+  <slot>cancelButtonClicked()</slot>
  </slots>
 </ui>

+ 14 - 4
Plugins/org.commontk.dah.app/ctkDicomAbstractApp.cpp

@@ -24,6 +24,7 @@
 #include <ctkDicomHostInterface.h>
 #include <ctkPluginContext.h>
 #include <ctkServiceTracker.h>
+#include <ctkDicomAppHostingTypesHelper.h>
 
 class ctkDicomAbstractAppPrivate
 {
@@ -67,6 +68,8 @@ ctkDicomAbstractApp::~ctkDicomAbstractApp()
 //----------------------------------------------------------------------------
 bool ctkDicomAbstractApp::setState(ctkDicomAppHosting::State newState)
 {
+
+  qDebug()<<"treating new state: "<< ctkDicomSoapState::toStringValue(newState);
   bool result = false;
   //received a new state,
   switch (newState){
@@ -102,11 +105,11 @@ bool ctkDicomAbstractApp::setState(ctkDicomAppHosting::State newState)
     if (d_ptr->currentState == ctkDicomAppHosting::INPROGRESS
         || d_ptr->currentState == ctkDicomAppHosting::SUSPENDED)
     {
-      //releasing resources
-      emit cancelProgress();
       //special state, a transitional state, so we notify straight away the new state.
       getHostInterface()->notifyStateChanged(ctkDicomAppHosting::CANCELED);
       d_ptr->currentState = ctkDicomAppHosting::CANCELED;
+      //releasing resources
+      emit cancelProgress();
       result = true;
     }
     break;
@@ -126,8 +129,10 @@ bool ctkDicomAbstractApp::setState(ctkDicomAppHosting::State newState)
   }
   if (!result)
   {
-    qDebug()<<"illegal transition to: "<< newState <<
-               "Current state is:" << d_ptr->currentState;
+    qDebug()<<"illegal transition to: "<< static_cast<int>(newState) <<
+               "Current state is:" << static_cast<int>(d_ptr->currentState);
+    qDebug()<<"illegal transition to: "<< ctkDicomSoapState::toStringValue(newState) <<
+               "Current state is:" << ctkDicomSoapState::toStringValue(d_ptr->currentState);
   }
   return result;
 }
@@ -146,4 +151,9 @@ ctkDicomAppHosting::State ctkDicomAbstractApp::getState()
   return d_ptr->currentState;
 }
 
+void ctkDicomAbstractApp::setInternalState(ctkDicomAppHosting::State state)
+{
+  d_ptr->currentState = state;
+}
+
 

+ 1 - 1
Plugins/org.commontk.dah.app/ctkDicomAbstractApp.h

@@ -50,7 +50,7 @@ public:
   virtual ctkDicomAppHosting::State getState();
 protected:
   virtual ctkDicomHostInterface* getHostInterface() const;
-
+ void setInternalState(ctkDicomAppHosting::State state);
 signals:
   void startProgress();
   void resumeProgress();

+ 19 - 2
Plugins/org.commontk.dah.exampleapp/ctkExampleDicomAppLogic.cpp

@@ -43,7 +43,7 @@ ctkDicomAbstractApp(ctkExampleDicomAppPlugin::getPluginContext()), Button(0)
 
   connect(this, SIGNAL(startProgress()), this, SLOT(onStartProgress()), Qt::QueuedConnection);
   connect(this, SIGNAL(resumeProgress()), this, SLOT(onResumeProgress()), Qt::QueuedConnection);
-  connect(this, SIGNAL(SuspendProgress()), this, SLOT(onSuspendProgress()), Qt::QueuedConnection);
+  connect(this, SIGNAL(suspendProgress()), this, SLOT(onSuspendProgress()), Qt::QueuedConnection);
   connect(this, SIGNAL(cancelProgress()), this, SLOT(onCancelProgress()), Qt::QueuedConnection);
   connect(this, SIGNAL(exitHostedApp()), this, SLOT(onExitHostedApp()), Qt::QueuedConnection);
 
@@ -95,7 +95,9 @@ void ctkExampleDicomAppLogic::do_something()
 //----------------------------------------------------------------------------
 void ctkExampleDicomAppLogic::onStartProgress()
 {
+  setInternalState(ctkDicomAppHosting::INPROGRESS);
   getHostInterface()->notifyStateChanged(ctkDicomAppHosting::INPROGRESS);
+
   do_something();
 }
 
@@ -105,6 +107,7 @@ void ctkExampleDicomAppLogic::onResumeProgress()
   //reclame all resources.
 
   //notify state changed
+  setInternalState(ctkDicomAppHosting::INPROGRESS);
   getHostInterface()->notifyStateChanged(ctkDicomAppHosting::INPROGRESS);
   //we're rolling
   //do something else normally, but this is an example
@@ -117,7 +120,8 @@ void ctkExampleDicomAppLogic::onSuspendProgress()
   //release resources it can reclame later to resume work
   this->Button->setEnabled(false);
   //notify state changed
-  getHostInterface()->notifyStateChanged(ctkDicomAppHosting::INPROGRESS);
+  setInternalState(ctkDicomAppHosting::SUSPENDED);
+  getHostInterface()->notifyStateChanged(ctkDicomAppHosting::SUSPENDED);
   //we're rolling
   //do something else normally, but this is an example
 }
@@ -128,15 +132,28 @@ void ctkExampleDicomAppLogic::onCancelProgress()
   //release all resources
   onReleaseResources();
   //update state
+  setInternalState(ctkDicomAppHosting::IDLE);
   getHostInterface()->notifyStateChanged(ctkDicomAppHosting::IDLE);
 }
 
 //----------------------------------------------------------------------------
 void ctkExampleDicomAppLogic::onExitHostedApp()
 {
+  //useless move, but correct:
+  setInternalState(ctkDicomAppHosting::EXIT);
+  getHostInterface()->notifyStateChanged(ctkDicomAppHosting::EXIT);
+  //die
   qApp->exit(0);
 }
 
+//----------------------------------------------------------------------------
+void ctkExampleDicomAppLogic::onReleaseResources()
+{
+  this->Button->hide();
+  delete (this->Button);
+  this->Button = 0 ;
+}
+
 
 //----------------------------------------------------------------------------
 bool ctkExampleDicomAppLogic::notifyDataAvailable(const ctkDicomAppHosting::AvailableData& data, bool lastData)

+ 97 - 19
Plugins/org.commontk.dah.examplehost/ctkExampleDicomHost.cpp

@@ -35,9 +35,16 @@
 ctkExampleDicomHost::ctkExampleDicomHost(ctkHostedAppPlaceholderWidget* placeholderWidget, int hostPort, int appPort) :
     ctkDicomAbstractHost(hostPort, appPort),
     PlaceholderWidget(placeholderWidget),
-    ApplicationState(ctkDicomAppHosting::IDLE)
+    exitingApplication(false)
 {
-  //connect(&this->AppProcess,SIGNAL(readyReadStandardOutput()),SLOT(forwardConsoleOutput()));
+  connect(this,SIGNAL(appReady()),SLOT(onAppReady()));
+  connect(this,SIGNAL(startProgress()),this,SLOT(onStartProgress()));
+  connect(this,SIGNAL(releaseAvailableResources()),this,SLOT(onReleaseAvailableResources()));
+  connect(this,SIGNAL(resumed()),this,SLOT(onResumed()));
+  connect(this,SIGNAL(completed()),this,SLOT(onCompleted()));
+  connect(this,SIGNAL(suspended()),this,SLOT(onSuspended()));
+  connect(this,SIGNAL(canceled()),this,SLOT(onCanceled()));
+  connect(this,SIGNAL(exited()),this,SLOT(onExited()));
 }
 
 //----------------------------------------------------------------------------
@@ -71,14 +78,6 @@ QRect ctkExampleDicomHost::getAvailableScreen(const QRect& preferredScreen)
   return rect;
 }
 
-//----------------------------------------------------------------------------
-void ctkExampleDicomHost::notifyStateChanged(ctkDicomAppHosting::State state)
-{
-  qDebug()<< "new state received:"<< static_cast<int>(state);
-  qDebug()<< "new state received:"<< ctkDicomSoapState::toStringValue(state);
-
-  emit stateChangedReceived(state);
-}
 
 //----------------------------------------------------------------------------
 void ctkExampleDicomHost::notifyStatus(const ctkDicomAppHosting::Status& status)
@@ -96,23 +95,96 @@ ctkExampleDicomHost::~ctkExampleDicomHost()
   this->AppProcess.kill();
 }
 
+
+//----------------------------------------------------------------------------
+bool ctkExampleDicomHost::notifyDataAvailable(const ctkDicomAppHosting::AvailableData& data, bool lastData)
+{
+  Q_UNUSED(data)
+  Q_UNUSED(lastData)
+  return false;
+}
+
 //----------------------------------------------------------------------------
-void ctkExampleDicomHost::forwardConsoleOutput()
+void ctkExampleDicomHost::onAppReady()
 {
-  while( this->AppProcess.bytesAvailable() )
+  //prepare some resources...
+  //tell app to start
+  //getDicomAppService()->setState(ctkDicomAppHosting::INPROGRESS);
+  qDebug() << "App ready to work";
+  if (this->exitingApplication)
   {
-    QString line( this->AppProcess.readLine() );
-    line.prepend(">>>> ");
-    std::cout << line.toStdString();
+    this->exitingApplication = false;
+    getDicomAppService ()->setState (ctkDicomAppHosting::EXIT);
   }
 }
 
 //----------------------------------------------------------------------------
-bool ctkExampleDicomHost::notifyDataAvailable(const ctkDicomAppHosting::AvailableData& data, bool lastData)
+void ctkExampleDicomHost::onStartProgress()
 {
-  Q_UNUSED(data)
-  Q_UNUSED(lastData)
-  return false;
+  ctkDicomAppHosting::ObjectDescriptor ourObjectDescriptor;
+  QList<ctkDicomAppHosting::Study> studies;
+  ctkDicomAppHosting::AvailableData data;
+  ctkDicomAppHosting::Patient patient;
+
+  patient.name = "John Doe";
+  patient.id = "0000";
+  patient.assigningAuthority = "authority";
+  patient.sex = "male";
+  patient.birthDate = "today";
+  patient.objectDescriptors = QList<ctkDicomAppHosting::ObjectDescriptor>();
+
+  patient.studies = studies;
+
+  ourObjectDescriptor.descriptorUUID = QUuid("{11111111-1111-1111-1111-111111111111}");
+  ourObjectDescriptor.mimeType = "text/plain";
+  ourObjectDescriptor.classUID = "lovelyClass";
+  ourObjectDescriptor.transferSyntaxUID = "transSyntaxUId";
+  ourObjectDescriptor.modality = "modMod";
+
+  data.objectDescriptors =  QList<ctkDicomAppHosting::ObjectDescriptor>();
+  data.objectDescriptors.append (ourObjectDescriptor);
+  data.patients = QList<ctkDicomAppHosting::Patient>();
+  data.patients.append (patient);
+
+  qDebug()<<"send dataDescriptors";
+  bool reply = getDicomAppService()->notifyDataAvailable (data,true);
+  qDebug() << "  notifyDataAvailable(1111) returned: " << reply;
+}
+
+//----------------------------------------------------------------------------
+void ctkExampleDicomHost::onResumed()
+{
+  qDebug() << "App resumed work";
+}
+
+//----------------------------------------------------------------------------
+void ctkExampleDicomHost::onCompleted()
+{
+  qDebug() << "App finished processing";
+}
+
+//----------------------------------------------------------------------------
+void ctkExampleDicomHost::onSuspended()
+{
+  qDebug() << "App paused";
+}
+
+//----------------------------------------------------------------------------
+void ctkExampleDicomHost::onCanceled()
+{
+  qDebug() << "App canceled";
+}
+
+//----------------------------------------------------------------------------
+void ctkExampleDicomHost::onExited()
+{
+  qDebug() << "App exited";
+}
+
+//----------------------------------------------------------------------------
+void ctkExampleDicomHost::onReleaseAvailableResources()
+{
+  qDebug() << "Should release resources put at the disposition of the app";
 }
 
 //----------------------------------------------------------------------------
@@ -154,3 +226,9 @@ void ctkExampleDicomHost::releaseData(const QList<QUuid>& objectUUIDs)
 {
   Q_UNUSED(objectUUIDs)
 }
+
+void ctkExampleDicomHost::exitApplication()
+{
+  this->exitingApplication=true;
+  getDicomAppService ()->setState (ctkDicomAppHosting::CANCELED);
+}

+ 19 - 11
Plugins/org.commontk.dah.examplehost/ctkExampleDicomHost.h

@@ -32,7 +32,8 @@
 
 #include <org_commontk_dah_examplehost_Export.h>
 
-class org_commontk_dah_examplehost_EXPORT ctkExampleDicomHost : public QObject, public ctkDicomAbstractHost
+
+class org_commontk_dah_examplehost_EXPORT ctkExampleDicomHost :  public ctkDicomAbstractHost
 {
   Q_OBJECT
 
@@ -41,11 +42,13 @@ public:
   ctkExampleDicomHost(ctkHostedAppPlaceholderWidget* placeholderWidget, int hostPort = 8080, int appPort = 8081);
   virtual ~ctkExampleDicomHost();
 
+  ctkDicomAppHosting::State getApplicationState() const;
+
   virtual void StartApplication(QString AppPath);
   virtual QString generateUID() { return ""; }
   virtual QRect getAvailableScreen(const QRect& preferredScreen);
   virtual QString getOutputLocation(const QStringList& /*preferredProtocols*/) { return ""; }
-  virtual void notifyStateChanged(ctkDicomAppHosting::State state);
+
   virtual void notifyStatus(const ctkDicomAppHosting::Status& status);
   // exchange methods
   virtual bool notifyDataAvailable(const ctkDicomAppHosting::AvailableData& data, bool lastData);
@@ -56,26 +59,31 @@ public:
   virtual void releaseData(const QList<QUuid>& objectUUIDs);
 
   const QProcess& getAppProcess() const { return this->AppProcess; }
-  ctkDicomAppHosting::State getApplicationState()const {return this->ApplicationState;}
-  void setApplicationState(ctkDicomAppHosting::State state){this->ApplicationState = state;}
+  void exitApplication();
 
   QByteArray processReadAll(){return this->AppProcess.readAllStandardOutput ();}
 
+public slots:
+  void onAppReady();
+  void onReleaseAvailableResources();
+  void onStartProgress();
+  void onResumed();
+  void onCompleted();
+  void onSuspended();
+  void onCanceled();
+  void onExited();
+
 signals:
 
-  void stateChangedReceived(ctkDicomAppHosting::State state);
-  void statusReceived(const ctkDicomAppHosting::Status& status);
+
   void giveAvailableScreen(QRect rect);
 
 protected:
 
   QProcess AppProcess;
   ctkHostedAppPlaceholderWidget* PlaceholderWidget;
-  ctkDicomAppHosting::State ApplicationState;
-
-protected slots:
-
-  void forwardConsoleOutput();
+private:
+  bool exitingApplication;
 };
 
 #endif // CTKEXAMPLEDICOMHOST_H

+ 1 - 0
Plugins/org.commontk.dah.host/CMakeLists.txt

@@ -17,6 +17,7 @@ SET(PLUGIN_SRCS
 SET(PLUGIN_MOC_SRCS
   ctkDicomHostPlugin_p.h
   ctkDicomHostServerPrivate.h
+  ctkDicomAbstractHost.h
 )
 
 # Qt Designer files which should be processed by Qts uic

+ 82 - 1
Plugins/org.commontk.dah.host/ctkDicomAbstractHost.cpp

@@ -22,6 +22,7 @@
 #include "ctkDicomAbstractHost.h"
 #include "ctkDicomHostServer.h"
 #include "ctkDicomAppService.h"
+#include "ctkDicomAppHostingTypesHelper.h"
 
 class ctkDicomAbstractHostPrivate
 {
@@ -34,7 +35,9 @@ public:
   int AppPort;
   ctkDicomHostServer* Server;
   ctkDicomAppInterface* AppService;
+  ctkDicomAppHosting::State AppState;
   // ctkDicomAppHosting::Status
+
 };
 
 //----------------------------------------------------------------------------
@@ -42,7 +45,7 @@ public:
 
 //----------------------------------------------------------------------------
 ctkDicomAbstractHostPrivate::ctkDicomAbstractHostPrivate(
-  ctkDicomAbstractHost* hostInterface, int hostPort, int appPort) : HostPort(hostPort), AppPort(appPort)
+  ctkDicomAbstractHost* hostInterface, int hostPort, int appPort) : HostPort(hostPort), AppPort(appPort),AppState(ctkDicomAppHosting::EXIT)
 {
   // start server
   if (this->HostPort==0)
@@ -75,6 +78,7 @@ ctkDicomAbstractHostPrivate::~ctkDicomAbstractHostPrivate()
 ctkDicomAbstractHost::ctkDicomAbstractHost(int hostPort, int appPort) :
   d_ptr(new ctkDicomAbstractHostPrivate(this, hostPort, appPort))
 {
+
 }
 
 //----------------------------------------------------------------------------
@@ -102,3 +106,80 @@ ctkDicomAppInterface* ctkDicomAbstractHost::getDicomAppService() const
   Q_D(const ctkDicomAbstractHost);
   return d->AppService;
 }
+
+//----------------------------------------------------------------------------
+void ctkDicomAbstractHost::notifyStateChanged(ctkDicomAppHosting::State newState)
+{
+  qDebug()<< "new state notification received:"<< static_cast<int>(newState);
+  qDebug()<< "new state notification received:"<< ctkDicomSoapState::toStringValue(newState);
+
+
+  switch (newState){
+  case ctkDicomAppHosting::IDLE:
+    if (d_ptr->AppState == ctkDicomAppHosting::COMPLETED)
+    {
+      d_ptr->AppState = ctkDicomAppHosting::IDLE;
+      releaseAvailableResources();
+    }
+    else if(d_ptr->AppState == ctkDicomAppHosting::EXIT
+            || d_ptr->AppState == ctkDicomAppHosting::IDLE
+            || d_ptr->AppState == ctkDicomAppHosting::CANCELED)
+    {
+      d_ptr->AppState = ctkDicomAppHosting::IDLE;
+      emit appReady();
+    }
+    else{
+      qDebug() << "Wrong transition from" << static_cast<int> (d_ptr->AppState)
+                  << "to:" << static_cast<int>(newState);
+    }
+    break;
+
+  case ctkDicomAppHosting::INPROGRESS:
+    if (d_ptr->AppState == ctkDicomAppHosting::IDLE)
+    {
+      emit startProgress();
+    }
+    else if(d_ptr->AppState == ctkDicomAppHosting::SUSPENDED)
+    {
+      //shouldn't be necessary, but can be useful for feedback
+      emit resumed();
+    }
+    else
+    {
+      qDebug() << "Wrong transition from" << static_cast<int>(d_ptr->AppState)
+                  << "to:" << static_cast<int>(newState);
+    }
+    break;
+
+  case ctkDicomAppHosting::COMPLETED:
+    emit completed();
+    break;
+
+  case ctkDicomAppHosting::SUSPENDED:
+    //shouldn't be necessary, but can be useful for feedback
+    emit suspended();
+    break;
+  case ctkDicomAppHosting::CANCELED:
+    //the app is in the process of canceling.
+    //perhaps filtering for answers to a cancel commands and a cancel because of an error in the client
+    emit canceled();
+    break;
+
+  case ctkDicomAppHosting::EXIT:
+    //check if current state is IDLE
+    emit exited();
+    break;
+
+  default:
+    //should never happen
+    qDebug() << "unexisting state Code, do nothing";
+  }
+
+  d_ptr->AppState = newState;
+  emit stateChangedReceived(newState);
+}
+
+ctkDicomAppHosting::State ctkDicomAbstractHost::getApplicationState()const
+{
+  return d_ptr->AppState;
+}

+ 22 - 1
Plugins/org.commontk.dah.host/ctkDicomAbstractHost.h

@@ -30,6 +30,7 @@
 
 class ctkDicomAbstractHostPrivate;
 
+
 /**
   * Provides a basic implementation for an application host.
   *
@@ -39,8 +40,10 @@ class ctkDicomAbstractHostPrivate;
   * The methods of the ctkDicomHostInterface have to be implemented for the business logic,
   *
   */
-class org_commontk_dah_host_EXPORT ctkDicomAbstractHost : public ctkDicomHostInterface
+class org_commontk_dah_host_EXPORT ctkDicomAbstractHost : public QObject, public ctkDicomHostInterface
 {
+ Q_OBJECT
+ Q_INTERFACES(ctkDicomHostInterface)
 
 public:
 
@@ -50,10 +53,28 @@ public:
   ctkDicomAbstractHost(int hostPort = 0, int appPort = 0);
   int getHostPort() const;
   int getAppPort() const;
+
+  virtual void notifyStateChanged(ctkDicomAppHosting::State state);
+ctkDicomAppHosting::State getApplicationState()const;
+
   virtual ~ctkDicomAbstractHost();
 
   ctkDicomAppInterface* getDicomAppService() const;
 
+signals:
+ void appReady();
+ void releaseAvailableResources();
+ void startProgress();
+ void resumed();
+ void completed();
+ void suspended();
+ void canceled();
+ void exited();
+ void stateChangedReceived(ctkDicomAppHosting::State state);
+ void statusReceived(const ctkDicomAppHosting::Status& status);
+
+
+
 private:
 
   Q_DECLARE_PRIVATE(ctkDicomAbstractHost)