Преглед изворни кода

Merge topic 'dah-exchange-data-implementation' into dah

* dah-exchange-data-implementation:
  Add ctkDicomObjectLocatorCacheTest1
  ctkDicomObjectLocatorCache - Add "ref count" for cached item
  Simplify ctkDicomObjectLocatorCache::getData signature
  Implement and test comparison operators associated with ctkDicomAppHostingTypes
Jean-Christophe Fillion-Robin пре 14 година
родитељ
комит
4307c1de6a

+ 3 - 1
Plugins/org.commontk.dah.app/ctkDicomAbstractApp.cpp

@@ -159,7 +159,9 @@ QList<ctkDicomAppHosting::ObjectLocator> ctkDicomAbstractApp::getData(
   const QList<QString>& acceptableTransferSyntaxUIDs,
   bool includeBulkData)
 {
-  return this->objectLocatorCache()->getData(objectUUIDs, acceptableTransferSyntaxUIDs, includeBulkData);
+  Q_UNUSED(acceptableTransferSyntaxUIDs);
+  Q_UNUSED(includeBulkData);
+  return this->objectLocatorCache()->getData(objectUUIDs);
 }
 
 //----------------------------------------------------------------------------

+ 6 - 1
Plugins/org.commontk.dah.core/CMakeLists.txt

