diff --git a/Libs/Core/ctkAbstractJob.cpp b/Libs/Core/ctkAbstractJob.cpp index 3225ebb1c3..74bf2165f1 100644 --- a/Libs/Core/ctkAbstractJob.cpp +++ b/Libs/Core/ctkAbstractJob.cpp @@ -45,12 +45,6 @@ ctkAbstractJob::~ctkAbstractJob() { } -//---------------------------------------------------------------------------- -void ctkAbstractJob::setJobUID(const QString &jobUID) -{ - this->JobUID = jobUID; -} - //---------------------------------------------------------------------------- QString ctkAbstractJob::className() const { @@ -67,6 +61,12 @@ QString ctkAbstractJob::jobUID() const return this->JobUID; } +//---------------------------------------------------------------------------- +void ctkAbstractJob::setJobUID(const QString &jobUID) +{ + this->JobUID = jobUID; +} + //---------------------------------------------------------------------------- ctkAbstractJob::JobStatus ctkAbstractJob::status() const { @@ -199,6 +199,30 @@ QDateTime ctkAbstractJob::completionDateTime() const return this->CompletionDateTime; } +//---------------------------------------------------------------------------- +QString ctkAbstractJob::runningThreadID() const +{ + return this->RunningThreadID; +} + +//---------------------------------------------------------------------------- +void ctkAbstractJob::setRunningThreadID(QString runningThreadID) +{ + this->RunningThreadID = runningThreadID; +} + +//---------------------------------------------------------------------------- +QString ctkAbstractJob::loggedText() const +{ + return this->LoggedText; +} + +//---------------------------------------------------------------------------- +void ctkAbstractJob::setLoggedText(QString loggedText) +{ + this->LoggedText += loggedText + "\n"; +} + //---------------------------------------------------------------------------- QVariant ctkAbstractJob::toVariant() { diff --git a/Libs/Core/ctkAbstractJob.h b/Libs/Core/ctkAbstractJob.h index 89a372e536..70cce73b8a 100644 --- a/Libs/Core/ctkAbstractJob.h +++ b/Libs/Core/ctkAbstractJob.h @@ -54,6 +54,8 @@ class CTK_CORE_EXPORT ctkAbstractJob : public QObject Q_PROPERTY(QDateTime creationDateTime READ creationDateTime); Q_PROPERTY(QDateTime startDateTime READ startDateTime); Q_PROPERTY(QDateTime completionDateTime READ completionDateTime); + Q_PROPERTY(QString runningThreadID READ runningThreadID WRITE setRunningThreadID); + Q_PROPERTY(QString loggedText READ loggedText WRITE setLoggedText); public: explicit ctkAbstractJob(); @@ -133,20 +135,32 @@ class CTK_CORE_EXPORT ctkAbstractJob : public QObject ///@} ///@{ - /// CreationDateTime + /// Creation Date Time QDateTime creationDateTime() const; ///@} ///@{ - /// StartDateTime + /// Start Date Time QDateTime startDateTime() const; ///@} ///@{ - /// CompletionDateTime + /// Completion Date Time QDateTime completionDateTime() const; ///@} + ///@{ + /// Running ThreadID + QString runningThreadID() const; + void setRunningThreadID(QString runningThreadID); + ///@} + + ///@{ + /// Logged Text + QString loggedText() const; + void setLoggedText(QString loggedText); + ///@} + /// Generate worker for job Q_INVOKABLE virtual ctkAbstractWorker* createWorker() = 0; @@ -182,6 +196,8 @@ class CTK_CORE_EXPORT ctkAbstractJob : public QObject QDateTime CreationDateTime; QDateTime StartDateTime; QDateTime CompletionDateTime; + QString RunningThreadID; + QString LoggedText; private: Q_DISABLE_COPY(ctkAbstractJob) @@ -198,6 +214,8 @@ struct CTK_CORE_EXPORT ctkJobDetail { this->CreationDateTime = job.creationDateTime().toString("HH:mm:ss.zzz ddd dd MMM yyyy"); this->StartDateTime = job.startDateTime().toString("HH:mm:ss.zzz ddd dd MMM yyyy"); this->CompletionDateTime = job.completionDateTime().toString("HH:mm:ss.zzz ddd dd MMM yyyy"); + this->RunningThreadID = job.runningThreadID(); + this->Logging = job.loggedText(); } virtual ~ctkJobDetail() = default; @@ -206,6 +224,8 @@ struct CTK_CORE_EXPORT ctkJobDetail { QString CreationDateTime; QString StartDateTime; QString CompletionDateTime; + QString RunningThreadID; + QString Logging; }; Q_DECLARE_METATYPE(ctkJobDetail); diff --git a/Libs/Core/ctkJobScheduler.h b/Libs/Core/ctkJobScheduler.h index cccbc26e76..76241893d9 100644 --- a/Libs/Core/ctkJobScheduler.h +++ b/Libs/Core/ctkJobScheduler.h @@ -40,6 +40,9 @@ class ctkJobSchedulerPrivate; class CTK_CORE_EXPORT ctkJobScheduler : public QObject { Q_OBJECT + Q_PROPERTY(int numberOfJobs READ numberOfJobs); + Q_PROPERTY(int numberOfPersistentJobs READ numberOfPersistentJobs); + Q_PROPERTY(int numberOfRunningJobs READ numberOfRunningJobs); Q_PROPERTY(int freezeJobsScheduling READ freezeJobsScheduling WRITE setFreezeJobsScheduling); Q_PROPERTY(int maximumThreadCount READ maximumThreadCount WRITE setMaximumThreadCount); Q_PROPERTY(int maximumNumberOfRetry READ maximumNumberOfRetry WRITE setMaximumNumberOfRetry); @@ -52,22 +55,17 @@ class CTK_CORE_EXPORT ctkJobScheduler : public QObject ///@{ /// Jobs managment - Q_INVOKABLE int numberOfJobs(); - Q_INVOKABLE int numberOfPersistentJobs(); - Q_INVOKABLE int numberOfRunningJobs(); - + int numberOfJobs(); + int numberOfPersistentJobs(); + int numberOfRunningJobs(); Q_INVOKABLE void addJob(ctkAbstractJob* job); - Q_INVOKABLE virtual void deleteJob(const QString& jobUID); 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); ///@} diff --git a/Libs/DICOM/Core/Testing/Cpp/ctkDICOMSchedulerTest1.cpp b/Libs/DICOM/Core/Testing/Cpp/ctkDICOMSchedulerTest1.cpp index e0189bfda5..e31df5260a 100644 --- a/Libs/DICOM/Core/Testing/Cpp/ctkDICOMSchedulerTest1.cpp +++ b/Libs/DICOM/Core/Testing/Cpp/ctkDICOMSchedulerTest1.cpp @@ -137,8 +137,6 @@ int ctkDICOMSchedulerTest1(int argc, char* argv[]) QStringList urls = database.urlsForSeries(seriesIstanceUID); urls.removeAll(QString("")); - - CHECK_INT(instances.count(), numberOfImages); CHECK_INT(files.count(), 0); CHECK_INT(urls.count(), numberOfImages); diff --git a/Libs/DICOM/Core/ctkDICOMInserterWorker.cpp b/Libs/DICOM/Core/ctkDICOMInserterWorker.cpp index 73e8fb1ff0..c8074d9a7d 100644 --- a/Libs/DICOM/Core/ctkDICOMInserterWorker.cpp +++ b/Libs/DICOM/Core/ctkDICOMInserterWorker.cpp @@ -32,6 +32,9 @@ #include "ctkDICOMInserterWorker_p.h" #include "ctkDICOMJobResponseSet.h" +// DCMTK includes +#include + static ctkLogger logger ("org.commontk.dicom.DICOMInserterWorker"); //------------------------------------------------------------------------------ @@ -100,6 +103,9 @@ void ctkDICOMInserterWorker::run() return; } + QString currentThread = dcmtk::log4cplus::thread::getCurrentThreadName().c_str(); + inserterJob->setRunningThreadID(currentThread); + if (d->Inserter->wasCanceled()) { this->onJobCanceled(d->Inserter->wasCanceled()); diff --git a/Libs/DICOM/Core/ctkDICOMJob.h b/Libs/DICOM/Core/ctkDICOMJob.h index c37ad86cdb..821a1ad9f8 100644 --- a/Libs/DICOM/Core/ctkDICOMJob.h +++ b/Libs/DICOM/Core/ctkDICOMJob.h @@ -140,7 +140,6 @@ struct CTK_DICOM_CORE_EXPORT ctkDICOMJobDetail : ctkJobDetail explicit ctkDICOMJobDetail(const ctkDICOMJob& job) : ctkJobDetail(job) { - this->DICOMLevel = job.dicomLevel(); this->JobType = job.getJobType(); this->PatientID = job.patientID(); diff --git a/Libs/DICOM/Core/ctkDICOMJobResponseSet.cpp b/Libs/DICOM/Core/ctkDICOMJobResponseSet.cpp index d0a0b5ab48..554cce0b12 100644 --- a/Libs/DICOM/Core/ctkDICOMJobResponseSet.cpp +++ b/Libs/DICOM/Core/ctkDICOMJobResponseSet.cpp @@ -57,6 +57,7 @@ class ctkDICOMJobResponseSetPrivate : public QObject QString SeriesInstanceUID; QString SOPInstanceUID; QString ConnectionName; + QString RunningThreadID; QMap> Datasets; }; diff --git a/Libs/DICOM/Core/ctkDICOMQueryWorker.cpp b/Libs/DICOM/Core/ctkDICOMQueryWorker.cpp index 62aa68b1f5..9b15a99aa2 100644 --- a/Libs/DICOM/Core/ctkDICOMQueryWorker.cpp +++ b/Libs/DICOM/Core/ctkDICOMQueryWorker.cpp @@ -30,6 +30,9 @@ #include "ctkDICOMScheduler.h" #include "ctkDICOMServer.h" +// DCMTK includes +#include + static ctkLogger logger ("org.commontk.dicom.DICOMQueryWorker"); //------------------------------------------------------------------------------ @@ -109,6 +112,9 @@ void ctkDICOMQueryWorker::run() return; } + QString currentThread = dcmtk::log4cplus::thread::getCurrentThreadName().c_str(); + queryJob->setRunningThreadID(currentThread); + QSharedPointer scheduler = qobject_cast>(this->Scheduler); if (!scheduler || diff --git a/Libs/DICOM/Core/ctkDICOMRetrieveWorker.cpp b/Libs/DICOM/Core/ctkDICOMRetrieveWorker.cpp index 06d80a8148..20cda68ef8 100644 --- a/Libs/DICOM/Core/ctkDICOMRetrieveWorker.cpp +++ b/Libs/DICOM/Core/ctkDICOMRetrieveWorker.cpp @@ -31,6 +31,9 @@ #include "ctkDICOMScheduler.h" #include "ctkDICOMServer.h" +// DCMTK includes +#include + static ctkLogger logger ("org.commontk.dicom.DICOMRetrieveWorker"); //------------------------------------------------------------------------------ @@ -129,6 +132,9 @@ void ctkDICOMRetrieveWorker::run() return; } + QString currentThread = dcmtk::log4cplus::thread::getCurrentThreadName().c_str(); + retrieveJob->setRunningThreadID(currentThread); + QSharedPointer scheduler = qSharedPointerObjectCast(this->Scheduler); ctkDICOMServer* server = retrieveJob->server(); diff --git a/Libs/DICOM/Core/ctkDICOMScheduler.cpp b/Libs/DICOM/Core/ctkDICOMScheduler.cpp index 446a42c31c..b6fd646b4b 100644 --- a/Libs/DICOM/Core/ctkDICOMScheduler.cpp +++ b/Libs/DICOM/Core/ctkDICOMScheduler.cpp @@ -40,10 +40,62 @@ // dcmtk includes #include - +#include +#include +#include "dcmtk/oflog/spi/logevent.h" static ctkLogger logger ( "org.commontk.dicom.DICOMScheduler" ); +//------------------------------------------------------------------------------ +// JobAppender class (custom DCMTK Appender) + +//------------------------------------------------------------------------------ +class ctkDICOMJobsAppender : public dcmtk::log4cplus::Appender { +public: + ctkDICOMJobsAppender() {}; + + virtual void close() {}; + + QMap messagesPerThread() const + { + return this->MessagesPerThread; + } + + QString messageByThreadID(QString threadID) + { + if (!this->MessagesPerThread.contains(threadID)) + { + return ""; + } + + return this->MessagesPerThread.take(threadID); + } + + void clearMessagesPerThread() + { + this->MessagesPerThread.clear(); + } + +protected: + void append(const dcmtk::log4cplus::spi::InternalLoggingEvent& event) + { + dcmtk::log4cplus::TTCCLayout *layout = + dynamic_cast(this->getLayout()); + if (!layout) + { + return; + } + + dcmtk::log4cplus::tostringstream oss; + layout->formatAndAppend(oss, event); + QString messageThread = event.getThread().c_str(); + this->MessagesPerThread[messageThread] += QString::fromLatin1(oss.str().c_str()) + "\n"; + } + +private: + QMap MessagesPerThread; +}; + //------------------------------------------------------------------------------ // ctkDICOMSchedulerPrivate methods @@ -52,6 +104,14 @@ ctkDICOMSchedulerPrivate::ctkDICOMSchedulerPrivate(ctkDICOMScheduler& obj) : ctkJobSchedulerPrivate(obj) { ctk::setDICOMLogLevel(ctkErrorLogLevel::Warning); + + OFunique_ptr layout(new dcmtk::log4cplus::TTCCLayout()); + this->Appender = (new ctkDICOMJobsAppender()); + this->Appender->setLayout(OFmove(layout)); + this->Appender->setThreshold(ctk::dicomLogLevel()); + + dcmtk::log4cplus::Logger rootLog = dcmtk::log4cplus::Logger::getRoot(); + rootLog.addAppender(this->Appender); } //------------------------------------------------------------------------------ @@ -59,6 +119,12 @@ ctkDICOMSchedulerPrivate::~ctkDICOMSchedulerPrivate() { Q_Q(ctkDICOMScheduler); q->removeAllServers(); + + if (this->Appender) + { + dcmtk::log4cplus::Logger rootLog = dcmtk::log4cplus::Logger::getRoot(); + rootLog.removeAppender(this->Appender); + } } //------------------------------------------------------------------------------ @@ -1013,3 +1079,98 @@ bool ctkDICOMScheduler::isStorageListenerActive() } return false; } + +//---------------------------------------------------------------------------- +void ctkDICOMScheduler::onJobStarted(ctkAbstractJob* job) +{ + Q_D(ctkDICOMScheduler); + if (!job) + { + return; + } + + ctkDICOMJobsAppender* appender = dynamic_cast(d->Appender.get()); + if (appender) + { + QString loggedText = appender->messageByThreadID(job->runningThreadID()); + job->setLoggedText(loggedText); + } + + ctkJobScheduler::onJobStarted(job); +} + +//---------------------------------------------------------------------------- +void ctkDICOMScheduler::onJobUserStopped(ctkAbstractJob* job) +{ + Q_D(ctkDICOMScheduler); + if (!job) + { + return; + } + + ctkDICOMJobsAppender* appender = dynamic_cast(d->Appender.get()); + if (appender) + { + QString loggedText = appender->messageByThreadID(job->runningThreadID()); + job->setLoggedText(loggedText); + } + + ctkJobScheduler::onJobUserStopped(job); +} + +//---------------------------------------------------------------------------- +void ctkDICOMScheduler::onJobFinished(ctkAbstractJob* job) +{ + Q_D(ctkDICOMScheduler); + if (!job) + { + return; + } + + ctkDICOMJobsAppender* appender = dynamic_cast(d->Appender.get()); + if (appender) + { + QString loggedText = appender->messageByThreadID(job->runningThreadID()); + job->setLoggedText(loggedText); + } + + ctkJobScheduler::onJobFinished(job); +} + +//---------------------------------------------------------------------------- +void ctkDICOMScheduler::onJobAttemptFailed(ctkAbstractJob* job) +{ + Q_D(ctkDICOMScheduler); + if (!job) + { + return; + } + + ctkDICOMJobsAppender* appender = dynamic_cast(d->Appender.get()); + if (appender) + { + QString loggedText = appender->messageByThreadID(job->runningThreadID()); + job->setLoggedText(loggedText); + } + + ctkJobScheduler::onJobAttemptFailed(job); +} + +//---------------------------------------------------------------------------- +void ctkDICOMScheduler::onJobFailed(ctkAbstractJob* job) +{ + Q_D(ctkDICOMScheduler); + if (!job) + { + return; + } + + ctkDICOMJobsAppender* appender = dynamic_cast(d->Appender.get()); + if (appender) + { + QString loggedText = appender->messageByThreadID(job->runningThreadID()); + job->setLoggedText(loggedText); + } + + ctkJobScheduler::onJobFailed(job); +} diff --git a/Libs/DICOM/Core/ctkDICOMScheduler.h b/Libs/DICOM/Core/ctkDICOMScheduler.h index 7aa26a1434..3409f86a77 100644 --- a/Libs/DICOM/Core/ctkDICOMScheduler.h +++ b/Libs/DICOM/Core/ctkDICOMScheduler.h @@ -206,6 +206,13 @@ class CTK_DICOM_CORE_EXPORT ctkDICOMScheduler : public ctkJobScheduler Q_INVOKABLE bool isStorageListenerActive(); ///@} +public Q_SLOTS: + virtual void onJobStarted(ctkAbstractJob* job); + virtual void onJobUserStopped(ctkAbstractJob* job); + virtual void onJobFinished(ctkAbstractJob* job); + virtual void onJobAttemptFailed(ctkAbstractJob* job); + virtual void onJobFailed(ctkAbstractJob* job); + protected: ctkDICOMScheduler(ctkDICOMSchedulerPrivate* pimpl, QObject* parent); diff --git a/Libs/DICOM/Core/ctkDICOMScheduler_p.h b/Libs/DICOM/Core/ctkDICOMScheduler_p.h index 48c90d8608..7762db7cf8 100644 --- a/Libs/DICOM/Core/ctkDICOMScheduler_p.h +++ b/Libs/DICOM/Core/ctkDICOMScheduler_p.h @@ -67,6 +67,8 @@ class ctkDICOMSchedulerPrivate : public ctkJobSchedulerPrivate QMap Filters; int MaximumPatientsQuery{25}; + + dcmtk::log4cplus::SharedAppenderPtr Appender; }; #endif diff --git a/Libs/DICOM/Core/ctkDICOMStorageListenerWorker.cpp b/Libs/DICOM/Core/ctkDICOMStorageListenerWorker.cpp index 994861e279..9f0f60924e 100644 --- a/Libs/DICOM/Core/ctkDICOMStorageListenerWorker.cpp +++ b/Libs/DICOM/Core/ctkDICOMStorageListenerWorker.cpp @@ -33,6 +33,9 @@ #include "ctkDICOMStorageListenerJob.h" #include "ctkDICOMStorageListenerWorker_p.h" +// DCMTK includes +#include + static ctkLogger logger ("org.commontk.dicom.DICOMStorageListenerWorker"); //------------------------------------------------------------------------------ @@ -123,6 +126,9 @@ void ctkDICOMStorageListenerWorker::run() return; } + QString currentThread = dcmtk::log4cplus::thread::getCurrentThreadName().c_str(); + storageListenerJob->setRunningThreadID(currentThread); + QSharedPointer scheduler = qSharedPointerObjectCast(this->Scheduler); if (!scheduler diff --git a/Libs/DICOM/Widgets/ctkDICOMJobListWidget.cpp b/Libs/DICOM/Widgets/ctkDICOMJobListWidget.cpp index 1f7d9a9f9e..6258077acc 100644 --- a/Libs/DICOM/Widgets/ctkDICOMJobListWidget.cpp +++ b/Libs/DICOM/Widgets/ctkDICOMJobListWidget.cpp @@ -108,7 +108,9 @@ class QCenteredItemModel : public QStandardItemModel SOPInstanceUID, Connection, JobUID, - JobClass + JobClass, + JobThread, + JobLogging, }; Q_ENUM(Columns); QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; @@ -270,6 +272,8 @@ void QCenteredItemModel::addJob(const ctkDICOMJobDetail &td, this->setData(this->index(row, Columns::JobUID), td.JobUID); 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); } //---------------------------------------------------------------------------- @@ -281,70 +285,76 @@ void QCenteredItemModel::updateJobStatus(const ctkDICOMJobDetail &td, const JobS } QList list = this->findItems(td.JobUID, Qt::MatchExactly, Columns::JobUID); - if (!list.empty()) + if (list.empty()) { - int row = list.first()->row(); - QIcon statusIcon; - QString statusText; - if (status == Queued) - { - statusIcon = QIcon(":/Icons/pending.svg"); - statusText = tr("queued"); - } - else if (status == Running) - { - statusIcon = QIcon(":/Icons/pending.svg"); - statusText = tr("in-progress"); - if (td.JobClass == "ctkDICOMQueryJob") - { - QList data; - data.append(20); - data.append(100); - this->setData(this->index(row, Columns::Progress), data); - } - } - else if (status == Failed) - { - statusIcon = QIcon(":/Icons/error.svg"); - statusText = tr("failed"); - } - else if (status == UserStopped) - { - statusIcon = QIcon(":/Icons/error.svg"); - statusText = tr("user-stopped"); - } - else if (status == AttemptFailed) - { - statusIcon = QIcon(":/Icons/error.svg"); - statusText = tr("attempt-failed"); - } - else if (status == Completed) + return; + } + + int row = list.first()->row(); + QIcon statusIcon; + QString statusText; + if (status == Queued) + { + statusIcon = QIcon(":/Icons/pending.svg"); + statusText = tr("queued"); + } + else if (status == Running) + { + statusIcon = QIcon(":/Icons/pending.svg"); + statusText = tr("in-progress"); + if (td.JobClass == "ctkDICOMQueryJob") { - statusIcon = QIcon(":/Icons/accept.svg"); - statusText = tr("completed"); QList data; - data.append(100); + data.append(20); data.append(100); this->setData(this->index(row, Columns::Progress), data); } + } + else if (status == Failed) + { + statusIcon = QIcon(":/Icons/error.svg"); + statusText = tr("failed"); + } + else if (status == UserStopped) + { + statusIcon = QIcon(":/Icons/error.svg"); + statusText = tr("user-stopped"); + } + else if (status == AttemptFailed) + { + statusIcon = QIcon(":/Icons/error.svg"); + statusText = tr("attempt-failed"); + } + else if (status == Completed) + { + statusIcon = QIcon(":/Icons/accept.svg"); + statusText = tr("completed"); + QList data; + data.append(100); + data.append(100); + this->setData(this->index(row, Columns::Progress), data); + } - QStandardItem *statusItem = new QStandardItem(QString("statusItem")); - statusItem->setIcon(statusIcon); - this->setItem(row, Columns::Status, statusItem); - this->setData(this->index(row, Columns::Status), statusText); - this->setData(this->index(row, Columns::Status), statusText, Qt::ToolTipRole); + QStandardItem *statusItem = new QStandardItem(QString("statusItem")); + statusItem->setIcon(statusIcon); + this->setItem(row, Columns::Status, statusItem); + this->setData(this->index(row, Columns::Status), statusText); + this->setData(this->index(row, Columns::Status), statusText, Qt::ToolTipRole); - if (status == Running) - { - this->setData(this->index(row, Columns::StartDateTime), td.CreationDateTime); - this->setData(this->index(row, Columns::StartDateTime), td.CreationDateTime, Qt::ToolTipRole); - } - else - { - this->setData(this->index(row, Columns::CompletionDateTime), td.CompletionDateTime); - this->setData(this->index(row, Columns::CompletionDateTime), td.CompletionDateTime, Qt::ToolTipRole); - } + if (status == Running) + { + this->setData(this->index(row, Columns::StartDateTime), td.CreationDateTime); + this->setData(this->index(row, Columns::StartDateTime), td.CreationDateTime, Qt::ToolTipRole); } + else + { + this->setData(this->index(row, Columns::CompletionDateTime), td.CompletionDateTime); + this->setData(this->index(row, Columns::CompletionDateTime), td.CompletionDateTime, Qt::ToolTipRole); + } + + this->setData(this->index(row, Columns::JobThread), td.RunningThreadID); + this->setData(this->index(row, Columns::JobThread), td.RunningThreadID, Qt::ToolTipRole); + this->setData(this->index(row, Columns::JobLogging), td.Logging); } //---------------------------------------------------------------------------- @@ -501,6 +511,14 @@ QCenteredItemModel::Columns QCenteredItemModel::getColumnIndexFromString(QString { return Columns::JobClass; } + else if (columnString == QCenteredItemModel::tr("Thread")) + { + return Columns::JobThread; + } + else if (columnString == QCenteredItemModel::tr("Logging")) + { + return Columns::JobLogging; + } else { return Columns::JobClass; @@ -544,6 +562,10 @@ QString QCenteredItemModel::getColumnStringFromIndex(Columns columnIndex) return QCenteredItemModel::tr("Job UID"); case Columns::JobClass: return QCenteredItemModel::tr("Class"); + case Columns::JobThread: + return QCenteredItemModel::tr("Thread"); + case Columns::JobLogging: + return QCenteredItemModel::tr("Logging"); default: return QCenteredItemModel::tr(""); } @@ -626,6 +648,8 @@ void ctkDICOMJobListWidgetPrivate::init() allColumnNames.append(QCenteredItemModel::getColumnStringFromIndex(QCenteredItemModel::Columns::Connection)); allColumnNames.append(QCenteredItemModel::getColumnStringFromIndex(QCenteredItemModel::Columns::JobUID)); allColumnNames.append(QCenteredItemModel::getColumnStringFromIndex(QCenteredItemModel::Columns::JobClass)); + allColumnNames.append(QCenteredItemModel::getColumnStringFromIndex(QCenteredItemModel::Columns::JobThread)); + allColumnNames.append(QCenteredItemModel::getColumnStringFromIndex(QCenteredItemModel::Columns::JobLogging)); this->dataModel = QSharedPointer(new QCenteredItemModel(0, allColumnNames.count(), q)); this->dataModel->setHorizontalHeaderLabels(allColumnNames); @@ -649,6 +673,8 @@ void ctkDICOMJobListWidgetPrivate::init() this->JobsView->setColumnHidden(QCenteredItemModel::Columns::SOPInstanceUID, true); this->JobsView->setColumnHidden(QCenteredItemModel::Columns::JobUID, true); this->JobsView->setColumnHidden(QCenteredItemModel::Columns::JobClass, true); + this->JobsView->setColumnHidden(QCenteredItemModel::Columns::JobThread, true); + this->JobsView->setColumnHidden(QCenteredItemModel::Columns::JobLogging, true); QObject::connect(this->JobsView->selectionModel(), &QItemSelectionModel::selectionChanged, q, &ctkDICOMJobListWidget::onJobsViewSelectionChanged); @@ -762,7 +788,7 @@ void ctkDICOMJobListWidgetPrivate::updateJobsDetailsWidget() { if (count != 0) { - detailsText.append(QString("\n ================================================================== \n")); + detailsText.append(QString("\n =============================================================== \n")); } int row = rowIndex.row(); @@ -796,85 +822,96 @@ void ctkDICOMJobListWidgetPrivate::updateJobsDetailsWidget() (row, QCenteredItemModel::Columns::JobUID).data().toString(); QString jobClass = this->showCompletedProxyModel->index (row, QCenteredItemModel::Columns::JobClass).data().toString(); + QString thread = this->showCompletedProxyModel->index + (row, QCenteredItemModel::Columns::JobThread).data().toString(); + QString logging = this->showCompletedProxyModel->index + (row, QCenteredItemModel::Columns::JobLogging).data().toString(); if (!jobType.isEmpty()) { detailsText.append(QCenteredItemModel::getColumnStringFromIndex(QCenteredItemModel::Columns::JobType)); - detailsText.append(QString(": ") + jobType + QString(" \n")); + detailsText.append(QString(": ") + jobType + QString("\n")); } if (!jobUID.isEmpty()) { detailsText.append(QCenteredItemModel::getColumnStringFromIndex(QCenteredItemModel::Columns::JobUID)); - detailsText.append(QString(": ") + jobUID + QString(" \n")); + detailsText.append(QString(": ") + jobUID + QString("\n")); } if (!jobClass.isEmpty()) { detailsText.append(QCenteredItemModel::getColumnStringFromIndex(QCenteredItemModel::Columns::JobClass)); - detailsText.append(QString(": ") + jobClass + QString(" \n")); + detailsText.append(QString(": ") + jobClass + QString("\n")); } if (!connection.isEmpty()) { detailsText.append(QCenteredItemModel::getColumnStringFromIndex(QCenteredItemModel::Columns::Connection)); - detailsText.append(QString(": ") + connection + QString(" \n")); + detailsText.append(QString(": ") + connection + QString("\n")); } if (!status.isEmpty()) { - detailsText.append(QCenteredItemModel::getColumnStringFromIndex(QCenteredItemModel::Columns::Status)); - detailsText.append(QString(": ") + status + QString(" \n")); + detailsText.append(QCenteredItemModel::getColumnStringFromIndex(QCenteredItemModel::Columns::Status)); + detailsText.append(QString(": ") + status + QString("\n")); } if (!creationDateTime.isEmpty()) { - detailsText.append(QCenteredItemModel::getColumnStringFromIndex(QCenteredItemModel::Columns::CreationDateTime)); - detailsText.append(QString(": ") + creationDateTime + QString(" \n")); + detailsText.append(QCenteredItemModel::getColumnStringFromIndex(QCenteredItemModel::Columns::CreationDateTime)); + detailsText.append(QString(": ") + creationDateTime + QString("\n")); } if (!startDateTime.isEmpty()) { - detailsText.append(QCenteredItemModel::getColumnStringFromIndex(QCenteredItemModel::Columns::StartDateTime)); - detailsText.append(QString(" : ") + startDateTime + QString(" \n")); + detailsText.append(QCenteredItemModel::getColumnStringFromIndex(QCenteredItemModel::Columns::StartDateTime)); + detailsText.append(QString(": ") + startDateTime + QString("\n")); } if (!completionDateTime.isEmpty()) { - detailsText.append(QCenteredItemModel::getColumnStringFromIndex(QCenteredItemModel::Columns::CompletionDateTime)); - detailsText.append(QString(": ") + completionDateTime + QString(" \n")); + detailsText.append(QCenteredItemModel::getColumnStringFromIndex(QCenteredItemModel::Columns::CompletionDateTime)); + detailsText.append(QString(": ") + completionDateTime + QString("\n")); } if (!dicomLevel.isEmpty() && dicomLevel != "None") { - detailsText.append(QCenteredItemModel::getColumnStringFromIndex(QCenteredItemModel::Columns::DICOMLevel)); - detailsText.append(QString(": ") + dicomLevel + QString(" \n")); + detailsText.append(QCenteredItemModel::getColumnStringFromIndex(QCenteredItemModel::Columns::DICOMLevel)); + detailsText.append(QString(": ") + dicomLevel + QString("\n")); } if (!patientID.isEmpty()) { - detailsText.append(QCenteredItemModel::getColumnStringFromIndex(QCenteredItemModel::Columns::PatientID)); - detailsText.append(QString(": ") + patientID + QString(" \n")); + detailsText.append(QCenteredItemModel::getColumnStringFromIndex(QCenteredItemModel::Columns::PatientID)); + detailsText.append(QString(": ") + patientID + QString("\n")); } if (!patientName.isEmpty()) { - detailsText.append(QCenteredItemModel::getColumnStringFromIndex(QCenteredItemModel::Columns::PatientName)); - detailsText.append(QString(": ") + patientName + QString(" \n")); + detailsText.append(QCenteredItemModel::getColumnStringFromIndex(QCenteredItemModel::Columns::PatientName)); + detailsText.append(QString(": ") + patientName + QString("\n")); } if (!patientBirthDate.isEmpty()) { - detailsText.append(QCenteredItemModel::getColumnStringFromIndex(QCenteredItemModel::Columns::PatientBirthDate)); - detailsText.append(QString(": ") + patientBirthDate + QString(" \n")); + detailsText.append(QCenteredItemModel::getColumnStringFromIndex(QCenteredItemModel::Columns::PatientBirthDate)); + detailsText.append(QString(": ") + patientBirthDate + QString("\n")); } if (!studyInstanceUID.isEmpty()) { - detailsText.append(QCenteredItemModel::getColumnStringFromIndex(QCenteredItemModel::Columns::StudyInstanceUID)); - detailsText.append(QString(": ") + studyInstanceUID + QString(" \n")); + detailsText.append(QCenteredItemModel::getColumnStringFromIndex(QCenteredItemModel::Columns::StudyInstanceUID)); + detailsText.append(QString(": ") + studyInstanceUID + QString("\n")); } if (!seriesInstanceUID.isEmpty()) { - detailsText.append(QCenteredItemModel::getColumnStringFromIndex(QCenteredItemModel::Columns::SeriesInstanceUID)); - detailsText.append(QString(": ") + seriesInstanceUID + QString(" \n")); + detailsText.append(QCenteredItemModel::getColumnStringFromIndex(QCenteredItemModel::Columns::SeriesInstanceUID)); + detailsText.append(QString(": ") + seriesInstanceUID + QString("\n")); } if (!sopInstanceUID.isEmpty()) { - detailsText.append(QCenteredItemModel::getColumnStringFromIndex(QCenteredItemModel::Columns::SOPInstanceUID)); - detailsText.append(QString(" : ") + sopInstanceUID + QString(" \n")); + detailsText.append(QCenteredItemModel::getColumnStringFromIndex(QCenteredItemModel::Columns::SOPInstanceUID)); + detailsText.append(QString(": ") + sopInstanceUID + QString("\n")); + } + if (!thread.isEmpty()) + { + detailsText.append(QCenteredItemModel::getColumnStringFromIndex(QCenteredItemModel::Columns::JobThread)); + detailsText.append(QString(": ") + thread + QString("\n")); + } + if (!logging.isEmpty()) + { + detailsText.append(QCenteredItemModel::getColumnStringFromIndex(QCenteredItemModel::Columns::JobLogging)); + detailsText.append(QString(":\n") + logging + QString("\n")); } - - //detailsText.append(QString("Logger: ") + QString(" \n")); - // To Do: get DCMTK logging stream per job if (count == 0) {