Browse Source

Merge branch '221-instanceAdded-signal'

* 221-instanceAdded-signal:
  Add summary dialog summarizing the imported directory information
Steve Pieper 12 years ago
parent
commit
1bf3f83444

+ 12 - 0
Libs/DICOM/Core/ctkDICOMDatabase.cpp

@@ -1228,6 +1228,9 @@ void ctkDICOMDatabasePrivate::insert( const ctkDICOMDataset& ctkDataset, const Q
 
           dbPatientID = insertPatient( ctkDataset );
 
+          // let users of this class track when things happen
+          emit q->patientAdded(dbPatientID, patientID, patientsName, patientsBirthDate);
+
           /// keep this for the next image
           LastPatientUID = dbPatientID;
           LastPatientID = patientID;
@@ -1242,11 +1245,17 @@ void ctkDICOMDatabasePrivate::insert( const ctkDICOMDataset& ctkDataset, const Q
       if ( studyInstanceUID != "" && LastStudyInstanceUID != studyInstanceUID )
         {
           insertStudy(ctkDataset,dbPatientID);
+
+          // let users of this class track when things happen
+          emit q->studyAdded(studyInstanceUID);
         }
 
       if ( seriesInstanceUID != "" && seriesInstanceUID != LastSeriesInstanceUID )
         {
           insertSeries(ctkDataset, studyInstanceUID);
+
+          // let users of this class track when things happen
+          emit q->seriesAdded(seriesInstanceUID);
         }
       // TODO: what to do with imported files
       //
@@ -1268,6 +1277,9 @@ void ctkDICOMDatabasePrivate::insert( const ctkDICOMDataset& ctkDataset, const Q
 
               // insert was needed, so cache any application-requested tags
               this->precacheTags(sopInstanceUID);
+
+              // let users of this class track when things happen
+              emit q->instanceAdded(sopInstanceUID);
             }
         }
 

+ 18 - 0
Libs/DICOM/Core/ctkDICOMDatabase.h

@@ -233,6 +233,24 @@ public:
 
 
 Q_SIGNALS:
+  /// Things inserted to database.
+  /// patientAdded arguments:
+  ///  - int: database index of patient (unique) within CTK database
+  ///  - QString: patient ID (not unique across institutions)
+  ///  - QString: patient Name (not unique)
+  ///  - QString: patient Birth Date (not unique)
+  void patientAdded(int, QString, QString, QString);
+  /// studyAdded arguments:
+  ///  - studyUID (unique)
+  void studyAdded(QString);
+  /// seriesAdded arguments:
+  ///  - seriesUID (unique)
+  void seriesAdded(QString);
+  /// instance UID is provided
+  /// instanceAdded arguments:
+  ///  - instanceUID (unique)
+  void instanceAdded(QString);
+  /// Indicates that an in-memory database has been updated
   void databaseChanged();
   /// Indicates that the schema is about to be updated and how many files will be processed
   void schemaUpdateStarted(int);

+ 1 - 1
Libs/DICOM/Widgets/Testing/Cpp/CMakeLists.txt

@@ -26,7 +26,7 @@ target_link_libraries(${KIT}CppTests ${LIBRARY_NAME})
 # Add Tests
 #
 
-SIMPLE_TEST(ctkDICOMAppWidgetTest1)
+SIMPLE_TEST(ctkDICOMAppWidgetTest1 ${CTKData_DIR}/Data/DICOM/MRHEAD)
 SIMPLE_TEST(ctkDICOMDatasetViewTest1 ${CTKData_DIR}/Data/DICOM/MRHEAD/000055.IMA)
 SIMPLE_TEST(ctkDICOMDirectoryListWidgetTest1)
 SIMPLE_TEST(ctkDICOMImageTest1 ${CTKData_DIR}/Data/DICOM/MRHEAD/000055.IMA)

+ 36 - 4
Libs/DICOM/Widgets/Testing/Cpp/ctkDICOMAppWidgetTest1.cpp

@@ -22,9 +22,13 @@
 #include <QApplication>
 #include <QDebug>
 #include <QDir>
+#include <QKeyEvent>
 #include <QTimer>
 #include <QString>
 
+// ctk includes
+#include "ctkUtils.h"
+
 // ctkDICOMCore includes
 #include "ctkDICOMAppWidget.h"
 
@@ -32,7 +36,9 @@
 #include <iostream>
 
 /* Test from build directory:
- ./CTK-build/bin/CTKDICOMWidgetsCxxTests ctkDICOMAppWidgetTest1 test.db ../CTK/Libs/DICOM/Core/Resources/dicom-sample.sql
+ ./CTK-build/bin/CTKDICOMWidgetsCppTests ctkDICOMAppWidgetTest1 <test directory>
+
+ if the test directory does not have 100 instances in one patient/study/series, test will fail
 */
 
 int ctkDICOMAppWidgetTest1( int argc, char * argv [] )
@@ -40,18 +46,44 @@ int ctkDICOMAppWidgetTest1( int argc, char * argv [] )
   QApplication app(argc, argv);
   
   ctkDICOMAppWidget appWidget;
-  appWidget.setDatabaseDirectory(QDir::currentPath());
+
+  QFileInfo tempFileInfo(QDir::tempPath() + QString("/ctkDICOMAppWidgetTest1-db"));
+  QString dbDir = tempFileInfo.absoluteFilePath();
+  std::cerr << "\n\nUsing directory: " << dbDir.toLatin1().data() << std::endl;
+  if (tempFileInfo.exists())
+    {
+    std::cerr << "\n\nRemoving directory: " << dbDir.toLatin1().data() << std::endl;
+    ctk::removeDirRecursively(dbDir);
+    }
+  std::cerr << "\n\nMaking directory: " << dbDir.toLatin1().data() << std::endl;
+  QDir dir(dbDir);
+  dir.mkdir(dbDir);
+
+  appWidget.setDatabaseDirectory(dbDir);
   QString testString = QString("Test String");
   appWidget.onFileIndexed(testString);
   appWidget.openImportDialog();
   appWidget.openExportDialog();
   appWidget.openQueryDialog();
+
+  appWidget.openQueryDialog();
   
-  appWidget.show();
+  appWidget.setDisplayImportSummary(false);
+  appWidget.onImportDirectory(argv[argc -1]);
+  if ( appWidget.patientsAddedDuringImport() != 1
+    || appWidget.studiesAddedDuringImport() != 1
+    || appWidget.seriesAddedDuringImport() != 1
+    || appWidget.instancesAddedDuringImport() != 100)
+    {
+    std::cerr << "\n\nDirectory did not import as expected!\n\n";
+    exit(-1);
+    }
+
 
-  if (argc <= 1 || QString(argv[1]) != "-I")
+  if (argc <= 2 || QString(argv[1]) != "-I")
     {
     QTimer::singleShot(200, &app, SLOT(quit()));
     }
+  std::cerr << "\n\nAdded to database directory: " << dbDir.toLatin1().data() << std::endl;
   return app.exec();
 }

