Browse Source

Enabled cancel-able progress for Query and Retrieve

This uses signals and slots to set the progress text and
works okay, but we should really set up the q/r code
in threads.  Or at least we should move the loops out
of the core helper classes so that the widgets can be
more responsive and interruptible.
Steve Pieper 14 years ago
parent
commit
650f427bb6

+ 23 - 1
Libs/DICOM/Core/ctkDICOMQuery.cpp

@@ -97,7 +97,8 @@ public:
   ctkDICOMQuerySCUPrivate SCU;
   ctkDICOMQuerySCUPrivate SCU;
   DcmDataset*             Query;
   DcmDataset*             Query;
   QStringList             StudyInstanceUIDList;
   QStringList             StudyInstanceUIDList;
-  QList<DcmDataset*>       StudyDatasetList;
+  QList<DcmDataset*>      StudyDatasetList;
+  bool                    Canceled;
 };
 };
 
 
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
@@ -108,6 +109,7 @@ ctkDICOMQueryPrivate::ctkDICOMQueryPrivate()
 {
 {
   this->Query = new DcmDataset();
   this->Query = new DcmDataset();
   this->Port = 0;
   this->Port = 0;
+  this->Canceled = false;
 }
 }
 
 
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
@@ -241,6 +243,7 @@ bool ctkDICOMQuery::query(ctkDICOMDatabase& database )
     emit progress("DB not open in Query");
     emit progress("DB not open in Query");
     }
     }
   emit progress(0);
   emit progress(0);
+  if (d->Canceled) {return false;}
 
 
   d->StudyInstanceUIDList.clear();
   d->StudyInstanceUIDList.clear();
   d->SCU.setAETitle ( OFString(this->callingAETitle().toStdString().c_str()) );
   d->SCU.setAETitle ( OFString(this->callingAETitle().toStdString().c_str()) );
@@ -251,6 +254,7 @@ bool ctkDICOMQuery::query(ctkDICOMDatabase& database )
   logger.error ( "Setting Transfer Syntaxes" );
   logger.error ( "Setting Transfer Syntaxes" );
   emit progress("Setting Transfer Syntaxes");
   emit progress("Setting Transfer Syntaxes");
   emit progress(10);
   emit progress(10);
+  if (d->Canceled) {return false;}
 
 
   OFList<OFString> transferSyntaxes;
   OFList<OFString> transferSyntaxes;
   transferSyntaxes.push_back ( UID_LittleEndianExplicitTransferSyntax );
   transferSyntaxes.push_back ( UID_LittleEndianExplicitTransferSyntax );
@@ -269,6 +273,7 @@ bool ctkDICOMQuery::query(ctkDICOMDatabase& database )
   logger.debug ( "Negotiating Association" );
   logger.debug ( "Negotiating Association" );
   emit progress("Negatiating Association");
   emit progress("Negatiating Association");
   emit progress(20);
   emit progress(20);
+  if (d->Canceled) {return false;}
 
 
   OFCondition result = d->SCU.negotiateAssociation();
   OFCondition result = d->SCU.negotiateAssociation();
   if (result.bad())
   if (result.bad())
@@ -359,6 +364,7 @@ bool ctkDICOMQuery::query(ctkDICOMDatabase& database )
     logger.debug("Query on study date " + dateRange);
     logger.debug("Query on study date " + dateRange);
     }
     }
   emit progress(30);
   emit progress(30);
+  if (d->Canceled) {return false;}
 
 
   OFList<QRResponse *> responses;
   OFList<QRResponse *> responses;
 
 
@@ -376,6 +382,7 @@ bool ctkDICOMQuery::query(ctkDICOMDatabase& database )
     emit progress("Found useful presentation context");
     emit progress("Found useful presentation context");
     }
     }
   emit progress(40);
   emit progress(40);
+  if (d->Canceled) {return false;}
 
 
   OFCondition status = d->SCU.sendFINDRequest ( presentationContext, d->Query, &responses );
   OFCondition status = d->SCU.sendFINDRequest ( presentationContext, d->Query, &responses );
   if ( !status.good() )
   if ( !status.good() )
