123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092 |
- /*=========================================================================
- 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.
- =========================================================================*/
- // std includes
- #include <iostream>
- // Qt includes
- #include <QAction>
- #include <QApplication>
- #include <QCoreApplication>
- #include <QCheckBox>
- #include <QDebug>
- #include <QFile>
- #include <QListView>
- #include <QMenu>
- #include <QMessageBox>
- #include <QProgressDialog>
- #include <QSettings>
- #include <QStringListModel>
- #include <QWidgetAction>
- // ctkWidgets includes
- #include "ctkDirectoryButton.h"
- #include "ctkFileDialog.h"
- #include "ctkMessageBox.h"
- // ctkDICOMCore includes
- #include "ctkDICOMDatabase.h"
- #include "ctkDICOMIndexer.h"
- // ctkDICOMWidgets includes
- #include "ctkDICOMBrowser.h"
- #include "ctkDICOMQueryResultsTabWidget.h"
- #include "ctkDICOMQueryRetrieveWidget.h"
- #include "ctkDICOMQueryWidget.h"
- #include "ctkDICOMTableManager.h"
- #include "ui_ctkDICOMBrowser.h"
- //logger
- #include <ctkLogger.h>
- static ctkLogger logger("org.commontk.DICOM.Widgets.ctkDICOMBrowser");
- //----------------------------------------------------------------------------
- class ctkDICOMBrowserPrivate: public Ui_ctkDICOMBrowser
- {
- public:
- ctkDICOMBrowser* const q_ptr;
- Q_DECLARE_PUBLIC(ctkDICOMBrowser);
- ctkDICOMBrowserPrivate(ctkDICOMBrowser* );
- ~ctkDICOMBrowserPrivate();
- ctkFileDialog* ImportDialog;
- ctkDICOMQueryRetrieveWidget* QueryRetrieveWidget;
- QSharedPointer<ctkDICOMDatabase> DICOMDatabase;
- QSharedPointer<ctkDICOMIndexer> DICOMIndexer;
- QProgressDialog *IndexerProgress;
- QProgressDialog *UpdateSchemaProgress;
- QProgressDialog *ExportProgress;
- void showIndexerDialog();
- void showUpdateSchemaDialog();
- // used when suspending the ctkDICOMModel
- QSqlDatabase EmptyDatabase;
- // 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;
- };
- //----------------------------------------------------------------------------
- // ctkDICOMBrowserPrivate methods
- ctkDICOMBrowserPrivate::ctkDICOMBrowserPrivate(ctkDICOMBrowser* parent): q_ptr(parent){
- DICOMDatabase = QSharedPointer<ctkDICOMDatabase> (new ctkDICOMDatabase);
- DICOMIndexer = QSharedPointer<ctkDICOMIndexer> (new ctkDICOMIndexer);
- IndexerProgress = 0;
- UpdateSchemaProgress = 0;
- ExportProgress = 0;
- DisplayImportSummary = true;
- PatientsAddedDuringImport = 0;
- StudiesAddedDuringImport = 0;
- SeriesAddedDuringImport = 0;
- InstancesAddedDuringImport = 0;
- }
- ctkDICOMBrowserPrivate::~ctkDICOMBrowserPrivate()
- {
- if ( IndexerProgress )
- {
- delete IndexerProgress;
- }
- if ( UpdateSchemaProgress )
- {
- delete UpdateSchemaProgress;
- }
- if ( ExportProgress )
- {
- delete ExportProgress;
- }
- }
- void ctkDICOMBrowserPrivate::showUpdateSchemaDialog()
- {
- Q_Q(ctkDICOMBrowser);
- if (UpdateSchemaProgress == 0)
- {
- //
- // Set up the Update Schema Progress Dialog
- //
- UpdateSchemaProgress = new QProgressDialog(
- q->tr("DICOM Schema Update"), "Cancel", 0, 100, q,
- Qt::WindowTitleHint | Qt::WindowSystemMenuHint);
- // We don't want the progress dialog to resize itself, so we bypass the label
- // by creating our own
- QLabel* progressLabel = new QLabel(q->tr("Initialization..."));
- UpdateSchemaProgress->setLabel(progressLabel);
- UpdateSchemaProgress->setWindowModality(Qt::ApplicationModal);
- UpdateSchemaProgress->setMinimumDuration(0);
- UpdateSchemaProgress->setValue(0);
- q->connect(DICOMDatabase.data(), SIGNAL(schemaUpdateStarted(int)),
- UpdateSchemaProgress, SLOT(setMaximum(int)));
- q->connect(DICOMDatabase.data(), SIGNAL(schemaUpdateProgress(int)),
- UpdateSchemaProgress, SLOT(setValue(int)));
- q->connect(DICOMDatabase.data(), SIGNAL(schemaUpdateProgress(QString)),
- progressLabel, SLOT(setText(QString)));
- // close the dialog
- q->connect(DICOMDatabase.data(), SIGNAL(schemaUpdated()),
- UpdateSchemaProgress, SLOT(close()));
- }
- UpdateSchemaProgress->show();
- }
- void ctkDICOMBrowserPrivate::showIndexerDialog()
- {
- Q_Q(ctkDICOMBrowser);
- if (IndexerProgress == 0)
- {
- //
- // Set up the Indexer Progress Dialog
- //
- IndexerProgress = new QProgressDialog( q->tr("DICOM Import"), "Cancel", 0, 100, q,
- Qt::WindowTitleHint | Qt::WindowSystemMenuHint);
- // We don't want the progress dialog to resize itself, so we bypass the label
- // by creating our own
- QLabel* progressLabel = new QLabel(q->tr("Initialization..."));
- IndexerProgress->setLabel(progressLabel);
- IndexerProgress->setWindowModality(Qt::ApplicationModal);
- IndexerProgress->setMinimumDuration(0);
- IndexerProgress->setValue(0);
- q->connect(IndexerProgress, SIGNAL(canceled()),
- DICOMIndexer.data(), SLOT(cancel()));
- q->connect(DICOMIndexer.data(), SIGNAL(progress(int)),
- IndexerProgress, SLOT(setValue(int)));
- q->connect(DICOMIndexer.data(), SIGNAL(indexingFilePath(QString)),
- progressLabel, SLOT(setText(QString)));
- q->connect(DICOMIndexer.data(), SIGNAL(indexingFilePath(QString)),
- q, SLOT(onFileIndexed(QString)));
- // close the dialog
- q->connect(DICOMIndexer.data(), SIGNAL(indexingComplete()),
- IndexerProgress, SLOT(close()));
- // stop indexing and reset the database if canceled
- q->connect(IndexerProgress, SIGNAL(canceled()),
- DICOMIndexer.data(), SLOT(cancel()));
- // allow users of this widget to know that the process has finished
- q->connect(IndexerProgress, SIGNAL(canceled()),
- q, SIGNAL(directoryImported()));
- q->connect(DICOMIndexer.data(), SIGNAL(indexingComplete()),
- q, SIGNAL(directoryImported()));
- }
- IndexerProgress->show();
- }
- //----------------------------------------------------------------------------
- // ctkDICOMBrowser methods
- //----------------------------------------------------------------------------
- ctkDICOMBrowser::ctkDICOMBrowser(QWidget* _parent):Superclass(_parent),
- d_ptr(new ctkDICOMBrowserPrivate(this))
- {
- Q_D(ctkDICOMBrowser);
- d->setupUi(this);
- // 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)));
- connect(d->tableDensityComboBox ,SIGNAL(currentIndexChanged (const QString&)),
- this, SLOT(onTablesDensityComboBox(QString)));
- //Set ToolBar button style
- d->ToolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
- //Initialize Q/R widget
- d->QueryRetrieveWidget = new ctkDICOMQueryRetrieveWidget();
- d->QueryRetrieveWidget->setWindowModality ( Qt::ApplicationModal );
- //initialize directory from settings, then listen for changes
- QSettings settings;
- if ( settings.value("DatabaseDirectory", "") == "" )
- {
- QString directory = QString("./ctkDICOM-Database");
- settings.setValue("DatabaseDirectory", directory);
- settings.sync();
- }
- QString databaseDirectory = settings.value("DatabaseDirectory").toString();
- this->setDatabaseDirectory(databaseDirectory);
- d->DirectoryButton->setDirectory(databaseDirectory);
- d->dicomTableManager->setDICOMDatabase(d->DICOMDatabase.data());
- // TableView signals
- connect(d->dicomTableManager, SIGNAL(patientsSelectionChanged(const QItemSelection&, const QItemSelection&)),
- this, SLOT(onModelSelected(const QItemSelection&,const QItemSelection&)));
- connect(d->dicomTableManager, SIGNAL(studiesSelectionChanged(const QItemSelection&, const QItemSelection&)),
- this, SLOT(onModelSelected(const QItemSelection&,const QItemSelection&)));
- connect(d->dicomTableManager, SIGNAL(seriesSelectionChanged(const QItemSelection&, const QItemSelection&)),
- this, SLOT(onModelSelected(const QItemSelection&,const QItemSelection&)));
- // set up context menus for working on selected patients, studies, series
- connect(d->dicomTableManager, SIGNAL(patientsRightClicked(const QPoint&)),
- this, SLOT(onPatientsRightClicked(const QPoint&)));
- connect(d->dicomTableManager, SIGNAL(studiesRightClicked(const QPoint&)),
- this, SLOT(onStudiesRightClicked(const QPoint&)));
- connect(d->dicomTableManager, SIGNAL(seriesRightClicked(const QPoint&)),
- this, SLOT(onSeriesRightClicked(const QPoint&)));
- connect(d->DirectoryButton, SIGNAL(directoryChanged(QString)), this, SLOT(setDatabaseDirectory(QString)));
- //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->setFileMode(QFileDialog::Directory);
- // XXX Method setSelectionMode must be called after setFileMode
- d->ImportDialog->setSelectionMode(QAbstractItemView::ExtendedSelection);
- d->ImportDialog->setLabelText(QFileDialog::Accept,"Import");
- d->ImportDialog->setWindowTitle("Import DICOM files from directory ...");
- d->ImportDialog->setWindowModality(Qt::ApplicationModal);
- //connect signal and slots
- connect(d->ImportDialog, SIGNAL(filesSelected(QStringList)),
- this,SLOT(onImportDirectories(QStringList)));
- connect(d->QueryRetrieveWidget, SIGNAL(canceled()), d->QueryRetrieveWidget, SLOT(hide()) );
- connect(d->QueryRetrieveWidget, SIGNAL(canceled()), this, SLOT(onQueryRetrieveFinished()) );
- }
- //----------------------------------------------------------------------------
- ctkDICOMBrowser::~ctkDICOMBrowser()
- {
- Q_D(ctkDICOMBrowser);
- d->QueryRetrieveWidget->deleteLater();
- d->ImportDialog->deleteLater();
- }
- //----------------------------------------------------------------------------
- bool ctkDICOMBrowser::displayImportSummary()
- {
- Q_D(ctkDICOMBrowser);
- return d->DisplayImportSummary;
- }
- //----------------------------------------------------------------------------
- void ctkDICOMBrowser::setDisplayImportSummary(bool onOff)
- {
- Q_D(ctkDICOMBrowser);
- d->DisplayImportSummary = onOff;
- }
- //----------------------------------------------------------------------------
- int ctkDICOMBrowser::patientsAddedDuringImport()
- {
- Q_D(ctkDICOMBrowser);
- return d->PatientsAddedDuringImport;
- }
- //----------------------------------------------------------------------------
- int ctkDICOMBrowser::studiesAddedDuringImport()
- {
- Q_D(ctkDICOMBrowser);
- return d->StudiesAddedDuringImport;
- }
- //----------------------------------------------------------------------------
- int ctkDICOMBrowser::seriesAddedDuringImport()
- {
- Q_D(ctkDICOMBrowser);
- return d->SeriesAddedDuringImport;
- }
- //----------------------------------------------------------------------------
- int ctkDICOMBrowser::instancesAddedDuringImport()
- {
- Q_D(ctkDICOMBrowser);
- return d->InstancesAddedDuringImport;
- }
- //----------------------------------------------------------------------------
- void ctkDICOMBrowser::updateDatabaseSchemaIfNeeded()
- {
- Q_D(ctkDICOMBrowser);
- d->showUpdateSchemaDialog();
- d->DICOMDatabase->updateSchemaIfNeeded();
- }
- //----------------------------------------------------------------------------
- void ctkDICOMBrowser::setDatabaseDirectory(const QString& directory)
- {
- Q_D(ctkDICOMBrowser);
- QSettings settings;
- settings.setValue("DatabaseDirectory", directory);
- settings.sync();
- //close the active DICOM database
- d->DICOMDatabase->closeDatabase();
- //open DICOM database on the directory
- QString databaseFileName = directory + QString("/ctkDICOM.sql");
- try
- {
- d->DICOMDatabase->openDatabase( databaseFileName );
- }
- catch (std::exception e)
- {
- std::cerr << "Database error: " << qPrintable(d->DICOMDatabase->lastError()) << "\n";
- d->DICOMDatabase->closeDatabase();
- return;
- }
- // update the database schema if needed and provide progress
- this->updateDatabaseSchemaIfNeeded();
- //pass DICOM database instance to Import widget
- d->QueryRetrieveWidget->setRetrieveDatabase(d->DICOMDatabase);
- // update the button and let any connected slots know about the change
- d->DirectoryButton->setDirectory(directory);
- d->dicomTableManager->updateTableViews();
- emit databaseDirectoryChanged(directory);
- }
- //----------------------------------------------------------------------------
- QString ctkDICOMBrowser::databaseDirectory() const
- {
- QSettings settings;
- return settings.value("DatabaseDirectory").toString();
- }
- //------------------------------------------------------------------------------
- void ctkDICOMBrowser::setTagsToPrecache( const QStringList tags)
- {
- Q_D(ctkDICOMBrowser);
- d->DICOMDatabase->setTagsToPrecache(tags);
- }
- //------------------------------------------------------------------------------
- const QStringList ctkDICOMBrowser::tagsToPrecache()
- {
- Q_D(ctkDICOMBrowser);
- return d->DICOMDatabase->tagsToPrecache();
- }
- //----------------------------------------------------------------------------
- ctkDICOMDatabase* ctkDICOMBrowser::database(){
- Q_D(ctkDICOMBrowser);
- return d->DICOMDatabase.data();
- }
- //----------------------------------------------------------------------------
- ctkDICOMTableManager* ctkDICOMBrowser::dicomTableManager()
- {
- Q_D(ctkDICOMBrowser);
- return d->dicomTableManager;
- }
- //----------------------------------------------------------------------------
- void ctkDICOMBrowser::onFileIndexed(const QString& filePath)
- {
- Q_UNUSED(filePath);
- }
- //----------------------------------------------------------------------------
- void ctkDICOMBrowser::openImportDialog()
- {
- Q_D(ctkDICOMBrowser);
- d->ImportDialog->show();
- d->ImportDialog->raise();
- }
- //----------------------------------------------------------------------------
- void ctkDICOMBrowser::openExportDialog()
- {
- }
- //----------------------------------------------------------------------------
- void ctkDICOMBrowser::openQueryDialog()
- {
- Q_D(ctkDICOMBrowser);
- d->QueryRetrieveWidget->show();
- d->QueryRetrieveWidget->raise();
- }
- //----------------------------------------------------------------------------
- void ctkDICOMBrowser::onQueryRetrieveFinished()
- {
- emit this->queryRetrieveFinished();
- }
- //----------------------------------------------------------------------------
- void ctkDICOMBrowser::onRemoveAction()
- {
- Q_D(ctkDICOMBrowser);
- QStringList selectedSeriesUIDs = d->dicomTableManager->currentSeriesSelection();
- foreach (const QString& uid, selectedSeriesUIDs)
- {
- d->DICOMDatabase->removeSeries(uid);
- }
- QStringList selectedStudiesUIDs = d->dicomTableManager->currentStudiesSelection();
- foreach (const QString& uid, selectedStudiesUIDs)
- {
- d->DICOMDatabase->removeStudy(uid);
- }
- QStringList selectedPatientUIDs = d->dicomTableManager->currentPatientsSelection();
- foreach (const QString& uid, selectedPatientUIDs)
- {
- d->DICOMDatabase->removePatient(uid);
- }
- // Update the table views
- d->dicomTableManager->updateTableViews();
- }
- //----------------------------------------------------------------------------
- void ctkDICOMBrowser::onRepairAction()
- {
- Q_D(ctkDICOMBrowser);
- QMessageBox* repairMessageBox;
- repairMessageBox = new QMessageBox;
- repairMessageBox->setWindowTitle("Database Repair");
- QStringList allFiles(d->DICOMDatabase->allFiles());
- QSet<QString> corruptedSeries;
- QStringList::const_iterator it;
- for (it = allFiles.constBegin(); it!= allFiles.constEnd();++it)
- {
- QString fileName(*it);
- QFile dicomFile(fileName);
- if(!dicomFile.exists())
- {
- QString seriesUid = d->DICOMDatabase->seriesForFile(fileName);
- corruptedSeries.insert(seriesUid);
- }
- }
- if (corruptedSeries.size() == 0)
- {
- repairMessageBox->setText("All the files in the local database are available.");
- repairMessageBox->addButton(QMessageBox::Ok);
- repairMessageBox->exec();
- }
- else
- {
- repairMessageBox->addButton(QMessageBox::Yes);
- repairMessageBox->addButton(QMessageBox::No);
- QSet<QString>::iterator i;
- for (i = corruptedSeries.begin(); i != corruptedSeries.end(); ++i)
- {
- QStringList fileList (d->DICOMDatabase->filesForSeries(*i));
- QString unavailableFileNames;
- QStringList::const_iterator it;
- for (it= fileList.constBegin(); it!= fileList.constEnd();++it)
- {
- unavailableFileNames.append(*it+"\n");
- }
- QString firstFile (*(fileList.constBegin()));
- QHash<QString,QString> descriptions (d->DICOMDatabase->descriptionsForFile(firstFile));
- repairMessageBox->setText("The files for the following series are not available on the disk: \nPatient Name: "
- + descriptions["PatientsName"]+ "\n"+
- "Study Desciption: " + descriptions["StudyDescription"]+ "\n"+
- "Series Desciption: " + descriptions["SeriesDescription"]+ "\n"+
- "Do you want to remove the series from the DICOM database? ");
- repairMessageBox->setDetailedText(unavailableFileNames);
- int selection = repairMessageBox->exec();
- if (selection == QMessageBox::Yes)
- {
- d->DICOMDatabase->removeSeries(*i);
- d->dicomTableManager->updateTableViews();
- }
- }
- }
- }
- //----------------------------------------------------------------------------
- void ctkDICOMBrowser::onTablesDensityComboBox(QString density)
- {
- Q_D(ctkDICOMBrowser);
- if ( density == "Comfortable")
- {
- d->dicomTableManager->setDisplayDensity(ctkDICOMTableManager::Comfortable);
- }
- else if ( density == "Cozy")
- {
- d->dicomTableManager->setDisplayDensity(ctkDICOMTableManager::Cozy);
- }
- else if ( density == "Compact")
- {
- d->dicomTableManager->setDisplayDensity(ctkDICOMTableManager::Compact);
- }
- }
- //----------------------------------------------------------------------------
- void ctkDICOMBrowser::onPatientAdded(int databaseID, QString patientID, QString patientName, QString patientBirthDate )
- {
- Q_D(ctkDICOMBrowser);
- Q_UNUSED(databaseID);
- Q_UNUSED(patientID);
- Q_UNUSED(patientName);
- Q_UNUSED(patientBirthDate);
- ++d->PatientsAddedDuringImport;
- }
- //----------------------------------------------------------------------------
- void ctkDICOMBrowser::onStudyAdded(QString studyUID)
- {
- Q_D(ctkDICOMBrowser);
- Q_UNUSED(studyUID);
- ++d->StudiesAddedDuringImport;
- }
- //----------------------------------------------------------------------------
- void ctkDICOMBrowser::onSeriesAdded(QString seriesUID)
- {
- Q_D(ctkDICOMBrowser);
- Q_UNUSED(seriesUID);
- ++d->SeriesAddedDuringImport;
- }
- //----------------------------------------------------------------------------
- void ctkDICOMBrowser::onInstanceAdded(QString instanceUID)
- {
- Q_D(ctkDICOMBrowser);
- Q_UNUSED(instanceUID);
- ++d->InstancesAddedDuringImport;
- }
- //----------------------------------------------------------------------------
- void ctkDICOMBrowser::onImportDirectories(QStringList directories)
- {
- foreach (const QString& directory, directories)
- {
- this->onImportDirectory(directory);
- }
- }
- //----------------------------------------------------------------------------
- void ctkDICOMBrowser::onImportDirectory(QString directory)
- {
- Q_D(ctkDICOMBrowser);
- if (QDir(directory).exists())
- {
- QString targetDirectory;
- QCheckBox* copyOnImport = qobject_cast<QCheckBox*>(d->ImportDialog->bottomWidget());
- 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);
- importTypeDialog.addButton("Copy",QMessageBox::AcceptRole);
- importTypeDialog.addButton("Add Link",QMessageBox::RejectRole);
- importTypeDialog.setDontShowAgainSettingsKey( "MainWindow/DontConfirmCopyOnImport" );
- int selection = importTypeDialog.exec();
- if (selection== QMessageBox::AcceptRole)
- {
- copyOnImport->setCheckState(Qt::Checked);
- }
- else
- {
- copyOnImport->setCheckState(Qt::Unchecked);
- }
- // reset counts
- d->PatientsAddedDuringImport = 0;
- d->StudiesAddedDuringImport = 0;
- d->SeriesAddedDuringImport = 0;
- d->InstancesAddedDuringImport = 0;
- if (copyOnImport->checkState() == Qt::Checked)
- {
- targetDirectory = d->DICOMDatabase->databaseDirectory();
- }
- // 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);
- }
- }
- }
- //----------------------------------------------------------------------------
- void ctkDICOMBrowser::onModelSelected(const QItemSelection &item1, const QItemSelection &item2)
- {
- Q_UNUSED(item1);
- Q_UNUSED(item2);
- Q_D(ctkDICOMBrowser);
- d->ActionRemove->setEnabled(true);
- }
- //----------------------------------------------------------------------------
- bool ctkDICOMBrowser::confirmDeleteSelectedUIDs(QStringList uids)
- {
- Q_D(ctkDICOMBrowser);
- if (uids.isEmpty())
- {
- return false;
- }
- ctkMessageBox confirmDeleteDialog;
- QString message("Do you want to delete the following selected items?");
- // add the information about the selected UIDs
- int numUIDs = uids.size();
- for (int i = 0; i < numUIDs; ++i)
- {
- QString uid = uids.at(i);
- // try using the given UID to find a descriptive string
- QString patientName = d->DICOMDatabase->nameForPatient(uid);
- QString studyDescription = d->DICOMDatabase->descriptionForStudy(uid);
- QString seriesDescription = d->DICOMDatabase->descriptionForSeries(uid);
- if (!patientName.isEmpty())
- {
- message += QString("\n") + patientName;
- }
- else if (!studyDescription.isEmpty())
- {
- message += QString("\n") + studyDescription;
- }
- else if (!seriesDescription.isEmpty())
- {
- message += QString("\n") + seriesDescription;
- }
- else
- {
- // if all other descriptors are empty, use the UID
- message += QString("\n") + uid;
- }
- }
- confirmDeleteDialog.setText(message);
- confirmDeleteDialog.setIcon(QMessageBox::Question);
- confirmDeleteDialog.addButton("Delete", QMessageBox::AcceptRole);
- confirmDeleteDialog.addButton("Cancel", QMessageBox::RejectRole);
- confirmDeleteDialog.setDontShowAgainSettingsKey( "MainWindow/DontConfirmDeleteSelected");
- int response = confirmDeleteDialog.exec();
- if (response == QMessageBox::AcceptRole)
- {
- return true;
- }
- else
- {
- return false;
- }
- }
- //----------------------------------------------------------------------------
- void ctkDICOMBrowser::onPatientsRightClicked(const QPoint &point)
- {
- Q_D(ctkDICOMBrowser);
- // get the list of patients that are selected
- QStringList selectedPatientsUIDs = d->dicomTableManager->currentPatientsSelection();
- int numPatients = selectedPatientsUIDs.size();
- if (numPatients == 0)
- {
- qDebug() << "No patients selected!";
- return;
- }
- QMenu *patientsMenu = new QMenu(d->dicomTableManager);
- QString deleteString = QString("Delete ")
- + QString::number(numPatients)
- + QString(" selected patients");
- QAction *deleteAction = new QAction(deleteString, patientsMenu);
- patientsMenu->addAction(deleteAction);
- QString exportString = QString("Export ")
- + QString::number(numPatients)
- + QString(" selected patients to file system");
- QAction *exportAction = new QAction(exportString, patientsMenu);
- patientsMenu->addAction(exportAction);
- // the table took care of mapping it to a global position so that the
- // menu will pop up at the correct place over this table.
- QAction *selectedAction = patientsMenu->exec(point);
- if (selectedAction == deleteAction
- && this->confirmDeleteSelectedUIDs(selectedPatientsUIDs))
- {
- qDebug() << "Deleting " << numPatients << " patients";
- foreach (const QString& uid, selectedPatientsUIDs)
- {
- d->DICOMDatabase->removePatient(uid);
- d->dicomTableManager->updateTableViews();
- }
- }
- else if (selectedAction == exportAction)
- {
- ctkFileDialog* directoryDialog = new ctkFileDialog();
- directoryDialog->setOption(QFileDialog::DontUseNativeDialog);
- directoryDialog->setOption(QFileDialog::ShowDirsOnly);
- directoryDialog->setFileMode(QFileDialog::DirectoryOnly);
- bool res = directoryDialog->exec();
- if (res)
- {
- QStringList dirs = directoryDialog->selectedFiles();
- QString dirPath = dirs[0];
- this->exportSelectedPatients(dirPath, selectedPatientsUIDs);
- }
- delete directoryDialog;
- }
- }
- //----------------------------------------------------------------------------
- void ctkDICOMBrowser::onStudiesRightClicked(const QPoint &point)
- {
- Q_D(ctkDICOMBrowser);
- // get the list of studies that are selected
- QStringList selectedStudiesUIDs = d->dicomTableManager->currentStudiesSelection();
- int numStudies = selectedStudiesUIDs.size();
- if (numStudies == 0)
- {
- qDebug() << "No studies selected!";
- return;
- }
- QMenu *studiesMenu = new QMenu(d->dicomTableManager);
- QString deleteString = QString("Delete ")
- + QString::number(numStudies)
- + QString(" selected studies");
- QAction *deleteAction = new QAction(deleteString, studiesMenu);
- studiesMenu->addAction(deleteAction);
- QString exportString = QString("Export ")
- + QString::number(numStudies)
- + QString(" selected studies to file system");
- QAction *exportAction = new QAction(exportString, studiesMenu);
- studiesMenu->addAction(exportAction);
- // the table took care of mapping it to a global position so that the
- // menu will pop up at the correct place over this table.
- QAction *selectedAction = studiesMenu->exec(point);
- if (selectedAction == deleteAction
- && this->confirmDeleteSelectedUIDs(selectedStudiesUIDs))
- {
- foreach (const QString& uid, selectedStudiesUIDs)
- {
- d->DICOMDatabase->removeStudy(uid);
- d->dicomTableManager->updateTableViews();
- }
- }
- else if (selectedAction == exportAction)
- {
- ctkFileDialog* directoryDialog = new ctkFileDialog();
- directoryDialog->setOption(QFileDialog::DontUseNativeDialog);
- directoryDialog->setOption(QFileDialog::ShowDirsOnly);
- directoryDialog->setFileMode(QFileDialog::DirectoryOnly);
- bool res = directoryDialog->exec();
- if (res)
- {
- QStringList dirs = directoryDialog->selectedFiles();
- QString dirPath = dirs[0];
- this->exportSelectedStudies(dirPath, selectedStudiesUIDs);
- }
- delete directoryDialog;
- }
- }
- //----------------------------------------------------------------------------
- void ctkDICOMBrowser::onSeriesRightClicked(const QPoint &point)
- {
- Q_D(ctkDICOMBrowser);
- // get the list of series that are selected
- QStringList selectedSeriesUIDs = d->dicomTableManager->currentSeriesSelection();
- int numSeries = selectedSeriesUIDs.size();
- if (numSeries == 0)
- {
- qDebug() << "No series selected!";
- return;
- }
- QMenu *seriesMenu = new QMenu(d->dicomTableManager);
- QString deleteString = QString("Delete ")
- + QString::number(numSeries)
- + QString(" selected series");
- QAction *deleteAction = new QAction(deleteString, seriesMenu);
- seriesMenu->addAction(deleteAction);
- QString exportString = QString("Export ")
- + QString::number(numSeries)
- + QString(" selected series to file system");
- QAction *exportAction = new QAction(exportString, seriesMenu);
- seriesMenu->addAction(exportAction);
- // the table took care of mapping it to a global position so that the
- // menu will pop up at the correct place over this table.
- QAction *selectedAction = seriesMenu->exec(point);
- if (selectedAction == deleteAction
- && this->confirmDeleteSelectedUIDs(selectedSeriesUIDs))
- {
- foreach (const QString& uid, selectedSeriesUIDs)
- {
- d->DICOMDatabase->removeSeries(uid);
- d->dicomTableManager->updateTableViews();
- }
- }
- else if (selectedAction == exportAction)
- {
- ctkFileDialog* directoryDialog = new ctkFileDialog();
- directoryDialog->setOption(QFileDialog::DontUseNativeDialog);
- directoryDialog->setOption(QFileDialog::ShowDirsOnly);
- directoryDialog->setFileMode(QFileDialog::DirectoryOnly);
- bool res = directoryDialog->exec();
- if (res)
- {
- QStringList dirs = directoryDialog->selectedFiles();
- QString dirPath = dirs[0];
- this->exportSelectedSeries(dirPath, selectedSeriesUIDs);
- }
- delete directoryDialog;
- }
- }
- //----------------------------------------------------------------------------
- void ctkDICOMBrowser::exportSelectedSeries(QString dirPath, QStringList uids)
- {
- Q_D(ctkDICOMBrowser);
- foreach (const QString& uid, uids)
- {
- QStringList filesForSeries = d->DICOMDatabase->filesForSeries(uid);
- // Use the first file to get the overall series information
- QString firstFilePath = filesForSeries[0];
- QHash<QString,QString> descriptions (d->DICOMDatabase->descriptionsForFile(firstFilePath));
- QString patientName = descriptions["PatientsName"];
- QString patientIDTag = QString("0010,0020");
- QString patientID = d->DICOMDatabase->fileValue(firstFilePath, patientIDTag);
- QString studyDescription = descriptions["StudyDescription"];
- QString seriesDescription = descriptions["SeriesDescription"];
- QString studyDateTag = QString("0008,0020");
- QString studyDate = d->DICOMDatabase->fileValue(firstFilePath,studyDateTag);
- QString seriesNumberTag = QString("0020,0011");
- QString seriesNumber = d->DICOMDatabase->fileValue(firstFilePath,seriesNumberTag);
- QString sep = "/";
- QString nameSep = "-";
- QString destinationDir = dirPath + sep + patientID;
- if (!patientName.isEmpty())
- {
- destinationDir += nameSep + patientName;
- }
- destinationDir += sep + studyDate;
- if (!studyDescription.isEmpty())
- {
- destinationDir += nameSep + studyDescription;
- }
- destinationDir += sep + seriesNumber;
- if (!seriesDescription.isEmpty())
- {
- destinationDir += nameSep + seriesDescription;
- }
- destinationDir += sep;
- // make sure only ascii characters are in the directory path
- destinationDir = destinationDir.toLatin1();
- // replace any question marks that were used as replacements for non ascii
- // characters with underscore
- destinationDir.replace("?", "_");
- // create the destination directory if necessary
- if (!QDir().exists(destinationDir))
- {
- if (!QDir().mkpath(destinationDir))
- {
- QString errorString =
- QString("Unable to create export destination directory:\n\n")
- + destinationDir
- + QString("\n\nHalting export.");
- ctkMessageBox createDirectoryErrorMessageBox;
- createDirectoryErrorMessageBox.setText(errorString);
- createDirectoryErrorMessageBox.setIcon(QMessageBox::Warning);
- createDirectoryErrorMessageBox.exec();
- return;
- }
- }
- // show progress
- if (d->ExportProgress == 0)
- {
- d->ExportProgress = new QProgressDialog(this->tr("DICOM Export"), "Close", 0, 100, this, Qt::WindowTitleHint | Qt::WindowSystemMenuHint);
- d->ExportProgress->setWindowModality(Qt::ApplicationModal);
- d->ExportProgress->setMinimumDuration(0);
- }
- QLabel *exportLabel = new QLabel(this->tr("Exporting series ") + seriesNumber);
- d->ExportProgress->setLabel(exportLabel);
- d->ExportProgress->setValue(0);
- int fileNumber = 0;
- int numFiles = filesForSeries.size();
- d->ExportProgress->setMaximum(numFiles);
- foreach (const QString& filePath, filesForSeries)
- {
- QString destinationFileName = destinationDir;
- QString fileNumberString;
- // sequentially number the files
- fileNumberString.sprintf("%06d", fileNumber);
- destinationFileName += fileNumberString + QString(".dcm");
- // replace non ASCII characters
- destinationFileName = destinationFileName.toLatin1();
- // replace any question marks that were used as replacements for non ascii
- // characters with underscore
- destinationFileName.replace("?", "_");
- if (!QFile::exists(filePath))
- {
- d->ExportProgress->setValue(numFiles);
- QString errorString = QString("Export source file not found:\n\n")
- + filePath
- + QString("\n\nHalting export.\n\nError may be fixed via Repair.");
- ctkMessageBox copyErrorMessageBox;
- copyErrorMessageBox.setText(errorString);
- copyErrorMessageBox.setIcon(QMessageBox::Warning);
- copyErrorMessageBox.exec();
- return;
- }
- if (QFile::exists(destinationFileName))
- {
- d->ExportProgress->setValue(numFiles);
- QString errorString = QString("Export destination file already exists:\n\n")
- + destinationFileName
- + QString("\n\nHalting export.");
- ctkMessageBox copyErrorMessageBox;
- copyErrorMessageBox.setText(errorString);
- copyErrorMessageBox.setIcon(QMessageBox::Warning);
- copyErrorMessageBox.exec();
- return;
- }
- bool copyResult = QFile::copy(filePath, destinationFileName);
- if (!copyResult)
- {
- d->ExportProgress->setValue(numFiles);
- QString errorString = QString("Failed to copy\n\n")
- + filePath
- + QString("\n\nto\n\n")
- + destinationFileName
- + QString("\n\nHalting export.");
- ctkMessageBox copyErrorMessageBox;
- copyErrorMessageBox.setText(errorString);
- copyErrorMessageBox.setIcon(QMessageBox::Warning);
- copyErrorMessageBox.exec();
- return;
- }
- fileNumber++;
- d->ExportProgress->setValue(fileNumber);
- }
- d->ExportProgress->setValue(numFiles);
- }
- }
- //----------------------------------------------------------------------------
- void ctkDICOMBrowser::exportSelectedStudies(QString dirPath, QStringList uids)
- {
- Q_D(ctkDICOMBrowser);
- foreach (const QString& uid, uids)
- {
- QStringList seriesUIDs = d->DICOMDatabase->seriesForStudy(uid);
- this->exportSelectedSeries(dirPath, seriesUIDs);
- }
- }
- //----------------------------------------------------------------------------
- void ctkDICOMBrowser::exportSelectedPatients(QString dirPath, QStringList uids)
- {
- Q_D(ctkDICOMBrowser);
- foreach (const QString& uid, uids)
- {
- QStringList studiesUIDs = d->DICOMDatabase->studiesForPatient(uid);
- this->exportSelectedStudies(dirPath, studiesUIDs);
- }
- }
|