Ver código fonte

Correct wrong automatic git merging to what was originally meant during adaption to latest DCMTK.

Michael Onken 13 anos atrás
pai
commit
220681ed3c
1 arquivos alterados com 424 adições e 430 exclusões
  1. 424 430
      Libs/DICOM/Core/ctkDICOMQuery.cpp

+ 424 - 430
Libs/DICOM/Core/ctkDICOMQuery.cpp

@@ -1,430 +1,424 @@
-/*=========================================================================
-
-  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.apache.org/licenses/LICENSE-2.0.txt
-
-  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 <QSqlQuery>
-#include <QSqlRecord>
-#include <QVariant>
-#include <QDate>
-#include <QStringList>
-#include <QSet>
-#include <QFile>
-#include <QDirIterator>
-#include <QFileInfo>
-#include <QDebug>
-
-// ctkDICOMCore includes
-#include "ctkDICOMQuery.h"
-#include "ctkLogger.h"
-
-// DCMTK includes
-#ifndef WIN32
-  #define HAVE_CONFIG_H
-#endif
-#include "dcmtk/dcmnet/dimse.h"
-#include "dcmtk/dcmnet/diutil.h"
-
-#include <dcmtk/dcmdata/dcfilefo.h>
-#include <dcmtk/dcmdata/dcfilefo.h>
-#include <dcmtk/dcmdata/dcdeftag.h>
-#include <dcmtk/dcmdata/dcdatset.h>
-#include <dcmtk/ofstd/ofcond.h>
-#include <dcmtk/ofstd/ofstring.h>
-#include <dcmtk/ofstd/ofstd.h>        /* for class OFStandard */
-#include <dcmtk/dcmdata/dcddirif.h>   /* for class DicomDirInterface */
-
-#include <dcmtk/dcmnet/scu.h>
-
-static ctkLogger logger ( "org.commontk.dicom.DICOMQuery" );
-
-//------------------------------------------------------------------------------
-class ctkDICOMQueryPrivate
-{
-public:
-  ctkDICOMQueryPrivate();
-  ~ctkDICOMQueryPrivate();
-
-  /// Add a StudyInstanceUID to be queried
-  void addStudyInstanceUID(const QString& StudyInstanceUID );
-
-  QString                 CallingAETitle;
-  QString                 CalledAETitle;
-  QString                 Host;
-  int                     Port;
-  QMap<QString,QVariant>  Filters;
-  DcmSCU                  SCU;
-  DcmDataset*             Query;
-  QStringList             StudyInstanceUIDList;
-};
-
-//------------------------------------------------------------------------------
-// ctkDICOMQueryPrivate methods
-
-//------------------------------------------------------------------------------
-ctkDICOMQueryPrivate::ctkDICOMQueryPrivate()
-{
-  this->Query = new DcmDataset();
-  this->Port = 0;
-}
-
-//------------------------------------------------------------------------------
-ctkDICOMQueryPrivate::~ctkDICOMQueryPrivate()
-{
-  delete this->Query;
-}
-
-//------------------------------------------------------------------------------
-void ctkDICOMQueryPrivate::addStudyInstanceUID( const QString& s )
-{
-  this->StudyInstanceUIDList.append ( s );
-}
-
-//------------------------------------------------------------------------------
-// ctkDICOMQuery methods
-
-//------------------------------------------------------------------------------
-ctkDICOMQuery::ctkDICOMQuery(QObject* parentObject)
-  : QObject(parentObject)
-  , d_ptr(new ctkDICOMQueryPrivate)
-{
-}
-
-//------------------------------------------------------------------------------
-ctkDICOMQuery::~ctkDICOMQuery()
-{
-}
-
-/// Set methods for connectivity
-//------------------------------------------------------------------------------
-void ctkDICOMQuery::setCallingAETitle( const QString& callingAETitle )
-{
-  Q_D(ctkDICOMQuery);
-  d->CallingAETitle = callingAETitle;
-}
-
-//------------------------------------------------------------------------------
-QString ctkDICOMQuery::callingAETitle() const
-{
-  Q_D(const ctkDICOMQuery);
-  return d->CallingAETitle;
-}
-
-//------------------------------------------------------------------------------
-void ctkDICOMQuery::setCalledAETitle( const QString& calledAETitle )
-{
-  Q_D(ctkDICOMQuery);
-  d->CalledAETitle = calledAETitle;
-}
-
-//------------------------------------------------------------------------------
-QString ctkDICOMQuery::calledAETitle()const
-{
-  Q_D(const ctkDICOMQuery);
-  return d->CalledAETitle;
-}
-
-//------------------------------------------------------------------------------
-void ctkDICOMQuery::setHost( const QString& host )
-{
-  Q_D(ctkDICOMQuery);
-  d->Host = host;
-}
-
-//------------------------------------------------------------------------------
-QString ctkDICOMQuery::host() const
-{
-  Q_D(const ctkDICOMQuery);
-  return d->Host;
-}
-
-//------------------------------------------------------------------------------
-void ctkDICOMQuery::setPort ( int port )
-{
-  Q_D(ctkDICOMQuery);
-  d->Port = port;
-}
-
-//------------------------------------------------------------------------------
-int ctkDICOMQuery::port()const
-{
-  Q_D(const ctkDICOMQuery);
-  return d->Port;
-}
-
-//------------------------------------------------------------------------------
-void ctkDICOMQuery::setFilters( const QMap<QString,QVariant>& filters )
-{
-  Q_D(ctkDICOMQuery);
-  d->Filters = filters;
-}
-
-//------------------------------------------------------------------------------
-QMap<QString,QVariant> ctkDICOMQuery::filters()const
-{
-  Q_D(const ctkDICOMQuery);
-  return d->Filters;
-}
-
-//------------------------------------------------------------------------------
-QStringList ctkDICOMQuery::studyInstanceUIDQueried()const
-{
-  Q_D(const ctkDICOMQuery);
-  return d->StudyInstanceUIDList;
-}
-
-//------------------------------------------------------------------------------
-bool ctkDICOMQuery::query(ctkDICOMDatabase& database )
-{
-  // ctkDICOMDatabase::setDatabase ( database );
-  Q_D(ctkDICOMQuery);
-  // In the following, we emit progress(int) after progress(QString), this
-  // is in case the connected object doesn't refresh its ui when the progress
-  // message is updated but only if the progress value is (e.g. QProgressDialog)
-  if ( database.database().isOpen() )
-    {
-    logger.debug ( "DB open in Query" );
-    emit progress("DB open in Query");
-    }
-  else
-    {
-    logger.debug ( "DB not open in Query" );
-    emit progress("DB not open in Query");
-    }
-  emit progress(0);
-
-  d->StudyInstanceUIDList.clear();
-  d->SCU.setAETitle ( OFString(this->callingAETitle().toStdString().c_str()) );
-  d->SCU.setPeerAETitle ( OFString(this->calledAETitle().toStdString().c_str()) );
-  d->SCU.setPeerHostName ( OFString(this->host().toStdString().c_str()) );
-  d->SCU.setPeerPort ( this->port() );
-
-  logger.error ( "Setting Transfer Syntaxes" );
-  emit progress("Setting Transfer Syntaxes");
-  emit progress(10);
-
-  OFList<OFString> transferSyntaxes;
-  transferSyntaxes.push_back ( UID_LittleEndianExplicitTransferSyntax );
-  transferSyntaxes.push_back ( UID_BigEndianExplicitTransferSyntax );
-  transferSyntaxes.push_back ( UID_LittleEndianImplicitTransferSyntax );
-
-  d->SCU.addPresentationContext ( UID_FINDStudyRootQueryRetrieveInformationModel, transferSyntaxes );
-  // d->SCU.addPresentationContext ( UID_VerificationSOPClass, transferSyntaxes );
-  if ( !d->SCU.initNetwork().good() )
-    {
-    logger.error( "Error initializing the network" );
-    emit progress("Error initializing the network");
-    emit progress(100);
-    return false;
-    }
-  logger.debug ( "Negotiating Association" );
-  emit progress("Negatiating Association");
-  emit progress(20);
-
-  OFCondition result = d->SCU.negotiateAssociation();
-  if (result.bad())
-    {
-    logger.error( "Error negotiating the association: " + QString(result.text()) );
-    emit progress("Error negotiating the association");
-    emit progress(100);
-    return false;
-    }
-
-  // Clear the query
-  d->Query->clear();
-
-  // Insert all keys that we like to receive values for
-  d->Query->insertEmptyElement ( DCM_PatientID );
-  d->Query->insertEmptyElement ( DCM_PatientName );
-  d->Query->insertEmptyElement ( DCM_PatientBirthDate );
-  d->Query->insertEmptyElement ( DCM_StudyID );
-  d->Query->insertEmptyElement ( DCM_StudyInstanceUID );
-  d->Query->insertEmptyElement ( DCM_StudyDescription );
-  d->Query->insertEmptyElement ( DCM_StudyDate );
-  d->Query->insertEmptyElement ( DCM_SeriesNumber );
-  d->Query->insertEmptyElement ( DCM_SeriesDescription );
-  d->Query->insertEmptyElement ( DCM_SeriesInstanceUID );
-  d->Query->insertEmptyElement ( DCM_StudyTime );
-  d->Query->insertEmptyElement ( DCM_SeriesDate );
-  d->Query->insertEmptyElement ( DCM_SeriesTime );
-  d->Query->insertEmptyElement ( DCM_Modality );
-  d->Query->insertEmptyElement ( DCM_ModalitiesInStudy );
-  d->Query->insertEmptyElement ( DCM_AccessionNumber );
-  d->Query->insertEmptyElement ( DCM_NumberOfSeriesRelatedInstances ); // Number of images in the series
-  d->Query->insertEmptyElement ( DCM_NumberOfStudyRelatedInstances ); // Number of images in the series
-  d->Query->insertEmptyElement ( DCM_NumberOfStudyRelatedSeries ); // Number of images in the series
-
-  // Make clear we define our search values in ISO Latin 1 (default would be ASCII)
-  d->Query->putAndInsertOFStringArray(DCM_SpecificCharacterSet, "ISO_IR 100");
-
-  d->Query->putAndInsertString ( DCM_QueryRetrieveLevel, "STUDY" );
-
-  /* Now, for all keys that the user provided for filtering on STUDY level,
-   * overwrite empty keys with value. For now, only Patient's Name, Patient ID,
-   * Study Description, Modalities in Study, and Study Date are used.
-   */
-  QString seriesDescription;
-  foreach( QString key, d->Filters.keys() )
-    {
-    if ( key == QString("Name") )
-      {
-      // make the filter a wildcard in dicom style
-      d->Query->putAndInsertString( DCM_PatientName,
-        (QString("*") + d->Filters[key].toString() + QString("*")).toAscii().data());
-      }
-    else if ( key == QString("Study") )
-      {
-      // make the filter a wildcard in dicom style
-      d->Query->putAndInsertString( DCM_StudyDescription,
-        (QString("*") + d->Filters[key].toString() + QString("*")).toAscii().data());
-      }
-    else if ( key == QString("ID") )
-      {
-      // make the filter a wildcard in dicom style
-      d->Query->putAndInsertString( DCM_PatientID,
-        (QString("*") + d->Filters[key].toString() + QString("*")).toAscii().data());
-      }
-    else if ( key == QString("Modalities") )
-      {
-      // make the filter be an "OR" of modalities using backslash (dicom-style)
-      QString modalitySearch("");
-      foreach (const QString& modality, d->Filters[key].toStringList())
-      {
-        modalitySearch += modality + QString("\\");
-      }
-      modalitySearch.chop(1); // remove final backslash
-      logger.debug("modalityInStudySearch " + modalitySearch);
-      d->Query->putAndInsertString( DCM_ModalitiesInStudy, modalitySearch.toAscii().data() );
-      }
-    // Rememer Series Description for later series query if we go through the keys now
-    else if ( key == QString("Series") )
-      {
-      // make the filter a wildcard in dicom style
-      seriesDescription = "*" + d->Filters[key].toString() + "*";
-      }
-    else
-      {
-      logger.debug("Ignoring unknown search key: " + key);
-      }
-    }
-
-  if ( d->Filters.keys().contains("StartDate") && d->Filters.keys().contains("EndDate") )
-    {
-    QString dateRange = d->Filters["StartDate"].toString() +
-                        QString("-") +
-                        d->Filters["EndDate"].toString();
-    d->Query->putAndInsertString ( DCM_StudyDate, dateRange.toAscii().data() );
-    logger.debug("Query on study date " + dateRange);
-    }
-  emit progress(30);
-
-  FINDResponses *responses = new FINDResponses();
-
-  Uint16 presentationContext = 0;
-  // Check for any accepted presentation context for FIND in study root (dont care about transfer syntax)
-  presentationContext = d->SCU.findPresentationContextID ( UID_FINDStudyRootQueryRetrieveInformationModel, "");
-  if ( presentationContext == 0 )
-    {
-    logger.error ( "Failed to find acceptable presentation context" );
-    emit progress("Failed to find acceptable presentation context");
-    }
-  else
-    {
-    logger.info ( "Found useful presentation context" );
-    emit progress("Found useful presentation context");
-    }
-  emit progress(40);
-
-  OFCondition status = d->SCU.sendFINDRequest ( presentationContext, d->Query, responses );
-  if ( !status.good() )
-    {
-    logger.error ( "Find failed" );
-    emit progress("Find failed");
-    d->SCU.closeAssociation ( DCMSCU_RELEASE_ASSOCIATION );
-    emit progress(100);
-    delete responses;
-    return false;
-    }
-  logger.debug ( "Find succeded");
-  emit progress("Find succeded");
-  emit progress(50);
-
-  for ( OFListIterator(FINDResponse*) it = responses->begin(); it != responses->end(); it++ )
-    {
-    DcmDataset *dataset = (*it)->m_dataset;
-    if ( dataset != NULL ) // the last response is always empty
-      {
-      database.insert ( dataset, false, false);
-      OFString StudyInstanceUID;
-      dataset->findAndGetOFString ( DCM_StudyInstanceUID, StudyInstanceUID );
-      d->addStudyInstanceUID ( StudyInstanceUID.c_str() );
-      }
-    }
-  delete responses;
-
-  /* Only ask for series attributes now. This requires kicking out the rest of former query. */
-  d->Query->clear();
-  d->Query->insertEmptyElement ( DCM_SeriesNumber );
-  d->Query->insertEmptyElement ( DCM_SeriesDescription );
-  d->Query->insertEmptyElement ( DCM_SeriesInstanceUID );
-  d->Query->insertEmptyElement ( DCM_SeriesDate );
-  d->Query->insertEmptyElement ( DCM_SeriesTime );
-  d->Query->insertEmptyElement ( DCM_Modality );
-
-  /* Add user-defined filters */
-  d->Query->putAndInsertOFStringArray(DCM_SeriesDescription, seriesDescription.toLatin1().data());
-
-  // Now search each within each Study that was identified
-  d->Query->putAndInsertString ( DCM_QueryRetrieveLevel, "SERIES" );
-  float progressRatio = 25. / d->StudyInstanceUIDList.count();
-  int i = 0;
-  foreach ( QString StudyInstanceUID, d->StudyInstanceUIDList )
-    {
-    logger.debug ( "Starting Series C-FIND for Study: " + StudyInstanceUID );
-    emit progress(QString("Starting Series C-FIND for Study: ") + StudyInstanceUID);
-    emit progress(50 + (progressRatio * i++));
-
-    d->Query->putAndInsertString ( DCM_StudyInstanceUID, StudyInstanceUID.toStdString().c_str() );
-    responses = new FINDResponses();
-    status = d->SCU.sendFINDRequest ( presentationContext, d->Query, responses );
-    if ( status.good() )
-      {
-      for ( OFListIterator(FINDResponse*) it = responses->begin(); it != responses->end(); it++ )
-        {
-        DcmDataset *dataset = (*it)->m_dataset;
-        if ( dataset != NULL )
-          {
-          database.insert ( dataset, false, false);
-          }
-        }
-      logger.debug ( "Find succeded on Series level for Study: " + StudyInstanceUID );
-      emit progress(QString("Find succeded on Series level for Study: ") + StudyInstanceUID);
-      }
-    else
-      {
-      logger.error ( "Find on Series level failed for Study: " + StudyInstanceUID );
-      emit progress(QString("Find on Series level failed for Study: ") + StudyInstanceUID);
-      }
-    emit progress(50 + (progressRatio * i++));
-    delete responses;
-    }
-  d->SCU.closeAssociation ( DCMSCU_RELEASE_ASSOCIATION );
-  emit progress(100);
-  return true;
-}
+/*=========================================================================
+
+  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.apache.org/licenses/LICENSE-2.0.txt
+
+  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 <QSqlQuery>
+#include <QSqlRecord>
+#include <QVariant>
+#include <QDate>
+#include <QStringList>
+#include <QSet>
+#include <QFile>
+#include <QDirIterator>
+#include <QFileInfo>
+#include <QDebug>
+
+// ctkDICOMCore includes
+#include "ctkDICOMQuery.h"
+#include "ctkLogger.h"
+
+// DCMTK includes
+#ifndef WIN32
+  #define HAVE_CONFIG_H 
+#endif
+#include "dcmtk/dcmnet/dimse.h"
+#include "dcmtk/dcmnet/diutil.h"
+
+#include <dcmtk/dcmdata/dcfilefo.h>
+#include <dcmtk/dcmdata/dcfilefo.h>
+#include <dcmtk/dcmdata/dcdeftag.h>
+#include <dcmtk/dcmdata/dcdatset.h>
+#include <dcmtk/ofstd/ofcond.h>
+#include <dcmtk/ofstd/ofstring.h>
+#include <dcmtk/ofstd/ofstd.h>        /* for class OFStandard */
+#include <dcmtk/dcmdata/dcddirif.h>   /* for class DicomDirInterface */
+
+#include <dcmtk/dcmnet/scu.h>
+
+static ctkLogger logger ( "org.commontk.dicom.DICOMQuery" );
+
+//------------------------------------------------------------------------------
+class ctkDICOMQueryPrivate
+{
+public:
+  ctkDICOMQueryPrivate();
+  ~ctkDICOMQueryPrivate();
+
+  /// Add a StudyInstanceUID to be queried
+  void addStudyInstanceUID(const QString& StudyInstanceUID );
+
+  QString                 CallingAETitle;
+  QString                 CalledAETitle;
+  QString                 Host;
+  int                     Port;
+  QMap<QString,QVariant>  Filters;
+  DcmSCU                  SCU;
+  DcmDataset*             Query;
+  QStringList             StudyInstanceUIDList;
+};
+
+//------------------------------------------------------------------------------
+// ctkDICOMQueryPrivate methods
+
+//------------------------------------------------------------------------------
+ctkDICOMQueryPrivate::ctkDICOMQueryPrivate()
+{
+  this->Query = new DcmDataset();
+  this->Port = 0;
+}
+
+//------------------------------------------------------------------------------
+ctkDICOMQueryPrivate::~ctkDICOMQueryPrivate()
+{
+  delete this->Query;
+}
+
+//------------------------------------------------------------------------------
+void ctkDICOMQueryPrivate::addStudyInstanceUID( const QString& s )
+{
+  this->StudyInstanceUIDList.append ( s );
+}
+
+//------------------------------------------------------------------------------
+// ctkDICOMQuery methods
+
+//------------------------------------------------------------------------------
+ctkDICOMQuery::ctkDICOMQuery(QObject* parentObject)
+  : QObject(parentObject)
+  , d_ptr(new ctkDICOMQueryPrivate)
+{
+}
+
+//------------------------------------------------------------------------------
+ctkDICOMQuery::~ctkDICOMQuery()
+{
+}
+
+/// Set methods for connectivity
+//------------------------------------------------------------------------------
+void ctkDICOMQuery::setCallingAETitle( const QString& callingAETitle )
+{
+  Q_D(ctkDICOMQuery);
+  d->CallingAETitle = callingAETitle;
+}
+
+//------------------------------------------------------------------------------
+QString ctkDICOMQuery::callingAETitle() const
+{
+  Q_D(const ctkDICOMQuery);
+  return d->CallingAETitle;
+}
+
+//------------------------------------------------------------------------------
+void ctkDICOMQuery::setCalledAETitle( const QString& calledAETitle )
+{
+  Q_D(ctkDICOMQuery);
+  d->CalledAETitle = calledAETitle;
+}
+
+//------------------------------------------------------------------------------
+QString ctkDICOMQuery::calledAETitle()const
+{
+  Q_D(const ctkDICOMQuery);
+  return d->CalledAETitle;
+}
+
+//------------------------------------------------------------------------------
+void ctkDICOMQuery::setHost( const QString& host )
+{
+  Q_D(ctkDICOMQuery);
+  d->Host = host;
+}
+
+//------------------------------------------------------------------------------
+QString ctkDICOMQuery::host() const
+{
+  Q_D(const ctkDICOMQuery);
+  return d->Host;
+}
+
+//------------------------------------------------------------------------------
+void ctkDICOMQuery::setPort ( int port )
+{
+  Q_D(ctkDICOMQuery);
+  d->Port = port;
+}
+
+//------------------------------------------------------------------------------
+int ctkDICOMQuery::port()const
+{
+  Q_D(const ctkDICOMQuery);
+  return d->Port;
+}
+
+//------------------------------------------------------------------------------
+void ctkDICOMQuery::setFilters( const QMap<QString,QVariant>& filters )
+{
+  Q_D(ctkDICOMQuery);
+  d->Filters = filters;
+}
+
+//------------------------------------------------------------------------------
+QMap<QString,QVariant> ctkDICOMQuery::filters()const
+{
+  Q_D(const ctkDICOMQuery);
+  return d->Filters;
+}
+
+//------------------------------------------------------------------------------
+QStringList ctkDICOMQuery::studyInstanceUIDQueried()const
+{
+  Q_D(const ctkDICOMQuery);
+  return d->StudyInstanceUIDList;
+}
+
+//------------------------------------------------------------------------------
+bool ctkDICOMQuery::query(ctkDICOMDatabase& database )
+{
+  // ctkDICOMDatabase::setDatabase ( database );
+  Q_D(ctkDICOMQuery);
+  // In the following, we emit progress(int) after progress(QString), this
+  // is in case the connected object doesn't refresh its ui when the progress
+  // message is updated but only if the progress value is (e.g. QProgressDialog)
+  if ( database.database().isOpen() )
+    {
+    logger.debug ( "DB open in Query" );
+    emit progress("DB open in Query");
+    }
+  else
+    {
+    logger.debug ( "DB not open in Query" );
+    emit progress("DB not open in Query");
+    }
+  emit progress(0);
+
+  d->StudyInstanceUIDList.clear();
+  d->SCU.setAETitle ( OFString(this->callingAETitle().toStdString().c_str()) );
+  d->SCU.setPeerAETitle ( OFString(this->calledAETitle().toStdString().c_str()) );
+  d->SCU.setPeerHostName ( OFString(this->host().toStdString().c_str()) );
+  d->SCU.setPeerPort ( this->port() );
+
+  logger.error ( "Setting Transfer Syntaxes" );
+  emit progress("Setting Transfer Syntaxes");
+  emit progress(10);
+
+  OFList<OFString> transferSyntaxes;
+  transferSyntaxes.push_back ( UID_LittleEndianExplicitTransferSyntax );
+  transferSyntaxes.push_back ( UID_BigEndianExplicitTransferSyntax );
+  transferSyntaxes.push_back ( UID_LittleEndianImplicitTransferSyntax );
+
+  d->SCU.addPresentationContext ( UID_FINDStudyRootQueryRetrieveInformationModel, transferSyntaxes );
+  // d->SCU.addPresentationContext ( UID_VerificationSOPClass, transferSyntaxes );
+  if ( !d->SCU.initNetwork().good() )
+    {
+    logger.error( "Error initializing the network" );
+    emit progress("Error initializing the network");
+    emit progress(100);
+    return false;
+    }
+  logger.debug ( "Negotiating Association" );
+  emit progress("Negatiating Association");
+  emit progress(20);
+
+  OFCondition result = d->SCU.negotiateAssociation();
+  if (result.bad())
+    {
+    logger.error( "Error negotiating the association: " + QString(result.text()) );
+    emit progress("Error negotiating the association");
+    emit progress(100);
+    return false;
+    }
+
+  // Clear the query
+  d->Query->clear();
+ 
+  // Insert all keys that we like to receive values for
+  d->Query->insertEmptyElement ( DCM_PatientID );
+  d->Query->insertEmptyElement ( DCM_PatientName );
+  d->Query->insertEmptyElement ( DCM_PatientBirthDate );
+  d->Query->insertEmptyElement ( DCM_StudyID );
+  d->Query->insertEmptyElement ( DCM_StudyInstanceUID );
+  d->Query->insertEmptyElement ( DCM_StudyDescription );
+  d->Query->insertEmptyElement ( DCM_StudyDate );
+  d->Query->insertEmptyElement ( DCM_StudyTime );
+  d->Query->insertEmptyElement ( DCM_ModalitiesInStudy );
+  d->Query->insertEmptyElement ( DCM_AccessionNumber );
+  d->Query->insertEmptyElement ( DCM_NumberOfSeriesRelatedInstances ); // Number of images in the series
+  d->Query->insertEmptyElement ( DCM_NumberOfStudyRelatedInstances ); // Number of images in the series
+  d->Query->insertEmptyElement ( DCM_NumberOfStudyRelatedSeries ); // Number of images in the series
+
+  // Make clear we define our search values in ISO Latin 1 (default would be ASCII)
+  d->Query->putAndInsertOFStringArray(DCM_SpecificCharacterSet, "ISO_IR 100");
+
+  d->Query->putAndInsertString ( DCM_QueryRetrieveLevel, "STUDY" );
+
+  /* Now, for all keys that the user provided for filtering on STUDY level, 
+   * overwrite empty keys with value. For now, only Patient's Name, Patient ID,
+   * Study Description, Modalities in Study, and Study Date are used.
+   */
+  QString seriesDescription;
+  foreach( QString key, d->Filters.keys() )
+    {
+    if ( key == QString("Name") )
+      {
+      // make the filter a wildcard in dicom style
+      d->Query->putAndInsertString( DCM_PatientName,
+        (QString("*") + d->Filters[key].toString() + QString("*")).toAscii().data());
+      }
+    else if ( key == QString("Study") )
+      {
+      // make the filter a wildcard in dicom style
+      d->Query->putAndInsertString( DCM_StudyDescription,
+        (QString("*") + d->Filters[key].toString() + QString("*")).toAscii().data());
+      }
+    else if ( key == QString("ID") )
+      {
+      // make the filter a wildcard in dicom style
+      d->Query->putAndInsertString( DCM_PatientID,
+        (QString("*") + d->Filters[key].toString() + QString("*")).toAscii().data());
+      }
+    else if ( key == QString("Modalities") )
+      {
+      // make the filter be an "OR" of modalities using backslash (dicom-style)
+      QString modalitySearch("");
+      foreach (const QString& modality, d->Filters[key].toStringList())
+      {
+        modalitySearch += modality + QString("\\");
+      }
+      modalitySearch.chop(1); // remove final backslash
+      logger.debug("modalityInStudySearch " + modalitySearch);
+      d->Query->putAndInsertString( DCM_ModalitiesInStudy, modalitySearch.toAscii().data() );
+      }
+    // Rememer Series Description for later series query if we go through the keys now
+    else if ( key == QString("Series") )
+      {
+      // make the filter a wildcard in dicom style
+      seriesDescription = "*" + d->Filters[key].toString() + "*";
+      }
+    else
+      {
+      logger.debug("Ignoring unknown search key: " + key);
+      }
+    }
+
+  if ( d->Filters.keys().contains("StartDate") && d->Filters.keys().contains("EndDate") )
+    {
+    QString dateRange = d->Filters["StartDate"].toString() + 
+                        QString("-") + 
+                        d->Filters["EndDate"].toString();
+    d->Query->putAndInsertString ( DCM_StudyDate, dateRange.toAscii().data() );
+    logger.debug("Query on study date " + dateRange);
+    }
+  emit progress(30);
+
+  FINDResponses *responses = new FINDResponses();
+
+  Uint16 presentationContext = 0;
+  // Check for any accepted presentation context for FIND in study root (dont care about transfer syntax)
+  presentationContext = d->SCU.findPresentationContextID ( UID_FINDStudyRootQueryRetrieveInformationModel, "");
+  if ( presentationContext == 0 )
+    {
+    logger.error ( "Failed to find acceptable presentation context" );
+    emit progress("Failed to find acceptable presentation context");
+    }
+  else
+    {
+    logger.info ( "Found useful presentation context" );
+    emit progress("Found useful presentation context");
+    }
+  emit progress(40);
+
+  OFCondition status = d->SCU.sendFINDRequest ( presentationContext, d->Query, responses );
+  if ( !status.good() )
+    {
+    logger.error ( "Find failed" );
+    emit progress("Find failed");
+    d->SCU.closeAssociation ( DCMSCU_RELEASE_ASSOCIATION );
+    emit progress(100);
+    delete responses;
+    return false;
+    }
+  logger.debug ( "Find succeded");
+  emit progress("Find succeded");
+  emit progress(50);
+
+  for ( OFListIterator(FINDResponse*) it = responses->begin(); it != responses->end(); it++ )
+    {
+    DcmDataset *dataset = (*it)->m_dataset;
+    if ( dataset != NULL ) // the last response is always empty
+      {
+      database.insert ( dataset, false /* do not store to disk*/, false /* no thumbnail*/);
+      OFString StudyInstanceUID;
+      dataset->findAndGetOFString ( DCM_StudyInstanceUID, StudyInstanceUID );
+      d->addStudyInstanceUID ( StudyInstanceUID.c_str() );
+      }
+    }
+  delete responses;
+
+  /* Only ask for series attributes now. This requires kicking out the rest of former query. */
+  d->Query->clear();
+  d->Query->insertEmptyElement ( DCM_SeriesNumber );
+  d->Query->insertEmptyElement ( DCM_SeriesDescription );
+  d->Query->insertEmptyElement ( DCM_SeriesInstanceUID );
+  d->Query->insertEmptyElement ( DCM_SeriesDate );
+  d->Query->insertEmptyElement ( DCM_SeriesTime );
+  d->Query->insertEmptyElement ( DCM_Modality );
+
+  /* Add user-defined filters */
+  d->Query->putAndInsertOFStringArray(DCM_SeriesDescription, seriesDescription.toLatin1().data());
+
+  // Now search each within each Study that was identified
+  d->Query->putAndInsertString ( DCM_QueryRetrieveLevel, "SERIES" );
+  float progressRatio = 25. / d->StudyInstanceUIDList.count();
+  int i = 0;
+  foreach ( QString StudyInstanceUID, d->StudyInstanceUIDList )
+    {
+    logger.debug ( "Starting Series C-FIND for Study: " + StudyInstanceUID );
+    emit progress(QString("Starting Series C-FIND for Study: ") + StudyInstanceUID);
+    emit progress(50 + (progressRatio * i++));
+
+    d->Query->putAndInsertString ( DCM_StudyInstanceUID, StudyInstanceUID.toStdString().c_str() );
+    responses = new FINDResponses();
+    status = d->SCU.sendFINDRequest ( presentationContext, d->Query, responses );
+    if ( status.good() )
+      {
+      for ( OFListIterator(FINDResponse*) it = responses->begin(); it != responses->end(); it++ )
+        {
+        DcmDataset *dataset = (*it)->m_dataset;
+        if ( dataset != NULL )
+          {
+          database.insert ( dataset, false /* do not store */, false /* no thumbnail */ );
+          }
+        }
+      logger.debug ( "Find succeded on Series level for Study: " + StudyInstanceUID );
+      emit progress(QString("Find succeded on Series level for Study: ") + StudyInstanceUID);
+      }
+    else
+      {
+      logger.error ( "Find on Series level failed for Study: " + StudyInstanceUID );
+      emit progress(QString("Find on Series level failed for Study: ") + StudyInstanceUID);
+      }
+    emit progress(50 + (progressRatio * i++));
+    delete responses;
+    }
+  d->SCU.closeAssociation ( DCMSCU_RELEASE_ASSOCIATION );
+  emit progress(100);
+  return true;
+}