From 13d243c7754b778be751324b2b7bf8de605676d6 Mon Sep 17 00:00:00 2001 From: Davide Punzo Date: Wed, 15 May 2024 19:57:28 +0200 Subject: [PATCH] BUG: Conceal empty patient and study widgets during filtering --- Libs/DICOM/Core/ctkDICOMQuery.cpp | 1 - Libs/DICOM/Core/ctkDICOMScheduler.h | 1 - .../Widgets/ctkDICOMPatientItemWidget.cpp | 25 +- .../DICOM/Widgets/ctkDICOMPatientItemWidget.h | 6 +- .../Widgets/ctkDICOMSeriesItemWidget.cpp | 46 ++-- Libs/DICOM/Widgets/ctkDICOMSeriesItemWidget.h | 2 +- .../DICOM/Widgets/ctkDICOMStudyItemWidget.cpp | 65 +++-- Libs/DICOM/Widgets/ctkDICOMStudyItemWidget.h | 13 +- .../Widgets/ctkDICOMVisualBrowserWidget.cpp | 228 +++++++++++++----- .../Widgets/ctkDICOMVisualBrowserWidget.h | 2 + 10 files changed, 278 insertions(+), 111 deletions(-) diff --git a/Libs/DICOM/Core/ctkDICOMQuery.cpp b/Libs/DICOM/Core/ctkDICOMQuery.cpp index e1152ca68e..d1ca7f2901 100644 --- a/Libs/DICOM/Core/ctkDICOMQuery.cpp +++ b/Libs/DICOM/Core/ctkDICOMQuery.cpp @@ -571,7 +571,6 @@ bool ctkDICOMQuery::queryPatients() { logger.warn(QString("ctkDICOMQuery: the number of responses of the query task at patients level " "surpassed the maximum value of permitted results (i.e. %1).").arg(d->MaximumPatientsQuery)); - break; } DcmDataset *dataset = (*it)->m_dataset; diff --git a/Libs/DICOM/Core/ctkDICOMScheduler.h b/Libs/DICOM/Core/ctkDICOMScheduler.h index a53296acff..3a98232b6e 100644 --- a/Libs/DICOM/Core/ctkDICOMScheduler.h +++ b/Libs/DICOM/Core/ctkDICOMScheduler.h @@ -190,7 +190,6 @@ class CTK_DICOM_CORE_EXPORT ctkDICOMScheduler : public ctkJobScheduler Q_INVOKABLE void runJobs(const QMap& jobDetails); Q_INVOKABLE void raiseJobsPriorityForSeries(const QStringList& selectedSeriesInstanceUIDs, QThread::Priority priority = QThread::HighestPriority); - ///@} ///@{ diff --git a/Libs/DICOM/Widgets/ctkDICOMPatientItemWidget.cpp b/Libs/DICOM/Widgets/ctkDICOMPatientItemWidget.cpp index 862189d315..61a6915eb4 100644 --- a/Libs/DICOM/Widgets/ctkDICOMPatientItemWidget.cpp +++ b/Libs/DICOM/Widgets/ctkDICOMPatientItemWidget.cpp @@ -70,7 +70,7 @@ class ctkDICOMPatientItemWidgetPrivate : public Ui_ctkDICOMPatientItemWidget QString formatDate(const QString&); bool isStudyItemAlreadyAdded(const QString& studyItem); void clearLayout(QLayout* layout, bool deleteWidgets = true); - void createStudies(bool queryRetrieve = true); + void createStudies(); void updateAllowedServersUIFromDB(); void setAllDeniedServerEnabledStatus(bool enabled); void saveAllowedServersStringListFromUI(); @@ -100,6 +100,8 @@ class ctkDICOMPatientItemWidgetPrivate : public Ui_ctkDICOMPatientItemWidget QStringList AllowedServers = QStringList(); bool IsGUIUpdating; + bool QueryOn; + bool RetrieveOn; }; //---------------------------------------------------------------------------- @@ -125,6 +127,8 @@ ctkDICOMPatientItemWidgetPrivate::ctkDICOMPatientItemWidgetPrivate(ctkDICOMPatie this->StudiesListVerticalSpacer = new QSpacerItem(0, 5, QSizePolicy::Fixed, QSizePolicy::Expanding); this->IsGUIUpdating = false; + this->QueryOn = true; + this->RetrieveOn = true; } //---------------------------------------------------------------------------- @@ -233,7 +237,7 @@ void ctkDICOMPatientItemWidgetPrivate::clearLayout(QLayout* layout, bool deleteW } //---------------------------------------------------------------------------- -void ctkDICOMPatientItemWidgetPrivate::createStudies(bool queryRetrieve) +void ctkDICOMPatientItemWidgetPrivate::createStudies() { Q_Q(ctkDICOMPatientItemWidget); if (this->IsGUIUpdating) @@ -269,6 +273,7 @@ void ctkDICOMPatientItemWidgetPrivate::createStudies(bool queryRetrieve) QStringList studiesList = this->DicomDatabase->studiesForPatient(this->PatientItem); if (studiesList.count() == 0) { + q->emit updateGUIFinished(); return; } @@ -369,7 +374,7 @@ void ctkDICOMPatientItemWidgetPrivate::createStudies(bool queryRetrieve) if (cont < this->NumberOfStudiesPerPatient) { studyItemWidget->setCollapsed(false); - studyItemWidget->generateSeries(queryRetrieve); + studyItemWidget->generateSeries(this->QueryOn, this->RetrieveOn); } cont++; @@ -388,6 +393,7 @@ void ctkDICOMPatientItemWidgetPrivate::createStudies(bool queryRetrieve) studiesListWidgetLayout->addItem(this->StudiesListVerticalSpacer); this->IsGUIUpdating = false; + q->emit updateGUIFinished(); } //---------------------------------------------------------------------------- @@ -761,6 +767,8 @@ void ctkDICOMPatientItemWidget::addStudyItemWidget(const QString& studyItem) this, SLOT(onSeriesItemClicked())); this->connect(studyItemWidget->seriesListTableWidget(), SIGNAL(itemSelectionChanged()), this, SLOT(raiseSelectedSeriesJobsPriority())); + this->connect(studyItemWidget, SIGNAL(updateGUIFinished()), + this, SIGNAL(updateGUIFinished())); d->StudyItemWidgetsList.append(studyItemWidget); } @@ -830,17 +838,22 @@ void ctkDICOMPatientItemWidget::updateAllowedServersUIFromDB() } //------------------------------------------------------------------------------ -void ctkDICOMPatientItemWidget::generateStudies(bool queryRetrieve) +void ctkDICOMPatientItemWidget::generateStudies(bool query, bool retrieve) { Q_D(ctkDICOMPatientItemWidget); - d->createStudies(queryRetrieve); - if (queryRetrieve && d->Scheduler && d->Scheduler->queryRetrieveServersCount() > 0) + d->QueryOn = query; + d->RetrieveOn = retrieve; + if (query && d->Scheduler && d->Scheduler->queryRetrieveServersCount() > 0) { d->Scheduler->queryStudies(d->PatientID, QThread::NormalPriority, d->AllowedServers); } + else + { + d->createStudies(); + } } //------------------------------------------------------------------------------ diff --git a/Libs/DICOM/Widgets/ctkDICOMPatientItemWidget.h b/Libs/DICOM/Widgets/ctkDICOMPatientItemWidget.h index 26faffd7ea..b57ad49ca7 100644 --- a/Libs/DICOM/Widgets/ctkDICOMPatientItemWidget.h +++ b/Libs/DICOM/Widgets/ctkDICOMPatientItemWidget.h @@ -178,13 +178,17 @@ class CTK_DICOM_WIDGETS_EXPORT ctkDICOMPatientItemWidget : public QWidget ///@} public Q_SLOTS: - void generateStudies(bool queryRetrieve = true); + void generateStudies(bool query = true, bool retrieve = true); void generateSeriesAtToggle(bool toggled = true, const QString& studyItem = ""); void updateGUIFromScheduler(const QVariant& data); void onSeriesItemClicked(); void raiseSelectedSeriesJobsPriority(); void onPatientServersCheckableComboBoxChanged(); +Q_SIGNALS: + /// Emitted when the GUI finished to update after a studies query. + void updateGUIFinished(); + protected: QScopedPointer d_ptr; diff --git a/Libs/DICOM/Widgets/ctkDICOMSeriesItemWidget.cpp b/Libs/DICOM/Widgets/ctkDICOMSeriesItemWidget.cpp index 08c735a93d..a0f0644f76 100644 --- a/Libs/DICOM/Widgets/ctkDICOMSeriesItemWidget.cpp +++ b/Libs/DICOM/Widgets/ctkDICOMSeriesItemWidget.cpp @@ -62,7 +62,7 @@ class ctkDICOMSeriesItemWidgetPrivate : public Ui_ctkDICOMSeriesItemWidget void init(); QString getDICOMCenterFrameFromInstances(QStringList instancesList); - void createThumbnail(ctkDICOMJobDetail td, bool queryRetrieve = true); + void createThumbnail(ctkDICOMJobDetail td); void drawModalityThumbnail(); void drawThumbnail(const QString& file, int numberOfFrames); void drawTextWithShadow(QPainter *painter, @@ -101,6 +101,9 @@ class ctkDICOMSeriesItemWidgetPrivate : public Ui_ctkDICOMSeriesItemWidget int NumberOfDownloads; QImage ThumbnailImage; bool isThumbnailDocument; + + bool QueryOn; + bool RetrieveOn; }; //---------------------------------------------------------------------------- @@ -133,6 +136,9 @@ ctkDICOMSeriesItemWidgetPrivate::ctkDICOMSeriesItemWidgetPrivate(ctkDICOMSeriesI this->DicomDatabase = nullptr; this->Scheduler = nullptr; + + this->QueryOn = true; + this->RetrieveOn = true; } //---------------------------------------------------------------------------- @@ -197,7 +203,7 @@ QString ctkDICOMSeriesItemWidgetPrivate::getDICOMCenterFrameFromInstances(QStrin } //---------------------------------------------------------------------------- -void ctkDICOMSeriesItemWidgetPrivate::createThumbnail(ctkDICOMJobDetail td, bool queryRetrieve) +void ctkDICOMSeriesItemWidgetPrivate::createThumbnail(ctkDICOMJobDetail td) { if (!this->DicomDatabase) { @@ -301,7 +307,7 @@ void ctkDICOMSeriesItemWidgetPrivate::createThumbnail(ctkDICOMJobDetail td, bool (jobType == ctkDICOMJobResponseSet::JobType::None || jobType == ctkDICOMJobResponseSet::JobType::QueryInstances)) { - if (queryRetrieve) + if (this->RetrieveOn) { this->Scheduler->retrieveSOPInstance(this->PatientID, this->StudyInstanceUID, @@ -326,7 +332,7 @@ void ctkDICOMSeriesItemWidgetPrivate::createThumbnail(ctkDICOMJobDetail td, bool this->Scheduler->getJobsByDICOMUIDs({}, {}, {this->SeriesInstanceUID}); - if (jobs.count() == 0 && queryRetrieve) + if (jobs.count() == 0 && this->RetrieveOn) { this->Scheduler->retrieveSeries(this->PatientID, this->StudyInstanceUID, @@ -417,7 +423,6 @@ void ctkDICOMSeriesItemWidgetPrivate::drawThumbnail(const QString& file, int num font.setPixelSize(textSize); QPixmap resultPixmap(scaledThumbnailSizePixel, scaledThumbnailSizePixel); - resultPixmap.fill(Qt::transparent); ctkDICOMThumbnailGenerator thumbnailGenerator; thumbnailGenerator.setWidth(scaledThumbnailSizePixel); @@ -425,7 +430,8 @@ void ctkDICOMSeriesItemWidgetPrivate::drawThumbnail(const QString& file, int num bool thumbnailGenerated = true; bool emptyThumbnailGenerated = false; QPainter painter; - if (this->ThumbnailImage.width() != scaledThumbnailSizePixel) + + if (this->ThumbnailImage.isNull()) { if (!thumbnailGenerator.generateThumbnail(file, this->ThumbnailImage)) { @@ -443,11 +449,12 @@ void ctkDICOMSeriesItemWidgetPrivate::drawThumbnail(const QString& file, int num painter.end(); } } - else - { + } + + if (thumbnailGenerated) + { QColor firstPixelColor = this->ThumbnailImage.pixelColor(0, 0); resultPixmap.fill(firstPixelColor); - } } if (thumbnailGenerated && !this->isThumbnailDocument) @@ -456,7 +463,6 @@ void ctkDICOMSeriesItemWidgetPrivate::drawThumbnail(const QString& file, int num { painter.setRenderHint(QPainter::Antialiasing, true); painter.setRenderHint(QPainter::SmoothPixmapTransform, true); - painter.setRenderHint(QPainter::LosslessImageRendering, true); painter.setFont(font); QRectF rect = resultPixmap.rect(); @@ -770,11 +776,11 @@ void ctkDICOMSeriesItemWidget::forceRetrieve() { Q_D(ctkDICOMSeriesItemWidget); - d->IsCloud = true; + d->IsCloud = false; d->RetrieveFailed = false; d->StopJobs = false; - ctkDICOMJobDetail td; - d->createThumbnail(td); + d->DicomDatabase->removeSeries(d->SeriesInstanceUID, false, false); + this->generateInstances(true); } //---------------------------------------------------------------------------- @@ -862,7 +868,7 @@ void ctkDICOMSeriesItemWidget::setDicomDatabase(QSharedPointer } //------------------------------------------------------------------------------ -void ctkDICOMSeriesItemWidget::generateInstances(bool queryRetrieve) +void ctkDICOMSeriesItemWidget::generateInstances(bool query, bool retrieve) { Q_D(ctkDICOMSeriesItemWidget); if (!d->DicomDatabase) @@ -871,10 +877,11 @@ void ctkDICOMSeriesItemWidget::generateInstances(bool queryRetrieve) return; } - ctkDICOMJobDetail td; - d->createThumbnail(td, queryRetrieve); + d->QueryOn = query; + d->RetrieveOn = retrieve; + QStringList instancesList = d->DicomDatabase->instancesForSeries(d->SeriesInstanceUID); - if (queryRetrieve && !d->StopJobs && + if (query && !d->StopJobs && instancesList.count() == 0 && d->Scheduler && d->Scheduler->queryRetrieveServersCount() > 0) @@ -885,6 +892,11 @@ void ctkDICOMSeriesItemWidget::generateInstances(bool queryRetrieve) d->RaiseJobsPriority ? QThread::HighestPriority : QThread::NormalPriority, d->AllowedServers); } + else + { + ctkDICOMJobDetail td; + d->createThumbnail(td); + } } //---------------------------------------------------------------------------- diff --git a/Libs/DICOM/Widgets/ctkDICOMSeriesItemWidget.h b/Libs/DICOM/Widgets/ctkDICOMSeriesItemWidget.h index cd6874781c..c1f9d0ebee 100644 --- a/Libs/DICOM/Widgets/ctkDICOMSeriesItemWidget.h +++ b/Libs/DICOM/Widgets/ctkDICOMSeriesItemWidget.h @@ -169,7 +169,7 @@ class CTK_DICOM_WIDGETS_EXPORT ctkDICOMSeriesItemWidget : public QWidget void setDicomDatabase(QSharedPointer dicomDatabase); public Q_SLOTS: - void generateInstances(bool queryRetrieve = true); + void generateInstances(bool query = true, bool retrieve = true); void updateGUIFromScheduler(const QVariant& data); void updateSeriesProgressBar(const QVariant& data); void onJobStarted(const QVariant& data); diff --git a/Libs/DICOM/Widgets/ctkDICOMStudyItemWidget.cpp b/Libs/DICOM/Widgets/ctkDICOMStudyItemWidget.cpp index ed0777a88c..662ee2ea51 100644 --- a/Libs/DICOM/Widgets/ctkDICOMStudyItemWidget.cpp +++ b/Libs/DICOM/Widgets/ctkDICOMStudyItemWidget.cpp @@ -66,13 +66,13 @@ class ctkDICOMStudyItemWidgetPrivate : public Ui_ctkDICOMStudyItemWidget void init(QWidget* parentWidget); void updateColumnsWidths(); - void createSeries(bool queryRetrieve = true); + void createSeries(); int getScreenWidth(); int getScreenHeight(); int calculateNumerOfSeriesPerRow(); int calculateThumbnailSizeInPixel(const ctkDICOMStudyItemWidget::ThumbnailSizeOption& thumbnailSize); void addEmptySeriesItemWidget(int rowIndex, int columnIndex); - bool isSeriesItemAlreadyAdded(const QString& seriesItem); + ctkDICOMSeriesItemWidget* isSeriesItemAlreadyAdded(const QString& seriesItem); QString FilteringSeriesDescription; QStringList FilteringModalities; @@ -89,6 +89,9 @@ class ctkDICOMStudyItemWidgetPrivate : public Ui_ctkDICOMStudyItemWidget QString StudyItem; bool IsGUIUpdating; + bool QueryOn; + bool RetrieveOn; + int FilteredSeriesCount; }; //---------------------------------------------------------------------------- @@ -112,6 +115,9 @@ ctkDICOMStudyItemWidgetPrivate::ctkDICOMStudyItemWidgetPrivate(ctkDICOMStudyItem this->VisualDICOMBrowser = nullptr; this->IsGUIUpdating = false; + this->QueryOn = true; + this->RetrieveOn = true; + this->FilteredSeriesCount = 0; } //---------------------------------------------------------------------------- @@ -148,8 +154,8 @@ void ctkDICOMStudyItemWidgetPrivate::init(QWidget* parentWidget) this->StudyDescriptionTextBrowser->setReadOnly(true); this->StudyItemCollapsibleGroupBox->setCollapsed(false); - q->connect(this->StudySelectionCheckBox, SIGNAL(clicked(bool)), - q, SLOT(onStudySelectionClicked(bool))); + q->connect(this->StudySelectionCheckBox, SIGNAL(clicked(bool)), + q, SLOT(onStudySelectionClicked(bool))); } //------------------------------------------------------------------------------ @@ -162,7 +168,7 @@ void ctkDICOMStudyItemWidgetPrivate::updateColumnsWidths() } //------------------------------------------------------------------------------ -void ctkDICOMStudyItemWidgetPrivate::createSeries(bool queryRetrieve) +void ctkDICOMStudyItemWidgetPrivate::createSeries() { Q_Q(ctkDICOMStudyItemWidget); if (this->IsGUIUpdating) @@ -179,6 +185,8 @@ void ctkDICOMStudyItemWidgetPrivate::createSeries(bool queryRetrieve) QStringList seriesList = this->DicomDatabase->seriesForStudy(this->StudyInstanceUID); if (seriesList.count() == 0) { + q->setVisible(false); + q->emit updateGUIFinished(); return; } @@ -186,10 +194,16 @@ void ctkDICOMStudyItemWidgetPrivate::createSeries(bool queryRetrieve) // Sort by SeriesNumber QMap seriesMap; + this->FilteredSeriesCount = 0; + int seriesIndex = 0; foreach (QString seriesItem, seriesList) { - if (this->isSeriesItemAlreadyAdded(seriesItem)) + ctkDICOMSeriesItemWidget* seriesItemWidget = this->isSeriesItemAlreadyAdded(seriesItem); + if (seriesItemWidget) { + this->FilteredSeriesCount++; + seriesIndex++; + seriesItemWidget->generateInstances(this->QueryOn, this->RetrieveOn); continue; } @@ -207,12 +221,11 @@ void ctkDICOMStudyItemWidgetPrivate::createSeries(bool queryRetrieve) } // QMap automatically sort in ascending with the key seriesMap[seriesNumber] = seriesItem; + this->FilteredSeriesCount++; } } - int tableIndex = 0; - int seriesIndex = 0; - int numberOfSeries = seriesMap.count(); + int numberOfSeries = seriesMap.count() + seriesIndex; foreach (QString seriesItem, seriesMap) { QString seriesInstanceUID = this->DicomDatabase->fieldForSeries("SeriesInstanceUID", seriesItem); @@ -221,23 +234,21 @@ void ctkDICOMStudyItemWidgetPrivate::createSeries(bool queryRetrieve) numberOfSeries--; continue; } - seriesIndex++; QString modality = this->DicomDatabase->fieldForSeries("Modality", seriesItem); QString seriesDescription = this->DicomDatabase->fieldForSeries("SeriesDescription", seriesItem); ctkDICOMSeriesItemWidget* seriesItemWidget = - q->addSeriesItemWidget(tableIndex, seriesItem, seriesInstanceUID, modality, seriesDescription); + q->addSeriesItemWidget(seriesIndex, seriesItem, seriesInstanceUID, modality, seriesDescription); if (seriesItemWidget) { - seriesItemWidget->generateInstances(queryRetrieve); + seriesItemWidget->generateInstances(this->QueryOn, this->RetrieveOn); } - - tableIndex++; + seriesIndex++; if (seriesIndex == numberOfSeries) { - int emptyIndex = tableIndex; + int emptyIndex = seriesIndex; int columnIndex = emptyIndex % this->SeriesListTableWidget->columnCount(); while (columnIndex != 0) { @@ -262,6 +273,8 @@ void ctkDICOMStudyItemWidgetPrivate::createSeries(bool queryRetrieve) } this->IsGUIUpdating = false; + q->setVisible(this->FilteredSeriesCount != 0); + q->emit updateGUIFinished(); } //------------------------------------------------------------------------------ @@ -346,9 +359,9 @@ void ctkDICOMStudyItemWidgetPrivate::addEmptySeriesItemWidget(int rowIndex, int } //------------------------------------------------------------------------------ -bool ctkDICOMStudyItemWidgetPrivate::isSeriesItemAlreadyAdded(const QString& seriesItem) +ctkDICOMSeriesItemWidget* ctkDICOMStudyItemWidgetPrivate::isSeriesItemAlreadyAdded(const QString& seriesItem) { - bool alreadyAdded = false; + ctkDICOMSeriesItemWidget* seriesItemWidgetFound = nullptr; for (int rowIndex = 0; rowIndex < this->SeriesListTableWidget->rowCount(); rowIndex++) { for (int columnIndex = 0; columnIndex < this->SeriesListTableWidget->columnCount(); columnIndex++) @@ -362,18 +375,18 @@ bool ctkDICOMStudyItemWidgetPrivate::isSeriesItemAlreadyAdded(const QString& ser if (seriesItemWidget->seriesItem() == seriesItem) { - alreadyAdded = true; + seriesItemWidgetFound = seriesItemWidget; break; } } - if (alreadyAdded) + if (seriesItemWidgetFound) { break; } } - return alreadyAdded; + return seriesItemWidgetFound; } //---------------------------------------------------------------------------- @@ -408,6 +421,7 @@ CTK_SET_CPP(ctkDICOMStudyItemWidget, const QString&, setFilteringSeriesDescripti CTK_GET_CPP(ctkDICOMStudyItemWidget, QString, filteringSeriesDescription, FilteringSeriesDescription); CTK_SET_CPP(ctkDICOMStudyItemWidget, const QStringList&, setFilteringModalities, FilteringModalities); CTK_GET_CPP(ctkDICOMStudyItemWidget, QStringList, filteringModalities, FilteringModalities); +CTK_GET_CPP(ctkDICOMStudyItemWidget, int, filteredSeriesCount, FilteredSeriesCount); //---------------------------------------------------------------------------- @@ -697,18 +711,23 @@ ctkCollapsibleGroupBox* ctkDICOMStudyItemWidget::collapsibleGroupBox() } //------------------------------------------------------------------------------ -void ctkDICOMStudyItemWidget::generateSeries(bool queryRetrieve) +void ctkDICOMStudyItemWidget::generateSeries(bool query, bool retrieve) { Q_D(ctkDICOMStudyItemWidget); - d->createSeries(queryRetrieve); - if (queryRetrieve && d->Scheduler && d->Scheduler->queryRetrieveServersCount() > 0) + d->QueryOn = query; + d->RetrieveOn = retrieve; + if (query && d->Scheduler && d->Scheduler->queryRetrieveServersCount() > 0) { d->Scheduler->querySeries(d->PatientID, d->StudyInstanceUID, QThread::NormalPriority, d->AllowedServers); } + else + { + d->createSeries(); + } } //------------------------------------------------------------------------------ diff --git a/Libs/DICOM/Widgets/ctkDICOMStudyItemWidget.h b/Libs/DICOM/Widgets/ctkDICOMStudyItemWidget.h index 06a69eb010..8ef1a6f349 100644 --- a/Libs/DICOM/Widgets/ctkDICOMStudyItemWidget.h +++ b/Libs/DICOM/Widgets/ctkDICOMStudyItemWidget.h @@ -57,6 +57,10 @@ class CTK_DICOM_WIDGETS_EXPORT ctkDICOMStudyItemWidget : public QWidget Q_PROPERTY(int numberOfSeriesPerRow READ numberOfSeriesPerRow); Q_PROPERTY(ThumbnailSizeOption thumbnailSize READ thumbnailSize WRITE setThumbnailSize); Q_PROPERTY(int thumbnailSizePixel READ thumbnailSizePixel); + Q_PROPERTY(int selection READ selection WRITE setSelection); + Q_PROPERTY(QString filteringSeriesDescription READ filteringSeriesDescription WRITE setFilteringSeriesDescription); + Q_PROPERTY(QStringList filteringModalities READ filteringModalities WRITE setFilteringModalities); + Q_PROPERTY(int filteredSeriesCount READ filteredSeriesCount); Q_PROPERTY(QStringList allowedServers READ allowedServers WRITE setAllowedServers); public: @@ -140,6 +144,9 @@ class CTK_DICOM_WIDGETS_EXPORT ctkDICOMStudyItemWidget : public QWidget QStringList filteringModalities() const; ///@} + /// Filtered series count + int filteredSeriesCount() const; + ///@{ /// Allowed Servers /// Empty by default @@ -187,10 +194,14 @@ class CTK_DICOM_WIDGETS_EXPORT ctkDICOMStudyItemWidget : public QWidget Q_INVOKABLE ctkCollapsibleGroupBox* collapsibleGroupBox(); public Q_SLOTS: - void generateSeries(bool queryRetrieve = true); + void generateSeries(bool query = true, bool retrieve = true); void updateGUIFromScheduler(const QVariant& data); void onStudySelectionClicked(bool); +Q_SIGNALS: + /// Emitted when the GUI finished to update after a series query. + void updateGUIFinished(); + protected: QScopedPointer d_ptr; diff --git a/Libs/DICOM/Widgets/ctkDICOMVisualBrowserWidget.cpp b/Libs/DICOM/Widgets/ctkDICOMVisualBrowserWidget.cpp index 32ddde01b1..19126b9539 100644 --- a/Libs/DICOM/Widgets/ctkDICOMVisualBrowserWidget.cpp +++ b/Libs/DICOM/Widgets/ctkDICOMVisualBrowserWidget.cpp @@ -146,9 +146,9 @@ class ctkDICOMVisualBrowserWidgetPrivate : public Ui_ctkDICOMVisualBrowserWidget void importOldSettings(); void showUpdateSchemaDialog(); void updateModalityCheckableComboBox(); - void createPatients(QString patientID = "", - QString patientName = "", - bool queryRetrieve = true); + void createPatients(bool queryRetrieve = true, + bool isImport = false); + bool areFiltersEmpty(); void resetFilters(); void updateFiltersWarnings(); void setBackgroundColorToFilterWidgets(bool warning = false); @@ -175,6 +175,9 @@ class ctkDICOMVisualBrowserWidgetPrivate : public Ui_ctkDICOMVisualBrowserWidget ctkDICOMStudyItemWidget* getCurrentPatientStudyWidgetByUIDs(const QString& studyInstanceUID); ctkDICOMSeriesItemWidget* getCurrentPatientSeriesWidgetByUIDs(const QString& studyInstanceUID, const QString& seriesInstanceUID); + void getPatientsMetadata(bool queryRetrieve = true); + void updateTabVisibilityForPatientItemWidgets(); + void updateTabVisibilityForPatientItemWidget(ctkDICOMPatientItemWidget* patientItemWidget); // Return a sanitized version of the string that is safe to be used // as a filename component. @@ -239,6 +242,7 @@ class ctkDICOMVisualBrowserWidgetPrivate : public Ui_ctkDICOMVisualBrowserWidget bool DeleteActionVisible; bool IsGUIUpdating; bool IsLoading; + QString SelectedPatientItem; QProgressDialog* UpdateSchemaProgress; QProgressDialog* ExportProgress; @@ -666,9 +670,8 @@ void ctkDICOMVisualBrowserWidgetPrivate::updateModalityCheckableComboBox() } //---------------------------------------------------------------------------- -void ctkDICOMVisualBrowserWidgetPrivate::createPatients(QString selectedPatientID, - QString selectedPatientName, - bool queryRetrieve) +void ctkDICOMVisualBrowserWidgetPrivate::createPatients(bool queryRetrieve, + bool isImport) { Q_Q(ctkDICOMVisualBrowserWidget); if (this->IsGUIUpdating) @@ -692,7 +695,6 @@ void ctkDICOMVisualBrowserWidgetPrivate::createPatients(QString selectedPatientI this->patientsTabMenuToolButton->show(); this->IsGUIUpdating = true; int wasBlocking = this->PatientsTabWidget->blockSignals(true); - int selectedIndex = -1; QMap patientsInsertDateTimeList; foreach (QString patientItem, patientList) { @@ -702,12 +704,6 @@ void ctkDICOMVisualBrowserWidgetPrivate::createPatients(QString selectedPatientI int index = this->findPatientTabIndexFromPatientItem(patientItem); if (index != -1) { - if (selectedPatientID == patientID && - selectedPatientName == patientName && - selectedIndex == -1) - { - selectedIndex = index; - } continue; } @@ -719,18 +715,13 @@ void ctkDICOMVisualBrowserWidgetPrivate::createPatients(QString selectedPatientI } index = q->addPatientItemWidget(patientItem); - if (selectedPatientID == patientID && - selectedPatientName == patientName && - selectedIndex == -1) - { - selectedIndex = index; - } QDateTime patientInsertDateTime = this->DicomDatabase->insertDateTimeForPatient(patientItem); patientsInsertDateTimeList[patientItem] = patientInsertDateTime; } - if (selectedIndex == -1 && patientsInsertDateTimeList.count() > 0) + int selectedIndex = this->findPatientTabIndexFromPatientItem(this->SelectedPatientItem); + if (isImport && patientsInsertDateTimeList.count() > 0) { QList> list; for (QMap::const_iterator it = patientsInsertDateTimeList.cbegin(); @@ -749,15 +740,20 @@ void ctkDICOMVisualBrowserWidgetPrivate::createPatients(QString selectedPatientI } this->PatientsTabWidget->setCurrentIndex(selectedIndex); this->PatientsTabWidget->blockSignals(wasBlocking); + this->IsGUIUpdating = false; - ctkDICOMPatientItemWidget* currentPatientItemWidget = - qobject_cast(this->PatientsTabWidget->currentWidget()); - if (currentPatientItemWidget) - { - currentPatientItemWidget->generateStudies(queryRetrieve); - } + this->getPatientsMetadata(queryRetrieve); +} - this->IsGUIUpdating = false; +//---------------------------------------------------------------------------- +bool ctkDICOMVisualBrowserWidgetPrivate::areFiltersEmpty() +{ + return this->FilteringPatientID.isEmpty() && + this->FilteringPatientName.isEmpty() && + this->FilteringStudyDescription.isEmpty() && + this->FilteringSeriesDescription.isEmpty() && + this->FilteringDate == ctkDICOMPatientItemWidget::DateType::Any && + this->FilteringModalities.contains("Any"); } //---------------------------------------------------------------------------- @@ -1509,6 +1505,116 @@ ctkDICOMSeriesItemWidget* ctkDICOMVisualBrowserWidgetPrivate::getCurrentPatientS return nullptr; } +//---------------------------------------------------------------------------- +void ctkDICOMVisualBrowserWidgetPrivate::getPatientsMetadata(bool queryRetrieve) +{ + ctkDICOMPatientItemWidget* currentPatientItemWidget = + qobject_cast(this->PatientsTabWidget->currentWidget()); + + for (int patientIndex = 0; patientIndex < this->PatientsTabWidget->count(); ++patientIndex) + { + ctkDICOMPatientItemWidget* patientItemWidget = + qobject_cast(this->PatientsTabWidget->widget(patientIndex)); + if (!patientItemWidget) + { + continue; + } + + bool query = queryRetrieve; + bool retrieve = false; + if (patientItemWidget == currentPatientItemWidget) + { + retrieve = queryRetrieve; + } + + patientItemWidget->generateStudies(query, retrieve); + } +} + +//---------------------------------------------------------------------------- +void ctkDICOMVisualBrowserWidgetPrivate::updateTabVisibilityForPatientItemWidgets() +{ + for (int patientIndex = 0; patientIndex < this->PatientsTabWidget->count(); ++patientIndex) + { + ctkDICOMPatientItemWidget* patientItemWidget = + qobject_cast(this->PatientsTabWidget->widget(patientIndex)); + if (!patientItemWidget) + { + continue; + } + this->updateTabVisibilityForPatientItemWidget(patientItemWidget); + } +} + +//---------------------------------------------------------------------------- +void ctkDICOMVisualBrowserWidgetPrivate::updateTabVisibilityForPatientItemWidget(ctkDICOMPatientItemWidget *patientItemWidget) +{ + if (this->IsGUIUpdating) + { + return; + } + + if(this->areFiltersEmpty()) + { + return; + } + + int index = this->findPatientTabIndexFromPatientItem(patientItemWidget->patientItem()); + if (index == -1) + { + return; + } + + this->IsGUIUpdating = true; + int wasBlocking = this->PatientsTabWidget->blockSignals(true); + + QString patientItem; + ctkDICOMPatientItemWidget* currentPatientItemWidget = + qobject_cast(this->PatientsTabWidget->currentWidget()); + if (currentPatientItemWidget) + { + patientItem = currentPatientItemWidget->patientItem(); + } + + bool patientVisible = false; + QStringList studiesList = this->DicomDatabase->studiesForPatient(patientItemWidget->patientItem()); + + QList studyItemWidgetsList = patientItemWidget->studyItemWidgetsList(); + foreach (ctkDICOMStudyItemWidget* studyItemWidget, studyItemWidgetsList) + { + if (!studyItemWidget) + { + continue; + } + + if (studyItemWidget->filteredSeriesCount() != 0) + { + patientVisible = true; + break; + } + } + +#if QT_VERSION <= QT_VERSION_CHECK(5, 13, 0) + this->PatientsTabWidget->setTabEnabled(index, patientVisible); + this->PatientsTabWidget->setTabText(index, patientVisible ? patientItemWidget->patientName() : ""); + this->PatientsTabWidget->setTabIcon(index, patientVisible ? QIcon(":/Icons/patient.svg") : QIcon()); +#else + this->PatientsTabWidget->setTabVisible(index, patientVisible); +#endif + + int selectedIndex = this->findPatientTabIndexFromPatientItem(patientItem); + if (selectedIndex == index && !patientVisible) + { + this->PatientsTabWidget->setCurrentIndex(0); + } + else if (selectedIndex != -1) + { + this->PatientsTabWidget->setCurrentIndex(selectedIndex); + } + this->PatientsTabWidget->blockSignals(wasBlocking); + this->IsGUIUpdating = false; +} + //---------------------------------------------------------------------------- // ctkDICOMVisualBrowserWidget methods @@ -1846,6 +1952,8 @@ int ctkDICOMVisualBrowserWidget::addPatientItemWidget(const QString& patientItem patientItemWidget->setContextMenuPolicy(Qt::CustomContextMenu); this->connect(patientItemWidget, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(showPatientContextMenu(const QPoint&))); + this->connect(patientItemWidget, SIGNAL(updateGUIFinished()), + this, SLOT(onPatientUpdateGUIFinished())); int index = d->PatientsTabWidget->addTab(patientItemWidget, QIcon(":/Icons/patient.svg"), patientName); d->PatientsTabWidget->setTabWhatsThis(index, patientItem); @@ -2183,7 +2291,7 @@ void ctkDICOMVisualBrowserWidget::onIndexingComplete(int patientsAdded, int stud // allow users of this widget to know that the process has finished emit directoryImported(); - d->createPatients("", "", false); + d->createPatients(false, true); d->setBackgroundColorToFilterWidgets(); } @@ -2598,14 +2706,12 @@ void ctkDICOMVisualBrowserWidget::onShowPatients() this->onStop(); // Save current patient selection - QString patientID; - QString patientName; + QString patientItem; ctkDICOMPatientItemWidget* currentPatientItemWidget = qobject_cast(d->PatientsTabWidget->currentWidget()); if (currentPatientItemWidget) { - patientID = currentPatientItemWidget->patientID(); - patientName = currentPatientItemWidget->patientName(); + d->SelectedPatientItem = currentPatientItemWidget->patientItem(); } // Clear the UI. @@ -2625,7 +2731,7 @@ void ctkDICOMVisualBrowserWidget::onShowPatients() d->WarningPushButton->hide(); } - d->createPatients(patientID, patientName, false); + d->createPatients(false); d->updateFiltersWarnings(); } @@ -2662,26 +2768,18 @@ void ctkDICOMVisualBrowserWidget::onQueryPatients() this->onStop(); // Save current patient selection - QString patientID; - QString patientName; + QString patientItem; ctkDICOMPatientItemWidget* currentPatientItemWidget = qobject_cast(d->PatientsTabWidget->currentWidget()); if (currentPatientItemWidget) { - patientID = currentPatientItemWidget->patientID(); - patientName = currentPatientItemWidget->patientName(); + d->SelectedPatientItem = currentPatientItemWidget->patientItem(); } // Clear the UI. d->removeAllPatientItemWidgets(); - bool filtersEmpty = - d->FilteringPatientID.isEmpty() && - d->FilteringPatientName.isEmpty() && - d->FilteringStudyDescription.isEmpty() && - d->FilteringSeriesDescription.isEmpty() && - d->FilteringDate == ctkDICOMPatientItemWidget::DateType::Any && - d->FilteringModalities.contains("Any"); + bool filtersEmpty = d->areFiltersEmpty(); if (d->DicomDatabase->patients().count() == 0 && (filtersEmpty || d->Scheduler->queryRetrieveServersCount() == 0)) @@ -2701,10 +2799,9 @@ void ctkDICOMVisualBrowserWidget::onQueryPatients() d->WarningPushButton->hide(); } - d->createPatients(patientID, patientName, true); - if (filtersEmpty || (d->Scheduler->queryRetrieveServersCount() == 0)) { + d->createPatients(); d->updateFiltersWarnings(); } else if (d->Scheduler->queryRetrieveServersCount() > 0) @@ -2775,19 +2872,12 @@ void ctkDICOMVisualBrowserWidget::updateGUIFromScheduler(const QVariant& data) d->WarningPushButton->setText(tr("The query provided no results. Please refine your filters.")); d->WarningPushButton->show(); } - - // Save current patient selection - QString patientID; - QString patientName; - ctkDICOMPatientItemWidget* currentPatientItemWidget = - qobject_cast(d->PatientsTabWidget->currentWidget()); - if (currentPatientItemWidget) + else { - patientID = currentPatientItemWidget->patientID(); - patientName = currentPatientItemWidget->patientName(); + d->WarningPushButton->hide(); } - d->createPatients(patientID, patientName); + d->createPatients(); } //------------------------------------------------------------------------------ @@ -3133,14 +3223,17 @@ void ctkDICOMVisualBrowserWidget::onPatientsTabMenuToolButtonClicked() { ctkDICOMPatientItemWidget* patientItemWidget = qobject_cast(d->PatientsTabWidget->widget(patientIndex)); - if (!patientItemWidget) + +#if QT_VERSION <= QT_VERSION_CHECK(5, 13, 0) + if (!patientItemWidget || d->PatientsTabWidget->tabText(patientIndex).isEmpty()) +#else + if (!patientItemWidget || !d->PatientsTabWidget->isTabVisible(patientIndex)) +#endif { continue; } - QString patientItem = patientItemWidget->patientItem(); - QString patientName = d->DicomDatabase->fieldForPatient("PatientsName", patientItem); - patientName.replace(R"(^)", R"( )"); + QString patientName = patientItemWidget->patientName(); QAction* changePatientAction = new QAction(patientName, patientMenu); if (patientItemWidget == d->PatientsTabWidget->currentWidget()) { @@ -3176,6 +3269,21 @@ void ctkDICOMVisualBrowserWidget::onPatientsTabMenuToolButtonClicked() } } +//------------------------------------------------------------------------------ +void ctkDICOMVisualBrowserWidget::onPatientUpdateGUIFinished() +{ + Q_D(ctkDICOMVisualBrowserWidget); + + ctkDICOMPatientItemWidget* patientItemWidget = + qobject_cast(QObject::sender()); + if (!patientItemWidget) + { + return; + } + + d->updateTabVisibilityForPatientItemWidget(patientItemWidget); +} + //------------------------------------------------------------------------------ void ctkDICOMVisualBrowserWidget::exportSelectedItems(ctkDICOMModel::IndexType level, const QList& selectedWidgets) diff --git a/Libs/DICOM/Widgets/ctkDICOMVisualBrowserWidget.h b/Libs/DICOM/Widgets/ctkDICOMVisualBrowserWidget.h index 15a925e51a..5af478862b 100644 --- a/Libs/DICOM/Widgets/ctkDICOMVisualBrowserWidget.h +++ b/Libs/DICOM/Widgets/ctkDICOMVisualBrowserWidget.h @@ -446,6 +446,8 @@ protected Q_SLOTS: void showSeriesContextMenu(const QPoint& point); /// Called when clicking patients tab menu void onPatientsTabMenuToolButtonClicked(); + /// Called when patient widget update is finished + void onPatientUpdateGUIFinished(); private: Q_DECLARE_PRIVATE(ctkDICOMVisualBrowserWidget);