diff --git a/Libs/DICOM/Widgets/Resources/UI/Icons/patient_failed.svg b/Libs/DICOM/Widgets/Resources/UI/Icons/patient_failed.svg
new file mode 100644
index 0000000000..75d95bd770
--- /dev/null
+++ b/Libs/DICOM/Widgets/Resources/UI/Icons/patient_failed.svg
@@ -0,0 +1,42 @@
+
+
diff --git a/Libs/DICOM/Widgets/Resources/UI/Icons/patient_pending.svg b/Libs/DICOM/Widgets/Resources/UI/Icons/patient_pending.svg
new file mode 100644
index 0000000000..e24e5cdff2
--- /dev/null
+++ b/Libs/DICOM/Widgets/Resources/UI/Icons/patient_pending.svg
@@ -0,0 +1,42 @@
+
+
diff --git a/Libs/DICOM/Widgets/Resources/UI/Icons/patient_success.svg b/Libs/DICOM/Widgets/Resources/UI/Icons/patient_success.svg
new file mode 100644
index 0000000000..8f97c7aa1c
--- /dev/null
+++ b/Libs/DICOM/Widgets/Resources/UI/Icons/patient_success.svg
@@ -0,0 +1,42 @@
+
+
diff --git a/Libs/DICOM/Widgets/Resources/UI/ctkDICOMWidget.qrc b/Libs/DICOM/Widgets/Resources/UI/ctkDICOMWidget.qrc
index 0651ac4304..c9b8a3bbb7 100644
--- a/Libs/DICOM/Widgets/Resources/UI/ctkDICOMWidget.qrc
+++ b/Libs/DICOM/Widgets/Resources/UI/ctkDICOMWidget.qrc
@@ -32,5 +32,8 @@
Icons/search_local.svg
Icons/query.svg
Icons/wait.svg
+ Icons/patient_failed.svg
+ Icons/patient_pending.svg
+ Icons/patient_success.svg
diff --git a/Libs/DICOM/Widgets/ctkDICOMPatientItemWidget.cpp b/Libs/DICOM/Widgets/ctkDICOMPatientItemWidget.cpp
index b62ec9dff7..3879a024a0 100644
--- a/Libs/DICOM/Widgets/ctkDICOMPatientItemWidget.cpp
+++ b/Libs/DICOM/Widgets/ctkDICOMPatientItemWidget.cpp
@@ -99,7 +99,8 @@ class ctkDICOMPatientItemWidgetPrivate : public Ui_ctkDICOMPatientItemWidget
QMap StudyItemWidgetsConnectionMap;
QSpacerItem* StudiesListVerticalSpacer;
- QStringList AllowedServers = QStringList();
+ QStringList AllowedServers;
+ ctkDICOMPatientItemWidget::OperationStatus Status;
bool IsGUIUpdating;
bool QueryOn;
@@ -131,6 +132,9 @@ ctkDICOMPatientItemWidgetPrivate::ctkDICOMPatientItemWidgetPrivate(ctkDICOMPatie
this->StudiesListVerticalSpacer = new QSpacerItem(0, 5, QSizePolicy::Fixed, QSizePolicy::Expanding);
+ this->AllowedServers = QStringList();
+ this->Status = ctkDICOMPatientItemWidget::NoOperation;
+
this->IsGUIUpdating = false;
this->QueryOn = true;
this->RetrieveOn = true;
@@ -580,6 +584,8 @@ ctkDICOMPatientItemWidget::~ctkDICOMPatientItemWidget()
//------------------------------------------------------------------------------
CTK_SET_CPP(ctkDICOMPatientItemWidget, const QStringList&, setAllowedServers, AllowedServers);
CTK_GET_CPP(ctkDICOMPatientItemWidget, QStringList, allowedServers, AllowedServers);
+CTK_SET_CPP(ctkDICOMPatientItemWidget, const OperationStatus&, setOperationStatus, Status);
+CTK_GET_CPP(ctkDICOMPatientItemWidget, ctkDICOMPatientItemWidget::OperationStatus, operationStatus, Status);
CTK_GET_CPP(ctkDICOMPatientItemWidget, QString, patientItem, PatientItem);
CTK_SET_CPP(ctkDICOMPatientItemWidget, const QString&, setPatientID, PatientID);
CTK_GET_CPP(ctkDICOMPatientItemWidget, QString, patientID, PatientID);
diff --git a/Libs/DICOM/Widgets/ctkDICOMPatientItemWidget.h b/Libs/DICOM/Widgets/ctkDICOMPatientItemWidget.h
index 9856795832..cdfad76798 100644
--- a/Libs/DICOM/Widgets/ctkDICOMPatientItemWidget.h
+++ b/Libs/DICOM/Widgets/ctkDICOMPatientItemWidget.h
@@ -50,6 +50,7 @@ class CTK_DICOM_WIDGETS_EXPORT ctkDICOMPatientItemWidget : public QWidget
Q_PROPERTY(int numberOfStudiesPerPatient READ numberOfStudiesPerPatient WRITE setNumberOfStudiesPerPatient);
Q_PROPERTY(ctkDICOMStudyItemWidget::ThumbnailSizeOption thumbnailSize READ thumbnailSize WRITE setThumbnailSize);
Q_PROPERTY(QStringList allowedServers READ allowedServers WRITE setAllowedServers);
+ Q_PROPERTY(OperationStatus operationStatus READ operationStatus WRITE setOperationStatus);
public:
typedef QWidget Superclass;
@@ -189,6 +190,21 @@ class CTK_DICOM_WIDGETS_EXPORT ctkDICOMPatientItemWidget : public QWidget
Q_INVOKABLE void updateAllowedServersUIFromDB();
///@}
+ enum OperationStatus
+ {
+ NoOperation = 0,
+ InProgress,
+ Completed,
+ Failed,
+ };
+
+ ///@{
+ /// Set the operation status
+ /// NoOperation by default
+ void setOperationStatus(const OperationStatus& status);
+ OperationStatus operationStatus() const;
+ ///@}
+
public Q_SLOTS:
void generateStudies(bool query = true, bool retrieve = true);
void generateSeriesAtToggle(bool toggled = true, const QString& studyItem = "");
diff --git a/Libs/DICOM/Widgets/ctkDICOMSeriesItemWidget.cpp b/Libs/DICOM/Widgets/ctkDICOMSeriesItemWidget.cpp
index 323e339ca1..77ae9ca404 100644
--- a/Libs/DICOM/Widgets/ctkDICOMSeriesItemWidget.cpp
+++ b/Libs/DICOM/Widgets/ctkDICOMSeriesItemWidget.cpp
@@ -986,7 +986,7 @@ void ctkDICOMSeriesItemWidget::onJobUserStopped(const QVariant &data)
td.SeriesInstanceUID == d->SeriesInstanceUID)
{
d->SeriesThumbnail->setOperationStatus(ctkThumbnailLabel::Failed);
- d->SeriesThumbnail->setStatusIcon(QIcon(":/Icons/error.svg"));
+ d->SeriesThumbnail->setStatusIcon(QIcon(":/Icons/error_red.svg"));
if (td.JobType == ctkDICOMJobResponseSet::JobType::RetrieveSOPInstance)
{
@@ -1015,7 +1015,7 @@ void ctkDICOMSeriesItemWidget::onJobFailed(const QVariant &data)
td.SeriesInstanceUID == d->SeriesInstanceUID)
{
d->SeriesThumbnail->setOperationStatus(ctkThumbnailLabel::Failed);
- d->SeriesThumbnail->setStatusIcon(QIcon(":/Icons/error.svg"));
+ d->SeriesThumbnail->setStatusIcon(QIcon(":/Icons/error_red.svg"));
if (td.JobType == ctkDICOMJobResponseSet::JobType::RetrieveSOPInstance)
{
diff --git a/Libs/DICOM/Widgets/ctkDICOMStudyItemWidget.cpp b/Libs/DICOM/Widgets/ctkDICOMStudyItemWidget.cpp
index 7484ec147f..bfd984d90c 100644
--- a/Libs/DICOM/Widgets/ctkDICOMStudyItemWidget.cpp
+++ b/Libs/DICOM/Widgets/ctkDICOMStudyItemWidget.cpp
@@ -813,7 +813,7 @@ void ctkDICOMStudyItemWidget::onJobUserStopped(const QVariant &data)
td.StudyInstanceUID == d->StudyInstanceUID)
{
d->Status = ctkDICOMStudyItemWidget::Failed;
- d->OperationStatusPushButton->setIcon(QIcon(":/Icons/error.svg"));
+ d->OperationStatusPushButton->setIcon(QIcon(":/Icons/error_red.svg"));
}
}
@@ -829,7 +829,7 @@ void ctkDICOMStudyItemWidget::onJobFailed(const QVariant &data)
td.StudyInstanceUID == d->StudyInstanceUID)
{
d->Status = ctkDICOMStudyItemWidget::Failed;
- d->OperationStatusPushButton->setIcon(QIcon(":/Icons/error.svg"));
+ d->OperationStatusPushButton->setIcon(QIcon(":/Icons/error_red.svg"));
}
}
diff --git a/Libs/DICOM/Widgets/ctkDICOMVisualBrowserWidget.cpp b/Libs/DICOM/Widgets/ctkDICOMVisualBrowserWidget.cpp
index 714916a0ab..98c54274c8 100644
--- a/Libs/DICOM/Widgets/ctkDICOMVisualBrowserWidget.cpp
+++ b/Libs/DICOM/Widgets/ctkDICOMVisualBrowserWidget.cpp
@@ -157,9 +157,9 @@ class ctkDICOMVisualBrowserWidgetPrivate : public Ui_ctkDICOMVisualBrowserWidget
void retrieveSeries();
bool updateServer(ctkDICOMServer* server);
void removeAllPatientItemWidgets();
- QString findPatientItemFromPatientInfo(const QString& patientID,
- const QString& patientName,
- const QString& patientBirthDate);
+ QString findPatientItemFromPatientInfo(const QString& patientID = "",
+ const QString& patientName = "",
+ const QString& patientBirthDate = "");
int findPatientTabIndexFromPatientItem(const QString& patientItem);
void updateSeriesTablesSelection(ctkDICOMSeriesItemWidget* selectedSeriesItemWidget);
QStringList getPatientItemsFromWidgets(ctkDICOMModel::IndexType level,
@@ -416,6 +416,9 @@ void ctkDICOMVisualBrowserWidgetPrivate::init()
QObject::connect(this->PatientsTabWidget, SIGNAL(currentChanged(int)),
q, SLOT(onPatientItemChanged(int)));
+ QObject::connect(this->PatientsTabWidget, SIGNAL(tabBarClicked(int)),
+ q, SLOT(onOperationStatusTabBarItemClicked(int)));
+
QObject::connect(this->ServerNodeWidget, SIGNAL(serversSettingsChanged()),
q, SLOT(onServersSettingsChanged()));
@@ -1134,6 +1137,11 @@ QString ctkDICOMVisualBrowserWidgetPrivate::findPatientItemFromPatientInfo(const
const QString &patientBirthDate)
{
QString patientItem;
+ if (patientID.isEmpty() && patientName.isEmpty() && patientBirthDate.isEmpty())
+ {
+ return patientItem;
+ }
+
for (int index = 0; index < this->PatientsTabWidget->count(); ++index)
{
ctkDICOMPatientItemWidget* patientItemWidget =
@@ -1142,12 +1150,12 @@ QString ctkDICOMVisualBrowserWidgetPrivate::findPatientItemFromPatientInfo(const
{
continue;
}
- if (patientItemWidget->patientID() == patientID &&
- patientItemWidget->patientName() == patientName &&
- patientItemWidget->patientBirthDate() == patientBirthDate)
+
+ if ((patientID.isEmpty() || patientItemWidget->patientID() == patientID) &&
+ (patientName.isEmpty() || patientItemWidget->patientName() == patientName) &&
+ (patientBirthDate.isEmpty() || patientItemWidget->patientBirthDate() == patientBirthDate))
{
- patientItem = this->PatientsTabWidget->tabWhatsThis(index);
- break;
+ return this->PatientsTabWidget->tabWhatsThis(index);
}
}
@@ -2953,12 +2961,28 @@ void ctkDICOMVisualBrowserWidget::onJobStarted(const QVariant& data)
Q_D(ctkDICOMVisualBrowserWidget);
ctkDICOMJobDetail td = data.value();
- if (!td.JobUID.isEmpty() &&
- td.JobType == ctkDICOMJobResponseSet::JobType::QueryPatients)
+ if (td.JobUID.isEmpty())
+ {
+ return;
+ }
+
+ if (td.JobType == ctkDICOMJobResponseSet::JobType::QueryPatients)
{
d->updateFiltersWarnings();
d->SearchMenuButton->setIcon(QIcon(":/Icons/wait.svg"));
}
+ else if (td.JobType == ctkDICOMJobResponseSet::JobType::QueryStudies)
+ {
+ QString patientItem = d->findPatientItemFromPatientInfo(td.PatientID);
+ int patientIndex = d->findPatientTabIndexFromPatientItem(patientItem);
+ ctkDICOMPatientItemWidget* patientItemWidget =
+ qobject_cast(d->PatientsTabWidget->widget(patientIndex));
+ if (patientItemWidget)
+ {
+ patientItemWidget->setOperationStatus(ctkDICOMPatientItemWidget::InProgress);
+ }
+ d->PatientsTabWidget->setTabIcon(patientIndex, QIcon(":/Icons/patient_pending.svg"));
+ }
}
//------------------------------------------------------------------------------
@@ -2967,12 +2991,28 @@ void ctkDICOMVisualBrowserWidget::onJobUserStopped(const QVariant& data)
Q_D(ctkDICOMVisualBrowserWidget);
ctkDICOMJobDetail td = data.value();
- if (!td.JobUID.isEmpty() &&
- td.JobType == ctkDICOMJobResponseSet::JobType::QueryPatients)
+ if (td.JobUID.isEmpty())
+ {
+ return;
+ }
+
+ if (td.JobType == ctkDICOMJobResponseSet::JobType::QueryPatients)
{
d->updateFiltersWarnings();
d->SearchMenuButton->setIcon(QIcon(":/Icons/query_failed.svg"));
}
+ else if (td.JobType == ctkDICOMJobResponseSet::JobType::QueryStudies)
+ {
+ QString patientItem = d->findPatientItemFromPatientInfo(td.PatientID);
+ int patientIndex = d->findPatientTabIndexFromPatientItem(patientItem);
+ ctkDICOMPatientItemWidget* patientItemWidget =
+ qobject_cast(d->PatientsTabWidget->widget(patientIndex));
+ if (patientItemWidget)
+ {
+ patientItemWidget->setOperationStatus(ctkDICOMPatientItemWidget::Failed);
+ }
+ d->PatientsTabWidget->setTabIcon(patientIndex, QIcon(":/Icons/patient_failed.svg"));
+ }
}
//------------------------------------------------------------------------------
@@ -2981,20 +3021,30 @@ void ctkDICOMVisualBrowserWidget::onJobFailed(const QVariant& data)
Q_D(ctkDICOMVisualBrowserWidget);
ctkDICOMJobDetail td = data.value();
- if (!td.JobUID.isEmpty() &&
- td.JobType == ctkDICOMJobResponseSet::JobType::QueryPatients)
+ if (td.JobUID.isEmpty())
+ {
+ return;
+ }
+
+ if (td.JobType == ctkDICOMJobResponseSet::JobType::QueryPatients)
{
d->updateFiltersWarnings();
d->SearchMenuButton->setIcon(QIcon(":/Icons/query_failed.svg"));
+ d->WarningPushButton->setText(tr("The patients query failed. Please check the servers settings."));
+ d->WarningPushButton->show();
}
-
- if (td.JobType != ctkDICOMJobResponseSet::JobType::QueryPatients)
+ else if (td.JobType == ctkDICOMJobResponseSet::JobType::QueryStudies)
{
- return;
+ QString patientItem = d->findPatientItemFromPatientInfo(td.PatientID);
+ int patientIndex = d->findPatientTabIndexFromPatientItem(patientItem);
+ ctkDICOMPatientItemWidget* patientItemWidget =
+ qobject_cast(d->PatientsTabWidget->widget(patientIndex));
+ if (patientItemWidget)
+ {
+ patientItemWidget->setOperationStatus(ctkDICOMPatientItemWidget::Failed);
+ }
+ d->PatientsTabWidget->setTabIcon(patientIndex, QIcon(":/Icons/patient_failed.svg"));
}
-
- d->WarningPushButton->setText(tr("The patients query failed. Please check the servers settings."));
- d->WarningPushButton->show();
}
//------------------------------------------------------------------------------
@@ -3003,12 +3053,28 @@ void ctkDICOMVisualBrowserWidget::onJobFinished(const QVariant& data)
Q_D(ctkDICOMVisualBrowserWidget);
ctkDICOMJobDetail td = data.value();
- if (!td.JobUID.isEmpty() &&
- td.JobType == ctkDICOMJobResponseSet::JobType::QueryPatients)
+ if (td.JobUID.isEmpty())
+ {
+ return;
+ }
+
+ if (td.JobType == ctkDICOMJobResponseSet::JobType::QueryPatients)
{
d->updateFiltersWarnings();
d->SearchMenuButton->setIcon(QIcon(":/Icons/query_success.svg"));
}
+ else if (td.JobType == ctkDICOMJobResponseSet::JobType::QueryStudies)
+ {
+ QString patientItem = d->findPatientItemFromPatientInfo(td.PatientID);
+ int patientIndex = d->findPatientTabIndexFromPatientItem(patientItem);
+ ctkDICOMPatientItemWidget* patientItemWidget =
+ qobject_cast(d->PatientsTabWidget->widget(patientIndex));
+ if (patientItemWidget)
+ {
+ patientItemWidget->setOperationStatus(ctkDICOMPatientItemWidget::Completed);
+ }
+ d->PatientsTabWidget->setTabIcon(patientIndex, QIcon(":/Icons/patient_success.svg"));
+ }
}
//------------------------------------------------------------------------------
@@ -3025,6 +3091,34 @@ void ctkDICOMVisualBrowserWidget::onPatientItemChanged(int index)
patientItem->generateStudies();
}
+//------------------------------------------------------------------------------
+void ctkDICOMVisualBrowserWidget::onOperationStatusTabBarItemClicked(int index)
+{
+ Q_D(ctkDICOMVisualBrowserWidget);
+ ctkDICOMPatientItemWidget* patientItemWidget =
+ qobject_cast(d->PatientsTabWidget->widget(index));
+ if (!patientItemWidget)
+ {
+ return;
+ }
+
+ ctkDICOMPatientItemWidget::OperationStatus status = patientItemWidget->operationStatus();
+ if (status == ctkDICOMPatientItemWidget::InProgress)
+ {
+ d->Scheduler->stopJobsByDICOMUIDs(QStringList(patientItemWidget->patientID()));
+ }
+ else if (status == ctkDICOMPatientItemWidget::Failed)
+ {
+ ctkDICOMJobDetail queryJobDetail;
+ queryJobDetail.JobClass = "ctkDICOMQueryJob";
+ queryJobDetail.DICOMLevel = ctkDICOMJob::DICOMLevels::Studies;
+ queryJobDetail.PatientID = patientItemWidget->patientID();
+
+ d->Scheduler->runJob(queryJobDetail, patientItemWidget->allowedServers());
+ }
+
+}
+
//------------------------------------------------------------------------------
void ctkDICOMVisualBrowserWidget::onServersSettingsChanged()
{
diff --git a/Libs/DICOM/Widgets/ctkDICOMVisualBrowserWidget.h b/Libs/DICOM/Widgets/ctkDICOMVisualBrowserWidget.h
index 0623c60f00..a3b0fc8a0c 100644
--- a/Libs/DICOM/Widgets/ctkDICOMVisualBrowserWidget.h
+++ b/Libs/DICOM/Widgets/ctkDICOMVisualBrowserWidget.h
@@ -388,6 +388,9 @@ public Q_SLOTS:
/// user change patient selection
void onPatientItemChanged(int);
+ /// user clicked on patient tab item
+ void onOperationStatusTabBarItemClicked(int);
+
/// server settings have been changed
void onServersSettingsChanged();