Skip to content

Commit

Permalink
ENH: Add ctkDICOMJobListWidget for logging jobs activity in the UI
Browse files Browse the repository at this point in the history
  • Loading branch information
Punzo committed Jan 23, 2024
1 parent 88ff72b commit fd14f5b
Show file tree
Hide file tree
Showing 56 changed files with 2,383 additions and 344 deletions.
43 changes: 34 additions & 9 deletions Applications/ctkDICOMVisualBrowser/ctkDICOMVisualBrowserMain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,37 @@ int main(int argc, char** argv)
app.setOrganizationDomain("commontk.org");
app.setApplicationName("ctkDICOM");

QSettings settings;
QString databaseDirectory;

// set up the database
if (argc > 1)
{
QString directory(argv[1]);
settings.setValue("DatabaseDirectory", directory);
settings.sync();
}

if (settings.value("DatabaseDirectory", "") == "")
{
databaseDirectory = QString("./ctkDICOM-Database");
std::cerr << "No DatabaseDirectory on command line or in settings. Using \"" << qPrintable(databaseDirectory) << "\".\n";
}
else
{
databaseDirectory = settings.value("DatabaseDirectory", "").toString();
}

QDir qdir(databaseDirectory);
if (!qdir.exists(databaseDirectory))
{
if (!qdir.mkpath(databaseDirectory))
{
std::cerr << "Could not create database directory \"" << qPrintable(databaseDirectory) << "\".\n";
return EXIT_FAILURE;
}
}

// set up Qt resource files
QResource::registerResource("./Resources/ctkDICOM.qrc");

Expand All @@ -67,10 +98,8 @@ int main(int argc, char** argv)
ctkDirectoryButton directoryButton;
directoryButton.setObjectName(QString::fromUtf8("DirectoryButton"));
directoryButton.setMinimumSize(QSize(200, 30));
if (argc > 1)
{
directoryButton.setDirectory(argv[1]);
}
directoryButton.setDirectory(databaseDirectory);

topLayout.addWidget(&directoryButton);

mainLayout.addLayout(&topLayout);
Expand All @@ -79,11 +108,7 @@ int main(int argc, char** argv)
DICOMVisualBrowser.setObjectName(QString::fromUtf8("DICOMVisualBrowser"));
DICOMVisualBrowser.setDatabaseDirectorySettingsKey("DatabaseDirectory");
DICOMVisualBrowser.setMinimumSize(QSize(1000, 1000));
// set up the database
if (argc > 1)
{
DICOMVisualBrowser.setDatabaseDirectory(argv[1]);
}
DICOMVisualBrowser.setDatabaseDirectory(databaseDirectory);

DICOMVisualBrowser.serverSettingsGroupBox()->setChecked(true);
QObject::connect(&directoryButton, SIGNAL(directoryChanged(const QString&)),
Expand Down
28 changes: 28 additions & 0 deletions Libs/Core/ctkAbstractJob.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ ctkAbstractJob::ctkAbstractJob()
this->MaximumNumberOfRetry = 3;
this->MaximumConcurrentJobsPerType = 20;
this->Priority = QThread::Priority::LowPriority;
this->CreationDateTime = QDateTime::currentDateTime();
}

//----------------------------------------------------------------------------
Expand Down Expand Up @@ -76,6 +77,15 @@ ctkAbstractJob::JobStatus ctkAbstractJob::status() const
void ctkAbstractJob::setStatus(JobStatus status)
{
this->Status = status;

if (this->Status == JobStatus::Running)
{
this->StartDateTime = QDateTime::currentDateTime();
}
else if (this->Status > JobStatus::Running)
{
this->CompletionDateTime = QDateTime::currentDateTime();
}
}

//----------------------------------------------------------------------------
Expand Down Expand Up @@ -150,6 +160,24 @@ void ctkAbstractJob::setPriority(const QThread::Priority &priority)
this->Priority = priority;
}

//----------------------------------------------------------------------------
QDateTime ctkAbstractJob::creationDateTime() const
{
return this->CreationDateTime;
}

//----------------------------------------------------------------------------
QDateTime ctkAbstractJob::startDateTime() const
{
return this->StartDateTime;
}

//----------------------------------------------------------------------------
QDateTime ctkAbstractJob::completionDateTime() const
{
return this->CompletionDateTime;
}