@@ -389,6 +396,7 @@ bool ctkDICOMQuery::query(ctkDICOMDatabase& database )
   logger.debug ( "Find succeded");
   logger.debug ( "Find succeded");
   emit progress("Find succeded");
   emit progress("Find succeded");
   emit progress(50);
   emit progress(50);
+  if (d->Canceled) {return false;}
 
 
   for ( OFIterator<QRResponse*> it = responses.begin(); it != responses.end(); it++ )
   for ( OFIterator<QRResponse*> it = responses.begin(); it != responses.end(); it++ )
     {
     {
@@ -399,6 +407,9 @@ bool ctkDICOMQuery::query(ctkDICOMDatabase& database )
       OFString StudyInstanceUID;
       OFString StudyInstanceUID;
       dataset->findAndGetOFString ( DCM_StudyInstanceUID, StudyInstanceUID );
       dataset->findAndGetOFString ( DCM_StudyInstanceUID, StudyInstanceUID );
       d->addStudyInstanceUIDAndDataset ( StudyInstanceUID.c_str(), dataset );
       d->addStudyInstanceUIDAndDataset ( StudyInstanceUID.c_str(), dataset );
+      emit progress(QString("Processing: ") + QString(StudyInstanceUID.c_str()));
+      emit progress(50);
+      if (d->Canceled) {return false;}
       }
       }
     }
     }
 
 
@@ -431,6 +442,7 @@ bool ctkDICOMQuery::query(ctkDICOMDatabase& database )
     logger.debug ( "Starting Series C-FIND for Study: " + StudyInstanceUID );
     logger.debug ( "Starting Series C-FIND for Study: " + StudyInstanceUID );
     emit progress(QString("Starting Series C-FIND for Study: ") + StudyInstanceUID);
     emit progress(QString("Starting Series C-FIND for Study: ") + StudyInstanceUID);
     emit progress(50 + (progressRatio * i++));
     emit progress(50 + (progressRatio * i++));
+    if (d->Canceled) {return false;}
 
 
     d->Query->putAndInsertString ( DCM_StudyInstanceUID, StudyInstanceUID.toStdString().c_str() );
     d->Query->putAndInsertString ( DCM_StudyInstanceUID, StudyInstanceUID.toStdString().c_str() );
     OFList<QRResponse *> responses;
     OFList<QRResponse *> responses;
@@ -451,6 +463,8 @@ bool ctkDICOMQuery::query(ctkDICOMDatabase& database )
         }
         }
       logger.debug ( "Find succeded on Series level for Study: " + StudyInstanceUID );
       logger.debug ( "Find succeded on Series level for Study: " + StudyInstanceUID );
       emit progress(QString("Find succeded on Series level for Study: ") + StudyInstanceUID);
       emit progress(QString("Find succeded on Series level for Study: ") + StudyInstanceUID);
+      emit progress(50 + (progressRatio * i++));
+      if (d->Canceled) {return false;}
       }
       }
     else
     else
       {
       {
@@ -458,8 +472,16 @@ bool ctkDICOMQuery::query(ctkDICOMDatabase& database )
       emit progress(QString("Find on Series level failed for Study: ") + StudyInstanceUID);
       emit progress(QString("Find on Series level failed for Study: ") + StudyInstanceUID);
       }
       }
     emit progress(50 + (progressRatio * i++));
     emit progress(50 + (progressRatio * i++));
+    if (d->Canceled) {return false;}
     }
     }
   d->SCU.closeAssociation ( DCMSCU_RELEASE_ASSOCIATION );
   d->SCU.closeAssociation ( DCMSCU_RELEASE_ASSOCIATION );
   emit progress(100);
   emit progress(100);
   return true;
   return true;
 }
 }
+
+//----------------------------------------------------------------------------
+void ctkDICOMQuery::cancel()
+{
+  Q_D(ctkDICOMQuery);
+  d->Canceled = true;
+}

+ 3 - 0
Libs/DICOM/Core/ctkDICOMQuery.h

@@ -105,6 +105,9 @@ Q_SIGNALS:
   /// true for success or false for error
   /// true for success or false for error
   void done(const bool& error);
   void done(const bool& error);
 
 
