瀏覽代碼

ENH: ctkDICOMBrowser: Improve import of multiple directories

* Adds comboxBox "Import Directory Mode" at the bottom of the import dialog
  with options: "Copy" and "Add Link".
  Associated settings is "DICOM/ImportDirectoryMode"

* Adds checkbox "Confirm Import Directory" at the bottom of the import dialog. It
  indicates if the import confirmation dialog should be displayed.
  Associated settings is "DICOM/DontConfirmImportDirectory"

* Only display import stats once

* Functions "onImportDirectories" and "onImportDirectory" now accept
  two optionals parameter:

  - mode: parameter of type ImportDirectoryMode indicating how files should be imported (default sets to "ImportDirectoryAddLink")
  - confirm: parameter of type bool indicating if import confirmation dialog should be displayed (default sets to "true")
Jean-Christophe Fillion-Robin 7 年之前
父節點
當前提交
2833bd742a

+ 4 - 3
Libs/DICOM/Widgets/Testing/Cpp/ctkDICOMBrowserTest1.cpp

@@ -69,7 +69,10 @@ int ctkDICOMBrowserTest1( int argc, char * argv [] )
   // make sure copy/link dialog doesn't pop up, always copy on import
   QSettings settings;
   QString settingsString = settings.value("MainWindow/DontConfirmCopyOnImport").toString();
-  settings.setValue("MainWindow/DontConfirmCopyOnImport", QString("0"));
+  settings.setValue("MainWindow/DontConfirmCopyOnImport", QString("0")); // QMessageBox::AcceptRole
+
+  CHECK_INT(browser.importDirectoryMode(), static_cast<int>(ctkDICOMBrowser::ImportDirectoryCopy));
+  CHECK_BOOL(browser.skipConfirmImportDirectory(), true);
 
   browser.onImportDirectories(QStringList() << argv[1]);
 
@@ -88,7 +91,5 @@ int ctkDICOMBrowserTest1( int argc, char * argv [] )
     QTimer::singleShot(200, &app, SLOT(quit()));
     }
 
-
-
   return app.exec();
 }

+ 214 - 46
Libs/DICOM/Widgets/ctkDICOMBrowser.cpp

@@ -26,12 +26,16 @@
 #include <QApplication>
 #include <QCoreApplication>
 #include <QCheckBox>
+#include <QComboBox>
 #include <QDebug>
+#include <QDialogButtonBox>
 #include <QFile>
+#include <QFormLayout>
 #include <QListView>
 #include <QMenu>
 #include <QMessageBox>
 #include <QProgressDialog>
+#include <QPushButton>
 #include <QSettings>
 #include <QStringListModel>
 #include <QWidgetAction>
@@ -68,7 +72,18 @@ public:
   ctkDICOMBrowserPrivate(ctkDICOMBrowser* );
   ~ctkDICOMBrowserPrivate();
 
+  /// \brief Popup dialog asking user to confirm the directory import.
+  ///
+  /// If user check the "do not show again" checkbox, its choice is saved
+  /// in the settings using the key `DICOM/DontConfirmImportDirectory`.
+  bool confirmDirectoryImport();
+
+  void importDirectory(QString directory, ctkDICOMBrowser::ImportDirectoryMode mode);
+
+  void importOldSettings();
+
   ctkFileDialog* ImportDialog;
+
   ctkDICOMQueryRetrieveWidget* QueryRetrieveWidget;
 
   QSharedPointer<ctkDICOMDatabase> DICOMDatabase;
@@ -93,9 +108,42 @@ public:
 };
 
 //----------------------------------------------------------------------------
+class ctkDICOMImportStats
+{
+public:
+  ctkDICOMImportStats(ctkDICOMBrowserPrivate* dicomBrowserPrivate) :
+    DICOMBrowserPrivate(dicomBrowserPrivate)
+  {
+    // reset counts
+    ctkDICOMBrowserPrivate* d = this->DICOMBrowserPrivate;
+    d->PatientsAddedDuringImport = 0;
+    d->StudiesAddedDuringImport = 0;
+    d->SeriesAddedDuringImport = 0;
+    d->InstancesAddedDuringImport = 0;
+  }
+
+  QString summary()
+  {
+    ctkDICOMBrowserPrivate* d = this->DICOMBrowserPrivate;
+    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));
+    return message;
+  }
+
+  ctkDICOMBrowserPrivate* DICOMBrowserPrivate;
+};
+
+//----------------------------------------------------------------------------
 // ctkDICOMBrowserPrivate methods
 