//----------------------------------------------------------------------------
QVariant ctkAbstractJob::toVariant()
{
Expand Down
28 changes: 28 additions & 0 deletions Libs/Core/ctkAbstractJob.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#define __ctkAbstractJob_h

// Qt includes
#include <QDateTime>
#include <QObject>
#include <QThread>
#include <QVariant>
Expand All @@ -49,6 +50,9 @@ class CTK_CORE_EXPORT ctkAbstractJob : public QObject
Q_PROPERTY(int retryDelay READ retryDelay WRITE setRetryDelay);
Q_PROPERTY(bool maximumConcurrentJobsPerType READ maximumConcurrentJobsPerType WRITE setMaximumConcurrentJobsPerType);
Q_PROPERTY(QThread::Priority priority READ priority WRITE setPriority);
Q_PROPERTY(QDateTime creationDateTime READ creationDateTime);
Q_PROPERTY(QDateTime startDateTime READ startDateTime);
Q_PROPERTY(QDateTime completionDateTime READ completionDateTime);

public:
explicit ctkAbstractJob();
Expand Down Expand Up @@ -116,6 +120,21 @@ class CTK_CORE_EXPORT ctkAbstractJob : public QObject
void setPriority(const QThread::Priority& priority);
///@}

///@{
/// CreationDateTime
QDateTime creationDateTime() const;
///@}

///@{
/// StartDateTime
QDateTime startDateTime() const;
///@}

///@{
/// CompletionDateTime
QDateTime completionDateTime() const;
///@}

/// Generate worker for job
Q_INVOKABLE virtual ctkAbstractWorker* createWorker() = 0;

Expand Down Expand Up @@ -147,6 +166,9 @@ class CTK_CORE_EXPORT ctkAbstractJob : public QObject
int MaximumNumberOfRetry;
int MaximumConcurrentJobsPerType;
QThread::Priority Priority;
QDateTime CreationDateTime;
QDateTime StartDateTime;
QDateTime CompletionDateTime;

private:
Q_DISABLE_COPY(ctkAbstractJob)
Expand All @@ -160,11 +182,17 @@ struct CTK_CORE_EXPORT ctkJobDetail {
{
this->JobClass = job.className();
this->JobUID = job.jobUID();
this->CreationDateTime = job.creationDateTime().toString("HH:mm:ss.zzz ddd MMM yyyy");
this->StartDateTime = job.startDateTime().toString("HH:mm:ss.zzz ddd MMM yyyy");
this->CompletionDateTime = job.completionDateTime().toString("HH:mm:ss.zzz ddd MMM yyyy");
}
virtual ~ctkJobDetail() = default;

QString JobClass;
QString JobUID;
QString CreationDateTime;
QString StartDateTime;
QString CompletionDateTime;
};
Q_DECLARE_METATYPE(ctkJobDetail);

Expand Down
4 changes: 2 additions & 2 deletions Libs/Core/ctkAbstractWorker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,14 +127,14 @@ void ctkAbstractWorker::onJobCanceled()

this->startNextJob();

emit this->Job->finished();
emit this->Job->canceled();
}
else if (this->Job->status() != ctkAbstractJob::JobStatus::Stopped)
{
emit this->Job->failed();
}
else
{
emit this->Job->finished();
emit this->Job->canceled();
}
}
18 changes: 14 additions & 4 deletions Libs/Core/ctkJobScheduler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -248,16 +248,19 @@ ctkAbstractJob* ctkJobScheduler::getJobByUID(const QString& jobUID)
}

//----------------------------------------------------------------------------
void ctkJobScheduler::waitForFinish()
void ctkJobScheduler::waitForFinish(bool waitForPersistentJobs)
{
Q_D(ctkJobScheduler);

int numberOfPersistentJobs = this->numberOfPersistentJobs();
if (waitForPersistentJobs)
{
numberOfPersistentJobs = 0;
}
while (this->numberOfJobs() > numberOfPersistentJobs)
{
QCoreApplication::processEvents();
d->ThreadPool->waitForDone(300);
}
}
}

//----------------------------------------------------------------------------
Expand Down Expand Up @@ -391,7 +394,13 @@ void ctkJobScheduler::onJobCanceled()
return;
}
logger.debug(job->loggerReport("canceled"));
emit this->jobCanceled(job->toVariant());

QVariant data = job->toVariant();
QString jobUID = job->jobUID();
this->deleteWorker(jobUID);
this->deleteJob(jobUID);

emit this->jobCanceled(data);
}

//----------------------------------------------------------------------------
Expand Down Expand Up @@ -468,6 +477,7 @@ void ctkJobScheduler::onQueueJobsInThreadPool()
.arg(QString::number(reinterpret_cast<quint64>(QThread::currentThreadId())), 16));

job->setStatus(ctkAbstractJob::JobStatus::Queued);
emit this->jobQueued(job->toVariant());

QSharedPointer<ctkAbstractWorker> worker =
QSharedPointer<ctkAbstractWorker>(job->createWorker());
Expand Down
3 changes: 2 additions & 1 deletion Libs/Core/ctkJobScheduler.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ class CTK_CORE_EXPORT ctkJobScheduler : public QObject
QSharedPointer<ctkAbstractJob> getJobSharedByUID(const QString& jobUID);
Q_INVOKABLE ctkAbstractJob* getJobByUID(const QString& jobUID);

