diff --git a/Libs/DICOM/Core/ctkDICOMScheduler.cpp b/Libs/DICOM/Core/ctkDICOMScheduler.cpp index bc95419df6..38674c8d26 100644 --- a/Libs/DICOM/Core/ctkDICOMScheduler.cpp +++ b/Libs/DICOM/Core/ctkDICOMScheduler.cpp @@ -899,7 +899,6 @@ void ctkDICOMScheduler::stopJobsByDICOMUIDs(const QStringList& patientIDs, continue; } - ctkDICOMInserterJob* inserterJob = qobject_cast(job.data()); if ((!dicomJob->patientID().isEmpty() && patientIDs.contains(dicomJob->patientID())) || (!dicomJob->studyInstanceUID().isEmpty() && studyInstanceUIDs.contains(dicomJob->studyInstanceUID())) || (!dicomJob->seriesInstanceUID().isEmpty() && seriesInstanceUIDs.contains(dicomJob->seriesInstanceUID())) || @@ -907,10 +906,6 @@ void ctkDICOMScheduler::stopJobsByDICOMUIDs(const QStringList& patientIDs, { jobsUIDs.append(dicomJob->jobUID()); } - else if (inserterJob) - { - jobsUIDs.append(dicomJob->jobUID()); - } } } diff --git a/Libs/DICOM/Widgets/ctkDICOMSeriesItemWidget.cpp b/Libs/DICOM/Widgets/ctkDICOMSeriesItemWidget.cpp index 310a98ab6a..b39be6a2bf 100644 --- a/Libs/DICOM/Widgets/ctkDICOMSeriesItemWidget.cpp +++ b/Libs/DICOM/Widgets/ctkDICOMSeriesItemWidget.cpp @@ -40,7 +40,6 @@ #include "ctkDICOMJob.h" #include "ctkDICOMJobResponseSet.h" #include "ctkDICOMScheduler.h" -#include "ctkDICOMStudyItemWidget.h" #include "ctkDICOMThumbnailGenerator.h" // ctkDICOMWidgets includes @@ -69,7 +68,7 @@ class ctkDICOMSeriesItemWidgetPrivate : public Ui_ctkDICOMSeriesItemWidget ctkDICOMSeriesItemWidgetPrivate(ctkDICOMSeriesItemWidget& obj); ~ctkDICOMSeriesItemWidgetPrivate(); - void init(ctkDICOMStudyItemWidget* top); + void init(QWidget* top); void connectToTop(); void disconnectFromTop(); QString getDICOMCenterFrameFromInstances(QStringList instancesList); @@ -90,7 +89,7 @@ class ctkDICOMSeriesItemWidgetPrivate : public Ui_ctkDICOMSeriesItemWidget QSharedPointer DicomDatabase; QSharedPointer Scheduler; - QSharedPointer StudyWidget; + QSharedPointer StudyWidget; QMap Connections; QStringList AllowedServers; @@ -163,12 +162,12 @@ ctkDICOMSeriesItemWidgetPrivate::~ctkDICOMSeriesItemWidgetPrivate() } //---------------------------------------------------------------------------- -void ctkDICOMSeriesItemWidgetPrivate::init(ctkDICOMStudyItemWidget* top) +void ctkDICOMSeriesItemWidgetPrivate::init(QWidget* top) { Q_Q(ctkDICOMSeriesItemWidget); this->setupUi(q); - this->StudyWidget = QSharedPointer(top, skipDelete); + this->StudyWidget = QSharedPointer(top, skipDelete); this->connectToTop(); this->SeriesThumbnail->setTransformationMode(Qt::TransformationMode::SmoothTransformation); @@ -744,7 +743,7 @@ void ctkDICOMSeriesItemWidgetPrivate::updateRetrieveUIOnFinished() // ctkDICOMSeriesItemWidget methods //---------------------------------------------------------------------------- -ctkDICOMSeriesItemWidget::ctkDICOMSeriesItemWidget(ctkDICOMStudyItemWidget* top, QWidget* parent) +ctkDICOMSeriesItemWidget::ctkDICOMSeriesItemWidget(QWidget* top, QWidget* parent) : Superclass(parent) , d_ptr(new ctkDICOMSeriesItemWidgetPrivate(*this)) { @@ -810,7 +809,7 @@ void ctkDICOMSeriesItemWidget::forceRetrieve() { Q_D(ctkDICOMSeriesItemWidget); - d->IsCloud = false; + d->IsCloud = true; d->RetrieveFailed = false; d->StopJobs = false; d->DicomDatabase->removeSeries(d->SeriesInstanceUID, false, false); diff --git a/Libs/DICOM/Widgets/ctkDICOMSeriesItemWidget.h b/Libs/DICOM/Widgets/ctkDICOMSeriesItemWidget.h index a3b8026a2a..5931456003 100644 --- a/Libs/DICOM/Widgets/ctkDICOMSeriesItemWidget.h +++ b/Libs/DICOM/Widgets/ctkDICOMSeriesItemWidget.h @@ -60,8 +60,8 @@ class CTK_DICOM_WIDGETS_EXPORT ctkDICOMSeriesItemWidget : public QWidget public: typedef QWidget Superclass; - explicit ctkDICOMSeriesItemWidget(ctkDICOMStudyItemWidget* top = nullptr, - QWidget* parent = nullptr); + explicit ctkDICOMSeriesItemWidget(QWidget* top = nullptr, + QWidget* parent = nullptr); virtual ~ctkDICOMSeriesItemWidget(); ///@{ diff --git a/Libs/DICOM/Widgets/ctkDICOMStudyItemWidget.cpp b/Libs/DICOM/Widgets/ctkDICOMStudyItemWidget.cpp index 2f8c57bf64..a15f42d22c 100644 --- a/Libs/DICOM/Widgets/ctkDICOMStudyItemWidget.cpp +++ b/Libs/DICOM/Widgets/ctkDICOMStudyItemWidget.cpp @@ -37,7 +37,6 @@ #include "ctkDICOMScheduler.h" // ctkDICOMWidgets includes -#include "ctkDICOMPatientItemWidget.h" #include "ctkDICOMStudyItemWidget.h" #include "ui_ctkDICOMStudyItemWidget.h" @@ -65,7 +64,7 @@ class ctkDICOMStudyItemWidgetPrivate : public Ui_ctkDICOMStudyItemWidget ctkDICOMStudyItemWidgetPrivate(ctkDICOMStudyItemWidget& obj); ~ctkDICOMStudyItemWidgetPrivate(); - void init(ctkDICOMPatientItemWidget* parent, QWidget* root); + void init(QWidget* top, QWidget* parent); void connectToTop(); void disconnectFromTop(); void updateColumnsWidths(); @@ -84,7 +83,7 @@ class ctkDICOMStudyItemWidgetPrivate : public Ui_ctkDICOMStudyItemWidget QSharedPointer DicomDatabase; QSharedPointer Scheduler; - QSharedPointer PatientWidget; + QSharedPointer PatientWidget; QSharedPointer VisualDICOMBrowser; QMap Connections; @@ -149,12 +148,12 @@ ctkDICOMStudyItemWidgetPrivate::~ctkDICOMStudyItemWidgetPrivate() } //---------------------------------------------------------------------------- -void ctkDICOMStudyItemWidgetPrivate::init(ctkDICOMPatientItemWidget* top, QWidget* parent) +void ctkDICOMStudyItemWidgetPrivate::init(QWidget* top, QWidget* parent) { Q_Q(ctkDICOMStudyItemWidget); this->setupUi(q); - this->PatientWidget = QSharedPointer(top, skipDelete); + this->PatientWidget = QSharedPointer(top, skipDelete); this->connectToTop(); this->VisualDICOMBrowser = QSharedPointer(parent, skipDelete); @@ -453,7 +452,7 @@ ctkDICOMSeriesItemWidget* ctkDICOMStudyItemWidgetPrivate::isSeriesItemAlreadyAdd // ctkDICOMStudyItemWidget methods //---------------------------------------------------------------------------- -ctkDICOMStudyItemWidget::ctkDICOMStudyItemWidget(ctkDICOMPatientItemWidget* top, QWidget* parent) +ctkDICOMStudyItemWidget::ctkDICOMStudyItemWidget(QWidget* top, QWidget* parent) : Superclass(parent) , d_ptr(new ctkDICOMStudyItemWidgetPrivate(*this)) { diff --git a/Libs/DICOM/Widgets/ctkDICOMStudyItemWidget.h b/Libs/DICOM/Widgets/ctkDICOMStudyItemWidget.h index a868dbffae..2514f1431b 100644 --- a/Libs/DICOM/Widgets/ctkDICOMStudyItemWidget.h +++ b/Libs/DICOM/Widgets/ctkDICOMStudyItemWidget.h @@ -41,7 +41,6 @@ class ctkDICOMScheduler; // ctkDICOMWidgets includes #include "ctkDICOMSeriesItemWidget.h" -class ctkDICOMPatientItemWidget; class ctkDICOMSeriesItemWidget; class ctkDICOMStudyItemWidgetPrivate; @@ -68,7 +67,7 @@ class CTK_DICOM_WIDGETS_EXPORT ctkDICOMStudyItemWidget : public QWidget public: typedef QWidget Superclass; - explicit ctkDICOMStudyItemWidget(ctkDICOMPatientItemWidget* top = nullptr, + explicit ctkDICOMStudyItemWidget(QWidget* top = nullptr, QWidget* parent = nullptr); virtual ~ctkDICOMStudyItemWidget(); diff --git a/Libs/DICOM/Widgets/ctkDICOMVisualBrowserWidget.cpp b/Libs/DICOM/Widgets/ctkDICOMVisualBrowserWidget.cpp index a094c4bed2..10789143fb 100644 --- a/Libs/DICOM/Widgets/ctkDICOMVisualBrowserWidget.cpp +++ b/Libs/DICOM/Widgets/ctkDICOMVisualBrowserWidget.cpp @@ -250,6 +250,7 @@ class ctkDICOMVisualBrowserWidgetPrivate : public Ui_ctkDICOMVisualBrowserWidget QProgressDialog* UpdateSchemaProgress; QProgressDialog* ExportProgress; + QProgressDialog* LoadSeriesProgress; }; CTK_GET_CPP(ctkDICOMVisualBrowserWidget, QString, databaseDirectoryBase, DatabaseDirectoryBase); @@ -311,11 +312,14 @@ ctkDICOMVisualBrowserWidgetPrivate::ctkDICOMVisualBrowserWidgetPrivate(ctkDICOMV this->ExportProgress = nullptr; this->UpdateSchemaProgress = nullptr; + this->LoadSeriesProgress = nullptr; } //---------------------------------------------------------------------------- ctkDICOMVisualBrowserWidgetPrivate::~ctkDICOMVisualBrowserWidgetPrivate() { + this->ImportDialog->deleteLater(); + this->MetadataDialog->deleteLater(); this->removeAllPatientItemWidgets(); } @@ -968,6 +972,33 @@ void ctkDICOMVisualBrowserWidgetPrivate::retrieveSeries() this->IsLoading = true; + // Get only the selected series widgets + QList selectedSeriesWidgetsList; + QList studyItemWidgetsList = currentPatientItemWidget->studyItemWidgetsList(); + foreach (ctkDICOMStudyItemWidget* studyItemWidget, studyItemWidgetsList) + { + QTableWidget* seriesListTableWidget = studyItemWidget->seriesListTableWidget(); + QModelIndexList indexList = seriesListTableWidget->selectionModel()->selectedIndexes(); + foreach (QModelIndex index, indexList) + { + ctkDICOMSeriesItemWidget* seriesItemWidget = qobject_cast + (seriesListTableWidget->cellWidget(index.row(), index.column())); + if (!seriesItemWidget) + { + continue; + } + + selectedSeriesWidgetsList.append(seriesItemWidget); + } + } + + if (selectedSeriesWidgetsList.count() == 0) + { + this->IsLoading = false; + return; + } + + // Get all series widgets QList seriesWidgetsList; for (int patientIndex = 0; patientIndex < this->PatientsTabWidget->count(); ++patientIndex) { @@ -999,31 +1030,7 @@ void ctkDICOMVisualBrowserWidgetPrivate::retrieveSeries() } } - QList selectedSeriesWidgetsList; - QList studyItemWidgetsList = currentPatientItemWidget->studyItemWidgetsList(); - foreach (ctkDICOMStudyItemWidget* studyItemWidget, studyItemWidgetsList) - { - QTableWidget* seriesListTableWidget = studyItemWidget->seriesListTableWidget(); - QModelIndexList indexList = seriesListTableWidget->selectionModel()->selectedIndexes(); - foreach (QModelIndex index, indexList) - { - ctkDICOMSeriesItemWidget* seriesItemWidget = qobject_cast - (seriesListTableWidget->cellWidget(index.row(), index.column())); - if (!seriesItemWidget) - { - continue; - } - - selectedSeriesWidgetsList.append(seriesItemWidget); - } - } - - if (selectedSeriesWidgetsList.count() == 0) - { - this->IsLoading = false; - return; - } - + // Update UI QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); bool deleteActionWasVisible = this->DeleteActionVisible; @@ -1032,8 +1039,9 @@ void ctkDICOMVisualBrowserWidgetPrivate::retrieveSeries() bool queryPatientButtonWasEnabled = this->SearchMenuButton->isEnabled(); this->SearchMenuButton->setEnabled(false); + // Set a flag in non selected series widget to stop any jobs creation + // and stop all the jobs connected to the widgets QStringList seriesInstanceUIDsToStop; - QStringList selectedSeriesInstanceUIDs; foreach (ctkDICOMSeriesItemWidget* seriesItemWidget, seriesWidgetsList) { if (!seriesItemWidget) @@ -1046,23 +1054,63 @@ void ctkDICOMVisualBrowserWidgetPrivate::retrieveSeries() seriesItemWidget->setStopJobs(true); seriesInstanceUIDsToStop.append(seriesItemWidget->seriesInstanceUID()); } - else + } + + this->Scheduler->stopJobsByDICOMUIDs({}, {}, seriesInstanceUIDsToStop); + this->Scheduler->waitForDone(300); + + // Check all the selected series widgets. If any widgets is not fully retrieved or the retrieve failed, + // and no jobs are running for the series, force the retrieve. + foreach (ctkDICOMSeriesItemWidget* seriesItemWidget, selectedSeriesWidgetsList) + { + if (!seriesItemWidget) { - selectedSeriesInstanceUIDs.append(seriesItemWidget->seriesInstanceUID()); + continue; + } + + if (!seriesItemWidget->isCloud() && !seriesItemWidget->retrieveFailed()) + { + continue; + } + + if (this->Scheduler->getJobsByDICOMUIDs({}, {}, {seriesItemWidget->seriesInstanceUID()}).count() == 0) + { + seriesItemWidget->forceRetrieve(); } } - this->Scheduler->stopJobsByDICOMUIDs({}, - {}, - seriesInstanceUIDsToStop); + // Create a progress dialog to show the progress of the retrieve + if (this->LoadSeriesProgress == 0) + { + this->LoadSeriesProgress = new QProgressDialog( + ctkDICOMVisualBrowserWidget::tr("Retrieving and processing selected series..."), + ctkDICOMVisualBrowserWidget::tr("Cancel"), 0, 100, q); + this->LoadSeriesProgress->setWindowModality(Qt::ApplicationModal); + this->LoadSeriesProgress->setMinimumDuration(0); + this->LoadSeriesProgress->setAutoClose(false); + this->LoadSeriesProgress->setAutoReset(false); - this->Scheduler->waitForDone(300); + QProgressBar *bar = new QProgressBar(this->LoadSeriesProgress); + bar->setTextVisible(false); + this->LoadSeriesProgress->setBar(bar); + } + // Wait for the selected series widgets to be fully retrieved + this->LoadSeriesProgress->show(); bool wait = true; + int progress = 0; while (wait) { - QCoreApplication::processEvents(); + qApp->processEvents(); this->Scheduler->waitForDone(300); + + progress++; + if (progress == 100) + { + progress = 0; + } + this->LoadSeriesProgress->setValue(progress); + wait = false; foreach (ctkDICOMSeriesItemWidget* seriesItemWidget, selectedSeriesWidgetsList) { @@ -1071,17 +1119,77 @@ void ctkDICOMVisualBrowserWidgetPrivate::retrieveSeries() continue; } + if (this->LoadSeriesProgress->wasCanceled()) + { + break; + } + if (seriesItemWidget->isCloud() && !seriesItemWidget->retrieveFailed()) { wait = true; break; } } + + if (this->LoadSeriesProgress->wasCanceled()) + { + break; + } } + // Update UI this->updateFiltersWarnings(); this->configureSearchIcon(); + this->IsLoading = false; + this->DeleteActionVisible = deleteActionWasVisible; + this->SearchMenuButton->setEnabled(queryPatientButtonWasEnabled); + QApplication::restoreOverrideCursor(); + + // Finalize the retrieve + QStringList selectedSeriesInstanceUIDs; + if (this->LoadSeriesProgress->wasCanceled()) + { + // It was canceled -> stop the jobs connected to the selected series widgets + foreach (ctkDICOMSeriesItemWidget* seriesItemWidget, selectedSeriesWidgetsList) + { + if (!seriesItemWidget) + { + continue; + } + + selectedSeriesInstanceUIDs.append(seriesItemWidget->seriesInstanceUID()); + } + + this->Scheduler->stopJobsByDICOMUIDs({}, {}, selectedSeriesInstanceUIDs); + this->Scheduler->waitForDone(300); + } + else + { + foreach (ctkDICOMSeriesItemWidget* seriesItemWidget, selectedSeriesWidgetsList) + { + // If the series was not fully retrieved or the retrieve failed -> skip + if (!seriesItemWidget || seriesItemWidget->isCloud() || seriesItemWidget->retrieveFailed()) + { + continue; + } + + // If the series has only metadata -> skip + if (this->DicomDatabase->instancesForSeries(seriesItemWidget->seriesInstanceUID()).count() == 0) + { + continue; + } + + selectedSeriesInstanceUIDs.append(seriesItemWidget->seriesInstanceUID()); + } + + q->emit seriesRetrieved(selectedSeriesInstanceUIDs); + } + + this->LoadSeriesProgress->reset(); + this->LoadSeriesProgress->hide(); + + // Re-allow all seriesItemWidgets to run jobs foreach (ctkDICOMSeriesItemWidget* seriesItemWidget, seriesWidgetsList) { if (!seriesItemWidget) @@ -1091,13 +1199,6 @@ void ctkDICOMVisualBrowserWidgetPrivate::retrieveSeries() seriesItemWidget->setStopJobs(false); } - - q->emit seriesRetrieved(selectedSeriesInstanceUIDs); - - this->IsLoading = false; - this->DeleteActionVisible = deleteActionWasVisible; - this->SearchMenuButton->setEnabled(queryPatientButtonWasEnabled); - QApplication::restoreOverrideCursor(); } //---------------------------------------------------------------------------- @@ -1697,13 +1798,7 @@ ctkDICOMVisualBrowserWidget::ctkDICOMVisualBrowserWidget(QWidget* parentWidget) } //---------------------------------------------------------------------------- -ctkDICOMVisualBrowserWidget::~ctkDICOMVisualBrowserWidget() -{ - Q_D(ctkDICOMVisualBrowserWidget); - - d->ImportDialog->deleteLater(); - d->MetadataDialog->deleteLater(); -} +ctkDICOMVisualBrowserWidget::~ctkDICOMVisualBrowserWidget() = default; //---------------------------------------------------------------------------- CTK_GET_CPP(ctkDICOMVisualBrowserWidget, QString, databaseDirectory, DatabaseDirectory);