Skip to content

Commit

Permalink
ENH: Add button slots and logic
Browse files Browse the repository at this point in the history
  • Loading branch information
Punzo committed Jan 18, 2024
1 parent cbbd7ea commit f79db5e
Show file tree
Hide file tree
Showing 5 changed files with 264 additions and 7 deletions.
128 changes: 128 additions & 0 deletions Libs/DICOM/Core/ctkDICOMScheduler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,134 @@ void ctkDICOMScheduler::stopJobsByUIDs(const QStringList& patientIDs,
}
}

//----------------------------------------------------------------------------
void ctkDICOMScheduler::stopJobsByJobUIDs(const QStringList &jobUIDs)
{
Q_D(ctkDICOMScheduler);

if (jobUIDs.count() == 0)
{
return;
}

QMutexLocker ml(&d->mMutex);

// Stops jobs without a worker (in waiting)
foreach (QSharedPointer<ctkAbstractJob> job, d->JobsQueue)
{
if (!job)
{
continue;
}

if (job->isPersistent())
{
continue;
}

if (job->status() != ctkAbstractJob::JobStatus::Initialized)
{
continue;
}

ctkDICOMJob* dicomJob = qobject_cast<ctkDICOMJob*>(job.data());
if (!dicomJob)
{
qCritical() << Q_FUNC_INFO << " failed: unexpected type of job";
continue;
}

if ((!dicomJob->jobUID().isEmpty() && jobUIDs.contains(dicomJob->jobUID())))
{
job->setStatus(ctkAbstractJob::JobStatus::Stopped);
this->deleteJob(job->jobUID());
}
}

// Stops queued and running jobs
foreach (QSharedPointer<ctkAbstractWorker> worker, d->Workers)
{
QSharedPointer<ctkAbstractJob> job = worker->jobShared();
if (!job)
{
continue;
}

if (job->isPersistent())
{
continue;
}

ctkDICOMJob* dicomJob = qobject_cast<ctkDICOMJob*>(job.data());
if (!dicomJob)
{
qCritical() << Q_FUNC_INFO << " failed: unexpected type of job";
continue;
}

if ((!dicomJob->jobUID().isEmpty() && jobUIDs.contains(dicomJob->jobUID())))
{
job->setStatus(ctkAbstractJob::JobStatus::Stopped);
worker->cancel();
}
}
}

//----------------------------------------------------------------------------
void ctkDICOMScheduler::retryJobsByJobUIDs(const QMap<QString, ctkDICOMJobDetail> &jobUIDs)
{
Q_D(ctkDICOMScheduler);
for(QString jobUID : jobUIDs.keys())
{
ctkDICOMJobDetail jd = jobUIDs.value(jobUID);
if (jd.JobClass == "ctkDICOMQueryJob")
{
switch (jd.DICOMLevel)
{
case ctkDICOMJob::DICOMLevels::Patients:
this->queryPatients();
break;
case ctkDICOMJob::DICOMLevels::Studies:
this->queryStudies(jd.PatientID);
break;
case ctkDICOMJob::DICOMLevels::Series:
this->querySeries(jd.PatientID,
jd.StudyInstanceUID);
break;
case ctkDICOMJob::DICOMLevels::Instances:
this->queryInstances(jd.PatientID,
jd.StudyInstanceUID,
jd.SeriesInstanceUID);
break;
}
}
else if (jd.JobClass == "ctkDICOMRetrieveJob")
{
switch (jd.DICOMLevel)
{
case ctkDICOMJob::DICOMLevels::Patients:
logger.warn("Retrieve Patient is not implemented");
break;
case ctkDICOMJob::DICOMLevels::Studies:
this->retrieveStudy(jd.PatientID,
jd.StudyInstanceUID);
break;
case ctkDICOMJob::DICOMLevels::Series:
this->retrieveSeries(jd.PatientID,
jd.StudyInstanceUID,
jd.SeriesInstanceUID);
break;
case ctkDICOMJob::DICOMLevels::Instances:
this->retrieveSOPInstance(jd.PatientID,
jd.StudyInstanceUID,
jd.SeriesInstanceUID,
jd.SOPInstanceUID);
break;
}
}
}
}