Q_INVOKABLE void waitForFinish();
Q_INVOKABLE void waitForFinish(bool waitForPersistentJobs = false);
Q_INVOKABLE void waitForDone(int msec);

Q_INVOKABLE void stopAllJobs(bool stopPersistentJobs = false);
Expand Down Expand Up @@ -93,6 +93,7 @@ class CTK_CORE_EXPORT ctkJobScheduler : public QObject
QSharedPointer<QThreadPool> threadPoolShared() const;

Q_SIGNALS:
void jobQueued(QVariant data);
void jobStarted(QVariant data);
void jobFinished(QVariant data);
void jobCanceled(QVariant data);
Expand Down
1 change: 0 additions & 1 deletion Libs/DICOM/Core/Resources/dicom-schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ CREATE TABLE 'Series' (
'BodyPartExamined' VARCHAR(255) NULL ,
'FrameOfReferenceUID' VARCHAR(64) NULL ,
'AcquisitionNumber' INT NULL ,

'ContrastAgent' VARCHAR(255) NULL ,
'ScanningSequence' VARCHAR(45) NULL ,
'EchoNumber' INT NULL ,
Expand Down
56 changes: 1 addition & 55 deletions Libs/DICOM/Core/ctkDICOMCorePythonQtDecorators.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,60 +122,6 @@ public slots:
return td->NumberOfDataSets;
}

//----------------------------------------------------------------------------
// ctkDICOMJobResponseSet
//----------------------------------------------------------------------------
void setFilePath(ctkDICOMJobResponseSet* ts, const QString& filePath)
{
ts->setFilePath(filePath);
}

void setCopyFile(ctkDICOMJobResponseSet* ts, bool copyFile)
{
ts->setCopyFile(copyFile);
}

void setOverwriteExistingDataset(ctkDICOMJobResponseSet* ts, bool overwriteExistingDataset)
{
ts->setOverwriteExistingDataset(overwriteExistingDataset);
}

void setJobType(ctkDICOMJobResponseSet* ts, ctkDICOMJobResponseSet::JobType jobType)
{
ts->setJobType(jobType);
}

void setJobUID(ctkDICOMJobResponseSet* ts, const QString& jobUID)
{
ts->setJobUID(jobUID);
}

void setPatientID(ctkDICOMJobResponseSet* ts, const QString& patientID)
{
ts->setPatientID(patientID);
}

void setStudyInstanceUID(ctkDICOMJobResponseSet* ts, const QString& studyInstanceUID)
{
ts->setStudyInstanceUID(studyInstanceUID);
}

void setSeriesInstanceUID(ctkDICOMJobResponseSet* ts, const QString& seriesInstanceUID)
{
ts->setSeriesInstanceUID(seriesInstanceUID);
}

void setSOPInstanceUID(ctkDICOMJobResponseSet* ts, const QString& sopInstanceUID)
{
ts->setSOPInstanceUID(sopInstanceUID);
}

void setConnectionName(ctkDICOMJobResponseSet* ts, const QString& connectionName)
{
ts->setConnectionName(connectionName);
}


//----------------------------------------------------------------------------
// ctkDICOMDisplayedFieldGeneratorRuleFactory

Expand All @@ -193,7 +139,7 @@ public slots:

//----------------------------------------------------------------------------
bool registerDisplayedFieldGeneratorRule(ctkDICOMDisplayedFieldGeneratorRuleFactory* factory,
PythonQtPassOwnershipToCPP<ctkDICOMDisplayedFieldGeneratorAbstractRule*> plugin)
PythonQtPassOwnershipToCPP<ctkDICOMDisplayedFieldGeneratorAbstractRule*> plugin)
{
return factory->registerDisplayedFieldGeneratorRule(plugin);
}
Expand Down
13 changes: 12 additions & 1 deletion Libs/DICOM/Core/ctkDICOMEcho.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ bool ctkDICOMEcho::echo()
return false;
}

logger.debug("Seding Echo");
logger.info("Seding Echo");
// Issue ECHO request and let scu find presentation context itself (0)
OFCondition status = d->SCU.sendECHORequest(0);
if (!status.good())
Expand All @@ -213,3 +213,14 @@ bool ctkDICOMEcho::echo()

return true;
}

//------------------------------------------------------------------------------
void ctkDICOMEcho::cancel()
{
Q_D(ctkDICOMEcho);

if (d->SCU.isConnected())
{
d->SCU.releaseAssociation();
}
}
5 changes: 4 additions & 1 deletion Libs/DICOM/Core/ctkDICOMEcho.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,10 @@ class CTK_DICOM_CORE_EXPORT ctkDICOMEcho : public QObject
///@}

/// Echo connection.
bool echo();
Q_INVOKABLE bool echo();

/// Cancel the current operation
Q_INVOKABLE void cancel();

protected:
QScopedPointer<ctkDICOMEchoPrivate> d_ptr;
Expand Down
Loading

0 comments on commit fd14f5b

Please sign in to comment.