+ 124 - 0
Libs/DICOM/Widgets/ctkDICOMAppWidget.cpp

@@ -28,6 +28,7 @@
 #include <QCoreApplication>
 #include <QCheckBox>
 #include <QDebug>
+#include <QMessageBox>
 #include <QMetaType>
 #include <QModelIndex>
 #include <QPersistentModelIndex>
@@ -94,6 +95,14 @@ public:
   QTimer* AutoPlayTimer;
 
   bool IsSearchWidgetPopUpMode;
+
+  // local count variables to keep track of the number of items
+  // added to the database during an import operation
+  bool DisplayImportSummary;
+  int PatientsAddedDuringImport;
+  int StudiesAddedDuringImport;
+  int SeriesAddedDuringImport;
+  int InstancesAddedDuringImport;
 };
 
 //----------------------------------------------------------------------------
@@ -106,6 +115,11 @@ ctkDICOMAppWidgetPrivate::ctkDICOMAppWidgetPrivate(ctkDICOMAppWidget* parent): q
   DICOMIndexer = QSharedPointer<ctkDICOMIndexer> (new ctkDICOMIndexer);
   IndexerProgress = 0;
   UpdateSchemaProgress = 0;
+  DisplayImportSummary = true;
+  PatientsAddedDuringImport = 0;
+  StudiesAddedDuringImport = 0;
+  SeriesAddedDuringImport = 0;
+  InstancesAddedDuringImport = 0;
 }
 
 ctkDICOMAppWidgetPrivate::~ctkDICOMAppWidgetPrivate()