-ctkDICOMBrowserPrivate::ctkDICOMBrowserPrivate(ctkDICOMBrowser* parent): q_ptr(parent){
+//----------------------------------------------------------------------------
+ctkDICOMBrowserPrivate::ctkDICOMBrowserPrivate(ctkDICOMBrowser* parent): q_ptr(parent)
+{
+  ImportDialog = 0;
+  QueryRetrieveWidget = 0;
   DICOMDatabase = QSharedPointer<ctkDICOMDatabase> (new ctkDICOMDatabase);
   DICOMIndexer = QSharedPointer<ctkDICOMIndexer> (new ctkDICOMIndexer);
   IndexerProgress = 0;
@@ -108,6 +156,7 @@ ctkDICOMBrowserPrivate::ctkDICOMBrowserPrivate(ctkDICOMBrowser* parent): q_ptr(p
   InstancesAddedDuringImport = 0;
 }
 
+//----------------------------------------------------------------------------
 ctkDICOMBrowserPrivate::~ctkDICOMBrowserPrivate()
 {
   if ( IndexerProgress )
@@ -124,6 +173,21 @@ ctkDICOMBrowserPrivate::~ctkDICOMBrowserPrivate()
     }
 }
 
+//----------------------------------------------------------------------------
+bool ctkDICOMBrowserPrivate::confirmDirectoryImport()
+{
+  Q_Q(ctkDICOMBrowser);
+  ctkMessageBox dialog(q);
+  QString message = q->tr("Are you sure you want to import files ?");
+  dialog.setText(message);
+  dialog.setIcon(QMessageBox::Question);
+  dialog.addButton(new QPushButton("Import"), QMessageBox::AcceptRole);
+  dialog.addButton(QMessageBox::Cancel);
+  dialog.setDontShowAgainSettingsKey("DICOM/DontConfirmImportDirectory");
+  return dialog.exec() == QMessageBox::AcceptRole;
+}
+
+//----------------------------------------------------------------------------
 void ctkDICOMBrowserPrivate::showUpdateSchemaDialog()
 {
   Q_Q(ctkDICOMBrowser);
@@ -158,6 +222,7 @@ void ctkDICOMBrowserPrivate::showUpdateSchemaDialog()
   UpdateSchemaProgress->show();
 }
 
+//----------------------------------------------------------------------------
 void ctkDICOMBrowserPrivate::showIndexerDialog()
 {
   Q_Q(ctkDICOMBrowser);
@@ -263,11 +328,29 @@ ctkDICOMBrowser::ctkDICOMBrowser(QWidget* _parent):Superclass(_parent),
 
   connect(d->DirectoryButton, SIGNAL(directoryChanged(QString)), this, SLOT(setDatabaseDirectory(QString)));
 
+  // Initialize directoryMode widget
+  QFormLayout *layout = new QFormLayout;
+  QComboBox* importDirectoryModeComboBox = new QComboBox();
+  importDirectoryModeComboBox->addItem("Add Link", ctkDICOMBrowser::ImportDirectoryAddLink);
+  importDirectoryModeComboBox->addItem("Copy", ctkDICOMBrowser::ImportDirectoryCopy);
+  importDirectoryModeComboBox->setToolTip(
+        tr("Indicate if the files should be copied to the local database"
+           " directory or if only links should be created ?"));
+  layout->addRow(new QLabel("Import Directory Mode:"), importDirectoryModeComboBox);
+  QCheckBox* skipConfirmImportDirectoryCheckBox = new QCheckBox();
+  layout->addRow(new QLabel("Skip Import Directory Confirmation:"), skipConfirmImportDirectoryCheckBox);
+  layout->setContentsMargins(0, 0, 0, 0);
+  QWidget* importDirectoryBottomWidget = new QWidget();
+  importDirectoryBottomWidget->setLayout(layout);
+
+  // Default values
+  importDirectoryModeComboBox->setCurrentIndex(
+        importDirectoryModeComboBox->findData(this->importDirectoryMode()));
+  skipConfirmImportDirectoryCheckBox->setChecked(this->skipConfirmImportDirectory());
+
   //Initialize import widget
   d->ImportDialog = new ctkFileDialog();
-  QCheckBox* importCheckbox = new QCheckBox("Copy on import", d->ImportDialog);
-  importCheckbox->setCheckState(Qt::Checked);
-  d->ImportDialog->setBottomWidget(importCheckbox);
+  d->ImportDialog->setBottomWidget(importDirectoryBottomWidget);
   d->ImportDialog->setFileMode(QFileDialog::Directory);
   // XXX Method setSelectionMode must be called after setFileMode
   d->ImportDialog->setSelectionMode(QAbstractItemView::ExtendedSelection);
@@ -277,7 +360,13 @@ ctkDICOMBrowser::ctkDICOMBrowser(QWidget* _parent):Superclass(_parent),
 
   //connect signal and slots
   connect(d->ImportDialog, SIGNAL(filesSelected(QStringList)),
-          this,SLOT(onImportDirectories(QStringList)));
+          this,SLOT(onImportDirectoriesSelected(QStringList)));
+
+  connect(importDirectoryModeComboBox, SIGNAL(currentIndexChanged(int)),
+          this, SLOT(onImportDirectoryComboBoxCurrentIndexChanged(int)));
+
+  connect(skipConfirmImportDirectoryCheckBox, SIGNAL(toggled(bool)),
+          this, SLOT(setSkipConfirmImportDirectory(bool)));
 
   connect(d->QueryRetrieveWidget, SIGNAL(canceled()), d->QueryRetrieveWidget, SLOT(hide()) );
   connect(d->QueryRetrieveWidget, SIGNAL(canceled()), this, SLOT(onQueryRetrieveFinished()) );
@@ -408,8 +497,6 @@ const QStringList ctkDICOMBrowser::tagsToPrecache()
   return d->DICOMDatabase->tagsToPrecache();
 }
 
