From 6e3f13f2b01e78f3ffbce0be8b73170b715c2a0e Mon Sep 17 00:00:00 2001 From: Davide Punzo Date: Mon, 2 Sep 2024 11:34:46 +0200 Subject: [PATCH] ENH: Clean retry --- Libs/Core/ctkAbstractJob.cpp | 13 ++ Libs/Core/ctkAbstractJob.h | 12 + Libs/Core/ctkJobScheduler.cpp | 194 ++++++++++++---- Libs/Core/ctkJobScheduler.h | 8 +- Libs/Core/ctkJobScheduler_p.h | 3 +- Libs/DICOM/Core/ctkDICOMJob.cpp | 6 + Libs/DICOM/Core/ctkDICOMJob.h | 4 + Libs/DICOM/Core/ctkDICOMScheduler.cpp | 137 ------------ Libs/DICOM/Core/ctkDICOMScheduler.h | 3 - Libs/DICOM/Core/ctkDICOMScheduler_p.h | 8 - Libs/DICOM/Widgets/ctkDICOMJobListWidget.cpp | 210 ++++++++---------- .../Widgets/ctkDICOMPatientItemWidget.cpp | 12 - .../DICOM/Widgets/ctkDICOMPatientItemWidget.h | 6 - .../Widgets/ctkDICOMSeriesItemWidget.cpp | 24 +- Libs/DICOM/Widgets/ctkDICOMSeriesItemWidget.h | 6 - .../Widgets/ctkDICOMServerNodeWidget2.cpp | 2 +- .../DICOM/Widgets/ctkDICOMStudyItemWidget.cpp | 23 +- Libs/DICOM/Widgets/ctkDICOMStudyItemWidget.h | 6 - .../Widgets/ctkDICOMVisualBrowserWidget.cpp | 20 +- .../Widgets/ctkDICOMVisualBrowserWidget.h | 2 +- 20 files changed, 307 insertions(+), 392 deletions(-) diff --git a/Libs/Core/ctkAbstractJob.cpp b/Libs/Core/ctkAbstractJob.cpp index fc9f923550..6a43b2789d 100644 --- a/Libs/Core/ctkAbstractJob.cpp +++ b/Libs/Core/ctkAbstractJob.cpp @@ -38,6 +38,7 @@ ctkAbstractJob::ctkAbstractJob() this->MaximumConcurrentJobsPerType = 20; this->Priority = QThread::Priority::LowPriority; this->CreationDateTime = QDateTime::currentDateTime(); + this->DestroyAfterUse = false; } //---------------------------------------------------------------------------- @@ -228,6 +229,18 @@ void ctkAbstractJob::setLoggedText(QString loggedText) this->LoggedText += loggedText; } +//---------------------------------------------------------------------------- +bool ctkAbstractJob::destroyAfterUse() const +{ + return this->DestroyAfterUse; +} + +//---------------------------------------------------------------------------- +void ctkAbstractJob::setDestroyAfterUse(bool destroyAfterUse) +{ + this->DestroyAfterUse = destroyAfterUse; +} + //---------------------------------------------------------------------------- QVariant ctkAbstractJob::toVariant() { diff --git a/Libs/Core/ctkAbstractJob.h b/Libs/Core/ctkAbstractJob.h index 27dbbcd1e8..2eb3aa3288 100644 --- a/Libs/Core/ctkAbstractJob.h +++ b/Libs/Core/ctkAbstractJob.h @@ -56,6 +56,7 @@ class CTK_CORE_EXPORT ctkAbstractJob : public QObject Q_PROPERTY(QDateTime completionDateTime READ completionDateTime); Q_PROPERTY(QString runningThreadID READ runningThreadID WRITE setRunningThreadID); Q_PROPERTY(QString loggedText READ loggedText WRITE setLoggedText); + Q_PROPERTY(bool destroyAfterUse READ destroyAfterUse WRITE setDestroyAfterUse); public: explicit ctkAbstractJob(); @@ -177,6 +178,16 @@ class CTK_CORE_EXPORT ctkAbstractJob : public QObject /// \sa ctkJobDetail Q_INVOKABLE virtual QVariant toVariant(); + /// Free used resources from job after worker is done + Q_INVOKABLE virtual void freeUsedResources() = 0; + + ///@{ + /// Destroy job pointer after worker is done + /// default: false + bool destroyAfterUse() const; + void setDestroyAfterUse(bool destroyAfterUse); + ///@} + Q_SIGNALS: void started(); void userStopped(); @@ -198,6 +209,7 @@ class CTK_CORE_EXPORT ctkAbstractJob : public QObject QDateTime CompletionDateTime; QString RunningThreadID; QString LoggedText; + bool DestroyAfterUse; private: Q_DISABLE_COPY(ctkAbstractJob) diff --git a/Libs/Core/ctkJobScheduler.cpp b/Libs/Core/ctkJobScheduler.cpp index e6ba99488f..0543eec020 100644 --- a/Libs/Core/ctkJobScheduler.cpp +++ b/Libs/Core/ctkJobScheduler.cpp @@ -198,10 +198,8 @@ bool ctkJobSchedulerPrivate::insertJob(QSharedPointer job) } //------------------------------------------------------------------------------ -bool ctkJobSchedulerPrivate::removeJob(const QString& jobUID) +bool ctkJobSchedulerPrivate::cleanJob(const QString &jobUID) { - Q_Q(ctkJobScheduler); - logger.debug(QString("ctkJobScheduler: deleting job object %1 in thread %2.\n") .arg(jobUID) .arg(QString::number(reinterpret_cast(QThread::currentThreadId()), 16))); @@ -216,16 +214,7 @@ bool ctkJobSchedulerPrivate::removeJob(const QString& jobUID) return false; } - QMap connections = this->JobsConnections.value(jobUID); - QObject::disconnect(connections.value("started")); - QObject::disconnect(connections.value("userStopped")); - QObject::disconnect(connections.value("finished")); - QObject::disconnect(connections.value("attemptFailed")); - QObject::disconnect(connections.value("failed")); - QObject::disconnect(connections.value("progress")); - - this->JobsConnections.remove(jobUID); - this->JobsQueue.remove(jobUID); + job->freeUsedResources(); } emit this->queueJobsInThreadPool(); @@ -234,7 +223,7 @@ bool ctkJobSchedulerPrivate::removeJob(const QString& jobUID) } //------------------------------------------------------------------------------ -void ctkJobSchedulerPrivate::removeJobs(const QStringList &jobUIDs) +void ctkJobSchedulerPrivate::cleanJobs(const QStringList &jobUIDs) { Q_Q(ctkJobScheduler); @@ -247,50 +236,73 @@ void ctkJobSchedulerPrivate::removeJobs(const QStringList &jobUIDs) foreach (QString jobUID, jobUIDs) { QSharedPointer job = this->JobsQueue.value(jobUID); - if (!job || !this->JobsConnections.contains(jobUID)) + if (!job) { continue; } datas.append(job->toVariant()); + job->freeUsedResources(); + } + } - QMap connections = this->JobsConnections.value(jobUID); - QObject::disconnect(connections.value("started")); - QObject::disconnect(connections.value("userStopped")); - QObject::disconnect(connections.value("finished")); - QObject::disconnect(connections.value("attemptFailed")); - QObject::disconnect(connections.value("failed")); - QObject::disconnect(connections.value("progress")); + emit q->jobUserStopped(datas); +} - this->JobsConnections.remove(jobUID); - this->JobsQueue.remove(jobUID); +//------------------------------------------------------------------------------ +bool ctkJobSchedulerPrivate::removeJob(const QString& jobUID) +{ + logger.debug(QString("ctkJobScheduler: deleting job object %1 in thread %2.\n") + .arg(jobUID) + .arg(QString::number(reinterpret_cast(QThread::currentThreadId()), 16))); + + { + // The QMutexLocker is enclosed within brackets to restrict its scope and + // prevent conflicts with other QMutexLockers within the scheduler's methods. + QMutexLocker locker(&this->QueueMutex); + QSharedPointer job = this->JobsQueue.value(jobUID); + if (!job || !this->JobsConnections.contains(jobUID)) + { + return false; } + + QMap connections = this->JobsConnections.value(jobUID); + QObject::disconnect(connections.value("started")); + QObject::disconnect(connections.value("userStopped")); + QObject::disconnect(connections.value("finished")); + QObject::disconnect(connections.value("attemptFailed")); + QObject::disconnect(connections.value("failed")); + QObject::disconnect(connections.value("progress")); + + this->JobsConnections.remove(jobUID); + this->JobsQueue.remove(jobUID); } - emit q->jobUserStopped(datas); + emit this->queueJobsInThreadPool(); + + return true; } //------------------------------------------------------------------------------ -void ctkJobSchedulerPrivate::removeAllJobs() +void ctkJobSchedulerPrivate::removeJobs(const QStringList &jobUIDs) { Q_Q(ctkJobScheduler); + QList datas; { // The QMutexLocker is enclosed within brackets to restrict its scope and // prevent conflicts with other QMutexLockers within the scheduler's methods. QMutexLocker locker(&this->QueueMutex); - foreach (QSharedPointer job, this->JobsQueue) + + foreach (QString jobUID, jobUIDs) { - if (!job) + QSharedPointer job = this->JobsQueue.value(jobUID); + if (!job || !this->JobsConnections.contains(jobUID)) { continue; } - QString jobUID = job->jobUID(); - if (!this->JobsConnections.contains(jobUID)) - { - continue; - } + datas.append(job->toVariant()); QMap connections = this->JobsConnections.value(jobUID); QObject::disconnect(connections.value("started")); @@ -304,6 +316,8 @@ void ctkJobSchedulerPrivate::removeAllJobs() this->JobsQueue.remove(jobUID); } } + + emit q->jobUserStopped(datas); } //------------------------------------------------------------------------------ @@ -453,6 +467,13 @@ void ctkJobScheduler::addJob(ctkAbstractJob* job) d->insertJob(jobShared); } +//---------------------------------------------------------------------------- +void ctkJobScheduler::resetJob(const QString &jobUID) +{ + Q_D(ctkJobScheduler); + d->cleanJob(jobUID); +} + //---------------------------------------------------------------------------- void ctkJobScheduler::deleteJob(const QString& jobUID) { @@ -460,6 +481,13 @@ void ctkJobScheduler::deleteJob(const QString& jobUID) d->removeJob(jobUID); } +//---------------------------------------------------------------------------- +void ctkJobScheduler::deleteJobs(const QStringList &jobUIDs) +{ + Q_D(ctkJobScheduler); + d->removeJobs(jobUIDs); +} + //---------------------------------------------------------------------------- void ctkJobScheduler::deleteWorker(const QString& jobUID) { @@ -540,11 +568,11 @@ void ctkJobScheduler::waitForDone(int msec) } //---------------------------------------------------------------------------- -void ctkJobScheduler::stopAllJobs(bool stopPersistentJobs) +QStringList ctkJobScheduler::stopAllJobs(bool stopPersistentJobs, bool removeJobs) { Q_D(ctkJobScheduler); - QStringList initializedStoppedJobsUIDs; + QStringList stoppedJobsUIDs; { // The QMutexLocker is enclosed within brackets to restrict its scope and // prevent conflicts with other QMutexLockers within the scheduler's methods. @@ -578,11 +606,18 @@ void ctkJobScheduler::stopAllJobs(bool stopPersistentJobs) QMap connections = d->JobsConnections.value(jobUID); QObject::disconnect(connections.value("userStopped")); job->setStatus(ctkAbstractJob::JobStatus::UserStopped); - initializedStoppedJobsUIDs.append(jobUID); + stoppedJobsUIDs.append(jobUID); } } - d->removeJobs(initializedStoppedJobsUIDs); + if (removeJobs) + { + d->removeJobs(stoppedJobsUIDs); + } + else + { + d->cleanJobs(stoppedJobsUIDs); + } // Stops queued and running jobs foreach (QSharedPointer worker, d->Workers) @@ -592,13 +627,16 @@ void ctkJobScheduler::stopAllJobs(bool stopPersistentJobs) { continue; } - + stoppedJobsUIDs.append(job->jobUID()); + job->setDestroyAfterUse(removeJobs); worker->requestCancel(); } + + return stoppedJobsUIDs; } //---------------------------------------------------------------------------- -void ctkJobScheduler::stopJobsByJobUIDs(const QStringList &jobUIDs) +void ctkJobScheduler::stopJobsByJobUIDs(const QStringList &jobUIDs, bool removeJobs) { Q_D(ctkJobScheduler); @@ -646,7 +684,14 @@ void ctkJobScheduler::stopJobsByJobUIDs(const QStringList &jobUIDs) } } - d->removeJobs(initializedStoppedJobsUIDs); + if (removeJobs) + { + d->removeJobs(initializedStoppedJobsUIDs); + } + else + { + d->cleanJobs(initializedStoppedJobsUIDs); + } // Stops running jobs foreach (QSharedPointer worker, d->Workers) @@ -659,11 +704,44 @@ void ctkJobScheduler::stopJobsByJobUIDs(const QStringList &jobUIDs) if ((!job->jobUID().isEmpty() && jobUIDs.contains(job->jobUID()))) { + job->setDestroyAfterUse(removeJobs); worker->requestCancel(); } } } +//---------------------------------------------------------------------------- +bool ctkJobScheduler::retryJob(const QString &jobUID) +{ + Q_D(ctkJobScheduler); + + QSharedPointer job = this->getJobSharedByUID(jobUID); + if (!job) + { + return false; + } + + if (job->status() < ctkAbstractJob::JobStatus::UserStopped && + job->status() > ctkAbstractJob::JobStatus::Finished) + { + return false; + } + + job->setStatus(ctkAbstractJob::JobStatus::Initialized); + emit this->jobInitialized(job->toVariant()); + emit d->queueJobsInThreadPool(); + return true; +} + +//---------------------------------------------------------------------------- +void ctkJobScheduler::retryJobs(const QStringList &jobUIDs) +{ + foreach (QString jobUID, jobUIDs) + { + this->retryJob(jobUID); + } +} + //---------------------------------------------------------------------------- int ctkJobScheduler::maximumThreadCount() const @@ -725,7 +803,14 @@ void ctkJobScheduler::onJobUserStopped(ctkAbstractJob* job) QVariant data = job->toVariant(); QString jobUID = job->jobUID(); this->deleteWorker(jobUID); - this->deleteJob(jobUID); + if (job->destroyAfterUse()) + { + this->deleteJob(jobUID); + } + else + { + this->resetJob(jobUID); + } d->BatchedJobsUserStopped.append(job->toVariant()); if (!d->ThrottleTimer->isActive()) @@ -748,7 +833,14 @@ void ctkJobScheduler::onJobFinished(ctkAbstractJob* job) QVariant data = job->toVariant(); QString jobUID = job->jobUID(); this->deleteWorker(jobUID); - this->deleteJob(jobUID); + if (job->destroyAfterUse()) + { + this->deleteJob(jobUID); + } + else + { + this->resetJob(jobUID); + } d->BatchedJobsFinished.append(job->toVariant()); if (!d->ThrottleTimer->isActive()) @@ -771,7 +863,14 @@ void ctkJobScheduler::onJobAttemptFailed(ctkAbstractJob* job) QVariant data = job->toVariant(); QString jobUID = job->jobUID(); this->deleteWorker(jobUID); - this->deleteJob(jobUID); + if (job->destroyAfterUse()) + { + this->deleteJob(jobUID); + } + else + { + this->resetJob(jobUID); + } d->BatchedJobsAttemptFailed.append(job->toVariant()); if (!d->ThrottleTimer->isActive()) @@ -794,7 +893,14 @@ void ctkJobScheduler::onJobFailed(ctkAbstractJob* job) QVariant data = job->toVariant(); QString jobUID = job->jobUID(); this->deleteWorker(jobUID); - this->deleteJob(jobUID); + if (job->destroyAfterUse()) + { + this->deleteJob(jobUID); + } + else + { + this->resetJob(jobUID); + } d->BatchedJobsFailed.append(job->toVariant()); if (!d->ThrottleTimer->isActive()) diff --git a/Libs/Core/ctkJobScheduler.h b/Libs/Core/ctkJobScheduler.h index 4ff945c054..cbe20c629d 100644 --- a/Libs/Core/ctkJobScheduler.h +++ b/Libs/Core/ctkJobScheduler.h @@ -59,15 +59,19 @@ class CTK_CORE_EXPORT ctkJobScheduler : public QObject int numberOfPersistentJobs(); int numberOfRunningJobs(); Q_INVOKABLE void addJob(ctkAbstractJob* job); + Q_INVOKABLE virtual void resetJob(const QString& jobUID); Q_INVOKABLE virtual void deleteJob(const QString& jobUID); + Q_INVOKABLE virtual void deleteJobs(const QStringList& jobUIDs); Q_INVOKABLE virtual void deleteWorker(const QString& jobUID); QSharedPointer getJobSharedByUID(const QString& jobUID); Q_INVOKABLE ctkAbstractJob* getJobByUID(const QString& jobUID); Q_INVOKABLE void waitForFinish(bool waitForPersistentJobs = false, bool processEvents = false); Q_INVOKABLE void waitForDone(int msec = -1); - Q_INVOKABLE void stopAllJobs(bool stopPersistentJobs = false); - Q_INVOKABLE void stopJobsByJobUIDs(const QStringList& jobUIDs); + Q_INVOKABLE QStringList stopAllJobs(bool stopPersistentJobs = false, bool removeJobs = true); + Q_INVOKABLE void stopJobsByJobUIDs(const QStringList& jobUIDs, bool removeJobs = false); + Q_INVOKABLE bool retryJob(const QString& jobUID); + Q_INVOKABLE void retryJobs(const QStringList& jobUIDs); ///@} ///@{ diff --git a/Libs/Core/ctkJobScheduler_p.h b/Libs/Core/ctkJobScheduler_p.h index f6a792abac..0d7efc8e77 100644 --- a/Libs/Core/ctkJobScheduler_p.h +++ b/Libs/Core/ctkJobScheduler_p.h @@ -58,9 +58,10 @@ public Q_SLOTS: virtual void init(); virtual bool insertJob(QSharedPointer job); + virtual bool cleanJob(const QString& jobUID); + virtual void cleanJobs(const QStringList& jobUIDs); virtual bool removeJob(const QString& jobUID); virtual void removeJobs(const QStringList& jobUIDs); - virtual void removeAllJobs(); int getSameTypeJobsInThreadPoolQueueOrRunning(QSharedPointer job); QString generateUniqueJobUID(); void clearBactchedJobsLists(); diff --git a/Libs/DICOM/Core/ctkDICOMJob.cpp b/Libs/DICOM/Core/ctkDICOMJob.cpp index 00c1cf46bd..f97fe73988 100644 --- a/Libs/DICOM/Core/ctkDICOMJob.cpp +++ b/Libs/DICOM/Core/ctkDICOMJob.cpp @@ -184,3 +184,9 @@ QVariant ctkDICOMJob::toVariant() { return QVariant::fromValue(ctkDICOMJobDetail(*this)); } + +//------------------------------------------------------------------------------ +void ctkDICOMJob::freeUsedResources() +{ + this->JobResponseSets.clear(); +} diff --git a/Libs/DICOM/Core/ctkDICOMJob.h b/Libs/DICOM/Core/ctkDICOMJob.h index 433241d29a..7bb405db65 100644 --- a/Libs/DICOM/Core/ctkDICOMJob.h +++ b/Libs/DICOM/Core/ctkDICOMJob.h @@ -117,6 +117,10 @@ class CTK_DICOM_CORE_EXPORT ctkDICOMJob : public ctkAbstractJob /// \sa ctkDICOMJobDetail Q_INVOKABLE virtual QVariant toVariant() override; + /// Free used resources from job + /// \sa ctkAbstractJob::freeUsedResources + Q_INVOKABLE virtual void freeUsedResources() override; + Q_SIGNALS: void progressJobDetail(QVariant); diff --git a/Libs/DICOM/Core/ctkDICOMScheduler.cpp b/Libs/DICOM/Core/ctkDICOMScheduler.cpp index 440af83d9a..7335da0d3b 100644 --- a/Libs/DICOM/Core/ctkDICOMScheduler.cpp +++ b/Libs/DICOM/Core/ctkDICOMScheduler.cpp @@ -173,112 +173,6 @@ ctkDICOMServer* ctkDICOMSchedulerPrivate::getServerFromProxyServersByConnectionN return nullptr; } -//------------------------------------------------------------------------------ -void ctkDICOMSchedulerPrivate::handleQueryJob(const ctkDICOMJobDetail& jd, - const QStringList& allowedServers) -{ - Q_Q(ctkDICOMScheduler); - - switch (jd.DICOMLevel) - { - case ctkDICOMJob::DICOMLevels::None: - logger.warn("ctkDICOMScheduler : DICOMLevels was not set."); - break; - case ctkDICOMJob::DICOMLevels::Patients: - jd.JobUID.isEmpty() ? q->queryPatients() : q->queryPatients(QThread::NormalPriority, jd.ConnectionName, jd.JobUID); - break; - case ctkDICOMJob::DICOMLevels::Studies: - jd.JobUID.isEmpty() ? q->queryStudies(jd.PatientID, QThread::NormalPriority, allowedServers) : - q->queryStudies(jd.PatientID, QThread::NormalPriority, allowedServers, jd.ConnectionName, jd.JobUID); - break; - case ctkDICOMJob::DICOMLevels::Series: - jd.JobUID.isEmpty() ? q->querySeries(jd.PatientID, jd.StudyInstanceUID, QThread::NormalPriority, allowedServers) : - q->querySeries(jd.PatientID, jd.StudyInstanceUID, QThread::NormalPriority, allowedServers, jd.ConnectionName, jd.JobUID); - break; - case ctkDICOMJob::DICOMLevels::Instances: - jd.JobUID.isEmpty() ? q->queryInstances(jd.PatientID, jd.StudyInstanceUID, jd.SeriesInstanceUID, QThread::NormalPriority, allowedServers) : - q->queryInstances(jd.PatientID, jd.StudyInstanceUID, jd.SeriesInstanceUID, QThread::NormalPriority, allowedServers, jd.ConnectionName, jd.JobUID); - break; - } -} - -//------------------------------------------------------------------------------ -void ctkDICOMSchedulerPrivate::handleRetrieveJob(const ctkDICOMJobDetail& jd, - const QStringList& allowedServers) -{ - Q_Q(ctkDICOMScheduler); - - switch (jd.DICOMLevel) - { - case ctkDICOMJob::DICOMLevels::None: - logger.warn("ctkDICOMScheduler : DICOMLevels was not set."); - break; - case ctkDICOMJob::DICOMLevels::Patients: - logger.warn("Retrieve Patient is not implemented"); - break; - case ctkDICOMJob::DICOMLevels::Studies: - jd.JobUID.isEmpty() ? q->retrieveStudy(jd.PatientID, jd.StudyInstanceUID, QThread::NormalPriority, allowedServers) : - q->retrieveStudy(jd.PatientID, jd.StudyInstanceUID, QThread::NormalPriority, allowedServers, jd.ConnectionName, jd.JobUID); - break; - case ctkDICOMJob::DICOMLevels::Series: - jd.JobUID.isEmpty() ? q->retrieveSeries(jd.PatientID, jd.StudyInstanceUID, jd.SeriesInstanceUID, QThread::NormalPriority, allowedServers) : - q->retrieveSeries(jd.PatientID, jd.StudyInstanceUID, jd.SeriesInstanceUID, QThread::NormalPriority, allowedServers, jd.ConnectionName, jd.JobUID); - break; - case ctkDICOMJob::DICOMLevels::Instances: - jd.JobUID.isEmpty() ? q->retrieveSOPInstance(jd.PatientID, jd.StudyInstanceUID, jd.SeriesInstanceUID, jd.SOPInstanceUID, QThread::NormalPriority, allowedServers) : - q->retrieveSOPInstance(jd.PatientID, jd.StudyInstanceUID, jd.SeriesInstanceUID, jd.SOPInstanceUID, QThread::NormalPriority, allowedServers, jd.ConnectionName, jd.JobUID); - break; - } -} - -//------------------------------------------------------------------------------ -void ctkDICOMSchedulerPrivate::handleJobByType(const ctkDICOMJobDetail& jd, - const QStringList& allowedServers) -{ - Q_Q(ctkDICOMScheduler); - - switch (jd.JobType) - { - case ctkDICOMJobResponseSet::JobType::None: - break; - case ctkDICOMJobResponseSet::JobType::StoreSOPInstance: - break; - case ctkDICOMJobResponseSet::JobType::Inserter: - break; - case ctkDICOMJobResponseSet::JobType::Echo: - break; - case ctkDICOMJobResponseSet::JobType::ThumbnailGenerator: - break; - case ctkDICOMJobResponseSet::JobType::QueryPatients: - jd.JobUID.isEmpty() ? q->queryPatients() : q->queryPatients(QThread::NormalPriority, jd.ConnectionName, jd.JobUID); - break; - case ctkDICOMJobResponseSet::JobType::QueryStudies: - jd.JobUID.isEmpty() ? q->queryStudies(jd.PatientID, QThread::NormalPriority, allowedServers) : - q->queryStudies(jd.PatientID, QThread::NormalPriority, allowedServers, jd.ConnectionName, jd.JobUID); - break; - case ctkDICOMJobResponseSet::JobType::QuerySeries: - jd.JobUID.isEmpty() ? q->querySeries(jd.PatientID, jd.StudyInstanceUID, QThread::NormalPriority, allowedServers) : - q->querySeries(jd.PatientID, jd.StudyInstanceUID, QThread::NormalPriority, allowedServers, jd.ConnectionName, jd.JobUID); - break; - case ctkDICOMJobResponseSet::JobType::QueryInstances: - jd.JobUID.isEmpty() ? q->queryInstances(jd.PatientID, jd.StudyInstanceUID, jd.SeriesInstanceUID, QThread::NormalPriority, allowedServers) : - q->queryInstances(jd.PatientID, jd.StudyInstanceUID, jd.SeriesInstanceUID, QThread::NormalPriority, allowedServers, jd.ConnectionName, jd.JobUID); - break; - case ctkDICOMJobResponseSet::JobType::RetrieveStudy: - jd.JobUID.isEmpty() ? q->retrieveStudy(jd.PatientID, jd.StudyInstanceUID, QThread::NormalPriority, allowedServers) : - q->retrieveStudy(jd.PatientID, jd.StudyInstanceUID, QThread::NormalPriority, allowedServers, jd.ConnectionName, jd.JobUID); - break; - case ctkDICOMJobResponseSet::JobType::RetrieveSeries: - jd.JobUID.isEmpty() ? q->retrieveSeries(jd.PatientID, jd.StudyInstanceUID, jd.SeriesInstanceUID, QThread::NormalPriority, allowedServers) : - q->retrieveSeries(jd.PatientID, jd.StudyInstanceUID, jd.SeriesInstanceUID, QThread::NormalPriority, allowedServers, jd.ConnectionName, jd.JobUID); - break; - case ctkDICOMJobResponseSet::JobType::RetrieveSOPInstance: - jd.JobUID.isEmpty() ? q->retrieveSOPInstance(jd.PatientID, jd.StudyInstanceUID, jd.SeriesInstanceUID, jd.SOPInstanceUID, QThread::NormalPriority, allowedServers) : - q->retrieveSOPInstance(jd.PatientID, jd.StudyInstanceUID, jd.SeriesInstanceUID, jd.SOPInstanceUID, QThread::NormalPriority, allowedServers, jd.ConnectionName, jd.JobUID); - break; - } -} - //------------------------------------------------------------------------------ bool ctkDICOMSchedulerPrivate::isJobDuplicate(ctkDICOMJob *referenceJob) { @@ -1159,37 +1053,6 @@ void ctkDICOMScheduler::stopJobsByDICOMUIDs(const QStringList& patientIDs, this->stopJobsByJobUIDs(jobsUIDs); } -//---------------------------------------------------------------------------- -void ctkDICOMScheduler::runJob(const ctkDICOMJobDetail& jd, const QStringList& allowedSeversForPatient) -{ - Q_D(ctkDICOMScheduler); - - QStringList allowedSevers = QStringList(jd.ConnectionName); - allowedSevers.append(allowedSeversForPatient); - - if (jd.JobClass == "ctkDICOMQueryJob") - { - d->handleQueryJob(jd, allowedSevers); - } - else if (jd.JobClass == "ctkDICOMRetrieveJob") - { - d->handleRetrieveJob(jd, allowedSevers); - } - else - { - d->handleJobByType(jd, allowedSevers); - } -} - -//---------------------------------------------------------------------------- -void ctkDICOMScheduler::runJobs(const QMap &jobDetails) -{ - for(QString jobUID : jobDetails.keys()) - { - this->runJob(jobDetails.value(jobUID)); - } -} - //---------------------------------------------------------------------------- void ctkDICOMScheduler::raiseJobsPriorityForSeries(const QStringList& selectedSeriesInstanceUIDs, QThread::Priority priority) diff --git a/Libs/DICOM/Core/ctkDICOMScheduler.h b/Libs/DICOM/Core/ctkDICOMScheduler.h index 059fd55cc1..de033f4753 100644 --- a/Libs/DICOM/Core/ctkDICOMScheduler.h +++ b/Libs/DICOM/Core/ctkDICOMScheduler.h @@ -210,9 +210,6 @@ class CTK_DICOM_CORE_EXPORT ctkDICOMScheduler : public ctkJobScheduler const QStringList& studyInstanceUIDs = {}, const QStringList& seriesInstanceUIDs = {}, const QStringList& sopInstanceUIDs = {}); - - Q_INVOKABLE void runJob(const ctkDICOMJobDetail& jobDetails, const QStringList& allowedSeversForPatient = QStringList()); - Q_INVOKABLE void runJobs(const QMap& jobDetails); Q_INVOKABLE void raiseJobsPriorityForSeries(const QStringList& selectedSeriesInstanceUIDs, QThread::Priority priority = QThread::HighestPriority); ///@} diff --git a/Libs/DICOM/Core/ctkDICOMScheduler_p.h b/Libs/DICOM/Core/ctkDICOMScheduler_p.h index 3799501a6c..a9994c3932 100644 --- a/Libs/DICOM/Core/ctkDICOMScheduler_p.h +++ b/Libs/DICOM/Core/ctkDICOMScheduler_p.h @@ -61,14 +61,6 @@ class ctkDICOMSchedulerPrivate : public ctkJobSchedulerPrivate bool isServerAllowed(ctkDICOMServer* server, const QStringList& allowedSeversForPatient); ctkDICOMServer* getServerFromProxyServersByConnectionName(const QString&); - - void handleQueryJob(const ctkDICOMJobDetail& jd, - const QStringList& allowedServers = QStringList()); - void handleRetrieveJob(const ctkDICOMJobDetail& jd, - const QStringList& allowedServers = QStringList()); - void handleJobByType(const ctkDICOMJobDetail& jd, - const QStringList& allowedServers = QStringList()); - bool isJobDuplicate(ctkDICOMJob* job); QSharedPointer DicomDatabase; diff --git a/Libs/DICOM/Widgets/ctkDICOMJobListWidget.cpp b/Libs/DICOM/Widgets/ctkDICOMJobListWidget.cpp index 673655aa20..dcc0ad0637 100644 --- a/Libs/DICOM/Widgets/ctkDICOMJobListWidget.cpp +++ b/Libs/DICOM/Widgets/ctkDICOMJobListWidget.cpp @@ -111,7 +111,6 @@ class QCenteredItemModel : public QStandardItemModel JobClass, JobThread, JobLogging, - JobBackupLogging, }; Q_ENUM(Columns); QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; @@ -120,7 +119,11 @@ class QCenteredItemModel : public QStandardItemModel void updateJobStatus(const ctkDICOMJobDetail &td, const JobStatus &status); void updateProgressBar(const ctkDICOMJobDetail &td, ctkDICOMDatabase* database); void setProgressBar(int row, const ctkDICOMJobDetail &td, ctkDICOMDatabase* database); - void clearCompletedJobs(); + QStringList clearJobsByType(QString type); + QStringList clearCompletedJobs(); + QStringList clearFailedJobs(); + QStringList clearUserStoppedJobs(); + void removeRowsByJobUIDs(QStringList jobUIDs); static Columns getColumnIndexFromString(QString columnString); static QString getColumnStringFromIndex(Columns columnIndex); }; @@ -206,18 +209,8 @@ void QCenteredItemModel::addJob(const ctkDICOMJobDetail &td, int row = 0; QString backupLogging, creationDateTime; - QList list = this->findItems(td.JobUID, Qt::MatchExactly, Columns::JobUID); - if (!list.empty()) - { - row = list.first()->row(); - backupLogging = this->index(row, QCenteredItemModel::Columns::JobLogging).data().toString(); - creationDateTime = this->index(row, QCenteredItemModel::Columns::CreationDateTime).data().toString(); - } - else - { - this->insertRow(row); - creationDateTime = td.CreationDateTime; - } + this->insertRow(row); + creationDateTime = td.CreationDateTime; QString jobType = this->getJobTypeAsString(td.JobClass, td.DICOMLevel); this->setData(this->index(row, Columns::JobType), jobType); @@ -290,7 +283,6 @@ void QCenteredItemModel::addJob(const ctkDICOMJobDetail &td, this->setData(this->index(row, Columns::JobClass), td.JobClass); this->setData(this->index(row, Columns::JobThread), td.RunningThreadID); this->setData(this->index(row, Columns::JobLogging), td.Logging); - this->setData(this->index(row, Columns::JobBackupLogging), backupLogging); } //---------------------------------------------------------------------------- @@ -309,6 +301,10 @@ void QCenteredItemModel::updateJobStatus(const ctkDICOMJobDetail &td, const JobS { statusIcon = QIcon(":/Icons/pending.svg"); statusText = ctkDICOMJobListWidget::tr("queued"); + QList data; + data.append(0); + data.append(100); + this->setData(this->index(row, Columns::Progress), data); } else if (status == Running) { @@ -439,20 +435,61 @@ void QCenteredItemModel::setProgressBar(int row, const ctkDICOMJobDetail &td, ct } //---------------------------------------------------------------------------- -void QCenteredItemModel::clearCompletedJobs() +QStringList QCenteredItemModel::clearJobsByType(QString type) { #if (QT_VERSION >= QT_VERSION_CHECK(5,15,0)) - QList attemptFailedList = this->findItems(ctkDICOMJobListWidget::tr("attempt-failed"), Qt::MatchRegularExpression, Columns::Status); - QList completedList = this->findItems(ctkDICOMJobListWidget::tr("completed"), Qt::MatchRegularExpression, Columns::Status); + QList list = this->findItems(type, Qt::MatchRegularExpression, Columns::Status); #else - QList attemptFailedList = this->findItems(ctkDICOMJobListWidget::tr("attempt-failed"), Qt::MatchRegExp, Columns::Status); - QList completedList = this->findItems(ctkDICOMJobListWidget::tr("completed"), Qt::MatchRegExp, Columns::Status); + QList list = this->findItems(type, Qt::MatchRegExp, Columns::Status); #endif - completedList.append(attemptFailedList); - foreach (QStandardItem* item, completedList) + QStringList jobUIDs; + foreach (QStandardItem* item, list) + { + int row = item->row(); + jobUIDs.append(this->index(row, QCenteredItemModel::Columns::JobUID).data().toString()); + this->removeRow(row); + } + + return jobUIDs; +} + +//---------------------------------------------------------------------------- +QStringList QCenteredItemModel::clearCompletedJobs() +{ + QStringList jobUIDs; + jobUIDs.append(this->clearJobsByType(ctkDICOMJobListWidget::tr("attempt-failed"))); + jobUIDs.append(this->clearJobsByType(ctkDICOMJobListWidget::tr("completed"))); + return jobUIDs; +} + +//---------------------------------------------------------------------------- +QStringList QCenteredItemModel::clearFailedJobs() +{ + return this->clearJobsByType(ctkDICOMJobListWidget::tr("failed"));; +} + +//---------------------------------------------------------------------------- +QStringList QCenteredItemModel::clearUserStoppedJobs() +{ + return this->clearJobsByType(ctkDICOMJobListWidget::tr("user-stopped"));; +} + +//---------------------------------------------------------------------------- +void QCenteredItemModel::removeRowsByJobUIDs(QStringList jobUIDs) +{ + foreach (QString jobUID, jobUIDs) { - this->removeRow(item->row()); +#if (QT_VERSION >= QT_VERSION_CHECK(5,15,0)) + QList list = this->findItems(jobUID, Qt::MatchRegularExpression, Columns::JobUID); +#else + QList list = this->findItems(jobUID, Qt::MatchRegExp, Columns::JobUID); +#endif + if (!list.empty()) + { + int row = list.first()->row(); + this->removeRow(row); + } } } @@ -531,10 +568,6 @@ QCenteredItemModel::Columns QCenteredItemModel::getColumnIndexFromString(QString { return Columns::JobLogging; } - else if (columnString == ctkDICOMJobListWidget::tr("BackupLogging")) - { - return Columns::JobBackupLogging; - } else { return Columns::JobClass; @@ -582,8 +615,6 @@ QString QCenteredItemModel::getColumnStringFromIndex(Columns columnIndex) return ctkDICOMJobListWidget::tr("Thread"); case Columns::JobLogging: return ctkDICOMJobListWidget::tr("Logging"); - case Columns::JobBackupLogging: - return ctkDICOMJobListWidget::tr("JobBackupLogging"); default: return QString(); } @@ -668,7 +699,6 @@ void ctkDICOMJobListWidgetPrivate::init() allColumnNames.append(QCenteredItemModel::getColumnStringFromIndex(QCenteredItemModel::Columns::JobClass)); allColumnNames.append(QCenteredItemModel::getColumnStringFromIndex(QCenteredItemModel::Columns::JobThread)); allColumnNames.append(QCenteredItemModel::getColumnStringFromIndex(QCenteredItemModel::Columns::JobLogging)); - allColumnNames.append(QCenteredItemModel::getColumnStringFromIndex(QCenteredItemModel::Columns::JobBackupLogging)); this->dataModel = QSharedPointer(new QCenteredItemModel(0, allColumnNames.count(), q)); this->dataModel->setHorizontalHeaderLabels(allColumnNames); @@ -694,7 +724,6 @@ void ctkDICOMJobListWidgetPrivate::init() this->JobsView->setColumnHidden(QCenteredItemModel::Columns::JobClass, true); this->JobsView->setColumnHidden(QCenteredItemModel::Columns::JobThread, true); this->JobsView->setColumnHidden(QCenteredItemModel::Columns::JobLogging, true); - this->JobsView->setColumnHidden(QCenteredItemModel::Columns::JobBackupLogging, true); QObject::connect(this->JobsView->selectionModel(), &QItemSelectionModel::selectionChanged, q, &ctkDICOMJobListWidget::onJobsViewSelectionChanged); @@ -844,8 +873,6 @@ void ctkDICOMJobListWidgetPrivate::updateJobsDetailsWidget() (row, QCenteredItemModel::Columns::JobClass).data().toString(); QString thread = this->showCompletedProxyModel->index (row, QCenteredItemModel::Columns::JobThread).data().toString(); - QString backupLogging = this->showCompletedProxyModel->index - (row, QCenteredItemModel::Columns::JobBackupLogging).data().toString(); QString logging = this->showCompletedProxyModel->index (row, QCenteredItemModel::Columns::JobLogging).data().toString(); @@ -932,7 +959,7 @@ void ctkDICOMJobListWidgetPrivate::updateJobsDetailsWidget() if (!logging.isEmpty()) { detailsText.append(QCenteredItemModel::getColumnStringFromIndex(QCenteredItemModel::Columns::JobLogging)); - detailsText.append(QString(":\n") + backupLogging + logging + QString("\n")); + detailsText.append(QString(":\n") + logging + QString("\n")); } if (count == 0) @@ -948,7 +975,7 @@ void ctkDICOMJobListWidgetPrivate::updateJobsDetailsWidget() //---------------------------------------------------------------------------- void ctkDICOMJobListWidgetPrivate::retryJobs() { - QMap jobsUIDsToRetry; + QStringList jobsUIDsToRetry; QItemSelectionModel *select = this->JobsView->selectionModel(); QModelIndexList selectedRows = select->selectedRows(); foreach (QModelIndex rowIndex, selectedRows) @@ -969,87 +996,12 @@ void ctkDICOMJobListWidgetPrivate::retryJobs() continue; } - ctkDICOMJobDetail jobDetail; - jobDetail.JobClass = this->showCompletedProxyModel->index - (row, QCenteredItemModel::Columns::JobClass).data().toString(); - - QString DICOMLevelString = this->showCompletedProxyModel->index - (row, QCenteredItemModel::Columns::DICOMLevel).data().toString(); - ctkDICOMJob::DICOMLevels DICOMLevel = ctkDICOMJob::DICOMLevels::None; - if (DICOMLevelString == "Patients") - { - DICOMLevel = ctkDICOMJob::DICOMLevels::Patients; - } - else 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 = this->showCompletedProxyModel->index - (row, QCenteredItemModel::Columns::PatientID).data().toString(); - jobDetail.StudyInstanceUID = this->showCompletedProxyModel->index - (row, QCenteredItemModel::Columns::StudyInstanceUID).data().toString(); - jobDetail.SeriesInstanceUID = this->showCompletedProxyModel->index - (row, QCenteredItemModel::Columns::SeriesInstanceUID).data().toString(); - jobDetail.SOPInstanceUID = this->showCompletedProxyModel->index - (row, QCenteredItemModel::Columns::SOPInstanceUID).data().toString(); - jobDetail.ConnectionName = this->showCompletedProxyModel->index - (row, QCenteredItemModel::Columns::Connection).data().toString(); - jobDetail.JobUID = this->showCompletedProxyModel->index - (row, QCenteredItemModel::Columns::JobUID).data().toString(); - jobsUIDsToRetry.insert(jobDetail.JobUID, jobDetail); - } - - // remove duplicate jobs (e.g., in the selected list there is multiple - // entries of the same job canceled/failed, we don't want running multiple - // times the same jobs) - QMap filteredJobsUIDsToRetry; - foreach (QString jobUID, jobsUIDsToRetry.keys()) - { - ctkDICOMJobDetail td = jobsUIDsToRetry.value(jobUID); - bool duplicate = false; - foreach (QString filteredJobUID, filteredJobsUIDsToRetry.keys()) - { - if (filteredJobUID == jobUID) - { - continue; - } - - ctkDICOMJobDetail filteredTD = jobsUIDsToRetry.value(filteredJobUID); - if (td.JobClass == filteredTD.JobClass && - td.DICOMLevel == filteredTD.DICOMLevel && - td.PatientID == filteredTD.PatientID && - td.StudyInstanceUID == filteredTD.StudyInstanceUID && - td.SeriesInstanceUID == filteredTD.SeriesInstanceUID && - td.SOPInstanceUID == filteredTD.SOPInstanceUID && - td.ConnectionName == filteredTD.ConnectionName) - { - duplicate = true; - break; - } - } - - if (duplicate) - { - continue; - } - else - { - filteredJobsUIDsToRetry.insert(jobUID, td); - } + jobsUIDsToRetry.append(this->showCompletedProxyModel->index + (row, QCenteredItemModel::Columns::JobUID).data().toString()); } this->JobsView->clearSelection(); - this->Scheduler->runJobs(filteredJobsUIDsToRetry); + this->Scheduler->retryJobs(jobsUIDsToRetry); } //---------------------------------------------------------------------------- @@ -1120,7 +1072,15 @@ void ctkDICOMJobListWidget::onJobInitialized(QVariant data) return; } - d->dataModel->addJob(td, d->Scheduler->dicomDatabase()); + QList list = d->dataModel->findItems(td.JobUID, Qt::MatchExactly, QCenteredItemModel::Columns::JobUID); + if (list.empty()) + { + d->dataModel->addJob(td, d->Scheduler->dicomDatabase()); + } + else + { + d->dataModel->updateJobStatus(td, QCenteredItemModel::Initialized); + } } //---------------------------------------------------------------------------- @@ -1369,7 +1329,11 @@ void ctkDICOMJobListWidget::onShowCompletedButtonToggled(bool toggled) void ctkDICOMJobListWidget::onClearCompletedButtonClicked() { Q_D(ctkDICOMJobListWidget); - d->dataModel->clearCompletedJobs(); + QStringList jobUIDs = d->dataModel->clearCompletedJobs(); + // Delete jobs pointer of completed jobs + // (for these the scheduler has only cleaned the memory footprint). + // NOTE: attempt-failed are considered completed jobs + d->Scheduler->deleteJobs(jobUIDs); } //---------------------------------------------------------------------------- @@ -1377,7 +1341,19 @@ void ctkDICOMJobListWidget::onClearAllButtonClicked() { Q_D(ctkDICOMJobListWidget); QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); - d->Scheduler->stopAllJobs(); + // Stop all initialized, queued, in-progress jobs and clean the UI rows. + // Jobs will destroyed automatically by the scheduler. + QStringList stoppedJobUIDs = d->Scheduler->stopAllJobs(); + d->dataModel->removeRowsByJobUIDs(stoppedJobUIDs); + + // Clean UI rows of completed, failed, user-stopped jobs + QStringList jobUIDsToDelete = d->dataModel->clearCompletedJobs(); + jobUIDsToDelete.append(d->dataModel->clearFailedJobs()); + jobUIDsToDelete.append(d->dataModel->clearUserStoppedJobs()); + // Delete jobs pointer of completed/failed/user-stopped jobs + // (for these the scheduler has only cleaned the memory footprint). + // NOTE: attempt-failed are considered completed jobs + d->Scheduler->deleteJobs(jobUIDsToDelete); + QApplication::restoreOverrideCursor(); - d->dataModel->removeRows(0, d->dataModel->rowCount()); } diff --git a/Libs/DICOM/Widgets/ctkDICOMPatientItemWidget.cpp b/Libs/DICOM/Widgets/ctkDICOMPatientItemWidget.cpp index 44abbd128d..5b5385e774 100644 --- a/Libs/DICOM/Widgets/ctkDICOMPatientItemWidget.cpp +++ b/Libs/DICOM/Widgets/ctkDICOMPatientItemWidget.cpp @@ -103,8 +103,6 @@ class ctkDICOMPatientItemWidgetPrivate : public Ui_ctkDICOMPatientItemWidget QStringList AllowedServers; ctkDICOMPatientItemWidget::OperationStatus Status; QString StoppedJobUID; - QString StoppedJobConnectionName; - ctkDICOMJobResponseSet::JobType StoppedJobType; bool IsGUIUpdating; bool QueryOn; @@ -139,8 +137,6 @@ ctkDICOMPatientItemWidgetPrivate::ctkDICOMPatientItemWidgetPrivate(ctkDICOMPatie this->AllowedServers = QStringList(); this->Status = ctkDICOMPatientItemWidget::NoOperation; this->StoppedJobUID = ""; - this->StoppedJobConnectionName = ""; - this->StoppedJobType = ctkDICOMJobResponseSet::JobType::None; this->IsGUIUpdating = false; this->QueryOn = true; @@ -657,9 +653,6 @@ CTK_GET_CPP(ctkDICOMPatientItemWidget, int, numberOfOpenedStudiesPerPatient, Num CTK_SET_CPP(ctkDICOMPatientItemWidget, const ctkDICOMStudyItemWidget::ThumbnailSizeOption&, setThumbnailSize, ThumbnailSize); CTK_GET_CPP(ctkDICOMPatientItemWidget, ctkDICOMStudyItemWidget::ThumbnailSizeOption, thumbnailSize, ThumbnailSize); CTK_GET_CPP(ctkDICOMPatientItemWidget, QString, stoppedJobUID, StoppedJobUID); -CTK_GET_CPP(ctkDICOMPatientItemWidget, QString, stoppedJobConnectionName, StoppedJobConnectionName); -CTK_GET_CPP(ctkDICOMPatientItemWidget, ctkDICOMJobResponseSet::JobType, stoppedJobType, StoppedJobType); - //------------------------------------------------------------------------------ void ctkDICOMPatientItemWidget::setPatientItem(const QString& patientItem) @@ -913,7 +906,6 @@ void ctkDICOMPatientItemWidget::generateStudies(bool query, bool retrieve) //------------------------------------------------------------------------------ void ctkDICOMPatientItemWidget::generateSeriesAtToggle(bool toggled, const QString& studyItem) { - Q_D(ctkDICOMPatientItemWidget); if (!toggled || studyItem.isEmpty()) { return; @@ -999,8 +991,6 @@ void ctkDICOMPatientItemWidget::onJobUserStopped(QList datas) if (td.JobType == ctkDICOMJobResponseSet::JobType::QueryStudies) { d->StoppedJobUID = td.JobUID; - d->StoppedJobConnectionName = td.ConnectionName; - d->StoppedJobType = td.JobType; } emit this->jobUserStopped(data); @@ -1024,8 +1014,6 @@ void ctkDICOMPatientItemWidget::onJobFailed(QList datas) if (td.JobType == ctkDICOMJobResponseSet::JobType::QueryStudies) { d->StoppedJobUID = td.JobUID; - d->StoppedJobConnectionName = td.ConnectionName; - d->StoppedJobType = td.JobType; } emit this->jobFailed(data); diff --git a/Libs/DICOM/Widgets/ctkDICOMPatientItemWidget.h b/Libs/DICOM/Widgets/ctkDICOMPatientItemWidget.h index 7d47fa855a..40d96fd593 100644 --- a/Libs/DICOM/Widgets/ctkDICOMPatientItemWidget.h +++ b/Libs/DICOM/Widgets/ctkDICOMPatientItemWidget.h @@ -52,8 +52,6 @@ class CTK_DICOM_WIDGETS_EXPORT ctkDICOMPatientItemWidget : public QWidget Q_PROPERTY(QStringList allowedServers READ allowedServers WRITE setAllowedServers); Q_PROPERTY(OperationStatus operationStatus READ operationStatus WRITE setOperationStatus); Q_PROPERTY(QString stoppedJobUID READ stoppedJobUID); - Q_PROPERTY(QString StoppedJobConnectionName READ stoppedJobConnectionName); - Q_PROPERTY(ctkDICOMJobResponseSet::JobType stoppedJobType READ stoppedJobType); public: typedef QWidget Superclass; @@ -208,12 +206,8 @@ class CTK_DICOM_WIDGETS_EXPORT ctkDICOMPatientItemWidget : public QWidget OperationStatus operationStatus() const; ///@} - ///@{ /// Last stopped job information operated by this widget Q_INVOKABLE QString stoppedJobUID() const; - Q_INVOKABLE QString stoppedJobConnectionName() const; - Q_INVOKABLE ctkDICOMJobResponseSet::JobType stoppedJobType() const; - ///@} public Q_SLOTS: void generateStudies(bool query = true, bool retrieve = true); diff --git a/Libs/DICOM/Widgets/ctkDICOMSeriesItemWidget.cpp b/Libs/DICOM/Widgets/ctkDICOMSeriesItemWidget.cpp index 350e1c7b48..836c779acc 100644 --- a/Libs/DICOM/Widgets/ctkDICOMSeriesItemWidget.cpp +++ b/Libs/DICOM/Widgets/ctkDICOMSeriesItemWidget.cpp @@ -110,8 +110,6 @@ class ctkDICOMSeriesItemWidgetPrivate : public Ui_ctkDICOMSeriesItemWidget QString ReferenceInstanceInserterJobUID; QString StoppedJobUID; - QString StoppedJobConnectionName; - ctkDICOMJobResponseSet::JobType StoppedJobType; bool StopJobs; bool RaiseJobsPriority; @@ -146,8 +144,6 @@ ctkDICOMSeriesItemWidgetPrivate::ctkDICOMSeriesItemWidgetPrivate(ctkDICOMSeriesI this->ReferenceInstanceInserterJobUID = ""; this->StoppedJobUID = ""; - this->StoppedJobConnectionName = ""; - this->StoppedJobType = ctkDICOMJobResponseSet::JobType::None; this->IsCloud = false; this->RetrieveFailed = false; @@ -839,8 +835,6 @@ CTK_GET_CPP(ctkDICOMSeriesItemWidget, QString, referenceInstanceInserterJobUID, CTK_SET_CPP(ctkDICOMSeriesItemWidget, int, setThumbnailSizePixel, ThumbnailSizePixel); CTK_GET_CPP(ctkDICOMSeriesItemWidget, int, thumbnailSizePixel, ThumbnailSizePixel); CTK_GET_CPP(ctkDICOMSeriesItemWidget, QString, stoppedJobUID, StoppedJobUID); -CTK_GET_CPP(ctkDICOMSeriesItemWidget, QString, stoppedJobConnectionName, StoppedJobConnectionName); -CTK_GET_CPP(ctkDICOMSeriesItemWidget, ctkDICOMJobResponseSet::JobType, stoppedJobType, StoppedJobType); //---------------------------------------------------------------------------- void ctkDICOMSeriesItemWidget::setSeriesDescription(const QString& seriesDescription) @@ -1052,8 +1046,6 @@ void ctkDICOMSeriesItemWidget::onJobUserStopped(const QVariant &data) } d->StoppedJobUID = td.JobUID; - d->StoppedJobConnectionName = td.ConnectionName; - d->StoppedJobType = td.JobType; } } @@ -1083,8 +1075,6 @@ void ctkDICOMSeriesItemWidget::onJobFailed(const QVariant &data) } d->StoppedJobUID = td.JobUID; - d->StoppedJobConnectionName = td.ConnectionName; - d->StoppedJobType = td.JobType; } } @@ -1166,14 +1156,10 @@ void ctkDICOMSeriesItemWidget::onOperationStatusButtonClicked(bool) } else if (status > ctkThumbnailLabel::InProgress) { - ctkDICOMJobDetail jd; - jd.JobUID = d->StoppedJobUID; - jd.ConnectionName = d->StoppedJobConnectionName; - jd.JobType = d->StoppedJobType; - jd.PatientID = d->PatientID; - jd.StudyInstanceUID = d->StudyInstanceUID; - jd.SeriesInstanceUID = d->SeriesInstanceUID; - - d->Scheduler->runJob(jd, d->AllowedServers); + if (!d->Scheduler->retryJob(d->StoppedJobUID)) + { + logger.info(QString("Unable to restart job %1 (series level) because the job has been fully cleared from the system. " + "Please initiate a new job if further processing is required.").arg(d->StoppedJobUID)); + } } } diff --git a/Libs/DICOM/Widgets/ctkDICOMSeriesItemWidget.h b/Libs/DICOM/Widgets/ctkDICOMSeriesItemWidget.h index 43e13d3929..776e6fe7fd 100644 --- a/Libs/DICOM/Widgets/ctkDICOMSeriesItemWidget.h +++ b/Libs/DICOM/Widgets/ctkDICOMSeriesItemWidget.h @@ -59,8 +59,6 @@ class CTK_DICOM_WIDGETS_EXPORT ctkDICOMSeriesItemWidget : public QWidget Q_PROPERTY(bool raiseJobsPriority READ raiseJobsPriority WRITE setRaiseJobsPriority); Q_PROPERTY(QStringList allowedServers READ allowedServers WRITE setAllowedServers); Q_PROPERTY(QString stoppedJobUID READ stoppedJobUID); - Q_PROPERTY(QString StoppedJobConnectionName READ stoppedJobConnectionName); - Q_PROPERTY(ctkDICOMJobResponseSet::JobType stoppedJobType READ stoppedJobType); public: typedef QWidget Superclass; @@ -183,12 +181,8 @@ class CTK_DICOM_WIDGETS_EXPORT ctkDICOMSeriesItemWidget : public QWidget /// (not Python-wrappable). void setDicomDatabase(QSharedPointer dicomDatabase); - ///@{ /// Last stopped job information operated by this widget Q_INVOKABLE QString stoppedJobUID() const; - Q_INVOKABLE QString stoppedJobConnectionName() const; - Q_INVOKABLE ctkDICOMJobResponseSet::JobType stoppedJobType() const; - ///@} public Q_SLOTS: void generateInstances(bool query = true, bool retrieve = true); diff --git a/Libs/DICOM/Widgets/ctkDICOMServerNodeWidget2.cpp b/Libs/DICOM/Widgets/ctkDICOMServerNodeWidget2.cpp index a9f8992e83..6c7140101c 100644 --- a/Libs/DICOM/Widgets/ctkDICOMServerNodeWidget2.cpp +++ b/Libs/DICOM/Widgets/ctkDICOMServerNodeWidget2.cpp @@ -1754,6 +1754,6 @@ void ctkDICOMServerNodeWidget2::stopAllJobs() } QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); - d->Scheduler->stopAllJobs(true); + d->Scheduler->stopAllJobs(true, false); QApplication::restoreOverrideCursor(); } diff --git a/Libs/DICOM/Widgets/ctkDICOMStudyItemWidget.cpp b/Libs/DICOM/Widgets/ctkDICOMStudyItemWidget.cpp index 1a5bd24878..ba1cb5be3f 100644 --- a/Libs/DICOM/Widgets/ctkDICOMStudyItemWidget.cpp +++ b/Libs/DICOM/Widgets/ctkDICOMStudyItemWidget.cpp @@ -94,8 +94,6 @@ class ctkDICOMStudyItemWidgetPrivate : public Ui_ctkDICOMStudyItemWidget QStringList AllowedServers; ctkDICOMStudyItemWidget::OperationStatus Status; QString StoppedJobUID; - QString StoppedJobConnectionName; - ctkDICOMJobResponseSet::JobType StoppedJobType; bool IsGUIUpdating; bool QueryOn; @@ -120,8 +118,6 @@ ctkDICOMStudyItemWidgetPrivate::ctkDICOMStudyItemWidgetPrivate(ctkDICOMStudyItem this->AllowedServers = QStringList(); this->Status = ctkDICOMStudyItemWidget::NoOperation; this->StoppedJobUID = ""; - this->StoppedJobConnectionName = ""; - this->StoppedJobType = ctkDICOMJobResponseSet::JobType::None; this->DicomDatabase = nullptr; this->Scheduler = nullptr; @@ -491,8 +487,6 @@ CTK_SET_CPP(ctkDICOMStudyItemWidget, const QStringList&, setFilteringModalities, CTK_GET_CPP(ctkDICOMStudyItemWidget, QStringList, filteringModalities, FilteringModalities); CTK_GET_CPP(ctkDICOMStudyItemWidget, int, filteredSeriesCount, FilteredSeriesCount); CTK_GET_CPP(ctkDICOMStudyItemWidget, QString, stoppedJobUID, StoppedJobUID); -CTK_GET_CPP(ctkDICOMStudyItemWidget, QString, stoppedJobConnectionName, StoppedJobConnectionName); -CTK_GET_CPP(ctkDICOMStudyItemWidget, ctkDICOMJobResponseSet::JobType, stoppedJobType, StoppedJobType); //---------------------------------------------------------------------------- void ctkDICOMStudyItemWidget::setTitle(const QString& title) @@ -869,8 +863,6 @@ void ctkDICOMStudyItemWidget::onJobUserStopped(const QVariant &data) d->OperationStatusPushButton->setIcon(QIcon(":/Icons/error_red.svg")); d->StoppedJobUID = td.JobUID; - d->StoppedJobConnectionName = td.ConnectionName; - d->StoppedJobType = td.JobType; } //------------------------------------------------------------------------------ @@ -896,8 +888,6 @@ void ctkDICOMStudyItemWidget::onJobFailed(const QVariant &data) d->OperationStatusPushButton->setIcon(QIcon(":/Icons/error_red.svg")); d->StoppedJobUID = td.JobUID; - d->StoppedJobConnectionName = td.ConnectionName; - d->StoppedJobType = td.JobType; } //------------------------------------------------------------------------------ @@ -942,13 +932,10 @@ void ctkDICOMStudyItemWidget::onOperationStatusButtonClicked(bool) } else if (status > ctkDICOMStudyItemWidget::InProgress) { - ctkDICOMJobDetail jd; - jd.JobUID = d->StoppedJobUID; - jd.ConnectionName = d->StoppedJobConnectionName; - jd.JobType = d->StoppedJobType; - jd.PatientID = d->PatientID; - jd.StudyInstanceUID = d->StudyInstanceUID; - - d->Scheduler->runJob(jd, d->AllowedServers); + if (!d->Scheduler->retryJob(d->StoppedJobUID)) + { + logger.info(QString("Unable to restart job %1 (study level) because the job has been fully cleared from the system. " + "Please initiate a new job if further processing is required.").arg(d->StoppedJobUID)); + } } } diff --git a/Libs/DICOM/Widgets/ctkDICOMStudyItemWidget.h b/Libs/DICOM/Widgets/ctkDICOMStudyItemWidget.h index 8424def0e4..9bfc8412f2 100644 --- a/Libs/DICOM/Widgets/ctkDICOMStudyItemWidget.h +++ b/Libs/DICOM/Widgets/ctkDICOMStudyItemWidget.h @@ -65,8 +65,6 @@ class CTK_DICOM_WIDGETS_EXPORT ctkDICOMStudyItemWidget : public QWidget Q_PROPERTY(QStringList allowedServers READ allowedServers WRITE setAllowedServers); Q_PROPERTY(OperationStatus operationStatus READ operationStatus WRITE setOperationStatus); Q_PROPERTY(QString stoppedJobUID READ stoppedJobUID); - Q_PROPERTY(QString StoppedJobConnectionName READ stoppedJobConnectionName); - Q_PROPERTY(ctkDICOMJobResponseSet::JobType stoppedJobType READ stoppedJobType); public: typedef QWidget Superclass; @@ -214,12 +212,8 @@ class CTK_DICOM_WIDGETS_EXPORT ctkDICOMStudyItemWidget : public QWidget OperationStatus operationStatus() const; ///@} - ///@{ /// Last stopped job information operated by this widget Q_INVOKABLE QString stoppedJobUID() const; - Q_INVOKABLE QString stoppedJobConnectionName() const; - Q_INVOKABLE ctkDICOMJobResponseSet::JobType stoppedJobType() const; - ///@} public Q_SLOTS: void generateSeries(bool query = true, bool retrieve = true); diff --git a/Libs/DICOM/Widgets/ctkDICOMVisualBrowserWidget.cpp b/Libs/DICOM/Widgets/ctkDICOMVisualBrowserWidget.cpp index e243420915..a715f896d4 100644 --- a/Libs/DICOM/Widgets/ctkDICOMVisualBrowserWidget.cpp +++ b/Libs/DICOM/Widgets/ctkDICOMVisualBrowserWidget.cpp @@ -3229,13 +3229,11 @@ void ctkDICOMVisualBrowserWidget::onOperationStatusTabBarItemClicked(int index) } else if (status > ctkDICOMPatientItemWidget::InProgress) { - ctkDICOMJobDetail jd; - jd.PatientID = patientItemWidget->patientID(); - jd.JobUID = patientItemWidget->stoppedJobUID(); - jd.ConnectionName = patientItemWidget->stoppedJobConnectionName(); - jd.JobType = patientItemWidget->stoppedJobType(); - - d->Scheduler->runJob(jd, patientItemWidget->allowedServers()); + if (!d->Scheduler->retryJob(patientItemWidget->stoppedJobUID())) + { + logger.info(QString("Unable to restart Job job %1 (patient level) because the job has been fully cleared from the system. " + "Please initiate a new job if further processing is required.").arg(patientItemWidget->stoppedJobUID())); + } } } @@ -3827,7 +3825,7 @@ void ctkDICOMVisualBrowserWidget::onClose() return; } - this->onStop(); + this->onStop(true, true); this->close(); } @@ -3844,7 +3842,7 @@ void ctkDICOMVisualBrowserWidget::onLoad() } //------------------------------------------------------------------------------ -void ctkDICOMVisualBrowserWidget::onStop(bool stopPersistentTasks) +void ctkDICOMVisualBrowserWidget::onStop(bool stopPersistentTasks, bool removeJobs) { Q_D(ctkDICOMVisualBrowserWidget); if (!d->Scheduler) @@ -3853,7 +3851,7 @@ void ctkDICOMVisualBrowserWidget::onStop(bool stopPersistentTasks) } QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); - d->Scheduler->stopAllJobs(stopPersistentTasks); + d->Scheduler->stopAllJobs(stopPersistentTasks, removeJobs); d->updateFiltersWarnings(); d->ProgressFrame->hide(); QApplication::restoreOverrideCursor(); @@ -3862,7 +3860,7 @@ void ctkDICOMVisualBrowserWidget::onStop(bool stopPersistentTasks) //------------------------------------------------------------------------------ void ctkDICOMVisualBrowserWidget::closeEvent(QCloseEvent* event) { - this->onStop(); + this->onStop(true, true); event->accept(); } diff --git a/Libs/DICOM/Widgets/ctkDICOMVisualBrowserWidget.h b/Libs/DICOM/Widgets/ctkDICOMVisualBrowserWidget.h index de3ef85dd8..d0fea3fc54 100644 --- a/Libs/DICOM/Widgets/ctkDICOMVisualBrowserWidget.h +++ b/Libs/DICOM/Widgets/ctkDICOMVisualBrowserWidget.h @@ -380,7 +380,7 @@ public Q_SLOTS: ///@} /// stops all the operations - void onStop(bool stopPersistentTasks = false); + void onStop(bool stopPersistentTasks = false, bool removeJobs = false); ///@{ /// high level UI slots: close, load, warning