@@ -243,6 +257,14 @@ ctkDICOMAppWidget::ctkDICOMAppWidget(QWidget* _parent):Superclass(_parent),
   d->ThumbnailsWidget->setThumbnailSize(
     QSize(d->ThumbnailWidthSlider->value(), d->ThumbnailWidthSlider->value()));
 
+  // signals related to tracking inserts
+  connect(d->DICOMDatabase.data(), SIGNAL(patientAdded(int,QString,QString,QString)), this,
+                              SLOT(onPatientAdded(int,QString,QString,QString)));
+  connect(d->DICOMDatabase.data(), SIGNAL(studyAdded(QString)), this, SLOT(onStudyAdded(QString)));
+  connect(d->DICOMDatabase.data(), SIGNAL(seriesAdded(QString)), this, SLOT(onSeriesAdded(QString)));
+  connect(d->DICOMDatabase.data(), SIGNAL(instanceAdded(QString)), this, SLOT(onInstanceAdded(QString)));
+
+  // Treeview signals
   connect(d->TreeView, SIGNAL(collapsed(QModelIndex)), this, SLOT(onTreeCollapsed(QModelIndex)));
   connect(d->TreeView, SIGNAL(expanded(QModelIndex)), this, SLOT(onTreeExpanded(QModelIndex)));
 
@@ -307,6 +329,54 @@ ctkDICOMAppWidget::~ctkDICOMAppWidget()
 }
 
 //----------------------------------------------------------------------------
+bool ctkDICOMAppWidget::displayImportSummary()
+{
+  Q_D(ctkDICOMAppWidget);
+
+  return d->DisplayImportSummary;
+}
+
+//----------------------------------------------------------------------------
+void ctkDICOMAppWidget::setDisplayImportSummary(bool onOff)
+{
+  Q_D(ctkDICOMAppWidget);
+
+  d->DisplayImportSummary = onOff;
+}
+
+//----------------------------------------------------------------------------
+int ctkDICOMAppWidget::patientsAddedDuringImport()
+{
+  Q_D(ctkDICOMAppWidget);
+
+  return d->PatientsAddedDuringImport;
+}
+
+//----------------------------------------------------------------------------
+int ctkDICOMAppWidget::studiesAddedDuringImport()
+{
+  Q_D(ctkDICOMAppWidget);
+
+  return d->StudiesAddedDuringImport;
+}
+
+//----------------------------------------------------------------------------
+int ctkDICOMAppWidget::seriesAddedDuringImport()
+{
+  Q_D(ctkDICOMAppWidget);
+
+  return d->SeriesAddedDuringImport;
+}
+
+//----------------------------------------------------------------------------
+int ctkDICOMAppWidget::instancesAddedDuringImport()
+{
+  Q_D(ctkDICOMAppWidget);
+
+  return d->InstancesAddedDuringImport;
+}
+
+//----------------------------------------------------------------------------
 void ctkDICOMAppWidget::updateDatabaseSchemaIfNeeded()
 {
 
@@ -557,6 +627,41 @@ void ctkDICOMAppWidget::onThumbnailDoubleClicked(const ctkThumbnailLabel& widget
 }
 
 //----------------------------------------------------------------------------
+void ctkDICOMAppWidget::onPatientAdded(int databaseID, QString patientID, QString patientName, QString patientBirthDate )
+{
+  Q_D(ctkDICOMAppWidget);
+  Q_UNUSED(databaseID);
+  Q_UNUSED(patientID);
+  Q_UNUSED(patientName);
+  Q_UNUSED(patientBirthDate);
+  ++d->PatientsAddedDuringImport;
+}
+
+//----------------------------------------------------------------------------
+void ctkDICOMAppWidget::onStudyAdded(QString studyUID)
+{
+  Q_D(ctkDICOMAppWidget);
+  Q_UNUSED(studyUID);
+  ++d->StudiesAddedDuringImport;
+}
+
+//----------------------------------------------------------------------------
+void ctkDICOMAppWidget::onSeriesAdded(QString seriesUID)
+{
+  Q_D(ctkDICOMAppWidget);
+  Q_UNUSED(seriesUID);
+  ++d->SeriesAddedDuringImport;
+}
+
+//----------------------------------------------------------------------------
+void ctkDICOMAppWidget::onInstanceAdded(QString instanceUID)
+{
+  Q_D(ctkDICOMAppWidget);
+  Q_UNUSED(instanceUID);
+  ++d->InstancesAddedDuringImport;
+}
+
+//----------------------------------------------------------------------------
 void ctkDICOMAppWidget::onImportDirectory(QString directory)
 {
   Q_D(ctkDICOMAppWidget);
@@ -568,8 +673,27 @@ void ctkDICOMAppWidget::onImportDirectory(QString directory)
       {
       targetDirectory = d->DICOMDatabase->databaseDirectory();
       }
+
+    // reset counts
+    d->PatientsAddedDuringImport = 0;
+    d->StudiesAddedDuringImport = 0;
+    d->SeriesAddedDuringImport = 0;
+    d->InstancesAddedDuringImport = 0;
+
+    // show progress dialog and perform indexing
     d->showIndexerDialog();
     d->DICOMIndexer->addDirectory(*d->DICOMDatabase,directory,targetDirectory);
+
+    // display summary result
+    if (d->DisplayImportSummary)
+      {
+      QString message = "Directory import completed.\n\n";
+      message += QString("%1 New Patients\n").arg(QString::number(d->PatientsAddedDuringImport));
+      message += QString("%1 New Studies\n").arg(QString::number(d->StudiesAddedDuringImport));
+      message += QString("%1 New Series\n").arg(QString::number(d->SeriesAddedDuringImport));
+      message += QString("%1 New Instances\n").arg(QString::number(d->InstancesAddedDuringImport));
+      QMessageBox::information(this,"DICOM Directory Import", message);
+      }
   }
 }
 