@@ -5,7 +5,7 @@ SET(PLUGIN_export_directive "org_commontk_dah_core_EXPORT")
 SET(PLUGIN_SRCS
   ctkDicomAppHostingCorePlugin.cpp
   ctkDicomAppHostingCorePlugin_p.h
-  ctkDicomAppHostingTypes.h
+  ctkDicomAppHostingTypes.cpp
   ctkDicomAppHostingTypesHelper.cpp
   ctkDicomAppInterface.h
   ctkDicomExchangeInterface.h
@@ -50,3 +50,8 @@ ctkMacroBuildPlugin(
   RESOURCES ${PLUGIN_resources}
   TARGET_LIBRARIES ${PLUGIN_target_libraries}
 )
+
+IF(BUILD_TESTING)
+  ADD_SUBDIRECTORY(Testing)
+ENDIF()
+

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

@@ -0,0 +1 @@
+ADD_SUBDIRECTORY(Cpp)

+ 28 - 0
Plugins/org.commontk.dah.core/Testing/Cpp/CMakeLists.txt

@@ -0,0 +1,28 @@
+SET(KIT ${PROJECT_NAME})
+
+CREATE_TEST_SOURCELIST(Tests ${KIT}CppTests.cxx
+  ctkDicomAppHostingTypesTest1.cpp
+  ctkDicomObjectLocatorCacheTest1.cpp
+  )
+
+SET (TestsToRun ${Tests})
+REMOVE (TestsToRun ${KIT}CppTests.cxx)
+
+SET(LIBRARY_NAME ${PROJECT_NAME})
+
+ADD_EXECUTABLE(${KIT}CppTests ${Tests})
+TARGET_LINK_LIBRARIES(${KIT}CppTests ${LIBRARY_NAME})
+
+SET(KIT_TESTS ${CPP_TEST_PATH}/${KIT}CppTests)
+
+MACRO( SIMPLE_TEST  TESTNAME )
+  ADD_TEST( ${TESTNAME} ${KIT_TESTS} ${TESTNAME} )
+  SET_PROPERTY(TEST ${TESTNAME} PROPERTY LABELS ${PROJECT_NAME})
+ENDMACRO( SIMPLE_TEST )
+
+#
+# Add Tests
+#
+
+SIMPLE_TEST( ctkDicomAppHostingTypesTest1 )
+SIMPLE_TEST( ctkDicomObjectLocatorCacheTest1 )

+ 274 - 0
Plugins/org.commontk.dah.core/Testing/Cpp/ctkDicomAppHostingTypesTest1.cpp

@@ -0,0 +1,274 @@
+
+// CTK includes
+#include <ctkDicomAppHostingTypes.h>
+
+// STD includes
+#include <cstdlib>
+#include <iostream>
+
+namespace
+{
+//----------------------------------------------------------------------------
+template<typename STRUCT>
+bool verifyOperator(const STRUCT& left, const STRUCT& right, bool equalExpected)
+{
+  bool equal = (left == right);
+  bool different = (left != right);
+
+  if (equalExpected)
+    {
+    if (!equal)
+      {
+      return false;
+      }
+    if (different)
+      {
+      return false;
+      }
+    }
+  else
+    {
+    if (equal)
+      {
+      return false;
+      }
+    if (!different)
+      {
+      return false;
+      }
+    }
+  return true;
+}
+}
+
+//----------------------------------------------------------------------------
+#define CHECK_OP(TYPE, LEFT, RIGHT, EQUAL_EXPECTED)        \
+  if (!verifyOperator<ctkDicomAppHosting::TYPE>(           \
+        LEFT, RIGHT, /*equalExpected=*/ EQUAL_EXPECTED))   \
+    {                                                      \
+    std::cerr << "Line "                                   \
+              << __LINE__ << " - Problem with " << #TYPE   \
+              << " comparison operator" << std::endl;      \
+    return EXIT_FAILURE;                                   \
+    }
+
+//----------------------------------------------------------------------------
+int ctkDicomAppHostingTypesTest1(int argc, char* argv[])
+{
+  Q_UNUSED(argc);
+  Q_UNUSED(argv);
+
+  //----------------------------------------------------------------------------
+  ctkDicomAppHosting::Status status1;
+  ctkDicomAppHosting::Status status2;
+  CHECK_OP(Status, status1, status2, /*EQUAL_EXPECTED=*/ true);
+
+  status2.codeMeaning = "codeMeaning";
+  CHECK_OP(Status, status1, status2, /*EQUAL_EXPECTED=*/ false);
+
+  status2.codeMeaning = "";
+  CHECK_OP(Status, status1, status2, /*EQUAL_EXPECTED=*/ true);
+
+  status2.codeValue = "codeValue";
+  CHECK_OP(Status, status1, status2, /*EQUAL_EXPECTED=*/ false);
+
+  status2.codeValue = "";
+  CHECK_OP(Status, status1, status2, /*EQUAL_EXPECTED=*/ true);
+
+  status2.codingSchemeDesignator = "codingSchemeDesignator";
+  CHECK_OP(Status, status1, status2, /*EQUAL_EXPECTED=*/ false);
+
+  status2.codingSchemeDesignator = "";
+  CHECK_OP(Status, status1, status2, /*EQUAL_EXPECTED=*/ true);
+
+  status2.statusType = ctkDicomAppHosting::FATALERROR;
+  CHECK_OP(Status, status1, status2, /*EQUAL_EXPECTED=*/ false);
+
+  status2.statusType = ctkDicomAppHosting::INFORMATION;
+  CHECK_OP(Status, status1, status2, /*EQUAL_EXPECTED=*/ true);
+
+  //----------------------------------------------------------------------------
+  ctkDicomAppHosting::ObjectLocator objectLocator1;
+  ctkDicomAppHosting::ObjectLocator objectLocator2;
+  CHECK_OP(ObjectLocator, objectLocator1, objectLocator2, /*EQUAL_EXPECTED=*/ true);
+
+  objectLocator2.length = 64;
+  CHECK_OP(ObjectLocator, objectLocator1, objectLocator2, /*EQUAL_EXPECTED=*/ false);
+
+  objectLocator2.length = 0;
+  CHECK_OP(ObjectLocator, objectLocator1, objectLocator2, /*EQUAL_EXPECTED=*/ true);
+
+  objectLocator2.locator = "locator";
+  CHECK_OP(ObjectLocator, objectLocator1, objectLocator2, /*EQUAL_EXPECTED=*/ false);
+
+  objectLocator2.locator = "";
+  CHECK_OP(ObjectLocator, objectLocator1, objectLocator2, /*EQUAL_EXPECTED=*/ true);
+
+  objectLocator2.offset = 100;
+  CHECK_OP(ObjectLocator, objectLocator1, objectLocator2, /*EQUAL_EXPECTED=*/ false);
+
+  objectLocator2.offset = 0;
+  CHECK_OP(ObjectLocator, objectLocator1, objectLocator2, /*EQUAL_EXPECTED=*/ true);
+
+  objectLocator2.source = "source";
+  CHECK_OP(ObjectLocator, objectLocator1, objectLocator2, /*EQUAL_EXPECTED=*/ false);
+
+  objectLocator2.source = "";
+  CHECK_OP(ObjectLocator, objectLocator1, objectLocator2, /*EQUAL_EXPECTED=*/ true);
+
+  objectLocator2.transferSyntax = "transferSyntax";
+  CHECK_OP(ObjectLocator, objectLocator1, objectLocator2, /*EQUAL_EXPECTED=*/ false);
+
+  objectLocator2.transferSyntax = "";
+  CHECK_OP(ObjectLocator, objectLocator1, objectLocator2, /*EQUAL_EXPECTED=*/ true);
+
+  objectLocator2.URI = "URI";
+  CHECK_OP(ObjectLocator, objectLocator1, objectLocator2, /*EQUAL_EXPECTED=*/ false);
+
+  objectLocator2.URI = "";
+  CHECK_OP(ObjectLocator, objectLocator1, objectLocator2, /*EQUAL_EXPECTED=*/ true);
+  
+  //----------------------------------------------------------------------------
+  ctkDicomAppHosting::ObjectDescriptor objectDescriptor1;
+  ctkDicomAppHosting::ObjectDescriptor objectDescriptor2;
+  CHECK_OP(ObjectDescriptor, objectDescriptor1, objectDescriptor2, /*EQUAL_EXPECTED=*/ true);
+  
+  objectDescriptor2.classUID = "classUID";
+  CHECK_OP(ObjectDescriptor, objectDescriptor1, objectDescriptor2, /*EQUAL_EXPECTED=*/ false);
+
+  objectDescriptor2.classUID = "";
+  CHECK_OP(ObjectDescriptor, objectDescriptor1, objectDescriptor2, /*EQUAL_EXPECTED=*/ true);
+
+  objectDescriptor2.descriptorUUID = "descriptorUUID";
+  CHECK_OP(ObjectDescriptor, objectDescriptor1, objectDescriptor2, /*EQUAL_EXPECTED=*/ false);
+
+  objectDescriptor2.descriptorUUID = "";
+  CHECK_OP(ObjectDescriptor, objectDescriptor1, objectDescriptor2, /*EQUAL_EXPECTED=*/ true);
+
+  objectDescriptor2.mimeType = "mimeType";
+  CHECK_OP(ObjectDescriptor, objectDescriptor1, objectDescriptor2, /*EQUAL_EXPECTED=*/ false);
+
+  objectDescriptor2.mimeType = "";
+  CHECK_OP(ObjectDescriptor, objectDescriptor1, objectDescriptor2, /*EQUAL_EXPECTED=*/ true);
+
+  objectDescriptor2.modality = "modality";
+  CHECK_OP(ObjectDescriptor, objectDescriptor1, objectDescriptor2, /*EQUAL_EXPECTED=*/ false);
+
+  objectDescriptor2.modality = "";
+  CHECK_OP(ObjectDescriptor, objectDescriptor1, objectDescriptor2, /*EQUAL_EXPECTED=*/ true);
+
+  objectDescriptor2.transferSyntaxUID = "transferSyntaxUID";
+  CHECK_OP(ObjectDescriptor, objectDescriptor1, objectDescriptor2, /*EQUAL_EXPECTED=*/ false);
+
+  objectDescriptor2.transferSyntaxUID = "";
+  CHECK_OP(ObjectDescriptor, objectDescriptor1, objectDescriptor2, /*EQUAL_EXPECTED=*/ true);
+
+  //----------------------------------------------------------------------------
+  ctkDicomAppHosting::Series series1;
+  ctkDicomAppHosting::Series series2;
+  CHECK_OP(Series, series1, series2, /*EQUAL_EXPECTED=*/ true);
+
+  series2.seriesUID = "studyUID";
+  CHECK_OP(Series, series1, series2, /*EQUAL_EXPECTED=*/ false);
+
+  series2.seriesUID = "";
+  CHECK_OP(Series, series1, series2, /*EQUAL_EXPECTED=*/ true);
+
+  series2.objectDescriptors << objectDescriptor1 << objectDescriptor2;
+  CHECK_OP(Series, series1, series2, /*EQUAL_EXPECTED=*/ false);
+
+  series1.objectDescriptors << objectDescriptor1 << objectDescriptor2;
+  CHECK_OP(Series, series1, series2, /*EQUAL_EXPECTED=*/ true);
+
+  series1.objectDescriptors.clear();
+  CHECK_OP(Series, series1, series2, /*EQUAL_EXPECTED=*/ false);
+
+  series2.objectDescriptors.clear();
+  CHECK_OP(Series, series1, series2, /*EQUAL_EXPECTED=*/ true);
+
+  //----------------------------------------------------------------------------
+  ctkDicomAppHosting::Study study1;
+  ctkDicomAppHosting::Study study2;
+  CHECK_OP(Study, study1, study2, /*EQUAL_EXPECTED=*/ true);
+
+  study1.series << series1 << series2;
+  CHECK_OP(Study, study1, study2, /*EQUAL_EXPECTED=*/ false);
+
+  study2.series << series1 << series2;
+  CHECK_OP(Study, study1, study2, /*EQUAL_EXPECTED=*/ true);
+
+  study2.studyUID = "studyUID";
+  CHECK_OP(Study, study1, study2, /*EQUAL_EXPECTED=*/ false);
+
+  study2.studyUID = "";
+  CHECK_OP(Study, study1, study2, /*EQUAL_EXPECTED=*/ true);
+
+  study2.objectDescriptors << objectDescriptor1 << objectDescriptor2;
+  CHECK_OP(Study, study1, study2, /*EQUAL_EXPECTED=*/ false);
+
+  study1.objectDescriptors << objectDescriptor1 << objectDescriptor2;
+  CHECK_OP(Study, study1, study2, /*EQUAL_EXPECTED=*/ true);
+
+  study1.objectDescriptors.clear();
+  CHECK_OP(Study, study1, study2, /*EQUAL_EXPECTED=*/ false);
+
+  study2.objectDescriptors.clear();
+  CHECK_OP(Study, study1, study2, /*EQUAL_EXPECTED=*/ true);
+
+  //----------------------------------------------------------------------------
+  ctkDicomAppHosting::Patient patient1;
+  ctkDicomAppHosting::Patient patient2;
+  CHECK_OP(Patient, patient1, patient2, /*EQUAL_EXPECTED=*/ true);
+
+  patient2.assigningAuthority = "assigningAuthority";
+  CHECK_OP(Patient, patient1, patient2, /*EQUAL_EXPECTED=*/ false);
+
+  patient2.assigningAuthority = "";
+  CHECK_OP(Patient, patient1, patient2, /*EQUAL_EXPECTED=*/ true);
+
+  patient2.birthDate = "birthDate";
+  CHECK_OP(Patient, patient1, patient2, /*EQUAL_EXPECTED=*/ false);
+
+  patient2.birthDate = "";
+  CHECK_OP(Patient, patient1, patient2, /*EQUAL_EXPECTED=*/ true);
+
+  patient2.id = "id";
+  CHECK_OP(Patient, patient1, patient2, /*EQUAL_EXPECTED=*/ false);
+
+  patient2.id = "";
+  CHECK_OP(Patient, patient1, patient2, /*EQUAL_EXPECTED=*/ true);
+
+  patient2.name = "name";
+  CHECK_OP(Patient, patient1, patient2, /*EQUAL_EXPECTED=*/ false);
+
+  patient2.name = "";
+  CHECK_OP(Patient, patient1, patient2, /*EQUAL_EXPECTED=*/ true);
+
+  patient2.sex = "sex";
+  CHECK_OP(Patient, patient1, patient2, /*EQUAL_EXPECTED=*/ false);
+
+  patient2.sex = "";
+  CHECK_OP(Patient, patient1, patient2, /*EQUAL_EXPECTED=*/ true);
+
+  //----------------------------------------------------------------------------
+  ctkDicomAppHosting::AvailableData availableData1;
+  ctkDicomAppHosting::AvailableData availableData2;
+  CHECK_OP(AvailableData, availableData1, availableData2, /*EQUAL_EXPECTED=*/ true);
+
+  ctkDicomAppHosting::Patient p1;
+  p1.name = "name";
+  p1.studies << study1 << study2;
+
+  ctkDicomAppHosting::Patient p2;
+  p2.name = "name";
+  p2.studies << study1 << study2;
+  CHECK_OP(Patient, p1, p2, /*EQUAL_EXPECTED=*/ true);
+
+  availableData1.patients << p1 << p2;
+  CHECK_OP(AvailableData, availableData1, availableData2, /*EQUAL_EXPECTED=*/ false);
+
+  availableData2.patients << p1 << p2;
+  CHECK_OP(AvailableData, availableData1, availableData2, /*EQUAL_EXPECTED=*/ true);
+  
+  return EXIT_SUCCESS;
+}

+ 196 - 0
Plugins/org.commontk.dah.core/Testing/Cpp/ctkDicomObjectLocatorCacheTest1.cpp

@@ -0,0 +1,196 @@
+
+// Qt includes
+#include <QUuid>
+
+// CTK includes
+#include <ctkDicomObjectLocatorCache.h>
+
+// STD includes
+#include <cstdlib>
+#include <iostream>
+
+//----------------------------------------------------------------------------
+int ctkDicomObjectLocatorCacheTest1(int argc, char* argv[])
+{
+  Q_UNUSED(argc);
+  Q_UNUSED(argv);
+
+  ctkDicomObjectLocatorCache cache;
+
+  //----------------------------------------------------------------------------
+  if (cache.remove(""))
+    {
+    std::cerr << "Line " << __LINE__ << " - Problem with remove() method" << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  //----------------------------------------------------------------------------
+  QString objectUuid = QUuid::createUuid();
+  ctkDicomAppHosting::ObjectLocator objectLocator;
+  objectLocator.length = 64;
+  objectLocator.source = "/path/to/source";
+
+  ctkDicomAppHosting::ObjectLocator objectLocatorFound;
+  if (cache.find(objectUuid, objectLocatorFound))
+    {
+    std::cerr << "Line " << __LINE__ << " - Problem with find() method" << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  cache.insert(objectUuid, objectLocator);
+
+  //----------------------------------------------------------------------------
+  if (!cache.find(objectUuid, objectLocatorFound))
+    {
+    std::cerr << "Line " << __LINE__ << " - Problem with find() method" << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  if (objectLocator != objectLocatorFound)
+    {
+    std::cerr << "Line " << __LINE__ << " - Problem with find() method"
+              << " - objectLocator != objectLocatorFound" << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  //----------------------------------------------------------------------------
+  if (!cache.remove(objectUuid))
+    {
+    std::cerr << "Line " << __LINE__ << " - Problem with remove() method" << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  //----------------------------------------------------------------------------
+  cache.insert(objectUuid, objectLocator);
+  cache.insert(objectUuid, objectLocator);
+  cache.insert(objectUuid, objectLocator);
+
+  // Since the Reference count associated with the objectLocator is equal to three,
+  // after two successive call of "remove()", the objectLocator should still be in the cache.
+
+  // First call to "remove()"
+  if (!cache.remove(objectUuid))
+    {
+    std::cerr << "Line " << __LINE__ << " - Problem with remove() method" << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  ctkDicomAppHosting::ObjectLocator objectLocatorFound2;
+  if (!cache.find(objectUuid, objectLocatorFound2))
+    {
+    std::cerr << "Line " << __LINE__ << " - Problem with find() method" << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  if (objectLocator != objectLocatorFound2)
+    {
+    std::cerr << "Line " << __LINE__ << " - Problem with find() method"
+              << " - objectLocator != objectLocatorFound" << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  // Second call to "remove()"
+  if (!cache.remove(objectUuid))
+    {
+    std::cerr << "Line " << __LINE__ << " - Problem with remove() method" << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  ctkDicomAppHosting::ObjectLocator objectLocatorFound3;
+  if (!cache.find(objectUuid, objectLocatorFound3))
+    {
+    std::cerr << "Line " << __LINE__ << " - Problem with find() method" << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  if (objectLocator != objectLocatorFound3)
+    {
+    std::cerr << "Line " << __LINE__ << " - Problem with find() method"
+              << " - objectLocator != objectLocatorFound" << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  // Third call to "remove()"
+  if (!cache.remove(objectUuid))
+    {
+    std::cerr << "Line " << __LINE__ << " - Problem with remove() method" << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  ctkDicomAppHosting::ObjectLocator objectLocatorFound4;
+  if (cache.find(objectUuid, objectLocatorFound4))
+    {
+    std::cerr << "Line " << __LINE__ << " - Problem with find() method" << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  // Fourth call to "remove()"
+  if (cache.remove(objectUuid))
+    {
+    std::cerr << "Line " << __LINE__ << " - Problem with remove() method" << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  //----------------------------------------------------------------------------
+
+  ctkDicomAppHosting::AvailableData availableData;
+
+  if (cache.isCached(availableData))
+    {
+    std::cerr << "Line " << __LINE__ << " - Problem with isCached() method" << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  ctkDicomAppHosting::Patient patient;
+  availableData.patients << patient;
+
+  if (cache.isCached(availableData))
+    {
+    std::cerr << "Line " << __LINE__ << " - Problem with isCached() method" << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  ctkDicomAppHosting::ObjectDescriptor objectDescriptor;
+  objectDescriptor.descriptorUUID = objectUuid;
+
+  availableData.objectDescriptors << objectDescriptor;
+
+  if (cache.isCached(availableData))
+    {
+    std::cerr << "Line " << __LINE__ << " - Problem with isCached() method" << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  cache.insert(objectUuid, objectLocator);
+
+  if (!cache.isCached(availableData))
+    {
+    std::cerr << "Line " << __LINE__ << " - Problem with isCached() method" << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  QString objectUuid2 = QUuid::createUuid();
+  ctkDicomAppHosting::ObjectDescriptor objectDescriptor2;
+  objectDescriptor2.descriptorUUID = objectUuid2;
+  ctkDicomAppHosting::ObjectLocator objectLocator2;
+  objectLocator2.length = 50;
+  objectLocator2.source = "/path/to/source2";
+
+  availableData.objectDescriptors << objectDescriptor2;
+
+  if (cache.isCached(availableData))
+    {
+    std::cerr << "Line " << __LINE__ << " - Problem with isCached() method" << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  cache.insert(objectUuid2, objectLocator2);
+
+  if (!cache.isCached(availableData))
+    {
+    std::cerr << "Line " << __LINE__ << " - Problem with isCached() method" << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  return EXIT_SUCCESS;
+}

+ 66 - 7
Plugins/org.commontk.dah.core/ctkDicomAppHostingTypes.h

@@ -19,25 +19,29 @@
 
 =============================================================================*/
 
-#include <QString>
-#include <QList>
-
 #ifndef CTKDICOMAPPHOSTINGTYPES_H
 #define CTKDICOMAPPHOSTINGTYPES_H
 
+// Qt includes
+#include <QString>
+#include <QList>
+
 #ifdef ERROR
-#error Try to reorder include files (this one first)\
- or write #undef ERROR before including this header.\
- Cause of this problem may be dcmimage.h, which indirectly\
+# error Try to reorder include files (this one first)       \
+ or write #undef ERROR before including this header.        \
+ Cause of this problem may be dcmimage.h, which indirectly  \
  includes windows.h.
 #endif
 
+#include <org_commontk_dah_core_Export.h>
+
 /**
   * \brief Typedefs and classes defined in the interfaces of DICOM Supplement 118.
   *
   */
 namespace ctkDicomAppHosting {
 
+  //----------------------------------------------------------------------------
   enum State {
     IDLE,
     INPROGRESS,
@@ -47,6 +51,7 @@ namespace ctkDicomAppHosting {
     EXIT
   };
 
+  //----------------------------------------------------------------------------
   enum StatusType {
     INFORMATION,
     WARNING,
@@ -54,14 +59,18 @@ namespace ctkDicomAppHosting {
     FATALERROR
   };
 
+  //----------------------------------------------------------------------------
   struct Status {
+    Status():statusType(INFORMATION){}
     StatusType statusType;
     QString codingSchemeDesignator;
     QString codeValue;
     QString codeMeaning;
   };
 
+  //----------------------------------------------------------------------------
   struct ObjectLocator {
+    ObjectLocator():length(0), offset(0){}
     QString locator;
     QString source;
     QString transferSyntax;
@@ -70,6 +79,7 @@ namespace ctkDicomAppHosting {
     QString URI;
   };
 
+  //----------------------------------------------------------------------------
   struct ObjectDescriptor {
     QString descriptorUUID;
     QString mimeType;
@@ -78,19 +88,23 @@ namespace ctkDicomAppHosting {
     QString modality;
   };
 
+  //----------------------------------------------------------------------------
   typedef QList<ObjectDescriptor> ArrayOfObjectDescriptors;
 
+  //----------------------------------------------------------------------------
   struct Series {
     QString seriesUID;
     ArrayOfObjectDescriptors objectDescriptors;
   };
 
+  //----------------------------------------------------------------------------
   struct Study {
     QString studyUID;
     ArrayOfObjectDescriptors objectDescriptors;
     QList<Series> series;
   };
 
+  //----------------------------------------------------------------------------
   struct Patient {
     QString name;
     QString id;
@@ -101,11 +115,56 @@ namespace ctkDicomAppHosting {
     QList<Study> studies;
   };
 
+  //----------------------------------------------------------------------------
   struct AvailableData {
     ArrayOfObjectDescriptors objectDescriptors;
     QList<Patient> patients;
   };
-
 }
 
+//----------------------------------------------------------------------------
+// Comparison operators
+
+bool org_commontk_dah_core_EXPORT operator ==(const ctkDicomAppHosting::Status& left,
+                                              const ctkDicomAppHosting::Status& right);
+
+bool org_commontk_dah_core_EXPORT operator !=(const ctkDicomAppHosting::Status& left,
+                                              const ctkDicomAppHosting::Status& right);
+
+bool org_commontk_dah_core_EXPORT operator ==(const ctkDicomAppHosting::ObjectLocator& left,
+                                              const ctkDicomAppHosting::ObjectLocator& right);
+
+bool org_commontk_dah_core_EXPORT operator !=(const ctkDicomAppHosting::ObjectLocator& left,
+                                              const ctkDicomAppHosting::ObjectLocator& right);
+
+bool org_commontk_dah_core_EXPORT operator ==(const ctkDicomAppHosting::ObjectDescriptor& left,
+                                              const ctkDicomAppHosting::ObjectDescriptor& right);
+
+bool org_commontk_dah_core_EXPORT operator !=(const ctkDicomAppHosting::ObjectDescriptor& left,
+                                              const ctkDicomAppHosting::ObjectDescriptor& right);
+
+bool org_commontk_dah_core_EXPORT operator ==(const ctkDicomAppHosting::Series& left,
+                                              const ctkDicomAppHosting::Series& right);
+
+bool org_commontk_dah_core_EXPORT operator !=(const ctkDicomAppHosting::Series& left,
+                                              const ctkDicomAppHosting::Series& right);
+
+bool org_commontk_dah_core_EXPORT operator ==(const ctkDicomAppHosting::Study& left,
+                                              const ctkDicomAppHosting::Study& right);
+
+bool org_commontk_dah_core_EXPORT operator !=(const ctkDicomAppHosting::Study& left,
+                                              const ctkDicomAppHosting::Study& right);
+
+bool org_commontk_dah_core_EXPORT operator ==(const ctkDicomAppHosting::Patient& left,
+                                              const ctkDicomAppHosting::Patient& right);
+
+bool org_commontk_dah_core_EXPORT operator !=(const ctkDicomAppHosting::Patient& left,
+                                              const ctkDicomAppHosting::Patient& right);
+
+bool org_commontk_dah_core_EXPORT operator ==(const ctkDicomAppHosting::AvailableData& left,
+                                              const ctkDicomAppHosting::AvailableData& right);
+
+bool org_commontk_dah_core_EXPORT operator !=(const ctkDicomAppHosting::AvailableData& left,
+                                              const ctkDicomAppHosting::AvailableData& right);
+
 #endif // CTKDICOMAPPHOSTINGTYPES

+ 78 - 20
Plugins/org.commontk.dah.core/ctkDicomObjectLocatorCache.cpp

@@ -21,17 +21,32 @@
 // Qt includes
 #include <QHash>
 #include <QUuid>
+#include <QSet>
+#include <QDebug>
 
 // CTK includes
 #include "ctkDicomAppHostingTypes.h"
 #include "ctkDicomObjectLocatorCache.h"
 
+namespace
+{
+struct ObjectLocatorCacheItem
+{
+  ObjectLocatorCacheItem():RefCount(1){}
+  ctkDicomAppHosting::ObjectLocator ObjectLocator;
+  int RefCount;
+};
+}
+
 class ctkDicomObjectLocatorCachePrivate
 {
 public:
   ctkDicomObjectLocatorCachePrivate();
 
-  QHash<QString, ctkDicomAppHosting::ObjectLocator> ObjectLocatorMap;
+  bool find(const QString& objectUuid, ObjectLocatorCacheItem& objectLocatorCacheItem)const;
+
+  QHash<QString, ObjectLocatorCacheItem> ObjectLocatorMap;
+  QSet<QString> TemporaryObjectLocatorSet;
 };
 
 //----------------------------------------------------------------------------
@@ -43,6 +58,18 @@ ctkDicomObjectLocatorCachePrivate::ctkDicomObjectLocatorCachePrivate()
 }
 
 //----------------------------------------------------------------------------
+bool ctkDicomObjectLocatorCachePrivate::find(const QString& objectUuid,
+                                             ObjectLocatorCacheItem& objectLocatorCacheItem)const
+{
+  if (!this->ObjectLocatorMap.contains(objectUuid))
+    {
+    return false;
+    }
+  objectLocatorCacheItem = this->ObjectLocatorMap[objectUuid];
+  return true;
+}
+
+//----------------------------------------------------------------------------
 // ctkDicomObjectLocatorCache methods
 
 //----------------------------------------------------------------------------
@@ -59,10 +86,12 @@ ctkDicomObjectLocatorCache::~ctkDicomObjectLocatorCache()
 bool ctkDicomObjectLocatorCache::isCached(const ctkDicomAppHosting::AvailableData& availableData)const
 {
   Q_D(const ctkDicomObjectLocatorCache);
+  bool hasCachedData = false;
   QList<QString> uuids = d->ObjectLocatorMap.keys();
   // Loop over top level object descriptors
   foreach(const ctkDicomAppHosting::ObjectDescriptor& objectDescriptor, availableData.objectDescriptors)
     {
+    if (!hasCachedData) { hasCachedData = true; }
     if (!uuids.contains(objectDescriptor.descriptorUUID))
       {
       return false;
@@ -74,6 +103,7 @@ bool ctkDicomObjectLocatorCache::isCached(const ctkDicomAppHosting::AvailableDat
     // Loop over patient level object descriptors
     foreach(const ctkDicomAppHosting::ObjectDescriptor& objectDescriptor, patient.objectDescriptors)
       {
+      if (!hasCachedData) { hasCachedData = true; }
       if (!uuids.contains(objectDescriptor.descriptorUUID))
         {
         return false;
@@ -104,47 +134,80 @@ bool ctkDicomObjectLocatorCache::isCached(const ctkDicomAppHosting::AvailableDat
         }
       }
     }
+  return hasCachedData;
 }
 
 //----------------------------------------------------------------------------
 bool ctkDicomObjectLocatorCache::find(const QString& objectUuid,
-                                         ctkDicomAppHosting::ObjectLocator& objectLocator)const
+                                      ctkDicomAppHosting::ObjectLocator& objectLocator)const
 {
   Q_D(const ctkDicomObjectLocatorCache);
-  if (!d->ObjectLocatorMap.contains(objectUuid))
+
+  ObjectLocatorCacheItem item;
+  bool found = d->find(objectUuid, item);
+  if (!found)
     {
     return false;
     }
-  objectLocator = d->ObjectLocatorMap.value(objectUuid);
+  objectLocator = item.ObjectLocator;
   return true;
 }
 
 //----------------------------------------------------------------------------
 void ctkDicomObjectLocatorCache::insert(const QString& objectUuid,
-                                        const ctkDicomAppHosting::ObjectLocator& objectLocator)
+                                        const ctkDicomAppHosting::ObjectLocator& objectLocator,
+                                        bool temporary)
 {
   Q_D(ctkDicomObjectLocatorCache);
+  ObjectLocatorCacheItem item;
+  d->find(objectUuid, item);
   if(d->ObjectLocatorMap.contains(objectUuid))
     {
+    Q_ASSERT(objectLocator == item.ObjectLocator); // ObjectLocator are expected to match
+    item.RefCount++;
+    d->ObjectLocatorMap.insert(objectUuid, item);
     return;
     }
-  d->ObjectLocatorMap.insert(objectUuid, objectLocator);
+  item.ObjectLocator = objectLocator;
+  d->ObjectLocatorMap.insert(objectUuid, item);
+
+  if (temporary)
+    {
+    d->TemporaryObjectLocatorSet.insert(objectUuid);
+    }
 }
 
 //----------------------------------------------------------------------------
 bool ctkDicomObjectLocatorCache::remove(const QString& objectUuid)
 {
   Q_D(ctkDicomObjectLocatorCache);
-  int removed = d->ObjectLocatorMap.remove(objectUuid);
-  Q_ASSERT(removed > 1);
-  return (removed == 1);
+  ObjectLocatorCacheItem item;
+  bool found = d->find(objectUuid, item);
+  if (!found)
+    {
+    return false;
+    }
+  Q_ASSERT(item.RefCount > 0);
+  item.RefCount--;
+  d->ObjectLocatorMap.insert(objectUuid, item);
+  if (item.RefCount == 0)
+    {
+    if (d->TemporaryObjectLocatorSet.contains(objectUuid))
+      {
+      // Not implemented - Delete the object
+      qDebug() << "ctkDicomObjectLocatorCache::remove - RefCount [1] - Temporary [True] - Not implemented";
+
+      bool removed = d->TemporaryObjectLocatorSet.remove(objectUuid);
+      Q_ASSERT(removed);
+      }
+    int removed = d->ObjectLocatorMap.remove(objectUuid);
+    Q_ASSERT(removed == 1);
+    }
+  return true;
 }
 
 //----------------------------------------------------------------------------
-QList<ctkDicomAppHosting::ObjectLocator> ctkDicomObjectLocatorCache::getData(
-  const QList<QUuid>& objectUUIDs,
-  const QList<QString>& acceptableTransferSyntaxUIDs,
-  bool includeBulkData)
+QList<ctkDicomAppHosting::ObjectLocator> ctkDicomObjectLocatorCache::getData(const QList<QUuid>& objectUUIDs)
 {
   QList<ctkDicomAppHosting::ObjectLocator> objectLocators;
   foreach(const QUuid& uuid, objectUUIDs)
@@ -153,13 +216,8 @@ QList<ctkDicomAppHosting::ObjectLocator> ctkDicomObjectLocatorCache::getData(
     bool found = this->find(uuid, objectLocator);
     if (!found)
       {
-      // What to do .. ? Create an empty objectLocator ...
-      continue;
-      }
-    if (includeBulkData)
-      {
-      Q_UNUSED(acceptableTransferSyntaxUIDs);
-      // Not implemented
+      // Use the empty objectLocator
+      // TODO Source should be set to NULL
       }
     objectLocators << objectLocator;
     }

+ 3 - 5
Plugins/org.commontk.dah.core/ctkDicomObjectLocatorCache.h

@@ -46,14 +46,12 @@ public:
 
   bool find(const QString& objectUuid, ctkDicomAppHosting::ObjectLocator& objectLocator)const;
 
-  void insert(const QString& objectUuid, const ctkDicomAppHosting::ObjectLocator& objectLocator);
+  void insert(
+    const QString& objectUuid, const ctkDicomAppHosting::ObjectLocator& objectLocator, bool temporary = false);
 
   bool remove(const QString& objectUuid);
 
-  QList<ctkDicomAppHosting::ObjectLocator> getData(
-    const QList<QUuid>& objectUUIDs,
-    const QList<QString>& acceptableTransferSyntaxUIDs,
-    bool includeBulkData);
+  QList<ctkDicomAppHosting::ObjectLocator> getData(const QList<QUuid>& objectUUIDs);
 
 private:
   Q_DECLARE_PRIVATE(ctkDicomObjectLocatorCache)

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

@@ -117,7 +117,9 @@ QList<ctkDicomAppHosting::ObjectLocator> ctkDicomAbstractHost::getData(
   const QList<QString>& acceptableTransferSyntaxUIDs,
   bool includeBulkData)
 {
-  return this->objectLocatorCache()->getData(objectUUIDs, acceptableTransferSyntaxUIDs, includeBulkData);
+  Q_UNUSED(acceptableTransferSyntaxUIDs);
+  Q_UNUSED(includeBulkData);
+  return this->objectLocatorCache()->getData(objectUUIDs);
 }
 
 //----------------------------------------------------------------------------