-
-
 //----------------------------------------------------------------------------
 ctkDICOMDatabase* ctkDICOMBrowser::database(){
   Q_D(ctkDICOMBrowser);
@@ -607,70 +694,151 @@ void ctkDICOMBrowser::onInstanceAdded(QString instanceUID)
 }
 
 //----------------------------------------------------------------------------
-void ctkDICOMBrowser::onImportDirectories(QStringList directories)
+void ctkDICOMBrowser::onImportDirectoriesSelected(QStringList directories)
 {
-  foreach (const QString& directory, directories)
+  Q_D(ctkDICOMBrowser);
+  if (!d->confirmDirectoryImport())
     {
-    this->onImportDirectory(directory);
+    return;
     }
+  this->onImportDirectories(directories, this->importDirectoryMode(), /* confirm= */ false);
+
+  // Clear selection
+  d->ImportDialog->clearSelection();
 }
 
 //----------------------------------------------------------------------------
-void ctkDICOMBrowser::onImportDirectory(QString directory)
+void ctkDICOMBrowser::onImportDirectoryComboBoxCurrentIndexChanged(int index)
 {
   Q_D(ctkDICOMBrowser);
+  Q_UNUSED(index);
+  this->setImportDirectoryMode(this->importDirectoryMode());
+}
 