+public Q_SLOTS:
+  void cancel();
+
 protected:
 protected:
   QScopedPointer<ctkDICOMQueryPrivate> d_ptr;
   QScopedPointer<ctkDICOMQueryPrivate> d_ptr;
 
 

+ 61 - 9
Libs/DICOM/Core/ctkDICOMRetrieve.cpp

@@ -74,7 +74,8 @@ public:
     {
     {
       if (this->retrieve)
       if (this->retrieve)
         {
         {
-        emit this->retrieve->debug("Got one!");
+        emit this->retrieve->progress("Got move request");
+        emit this->retrieve->progress(0);
         return this->ctkDcmSCU::handleMOVEResponse(
         return this->ctkDcmSCU::handleMOVEResponse(
                         presID, response, waitForNextResponse);
                         presID, response, waitForNextResponse);
         }
         }
@@ -90,7 +91,12 @@ public:
     {
     {
       if (this->retrieve)
       if (this->retrieve)
         {
         {
-        emit this->retrieve->debug("Got a store request!");
+        OFString instanceUID;
+        incomingObject->findAndGetOFString(DCM_SOPInstanceUID, instanceUID);
+        QString qInstanceUID(instanceUID.c_str());
+        emit this->retrieve->progress("Got STORE request for " + qInstanceUID);
+        emit this->retrieve->progress(0);
+        continueCGETSession = not this->retrieve->wasCanceled();
         if (this->retrieve && this->retrieve->database())
         if (this->retrieve && this->retrieve->database())
           {
           {
           this->retrieve->database()->insert(incomingObject);
           this->retrieve->database()->insert(incomingObject);
@@ -113,7 +119,9 @@ public:
     {
     {
       if (this->retrieve)
       if (this->retrieve)
         {
         {
-        emit this->retrieve->debug("Got a cget response!");
+        emit this->retrieve->progress("Got CGET response");
+        emit this->retrieve->progress(0);
+        continueCGETSession = not this->retrieve->wasCanceled();
         return this->ctkDcmSCU::handleCGETResponse(presID, response, continueCGETSession);
         return this->ctkDcmSCU::handleCGETResponse(presID, response, continueCGETSession);
         }
         }
       return false;
       return false;
@@ -122,13 +130,19 @@ public:
 
 
 
 
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
-class ctkDICOMRetrievePrivate
+class ctkDICOMRetrievePrivate: public QObject
 {
 {
+  Q_DECLARE_PUBLIC( ctkDICOMRetrieve );
+
+protected:
+  ctkDICOMRetrieve* const q_ptr;
+
 public:
 public:
-  ctkDICOMRetrievePrivate();
+  ctkDICOMRetrievePrivate(ctkDICOMRetrieve& obj);
   ~ctkDICOMRetrievePrivate();
   ~ctkDICOMRetrievePrivate();
   /// Keep the currently negotiated connection to the 
   /// Keep the currently negotiated connection to the 
   /// peer host open unless the connection parameters change
   /// peer host open unless the connection parameters change
+  bool          WasCanceled;
   bool          KeepAssociationOpen;
   bool          KeepAssociationOpen;
   bool          ConnectionParamsChanged;
   bool          ConnectionParamsChanged;
   bool          LastRetrieveType;
   bool          LastRetrieveType;
@@ -153,9 +167,11 @@ public:
 // ctkDICOMRetrievePrivate methods
 // ctkDICOMRetrievePrivate methods
 
 
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
-ctkDICOMRetrievePrivate::ctkDICOMRetrievePrivate()
+ctkDICOMRetrievePrivate::ctkDICOMRetrievePrivate(ctkDICOMRetrieve& obj)
+  : q_ptr(&obj)
 {
 {
   this->Database = QSharedPointer<ctkDICOMDatabase> (0);
   this->Database = QSharedPointer<ctkDICOMDatabase> (0);
+  this->WasCanceled = false;
   this->KeepAssociationOpen = true;
   this->KeepAssociationOpen = true;
   this->ConnectionParamsChanged = false;
   this->ConnectionParamsChanged = false;
   this->LastRetrieveType = RetrieveNone;
   this->LastRetrieveType = RetrieveNone;
@@ -367,6 +383,8 @@ bool ctkDICOMRetrievePrivate::get ( const QString& studyInstanceUID,
                                          const QString& seriesInstanceUID,
                                          const QString& seriesInstanceUID,
                                          const RetrieveType retrieveType )
                                          const RetrieveType retrieveType )
 {
 {
+  Q_Q(ctkDICOMRetrieve);
+
   DcmDataset *retrieveParameters = new DcmDataset();
   DcmDataset *retrieveParameters = new DcmDataset();
   if (! this->initializeSCU(studyInstanceUID, seriesInstanceUID, retrieveType, retrieveParameters) )
   if (! this->initializeSCU(studyInstanceUID, seriesInstanceUID, retrieveType, retrieveParameters) )
     {
     {
@@ -376,6 +394,8 @@ bool ctkDICOMRetrievePrivate::get ( const QString& studyInstanceUID,
 
 
   // Issue request
   // Issue request
   logger.debug ( "Sending Get Request" );
   logger.debug ( "Sending Get Request" );
+  emit q->progress("Sending Get Request");
+  emit q->progress(0);
   OFList<RetrieveResponse*> responses;
   OFList<RetrieveResponse*> responses;
   T_ASC_PresentationContextID presID = this->SCU.findPresentationContextID(
   T_ASC_PresentationContextID presID = this->SCU.findPresentationContextID(
                                           UID_GETStudyRootQueryRetrieveInformationModel, 
                                           UID_GETStudyRootQueryRetrieveInformationModel, 
@@ -391,11 +411,16 @@ bool ctkDICOMRetrievePrivate::get ( const QString& studyInstanceUID,
     return false;
     return false;
     }
     }
 
 
+  emit q->progress("Found Presentation Context");
+  emit q->progress(1);
 
 
   // do the actual move request
   // do the actual move request
   OFCondition status = this->SCU.sendCGETRequest ( 
   OFCondition status = this->SCU.sendCGETRequest ( 
                           presID, retrieveParameters, &responses );
                           presID, retrieveParameters, &responses );
 
 
+  emit q->progress("Sent Get Request");
+  emit q->progress(2);
+
   // Close association if we do not want to explicitly keep it open
   // Close association if we do not want to explicitly keep it open
   if (!this->KeepAssociationOpen)
   if (!this->KeepAssociationOpen)
     {
     {
@@ -409,9 +434,13 @@ bool ctkDICOMRetrievePrivate::get ( const QString& studyInstanceUID,
     {
     {
     logger.error ( "No responses received at all! (at least one empty response always expected)" );
     logger.error ( "No responses received at all! (at least one empty response always expected)" );
     //throw std::runtime_error( std::string("No responses received from server!") );
     //throw std::runtime_error( std::string("No responses received from server!") );
+    emit q->progress("No Responses from Server!");
     return false;
     return false;
     }
     }
 
 
+  emit q->progress("Got Responses");
+  emit q->progress(3);
+
   /* The server is permitted to acknowledge every image that was received, or
   /* The server is permitted to acknowledge every image that was received, or
    * to send a single move response.
    * to send a single move response.
    * If there is only a single response, this can mean the following:
    * If there is only a single response, this can mean the following:
@@ -452,8 +481,8 @@ bool ctkDICOMRetrievePrivate::get ( const QString& studyInstanceUID,
       return false;
       return false;
       }
       }
     }
     }
-    // Select the last GET response to output meaningful status information
-    OFIterator<RetrieveResponse*> it = responses.begin();
+  // Select the last GET response to output meaningful status information
+  OFIterator<RetrieveResponse*> it = responses.begin();
   Uint32 numResults = responses.size();
   Uint32 numResults = responses.size();
   for (Uint32 i = 1; i < numResults; i++)
   for (Uint32 i = 1; i < numResults; i++)
     {
     {
@@ -467,6 +496,9 @@ bool ctkDICOMRetrievePrivate::get ( const QString& studyInstanceUID,
     + QString::number(static_cast<unsigned int>((*it)->m_numberOfFailedSubops))
     + QString::number(static_cast<unsigned int>((*it)->m_numberOfFailedSubops))
         + " images transfers failed");
         + " images transfers failed");
 
 
+  emit q->progress("Finished Get");
+  emit q->progress(100);
+
   return true;
   return true;
 }
 }
 
 
@@ -475,7 +507,7 @@ bool ctkDICOMRetrievePrivate::get ( const QString& studyInstanceUID,
 
 
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 ctkDICOMRetrieve::ctkDICOMRetrieve()
 ctkDICOMRetrieve::ctkDICOMRetrieve()
-   : d_ptr(new ctkDICOMRetrievePrivate)
+   : d_ptr(new ctkDICOMRetrievePrivate(*this))
 {
 {
   Q_D(ctkDICOMRetrieve);
   Q_D(ctkDICOMRetrieve);
   d->SCU.retrieve = this; // give the dcmtk level access to this for emitting signals
   d->SCU.retrieve = this; // give the dcmtk level access to this for emitting signals
@@ -604,6 +636,19 @@ bool ctkDICOMRetrieve::keepAssociationOpen()
   return d->KeepAssociationOpen;
   return d->KeepAssociationOpen;
 }
 }
 
 
+void ctkDICOMRetrieve::setWasCanceled(const bool wasCanceled)
+{
+  Q_D(ctkDICOMRetrieve);
+  d->WasCanceled = wasCanceled;
+}
+
+//------------------------------------------------------------------------------
+bool ctkDICOMRetrieve::wasCanceled()
+{
+  Q_D(const ctkDICOMRetrieve);
+  return d->WasCanceled;
+}
+
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 bool ctkDICOMRetrieve::moveStudy(const QString& studyInstanceUID)
 bool ctkDICOMRetrieve::moveStudy(const QString& studyInstanceUID)
 {
 {
@@ -658,3 +703,10 @@ bool ctkDICOMRetrieve::getSeries(const QString& studyInstanceUID,
   return d->get ( studyInstanceUID, seriesInstanceUID, ctkDICOMRetrievePrivate::RetrieveSeries );
   return d->get ( studyInstanceUID, seriesInstanceUID, ctkDICOMRetrievePrivate::RetrieveSeries );
 }
 }
 
 
+//------------------------------------------------------------------------------
+bool ctkDICOMRetrieve::cancel()
+{
+  Q_D(ctkDICOMRetrieve);
+  d->WasCanceled = true;
+}
+

+ 7 - 0
Libs/DICOM/Core/ctkDICOMRetrieve.h

@@ -42,6 +42,7 @@ class CTK_DICOM_CORE_EXPORT ctkDICOMRetrieve : public QObject
   Q_PROPERTY(int port READ port WRITE setPort);
   Q_PROPERTY(int port READ port WRITE setPort);
   Q_PROPERTY(QString moveDestinationAETitle READ moveDestinationAETitle WRITE setMoveDestinationAETitle)
   Q_PROPERTY(QString moveDestinationAETitle READ moveDestinationAETitle WRITE setMoveDestinationAETitle)
   Q_PROPERTY(bool keepAssociationOpen READ keepAssociationOpen WRITE setKeepAssociationOpen)
   Q_PROPERTY(bool keepAssociationOpen READ keepAssociationOpen WRITE setKeepAssociationOpen)
+  Q_PROPERTY(bool wasCanceled READ wasCanceled WRITE setWasCanceled)
 
 
 public:
 public:
   explicit ctkDICOMRetrieve();
   explicit ctkDICOMRetrieve();
@@ -71,6 +72,10 @@ public:
   /// multiple requests (default true)
   /// multiple requests (default true)
   void setKeepAssociationOpen(const bool keepOpen);
   void setKeepAssociationOpen(const bool keepOpen);
   bool keepAssociationOpen();
   bool keepAssociationOpen();
+  /// did someone cancel us during operation?
+  /// (default false)
+  void setWasCanceled(const bool wasCanceled);
+  bool wasCanceled();
   /// where to insert new data sets obtained via get (must be set for
   /// where to insert new data sets obtained via get (must be set for
   /// get to succeed
   /// get to succeed
   Q_INVOKABLE void setDatabase(QSharedPointer<ctkDICOMDatabase> dicomDatabase);
   Q_INVOKABLE void setDatabase(QSharedPointer<ctkDICOMDatabase> dicomDatabase);
@@ -87,6 +92,8 @@ public Q_SLOTS:
                        const QString& seriesInstanceUID );
                        const QString& seriesInstanceUID );
   /// Use CGET to ask peer host to store data to us
   /// Use CGET to ask peer host to store data to us
   bool getStudy( const QString& studyInstanceUID );
   bool getStudy( const QString& studyInstanceUID );
+  /// Cancel the current operation
+  bool cancel();
 
 
 Q_SIGNALS:
 Q_SIGNALS:
   /// Signal is emitted inside the retrieve() function. It ranges from 0 to 100.
   /// Signal is emitted inside the retrieve() function. It ranges from 0 to 100.

+ 42 - 12
Libs/DICOM/Widgets/ctkDICOMQueryRetrieveWidget.cpp

@@ -64,6 +64,7 @@ public:
   ctkDICOMDatabase                  QueryResultDatabase;
   ctkDICOMDatabase                  QueryResultDatabase;
   QSharedPointer<ctkDICOMDatabase>  RetrieveDatabase;
   QSharedPointer<ctkDICOMDatabase>  RetrieveDatabase;
   ctkDICOMModel                     Model;
   ctkDICOMModel                     Model;
+  ctkDICOMQuery                     *CurrentQuery;
   
   
   QProgressDialog*                  ProgressDialog;
   QProgressDialog*                  ProgressDialog;
   QString                           CurrentServer;
   QString                           CurrentServer;
@@ -171,9 +172,10 @@ void ctkDICOMQueryRetrieveWidget::query()
   QLabel* progressLabel = new QLabel(tr("Initialization..."));
   QLabel* progressLabel = new QLabel(tr("Initialization..."));
   progress.setLabel(progressLabel);
   progress.setLabel(progressLabel);
   d->ProgressDialog = &progress;
   d->ProgressDialog = &progress;
-  progress.setWindowModality(Qt::WindowModal);
+  progress.setWindowModality(Qt::ApplicationModal);
   progress.setMinimumDuration(0);
   progress.setMinimumDuration(0);
   progress.setValue(0);
   progress.setValue(0);
+  progress.show();
   foreach (d->CurrentServer, d->ServerNodeWidget->selectedServerNodes())
   foreach (d->CurrentServer, d->ServerNodeWidget->selectedServerNodes())
     {
     {
     if (progress.wasCanceled())
     if (progress.wasCanceled())
@@ -186,6 +188,7 @@ void ctkDICOMQueryRetrieveWidget::query()
     Q_ASSERT(parameters["CheckState"] == static_cast<int>(Qt::Checked) );
     Q_ASSERT(parameters["CheckState"] == static_cast<int>(Qt::Checked) );
     // create a query for the current server
     // create a query for the current server
     ctkDICOMQuery* query = new ctkDICOMQuery;
     ctkDICOMQuery* query = new ctkDICOMQuery;
+    d->CurrentQuery = query;
     query->setCallingAETitle(d->ServerNodeWidget->callingAETitle());
     query->setCallingAETitle(d->ServerNodeWidget->callingAETitle());
     query->setCalledAETitle(parameters["AETitle"].toString());
     query->setCalledAETitle(parameters["AETitle"].toString());
     query->setHost(parameters["Address"].toString());
     query->setHost(parameters["Address"].toString());
@@ -196,19 +199,20 @@ void ctkDICOMQueryRetrieveWidget::query()
 
 
     try
     try
       {
       {
+      connect(&progress, SIGNAL(canceled()), query, SLOT(cancel()));
       connect(query, SIGNAL(progress(QString)),
       connect(query, SIGNAL(progress(QString)),
-              //&progress, SLOT(setLabelText(QString)));
               progressLabel, SLOT(setText(QString)));
               progressLabel, SLOT(setText(QString)));
-      // for some reasons, setLabelText() doesn't refresh the dialog.
       connect(query, SIGNAL(progress(int)),
       connect(query, SIGNAL(progress(int)),
               this, SLOT(onQueryProgressChanged(int)));
               this, SLOT(onQueryProgressChanged(int)));
+
       // run the query against the selected server and put results in database
       // run the query against the selected server and put results in database
       query->query ( d->QueryResultDatabase );
       query->query ( d->QueryResultDatabase );
+
       disconnect(query, SIGNAL(progress(QString)),
       disconnect(query, SIGNAL(progress(QString)),
-                 //&progress, SLOT(setLabelText(QString)));
                  progressLabel, SLOT(setText(QString)));
                  progressLabel, SLOT(setText(QString)));
       disconnect(query, SIGNAL(progress(int)),
       disconnect(query, SIGNAL(progress(int)),
                  this, SLOT(onQueryProgressChanged(int)));
                  this, SLOT(onQueryProgressChanged(int)));
+      disconnect(&progress, SIGNAL(canceled()), query, SLOT(cancel()));
       }
       }
     catch (std::exception e)
     catch (std::exception e)
       {
       {
@@ -225,11 +229,14 @@ void ctkDICOMQueryRetrieveWidget::query()
       }
       }
     }
     }
   
   
-  // checkable headers - allow user to select the patient/studies to retrieve
-  d->Model.setDatabase(d->QueryResultDatabase.database());
+  if (!progress.wasCanceled())
+    {
+    d->Model.setDatabase(d->QueryResultDatabase.database());
+    }
 
 
   progress.setValue(progress.maximum());
   progress.setValue(progress.maximum());
   d->ProgressDialog = 0;
   d->ProgressDialog = 0;
+  d->CurrentQuery = 0;
 }
 }
 
 
 //----------------------------------------------------------------------------
 //----------------------------------------------------------------------------
@@ -250,9 +257,10 @@ void ctkDICOMQueryRetrieveWidget::retrieve()
   QLabel* progressLabel = new QLabel(tr("Initialization..."));
   QLabel* progressLabel = new QLabel(tr("Initialization..."));
   progress.setLabel(progressLabel);
   progress.setLabel(progressLabel);
   d->ProgressDialog = &progress;
   d->ProgressDialog = &progress;
-  progress.setWindowModality(Qt::WindowModal);
+  progress.setWindowModality(Qt::ApplicationModal);
   progress.setMinimumDuration(0);
   progress.setMinimumDuration(0);
   progress.setValue(0);
   progress.setValue(0);
+  progress.show();
 
 
   QMap<QString,QVariant> serverParameters = d->ServerNodeWidget->parameters();
   QMap<QString,QVariant> serverParameters = d->ServerNodeWidget->parameters();
   ctkDICOMRetrieve *retrieve = new ctkDICOMRetrieve;
   ctkDICOMRetrieve *retrieve = new ctkDICOMRetrieve;
@@ -261,9 +269,6 @@ void ctkDICOMQueryRetrieveWidget::retrieve()
   // pull from GUI
   // pull from GUI
   retrieve->setMoveDestinationAETitle( serverParameters["StorageAETitle"].toString() );
   retrieve->setMoveDestinationAETitle( serverParameters["StorageAETitle"].toString() );
   int step = 0;
   int step = 0;
-  progress.setMaximum(d->QueriesByStudyUID.keys().size());
-  progress.open();
-  progress.setValue(1);
 
 
   // do the rerieval for each selected series
   // do the rerieval for each selected series
   foreach( QString studyUID, d->QueriesByStudyUID.keys() )
   foreach( QString studyUID, d->QueriesByStudyUID.keys() )
@@ -289,6 +294,12 @@ void ctkDICOMQueryRetrieveWidget::retrieve()
     logger.debug("About to retrieve " + studyUID + " from " + d->QueriesByStudyUID[studyUID]->host());
     logger.debug("About to retrieve " + studyUID + " from " + d->QueriesByStudyUID[studyUID]->host());
     logger.info ( "Starting to retrieve" );
     logger.info ( "Starting to retrieve" );
 
 
+    connect(&progress, SIGNAL(canceled()), retrieve, SLOT(cancel()));
+    connect(retrieve, SIGNAL(progress(QString)),
+            progressLabel, SLOT(setText(QString)));
+    connect(retrieve, SIGNAL(progress(int)),
+            this, SLOT(updateRetrieveProgress(int)));
+
     try
     try
       {
       {
       // perform the retrieve
       // perform the retrieve
@@ -310,6 +321,13 @@ void ctkDICOMQueryRetrieveWidget::retrieve()
         break;
         break;
         }
         }
       }
       }
+
+    disconnect(retrieve, SIGNAL(progress(QString)),
+            progressLabel, SLOT(setText(QString)));
+    disconnect(retrieve, SIGNAL(progress(int)),
+            this, SLOT(updateRetrieveProgress(int)));
+    disconnect(&progress, SIGNAL(canceled()), retrieve, SLOT(cancel()));
+
     // Store retrieve structure for later use.
     // Store retrieve structure for later use.
     // Comment MO: I do not think that makes much sense; you store per study one fat
     // Comment MO: I do not think that makes much sense; you store per study one fat
     // structure including an SCU. Also, I switched the code to re-use the retrieve
     // structure including an SCU. Also, I switched the code to re-use the retrieve
@@ -322,10 +340,16 @@ void ctkDICOMQueryRetrieveWidget::retrieve()
   progressLabel->setText(tr("Retrieving Finished"));
   progressLabel->setText(tr("Retrieving Finished"));
   this->updateRetrieveProgress(progress.maximum());
   this->updateRetrieveProgress(progress.maximum());
 
 
+  QString message(tr("Retrieve Process Finished"));
+  if (retrieve->wasCanceled())
+    {
+    message = tr("Retrieve Process Canceled");
+    }
+  QMessageBox::information ( this, tr("Query Retrieve"), message );
+  emit studiesRetrieved(d->RetrievalsByStudyUID.keys());
+
   delete retrieve;
   delete retrieve;
   d->ProgressDialog = 0;
   d->ProgressDialog = 0;
-  QMessageBox::information ( this, tr("Query Retrieve"), tr("Retrieve Process Finished.") );
-  emit studiesRetrieved(d->RetrievalsByStudyUID.keys());
 }
 }
 
 
 //----------------------------------------------------------------------------
 //----------------------------------------------------------------------------
@@ -343,6 +367,10 @@ void ctkDICOMQueryRetrieveWidget::onQueryProgressChanged(int value)
     {
     {
     return;
     return;
     }
     }
+  if (d->CurrentQuery && d->ProgressDialog->wasCanceled())
+    {
+    d->CurrentQuery->cancel();
+    }
   QStringList servers = d->ServerNodeWidget->selectedServerNodes();
   QStringList servers = d->ServerNodeWidget->selectedServerNodes();
   int serverIndex = servers.indexOf(d->CurrentServer);
   int serverIndex = servers.indexOf(d->CurrentServer);
   if (serverIndex < 0)
   if (serverIndex < 0)
@@ -359,6 +387,7 @@ void ctkDICOMQueryRetrieveWidget::onQueryProgressChanged(int value)
     }
     }
   float serverProgress = 100. / servers.size();
   float serverProgress = 100. / servers.size();
   d->ProgressDialog->setValue( (serverIndex + (value / 101.)) * serverProgress);
   d->ProgressDialog->setValue( (serverIndex + (value / 101.)) * serverProgress);
+  QApplication::processEvents();
 }
 }
 
 
 //----------------------------------------------------------------------------
 //----------------------------------------------------------------------------
@@ -379,6 +408,7 @@ void ctkDICOMQueryRetrieveWidget::updateRetrieveProgress(int value)
     }
     }
   d->ProgressDialog->setValue( value );
   d->ProgressDialog->setValue( value );
   logger.error(QString("setting value to %1").arg(value) );
   logger.error(QString("setting value to %1").arg(value) );
+  QApplication::processEvents();
 }
 }
 
 
 //----------------------------------------------------------------------------
 //----------------------------------------------------------------------------

+ 3 - 1
Libs/DICOM/Widgets/ctkDICOMQueryWidget.h

@@ -53,9 +53,11 @@ Q_SIGNALS:
   /// This signal is emitted when the user hits return in any of the line edits
   /// This signal is emitted when the user hits return in any of the line edits
   void returnPressed();
   void returnPressed();
 
 
+public Q_SLOTS:
+  void onReturnPressed();
+
 protected Q_SLOTS:
 protected Q_SLOTS:
   void startTimer();
   void startTimer();
-  void onReturnPressed();
 };
 };
 
 
 #endif
 #endif