+ 24 - 1
Libs/DICOM/Widgets/ctkDICOMAppWidget.h

@@ -39,6 +39,7 @@ class CTK_DICOM_WIDGETS_EXPORT ctkDICOMAppWidget : public QWidget
   Q_PROPERTY(QString databaseDirectory READ databaseDirectory WRITE setDatabaseDirectory)
   Q_PROPERTY(bool searchWidgetPopUpMode READ searchWidgetPopUpMode WRITE setSearchWidgetPopUpMode)
   Q_PROPERTY(QStringList tagsToPrecache READ tagsToPrecache WRITE setTagsToPrecache)
+  Q_PROPERTY(bool displayImportSummary READ displayImportSummary WRITE setDisplayImportSummary)
 
 public:
   typedef QWidget Superclass;
@@ -67,6 +68,17 @@ public:
   bool searchWidgetPopUpMode();
   ctkDICOMDatabase* database();
 
+  /// Option to show or not import summary dialog.
+  /// Since the summary dialog is modal, we give the option
+  /// of disabling it for batch modes or testing.
+  void setDisplayImportSummary(bool);
+  bool displayImportSummary();
+  /// Accessors to status of last directory import operation
+  int patientsAddedDuringImport();
+  int studiesAddedDuringImport();
+  int seriesAddedDuringImport();
+  int instancesAddedDuringImport();
+
 public Q_SLOTS:
   void setDatabaseDirectory(const QString& directory);
   void onFileIndexed(const QString& filePath);
@@ -80,6 +92,18 @@ public Q_SLOTS:
   void resumeModel();
   void resetModel();
 
+  /// Import a directory - this is used when the user selects a directory
+  /// from the Import Dialog, but can also be used externally to trigger
+  /// an import (i.e. for testing or to support drag-and-drop)
+  void onImportDirectory(QString directory);
+
+  /// slots to capture status updates from the database during an 
+  /// import operation
+  void onPatientAdded(int, QString, QString, QString);
+  void onStudyAdded(QString);
+  void onSeriesAdded(QString);
+  void onInstanceAdded(QString);
+
 Q_SIGNALS:
   /// Emited when directory is changed
   void databaseDirectoryChanged(const QString&);
@@ -91,7 +115,6 @@ Q_SIGNALS:
 protected:
     QScopedPointer<ctkDICOMAppWidgetPrivate> d_ptr;
 protected Q_SLOTS:
-    void onImportDirectory(QString directory);
     void onModelSelected(const QModelIndex& index);
 
     /// To be called when a thumbnail in thumbnail list widget is selected