-  if (QDir(directory).exists())
-  {
-    QString targetDirectory;
+//----------------------------------------------------------------------------
+void ctkDICOMBrowser::onImportDirectories(QStringList directories, ctkDICOMBrowser::ImportDirectoryMode mode, bool confirm)
+{
+  Q_D(ctkDICOMBrowser);
+  if(confirm && !d->confirmDirectoryImport())
+    {
+    return;
+    }
+  ctkDICOMImportStats stats(d);
+  foreach (const QString& directory, directories)
+    {
+    d->importDirectory(directory, mode);
+    }
 
-    QCheckBox* copyOnImport = qobject_cast<QCheckBox*>(d->ImportDialog->bottomWidget());
+  if (d->DisplayImportSummary)
+    {
+    QMessageBox::information(this,"DICOM Directory Import", stats.summary());
+    }
+}
 
-    ctkMessageBox importTypeDialog;
-    QString message("Do you want to copy the files to the local database directory or just add the links?");
-    importTypeDialog.setText(message);
-    importTypeDialog.setIcon(QMessageBox::Question);
+//----------------------------------------------------------------------------
+void ctkDICOMBrowser::onImportDirectory(QString directory, ctkDICOMBrowser::ImportDirectoryMode mode, bool confirm)
+{
+  Q_D(ctkDICOMBrowser);
+  if(confirm && !d->confirmDirectoryImport())
+    {
+    return;
+    }
+  ctkDICOMImportStats stats(d);
+  d->importDirectory(directory, mode);
+  if (d->DisplayImportSummary)
+    {
+    QMessageBox::information(this,"DICOM Directory Import", stats.summary());
+    }
+}
 
-    importTypeDialog.addButton("Copy",QMessageBox::AcceptRole);
-    importTypeDialog.addButton("Add Link",QMessageBox::RejectRole);
-    importTypeDialog.setDontShowAgainSettingsKey( "MainWindow/DontConfirmCopyOnImport" );
-    int selection = importTypeDialog.exec();
+//----------------------------------------------------------------------------
+void ctkDICOMBrowserPrivate::importDirectory(QString directory, ctkDICOMBrowser::ImportDirectoryMode mode)
+{
+  if (!QDir(directory).exists())
+    {
+    return;
+    }
 
-    if (selection== QMessageBox::AcceptRole)
+  QString targetDirectory;
+  if (mode == ctkDICOMBrowser::ImportDirectoryCopy)
     {
-      copyOnImport->setCheckState(Qt::Checked);
+    targetDirectory = this->DICOMDatabase->databaseDirectory();
     }
-    else
+
+  // show progress dialog and perform indexing
+  this->showIndexerDialog();
+  this->DICOMIndexer->addDirectory(*this->DICOMDatabase, directory, targetDirectory);
+}
+
+//----------------------------------------------------------------------------
+void ctkDICOMBrowserPrivate::importOldSettings()
+{
+  Q_Q(ctkDICOMBrowser);
+  // Backward compatibility
+  QSettings settings;
+  int dontConfirmCopyOnImport = settings.value("MainWindow/DontConfirmCopyOnImport", static_cast<int>(QMessageBox::InvalidRole)).toInt();
+  if (dontConfirmCopyOnImport == QMessageBox::AcceptRole)
     {
-      copyOnImport->setCheckState(Qt::Unchecked);
+    q->setSkipConfirmImportDirectory(true);
+    // settings.setValue("DICOM/DontConfirmImportDirectory", QMessageBox::AcceptRole);
+    settings.setValue("DICOM/ImportDirectoryMode", static_cast<int>(ctkDICOMBrowser::ImportDirectoryCopy));
+    settings.remove("MainWindow/DontConfirmCopyOnImport");
     }
+}
 
-    // reset counts
-    d->PatientsAddedDuringImport = 0;
-    d->StudiesAddedDuringImport = 0;
-    d->SeriesAddedDuringImport = 0;
-    d->InstancesAddedDuringImport = 0;
+//----------------------------------------------------------------------------
+bool ctkDICOMBrowser::skipConfirmImportDirectory()const
+{
+  Q_D(const ctkDICOMBrowser);
+  ctkDICOMBrowserPrivate* mutable_d =
+    const_cast<ctkDICOMBrowserPrivate*>(d);
+  mutable_d->importOldSettings();
+  QSettings settings;
+  return settings.value(
+        "DICOM/DontConfirmImportDirectory",
+        static_cast<int>(QMessageBox::InvalidRole)).toInt() == QMessageBox::AcceptRole;
+}
 
-    if (copyOnImport->checkState() == Qt::Checked)
+//----------------------------------------------------------------------------
+void ctkDICOMBrowser::setSkipConfirmImportDirectory(bool value)
+{
+  Q_D(ctkDICOMBrowser);
+
+  QSettings settings;
+  settings.setValue("DICOM/DontConfirmImportDirectory", value ? QMessageBox::AcceptRole : QMessageBox::RejectRole);
+  if (!d->ImportDialog)
     {
-      targetDirectory = d->DICOMDatabase->databaseDirectory();
+    return;
     }
+  QCheckBox* checkBox = d->ImportDialog->bottomWidget()->findChild<QCheckBox*>();
+  checkBox->setChecked(value);
+}
+
+//----------------------------------------------------------------------------
+ctkDICOMBrowser::ImportDirectoryMode ctkDICOMBrowser::importDirectoryMode()const
+{
+  Q_D(const ctkDICOMBrowser);
+  ctkDICOMBrowserPrivate* mutable_d =
+    const_cast<ctkDICOMBrowserPrivate*>(d);
+  mutable_d->importOldSettings();
+  QSettings settings;
+  return static_cast<ctkDICOMBrowser::ImportDirectoryMode>(settings.value(
+        "DICOM/ImportDirectoryMode", static_cast<int>(ctkDICOMBrowser::ImportDirectoryAddLink)).toInt());
+}
 
-    // show progress dialog and perform indexing
-    d->showIndexerDialog();
-    d->DICOMIndexer->addDirectory(*d->DICOMDatabase,directory,targetDirectory);
+//----------------------------------------------------------------------------
+void ctkDICOMBrowser::setImportDirectoryMode(ctkDICOMBrowser::ImportDirectoryMode mode)
+{
+  Q_D(ctkDICOMBrowser);
 
-    // display summary result
-    if (d->DisplayImportSummary)
+  QSettings settings;
+  settings.setValue("DICOM/ImportDirectoryMode", static_cast<int>(mode));
+  if (!d->ImportDialog)
     {
-      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);
+    return;
     }
-  }
+  QComboBox* comboBox = d->ImportDialog->bottomWidget()->findChild<QComboBox*>();
+  comboBox->setCurrentIndex(comboBox->findData(mode));
 }
 
 //----------------------------------------------------------------------------

