12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229 |
- /*=========================================================================
- 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 <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>
- // 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();
- void importDirectory(QString directory, ctkDICOMBrowser::ImportDirectoryMode mode);
- void importOldSettings();
- 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;
- };
- //----------------------------------------------------------------------------
- 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)
- {
- ImportDialog = 0;
- QueryRetrieveWidget = 0;
- 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);
- qRegisterMetaType<ctkDICOMBrowser::ImportDirectoryMode>("ctkDICOMBrowser::ImportDirectoryMode");
- 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(Self::databaseDirectorySettingsKey(), "") == "" )
- {
- settings.setValue(Self::databaseDirectorySettingsKey(), QString("./ctkDICOM-Database"));
- settings.sync();
- }
- QString databaseDirectory = this->databaseDirectory();
- 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 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);
- layout->setContentsMargins(0, 0, 0, 0);
- QWidget* importDirectoryBottomWidget = new QWidget();
- importDirectoryBottomWidget->setLayout(layout);
- // Default values
- importDirectoryModeComboBox->setCurrentIndex(
- importDirectoryModeComboBox->findData(this->importDirectoryMode()));
- //Initialize import widget
- d->ImportDialog = new ctkFileDialog();
- d->ImportDialog->setBottomWidget(importDirectoryBottomWidget);
- 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(onImportDirectoriesSelected(QStringList)));
- connect(importDirectoryModeComboBox, SIGNAL(currentIndexChanged(int)),
- this, SLOT(onImportDirectoryComboBoxCurrentIndexChanged(int)));
- 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);
- // If needed, create database directory
- if (!QDir(directory).exists())
- {
- QDir().mkdir(directory);
- }
- QSettings settings;
- settings.setValue(Self::databaseDirectorySettingsKey(), 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
- {
- return QSettings().value(Self::databaseDirectorySettingsKey()).toString();
- }
- //------------------------------------------------------------------------------
- QString ctkDICOMBrowser::databaseDirectorySettingsKey()
- {
- return QLatin1String("DatabaseDirectory");
- }
- //------------------------------------------------------------------------------
- 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::onImportDirectoriesSelected(QStringList directories)
- {
- Q_D(ctkDICOMBrowser);
- this->importDirectories(directories, this->importDirectoryMode());
- // Clear selection
- d->ImportDialog->clearSelection();
- }
- //----------------------------------------------------------------------------
- void ctkDICOMBrowser::onImportDirectoryComboBoxCurrentIndexChanged(int index)
- {
- Q_D(ctkDICOMBrowser);
- Q_UNUSED(index);
- QComboBox* comboBox = d->ImportDialog->bottomWidget()->findChild<QComboBox*>();
- ctkDICOMBrowser::ImportDirectoryMode mode =
- static_cast<ctkDICOMBrowser::ImportDirectoryMode>(comboBox->itemData(index).toInt());
- this->setImportDirectoryMode(mode);
- }
- //----------------------------------------------------------------------------
- void ctkDICOMBrowser::importDirectories(QStringList directories, ctkDICOMBrowser::ImportDirectoryMode mode)
- {
- Q_D(ctkDICOMBrowser);
- ctkDICOMImportStats stats(d);
- if (!d->DICOMDatabase || !d->DICOMIndexer)
- {
- qWarning() << Q_FUNC_INFO << " failed: database or indexer is invalid";
- return;
- }
- // Only emit one indexingComplete event, when all imports have been completed
- ctkDICOMIndexer::ScopedIndexing indexingBatch(*d->DICOMIndexer, *d->DICOMDatabase);
- foreach (const QString& directory, directories)
- {
- d->importDirectory(directory, mode);
- }
- if (d->DisplayImportSummary)
- {
- QMessageBox::information(d->ImportDialog,"DICOM Directory Import", stats.summary());
- }
- }
- //----------------------------------------------------------------------------
- void ctkDICOMBrowser::importDirectory(QString directory, ctkDICOMBrowser::ImportDirectoryMode mode)
- {
- Q_D(ctkDICOMBrowser);
- ctkDICOMImportStats stats(d);
- d->importDirectory(directory, mode);
- if (d->DisplayImportSummary)
- {
- QMessageBox::information(d->ImportDialog,"DICOM Directory Import", stats.summary());
- }
- }
- //----------------------------------------------------------------------------
- void ctkDICOMBrowser::onImportDirectory(QString directory, ctkDICOMBrowser::ImportDirectoryMode mode)
- {
- this->importDirectory(directory, mode);
- }
- //----------------------------------------------------------------------------
- void ctkDICOMBrowserPrivate::importDirectory(QString directory, ctkDICOMBrowser::ImportDirectoryMode mode)
- {
- if (!QDir(directory).exists())
- {
- return;
- }
- QString targetDirectory;
- if (mode == ctkDICOMBrowser::ImportDirectoryCopy)
- {
- targetDirectory = this->DICOMDatabase->databaseDirectory();
- }
- // show progress dialog and perform indexing
- this->showIndexerDialog();
- this->DICOMIndexer->addDirectory(*this->DICOMDatabase, directory, targetDirectory);
- }
- //----------------------------------------------------------------------------
- void ctkDICOMBrowserPrivate::importOldSettings()
- {
- // Backward compatibility
- QSettings settings;
- int dontConfirmCopyOnImport = settings.value("MainWindow/DontConfirmCopyOnImport", static_cast<int>(QMessageBox::InvalidRole)).toInt();
- if (dontConfirmCopyOnImport == QMessageBox::AcceptRole)
- {
- settings.setValue("DICOM/ImportDirectoryMode", static_cast<int>(ctkDICOMBrowser::ImportDirectoryCopy));
- }
- settings.remove("MainWindow/DontConfirmCopyOnImport");
- }
- //----------------------------------------------------------------------------
- ctkFileDialog* ctkDICOMBrowser::importDialog() const
- {
- Q_D(const ctkDICOMBrowser);
- return d->ImportDialog;
- }
- //----------------------------------------------------------------------------
- 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());
- }
- //----------------------------------------------------------------------------
- void ctkDICOMBrowser::setImportDirectoryMode(ctkDICOMBrowser::ImportDirectoryMode mode)
- {
- Q_D(ctkDICOMBrowser);
- QSettings settings;
- settings.setValue("DICOM/ImportDirectoryMode", static_cast<int>(mode));
- if (!d->ImportDialog)
- {
- return;
- }
- QComboBox* comboBox = d->ImportDialog->bottomWidget()->findChild<QComboBox*>();
- comboBox->setCurrentIndex(comboBox->findData(mode));
- }
- //----------------------------------------------------------------------------
- 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);
- }
- }
|