//----------------------------------------------------------------------------
void ctkDICOMScheduler::raiseJobsPriorityForSeries(const QStringList& selectedSeriesInstanceUIDs,
QThread::Priority priority)
Expand Down
3 changes: 3 additions & 0 deletions Libs/DICOM/Core/ctkDICOMScheduler.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ class ctkAbstractJob;
#include "ctkDICOMCoreExport.h"
#include "ctkDICOMDatabase.h"
class ctkDICOMJob;
class ctkDICOMJobDetail;
class ctkDICOMIndexer;
class ctkDICOMSchedulerPrivate;
class ctkDICOMServer;
Expand Down Expand Up @@ -170,6 +171,8 @@ class CTK_DICOM_CORE_EXPORT ctkDICOMScheduler : public ctkAbstractScheduler
const QStringList& studyInstanceUIDs = {},
const QStringList& seriesInstanceUIDs = {},
const QStringList& sopInstanceUIDs = {});
Q_INVOKABLE void stopJobsByJobUIDs(const QStringList& jobUIDs);
Q_INVOKABLE void retryJobsByJobUIDs(const QMap<QString, ctkDICOMJobDetail>& jobUIDs);
Q_INVOKABLE void raiseJobsPriorityForSeries(const QStringList& selectedSeriesInstanceUIDs,
QThread::Priority priority = QThread::HighestPriority);
///@}
Expand Down
2 changes: 1 addition & 1 deletion Libs/DICOM/Widgets/Resources/UI/ctkDICOMJobListWidget.ui
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@
</sizepolicy>
</property>
<property name="toolTip">
<string>All the completed jobs will be hidden when untoggled.</string>
<string>All the completed jobs will be hidden if unchecked.</string>
</property>
<property name="text">
<string>Show all</string>
Expand Down
132 changes: 126 additions & 6 deletions Libs/DICOM/Widgets/ctkDICOMJobListWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,12 @@ class QCenteredQStandardItemModel : public QStandardItemModel
this->setData(this->index(0, Columns::JobClass), td.JobClass, Qt::ToolTipRole);

QIcon statusIcon = QIcon(":/Icons/pending.svg");
QString status = QObject::tr("queued");
QString statusText = QObject::tr("queued");
QStandardItem *statusItem = new QStandardItem(QString("statusItem"));
statusItem->setIcon(statusIcon);
statusItem->setText(status);
statusItem->setToolTip(status);
this->setItem(row, Columns::Status, statusItem);
this->setData(this->index(row, Columns::Status), statusText);
this->setData(this->index(row, Columns::Status), statusText, Qt::ToolTipRole);

QString DICOMLevel;
if (td.JobClass != "ctkDICOMInserterJob")
Expand Down Expand Up @@ -149,9 +149,18 @@ class QCenteredQStandardItemModel : public QStandardItemModel

QStandardItem *statusItem = new QStandardItem(QString("statusItem"));
statusItem->setIcon(statusIcon);
statusItem->setText(statusText);
statusItem->setToolTip(statusText);
this->setItem(row, Columns::Status, statusItem);
this->setData(this->index(row, Columns::Status), statusText);
this->setData(this->index(row, Columns::Status), statusText, Qt::ToolTipRole);
}
}

void clearCompletedJobs()
{
QList<QStandardItem*> list = this->findItems(tr("completed|canceled|failed"), Qt::MatchRegularExpression, Columns::Status);
foreach (QStandardItem* item, list)
{
this->removeRow(item->row());
}
}
};
Expand All @@ -174,6 +183,7 @@ class ctkDICOMJobListWidgetPrivate: public Ui_ctkDICOMJobListWidget

QSharedPointer<ctkDICOMScheduler> Scheduler;
QSharedPointer<QSortFilterProxyModel> proxyModel;
QSharedPointer<QSortFilterProxyModel> showAllProxyModel;
QSharedPointer<QCenteredQStandardItemModel> dataModel;
};

Expand All @@ -186,6 +196,7 @@ ctkDICOMJobListWidgetPrivate::ctkDICOMJobListWidgetPrivate(ctkDICOMJobListWidget
{
this->Scheduler = nullptr;
this->proxyModel = nullptr;
this->showAllProxyModel = nullptr;
this->dataModel = nullptr;
}

Expand Down Expand Up @@ -219,13 +230,32 @@ void ctkDICOMJobListWidgetPrivate::init()
this->proxyModel = QSharedPointer<QSortFilterProxyModel>(new QSortFilterProxyModel);
this->proxyModel->setSourceModel(this->dataModel.data());

this->showAllProxyModel = QSharedPointer<QSortFilterProxyModel>(new QSortFilterProxyModel);
this->showAllProxyModel->setSourceModel(this->proxyModel.data());
this->showAllProxyModel->setFilterKeyColumn(QCenteredQStandardItemModel::Columns::Status);

this->JobsView->setAlternatingRowColors(false);
this->JobsView->setModel(this->proxyModel.data());
this->JobsView->setModel(this->showAllProxyModel.data());

QObject::connect(this->JobsView->selectionModel(), &QItemSelectionModel::selectionChanged,
q, &ctkDICOMJobListWidget::onJobsViewSelectionChanged);

QObject::connect(this->FilterLineEdit, SIGNAL(textChanged(QString)),
q, SLOT(onFilterTextChanged(QString)));
QObject::connect(this->ColumnComboBox, SIGNAL(currentIndexChanged(int)),
q, SLOT(onFilterColumnChanged(int)));

this->StopButton->setEnabled(false);
this->RetryButton->setEnabled(false);

QObject::connect(this->StopButton, SIGNAL(clicked()),
q, SLOT(onStopButtonClicked()));
QObject::connect(this->RetryButton, SIGNAL(clicked()),
q, SLOT(onRetryButtonClicked()));
QObject::connect(this->ShowCompletedButton, SIGNAL(toggled(bool)),
q, SLOT(onShowCompletedButtonToggled(bool)));
QObject::connect(this->ClearCompletedButton, SIGNAL(clicked()),
q, SLOT(onClearCompletedButtonClicked()));
}