+ 89 - 10
Libs/DICOM/Widgets/ctkDICOMBrowser.h

@@ -21,7 +21,7 @@
 #ifndef __ctkDICOMBrowser_h
 #define __ctkDICOMBrowser_h
 
-// Qt includes 
+// Qt includes
 #include <QItemSelection>
 #include <QWidget>
 
@@ -35,14 +35,33 @@ class ctkDICOMDatabase;
 class ctkDICOMTableManager;
 
 /// \ingroup DICOM_Widgets
+///
+/// \brief The DICOM browser widget provides an interface to organize DICOM
+/// data stored in a local ctkDICOMDatabase.
+///
+/// Using a local database avoids redundant calculations and speed up subsequent
+/// access.
+///
+/// Supported operations are:
+///
+/// * Import
+/// * Export
+/// * Send
+/// * Query
+/// * Remove
+/// * Repair
+///
 class CTK_DICOM_WIDGETS_EXPORT ctkDICOMBrowser : public QWidget
 {
   Q_OBJECT
+  Q_ENUMS(ImportDirectoryMode)
   Q_PROPERTY(ctkDICOMDatabase* database READ database)
   Q_PROPERTY(QString databaseDirectory READ databaseDirectory WRITE setDatabaseDirectory)
   Q_PROPERTY(QStringList tagsToPrecache READ tagsToPrecache WRITE setTagsToPrecache)
   Q_PROPERTY(bool displayImportSummary READ displayImportSummary WRITE setDisplayImportSummary)
   Q_PROPERTY(ctkDICOMTableManager* dicomTableManager READ dicomTableManager)
+  Q_PROPERTY(ctkDICOMBrowser::ImportDirectoryMode ImportDirectoryMode READ importDirectoryMode WRITE setImportDirectoryMode)
+  Q_PROPERTY(bool SkipConfirmImportDirectory READ skipConfirmImportDirectory WRITE setSkipConfirmImportDirectory)
 
 public:
   typedef QWidget Superclass;
@@ -79,11 +98,55 @@ public:
   int seriesAddedDuringImport();
   int instancesAddedDuringImport();
 
+  enum ImportDirectoryMode
+  {
+    ImportDirectoryCopy = 0,
+    ImportDirectoryAddLink
+  };
+
+  /// \brief Get value of ImportDirectoryMode settings.
+  ///
+  /// \sa setImportDirectoryMode(ctkDICOMBrowser::ImportDirectoryMode)
+  ctkDICOMBrowser::ImportDirectoryMode importDirectoryMode()const;
+
+  /// \brief Get SkipConfirmImportDirectory.
+  ///
+  /// \sa setSkipConfirmImportDirectory(bool)
+  bool skipConfirmImportDirectory()const;
+
 public Q_SLOTS:
+
+  /// \brief Set value of ImportDirectoryMode settings.
+  ///
+  /// Setting the value will update the comboBox found at the bottom
+  /// of the import dialog.
+  ///
+  /// \sa importDirectoryMode()
+  void setImportDirectoryMode(ctkDICOMBrowser::ImportDirectoryMode mode);
+
+  /// \brief Set SkipConfirmImportDirectory.
+  ///
+  /// Setting the value will update the checkbox found at the bottom
+  /// of the import dialog.
+  ///
+  /// \sa skipConfirmImportDirectory()
+  void setSkipConfirmImportDirectory(bool value);
+
   void setDatabaseDirectory(const QString& directory);
   void onFileIndexed(const QString& filePath);
 
+  /// \brief Pop-up file dialog allowing to select and import one or multiple
+  /// DICOM directories.
+  ///
+  /// The dialog is extented with two additional controls:
+  ///
+  /// * **ImportDirectoryMode** combox: Allow user to select "Add Link" or "Copy" mode.
+  ///   Associated settings is stored using key `DICOM/ImportDirectoryMode`.
+  ///
+  /// * **ConfirmImportDirectory** checkbox: Allow user to skip import directory confirmation dialog.
+  ///   Associated settings is stored using key `DICOM/DontConfirmImportDirectory`.
   void openImportDialog();
+
   void openExportDialog();
   void openQueryDialog();
   void onRemoveAction();
@@ -93,20 +156,25 @@ public Q_SLOTS:
 
   /// \brief Import directories
   ///
-  /// This is used when user selected one or multiple
-  /// directories from the Import Dialog, but can used externally to trigger
-  /// an import (i.e. for testing or to support drag-and-drop)
+  /// This can be used to externally trigger an import (i.e. for testing or to support drag-and-drop)
+  ///
+  /// By default, \a mode is ImportDirectoryMode::ImportDirectoryCopy and \a confirm is true.
+  ///
+  /// Setting \a confirm to false will skip the confirmation dialog.
   ///
-  /// \sa onImportDirectory(QString directory)
-  void onImportDirectories(QStringList directories);
+  /// \sa onImportDirectory(QString directory, int mode)
+  void onImportDirectories(QStringList directories, ctkDICOMBrowser::ImportDirectoryMode mode = ImportDirectoryAddLink, bool confirm = true);
 
   /// \brief Import a directory
   ///
-  /// This can also be used externally to trigger
-  /// an import (i.e. for testing or to support drag-and-drop)
-  void onImportDirectory(QString directory);
+  /// This can be used to externally trigger an import (i.e. for testing or to support drag-and-drop)
+  ///
+  /// By default, \a mode is ImportDirectoryMode::ImportDirectoryCopy and \a confirm is true.
+  ///
+  /// Setting \a confirm to false will skip the confirmation dialog.
+  void onImportDirectory(QString directory, ctkDICOMBrowser::ImportDirectoryMode mode = ImportDirectoryAddLink, bool confirm = true);
 
-  /// slots to capture status updates from the database during an 
+  /// slots to capture status updates from the database during an
   /// import operation
   void onPatientAdded(int, QString, QString, QString);
   void onStudyAdded(QString);
@@ -133,6 +201,17 @@ protected:
     bool confirmDeleteSelectedUIDs(QStringList uids);
 
 protected Q_SLOTS:
+
+    /// \brief Import directories
+    ///
+    /// This is used when user selected one or multiple
+    /// directories from the Import Dialog.
+    ///
+    /// \sa onImportDirectories(QString directory, int mode)
+    void onImportDirectoriesSelected(QStringList directories);
+
+    void onImportDirectoryComboBoxCurrentIndexChanged(int index);
+
     void onModelSelected(const QItemSelection&, const QItemSelection&);
 
     /// Called when a right mouse click is made in the patients table