//----------------------------------------------------------------------------
Expand Down Expand Up @@ -411,3 +441,93 @@ void ctkDICOMJobListWidget::onFilterColumnChanged(int index)
d->proxyModel->setFilterKeyColumn(index);
}

//----------------------------------------------------------------------------
void ctkDICOMJobListWidget::onJobsViewSelectionChanged()
{
Q_D(ctkDICOMJobListWidget);
QItemSelectionModel *select = d->JobsView->selectionModel();
bool selectionOn = select->hasSelection();
d->StopButton->setEnabled(selectionOn);
d->RetryButton->setEnabled(selectionOn);
}

//----------------------------------------------------------------------------
void ctkDICOMJobListWidget::onStopButtonClicked()
{
Q_D(ctkDICOMJobListWidget);
QStringList jobsUIDsToStop;
QItemSelectionModel *select = d->JobsView->selectionModel();
QModelIndexList selectedRows = select->selectedRows();
foreach (QModelIndex rowIndex, selectedRows)
{
int row = rowIndex.row();
QString status = d->dataModel->index(row, QCenteredQStandardItemModel::Columns::Status).data().toString();
QString jobUID = d->dataModel->index(row, QCenteredQStandardItemModel::Columns::JobUID).data().toString();
if (status == tr("in-progress") || status == tr("queued"))
{
jobsUIDsToStop.append(jobUID);
}
}

d->Scheduler->stopJobsByJobUIDs(jobsUIDsToStop);
}

//----------------------------------------------------------------------------
void ctkDICOMJobListWidget::onRetryButtonClicked()
{
Q_D(ctkDICOMJobListWidget);
QMap<QString, ctkDICOMJobDetail> jobsUIDsToRetry;
QItemSelectionModel *select = d->JobsView->selectionModel();
QModelIndexList selectedRows = select->selectedRows();
foreach (QModelIndex rowIndex, selectedRows)
{
int row = rowIndex.row();
QString status = d->dataModel->index(row, QCenteredQStandardItemModel::Columns::Status).data().toString();
QString jobUID = d->dataModel->index(row, QCenteredQStandardItemModel::Columns::JobUID).data().toString();
if (status == tr("failed"))
{
ctkDICOMJobDetail jobDetail;
jobDetail.JobClass = d->dataModel->index(row, QCenteredQStandardItemModel::Columns::JobClass).data().toString();

QString DICOMLevelString = d->dataModel->index(row, QCenteredQStandardItemModel::Columns::DICOMLevel).data().toString();
ctkDICOMJob::DICOMLevels DICOMLevel = ctkDICOMJob::DICOMLevels::Patients;
if (DICOMLevelString == "Studies")
{
DICOMLevel = ctkDICOMJob::DICOMLevels::Studies;
}
else if (DICOMLevelString == "Series")
{
DICOMLevel = ctkDICOMJob::DICOMLevels::Series;
}
else if (DICOMLevelString == "Instances")
{
DICOMLevel = ctkDICOMJob::DICOMLevels::Instances;
}

jobDetail.DICOMLevel = DICOMLevel;
jobDetail.PatientID = d->dataModel->index(row, QCenteredQStandardItemModel::Columns::PatientID).data().toString();
jobDetail.StudyInstanceUID = d->dataModel->index(row, QCenteredQStandardItemModel::Columns::StudyInstanceUID).data().toString();
jobDetail.SeriesInstanceUID = d->dataModel->index(row, QCenteredQStandardItemModel::Columns::SeriesInstanceUID).data().toString();
jobDetail.SOPInstanceUID = d->dataModel->index(row, QCenteredQStandardItemModel::Columns::SOPInstanceUID).data().toString();
jobsUIDsToRetry.insert(jobUID, jobDetail);
}
}

d->Scheduler->retryJobsByJobUIDs(jobsUIDsToRetry);
}

//----------------------------------------------------------------------------
void ctkDICOMJobListWidget::onShowCompletedButtonToggled(bool toggled)
{
Q_D(ctkDICOMJobListWidget);
QString text = toggled ? "" : tr("queued|in-progress");
d->showAllProxyModel->setFilterRegExp(text);
}

//----------------------------------------------------------------------------
void ctkDICOMJobListWidget::onClearCompletedButtonClicked()
{
Q_D(ctkDICOMJobListWidget);
d->dataModel->clearCompletedJobs();
}

6 changes: 6 additions & 0 deletions Libs/DICOM/Widgets/ctkDICOMJobListWidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ public Q_SLOTS:
void onFilterTextChanged(QString);
void onFilterColumnChanged(int);

void onJobsViewSelectionChanged();
void onStopButtonClicked();
void onRetryButtonClicked();
void onShowCompletedButtonToggled(bool);
void onClearCompletedButtonClicked();

protected:
QScopedPointer<ctkDICOMJobListWidgetPrivate> d_ptr;

Expand Down

0 comments on commit f79db5e

Please sign in to comment.