diff --git a/Libs/DICOM/Core/CMakeLists.txt b/Libs/DICOM/Core/CMakeLists.txt index 8a0f228042..d7b03107cd 100644 --- a/Libs/DICOM/Core/CMakeLists.txt +++ b/Libs/DICOM/Core/CMakeLists.txt @@ -16,6 +16,8 @@ set(KIT_SRCS ctkDICOMItem.h ctkDICOMDisplayedFieldGenerator.cpp ctkDICOMDisplayedFieldGenerator.h + ctkDICOMEcho.cpp + ctkDICOMEcho.h ctkDICOMFilterProxyModel.cpp ctkDICOMFilterProxyModel.h ctkDICOMIndexer.cpp @@ -79,6 +81,7 @@ set(KIT_MOC_SRCS ctkDICOMDisplayedFieldGenerator.h ctkDICOMDisplayedFieldGenerator_p.h ctkDICOMDisplayedFieldGeneratorRuleFactory.h + ctkDICOMEcho.h ctkDICOMIndexer.h ctkDICOMIndexer_p.h ctkDICOMFilterProxyModel.h diff --git a/Libs/DICOM/Core/ctkDICOMEcho.cpp b/Libs/DICOM/Core/ctkDICOMEcho.cpp new file mode 100644 index 0000000000..a49685a1d0 --- /dev/null +++ b/Libs/DICOM/Core/ctkDICOMEcho.cpp @@ -0,0 +1,261 @@ +/*========================================================================= + + Library: CTK + + Copyright (c) Kitware Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +// Qt includes +#include +#include +#include +#include + +// ctkDICOMCore includes +#include "ctkDICOMEcho.h" +#include "ctkLogger.h" + +// DCMTK includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for class OFStandard */ +#include /* for class DicomDirInterface */ + +static ctkLogger logger ( "org.commontk.dicom.DICOMEcho" ); + +//------------------------------------------------------------------------------ +class ctkDICOMEchoPrivate +{ +public: + ctkDICOMEchoPrivate(); + ~ctkDICOMEchoPrivate(); + + QString ConnectionName; + QString CallingAETitle; + QString CalledAETitle; + QString Host; + int Port; + DcmSCU SCU; +}; + +//------------------------------------------------------------------------------ +// ctkDICOMEchoPrivate methods + +//------------------------------------------------------------------------------ +ctkDICOMEchoPrivate::ctkDICOMEchoPrivate() +{ + this->Port = 0; + + this->SCU.setACSETimeout(3); + this->SCU.setConnectionTimeout(3); +} + +//------------------------------------------------------------------------------ +ctkDICOMEchoPrivate::~ctkDICOMEchoPrivate() +{ +} + +//------------------------------------------------------------------------------ +// ctkDICOMEcho methods + +//------------------------------------------------------------------------------ +ctkDICOMEcho::ctkDICOMEcho(QObject* parentObject) + : QObject(parentObject) + , d_ptr(new ctkDICOMEchoPrivate) +{ + Q_D(ctkDICOMEcho); + + d->SCU.setVerbosePCMode(false); + d->SCU.setProgressNotificationMode(false); + + QSettings settings; + this->setDCMTKLogLevel(ctkErrorLogLevel::logLevelFromString(settings.value("CTKLogging/Level").toString())); +} + +//------------------------------------------------------------------------------ +ctkDICOMEcho::~ctkDICOMEcho() +{ +} + +//----------------------------------------------------------------------------- +void ctkDICOMEcho::setDCMTKLogLevel(const ctkErrorLogLevel::LogLevel& level) +{ + OFLogger::LogLevel dcmtkLogLevel = OFLogger::OFF_LOG_LEVEL; + if (level == ctkErrorLogLevel::LogLevel::Fatal) + { + dcmtkLogLevel = OFLogger::FATAL_LOG_LEVEL; + } + else if (level == ctkErrorLogLevel::LogLevel::Critical || + level == ctkErrorLogLevel::LogLevel::Error) + { + dcmtkLogLevel = OFLogger::ERROR_LOG_LEVEL; + } + else if (level == ctkErrorLogLevel::LogLevel::Warning) + { + dcmtkLogLevel = OFLogger::WARN_LOG_LEVEL; + } + else if (level == ctkErrorLogLevel::LogLevel::Info) + { + dcmtkLogLevel = OFLogger::INFO_LOG_LEVEL; + } + else if (level == ctkErrorLogLevel::LogLevel::Debug) + { + dcmtkLogLevel = OFLogger::DEBUG_LOG_LEVEL; + } + else if (level == ctkErrorLogLevel::LogLevel::Trace || + level == ctkErrorLogLevel::LogLevel::Status) + { + dcmtkLogLevel = OFLogger::TRACE_LOG_LEVEL; + } + + OFLog::configure(dcmtkLogLevel); +} + +//----------------------------------------------------------------------------- +ctkErrorLogLevel::LogLevel ctkDICOMEcho::DCMTKLogLevel() const +{ + return logger.logLevel(); +} + +/// Set methods for connectivity +//------------------------------------------------------------------------------ +void ctkDICOMEcho::setConnectionName(const QString& connectionName) +{ + Q_D(ctkDICOMEcho); + d->ConnectionName = connectionName; +} + +//------------------------------------------------------------------------------ +QString ctkDICOMEcho::connectionName() const +{ + Q_D(const ctkDICOMEcho); + return d->ConnectionName; +} + +//------------------------------------------------------------------------------ +void ctkDICOMEcho::setCallingAETitle(const QString& callingAETitle) +{ + Q_D(ctkDICOMEcho); + d->CallingAETitle = callingAETitle; +} + +//------------------------------------------------------------------------------ +QString ctkDICOMEcho::callingAETitle() const +{ + Q_D(const ctkDICOMEcho); + return d->CallingAETitle; +} + +//------------------------------------------------------------------------------ +void ctkDICOMEcho::setCalledAETitle(const QString& calledAETitle) +{ + Q_D(ctkDICOMEcho); + d->CalledAETitle = calledAETitle; +} + +//------------------------------------------------------------------------------ +QString ctkDICOMEcho::calledAETitle()const +{ + Q_D(const ctkDICOMEcho); + return d->CalledAETitle; +} + +//------------------------------------------------------------------------------ +void ctkDICOMEcho::setHost(const QString& host) +{ + Q_D(ctkDICOMEcho); + d->Host = host; +} + +//------------------------------------------------------------------------------ +QString ctkDICOMEcho::host() const +{ + Q_D(const ctkDICOMEcho); + return d->Host; +} + +//------------------------------------------------------------------------------ +void ctkDICOMEcho::setPort (int port) +{ + Q_D(ctkDICOMEcho); + d->Port = port; +} + +//------------------------------------------------------------------------------ +int ctkDICOMEcho::port()const +{ + Q_D(const ctkDICOMEcho); + return d->Port; +} + +//----------------------------------------------------------------------------- +void ctkDICOMEcho::setConnectionTimeout(const int timeout) +{ + Q_D(ctkDICOMEcho); + d->SCU.setACSETimeout(timeout); + d->SCU.setConnectionTimeout(timeout); +} + +//----------------------------------------------------------------------------- +int ctkDICOMEcho::connectionTimeout() +{ + Q_D(const ctkDICOMEcho); + return d->SCU.getConnectionTimeout(); +} + +//------------------------------------------------------------------------------ +bool ctkDICOMEcho::echo() +{ + Q_D(ctkDICOMEcho); + + d->SCU.setAETitle(OFString(this->callingAETitle().toStdString().c_str())); + d->SCU.setPeerAETitle(OFString(this->calledAETitle().toStdString().c_str())); + d->SCU.setPeerHostName(OFString(this->host().toStdString().c_str())); + d->SCU.setPeerPort(this->port()); + + logger.debug("Setting Transfer Syntaxes"); + + OFList transferSyntaxes; + transferSyntaxes.push_back(UID_LittleEndianExplicitTransferSyntax); + transferSyntaxes.push_back(UID_BigEndianExplicitTransferSyntax); + transferSyntaxes.push_back(UID_LittleEndianImplicitTransferSyntax); + + d->SCU.addPresentationContext(UID_FINDStudyRootQueryRetrieveInformationModel, transferSyntaxes); + if (!d->SCU.initNetwork().good()) + { + logger.error("Error initializing the network"); + return false; + } + logger.debug("Negotiating Association"); + + OFCondition result = d->SCU.negotiateAssociation(); + if (result.bad()) + { + logger.error("Error negotiating the association: " + QString(result.text())); + return false; + } + + d->SCU.releaseAssociation(); + + return true; +} diff --git a/Libs/DICOM/Core/ctkDICOMEcho.h b/Libs/DICOM/Core/ctkDICOMEcho.h new file mode 100644 index 0000000000..2a2f70d9ca --- /dev/null +++ b/Libs/DICOM/Core/ctkDICOMEcho.h @@ -0,0 +1,93 @@ +/*========================================================================= + + Library: CTK + + Copyright (c) Kitware Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#ifndef __ctkDICOMEcho_h +#define __ctkDICOMEcho_h + +// Qt includes +#include +#include +#include + +// CTK includes +#include + +// ctkDICOMCore includes +#include "ctkDICOMCoreExport.h" +#include "ctkErrorLogLevel.h" + +class ctkDICOMEchoPrivate; +class ctkDICOMTaskResults; + +/// \ingroup DICOM_Core +class CTK_DICOM_CORE_EXPORT ctkDICOMEcho : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString connectionName READ connectionName WRITE setConnectionName); + Q_PROPERTY(QString callingAETitle READ callingAETitle WRITE setCallingAETitle); + Q_PROPERTY(QString calledAETitle READ calledAETitle WRITE setCalledAETitle); + Q_PROPERTY(QString host READ host WRITE setHost); + Q_PROPERTY(int port READ port WRITE setPort); + Q_PROPERTY(int connectionTimeout READ connectionTimeout WRITE setConnectionTimeout); + +public: + explicit ctkDICOMEcho(QObject* parent = 0); + virtual ~ctkDICOMEcho(); + + /// Set methods for connectivity. + /// Empty by default + void setConnectionName ( const QString& connectionName ); + QString connectionName()const; + /// Empty by default + void setCallingAETitle ( const QString& callingAETitle ); + QString callingAETitle()const; + /// Empty by default + void setCalledAETitle ( const QString& calledAETitle ); + QString calledAETitle()const; + /// Empty by default + void setHost ( const QString& host ); + QString host()const; + /// Specify a port for the packet headers. + /// \a port ranges from 0 to 65535. + /// 0 by default. + void setPort ( int port ); + int port()const; + /// connection timeout, default 3 sec. + void setConnectionTimeout(const int timeout); + int connectionTimeout(); + + /// Log level for dcmtk. Default: Error. + Q_INVOKABLE void setDCMTKLogLevel(const ctkErrorLogLevel::LogLevel& level); + Q_INVOKABLE ctkErrorLogLevel::LogLevel DCMTKLogLevel() const; + + /// Echo connection. + bool echo(); + +protected: + QScopedPointer d_ptr; + +private: + Q_DECLARE_PRIVATE(ctkDICOMEcho); + Q_DISABLE_COPY(ctkDICOMEcho); + + friend class ctkDICOMEchoSCUPrivate; // for access to EchoResponseHandled +}; + +#endif diff --git a/Libs/DICOM/Core/ctkDICOMServer.cpp b/Libs/DICOM/Core/ctkDICOMServer.cpp index 8703423017..4c475441d9 100644 --- a/Libs/DICOM/Core/ctkDICOMServer.cpp +++ b/Libs/DICOM/Core/ctkDICOMServer.cpp @@ -43,6 +43,8 @@ class ctkDICOMServerPrivate: public QObject ~ctkDICOMServerPrivate(); QString ConnectionName; + bool DownloadEnabled; + bool UploadEnabled; QString CallingAETitle; QString CalledAETitle; QString Host; @@ -61,6 +63,8 @@ class ctkDICOMServerPrivate: public QObject ctkDICOMServerPrivate::ctkDICOMServerPrivate(ctkDICOMServer& obj) : q_ptr(&obj) { + this->DownloadEnabled = true; + this->UploadEnabled = true; this->KeepAssociationOpen = false; this->ConnectionTimeout = 3; this->RetrieveProtocol = ctkDICOMServer::RetrieveProtocol::CGET; @@ -100,6 +104,34 @@ QString ctkDICOMServer::connectionName() const return d->ConnectionName; } +//------------------------------------------------------------------------------ +void ctkDICOMServer::setDownloadEnabled(bool downloadEnabled) +{ + Q_D(ctkDICOMServer); + d->DownloadEnabled = downloadEnabled; +} + +//------------------------------------------------------------------------------ +bool ctkDICOMServer::downloadEnabled() const +{ + Q_D(const ctkDICOMServer); + return d->DownloadEnabled; +} + +//------------------------------------------------------------------------------ +void ctkDICOMServer::setUploadEnabled(bool uploadEnabled) +{ + Q_D(ctkDICOMServer); + d->UploadEnabled = uploadEnabled; +} + +//------------------------------------------------------------------------------ +bool ctkDICOMServer::uploadEnabled() const +{ + Q_D(const ctkDICOMServer); + return d->UploadEnabled; +} + //------------------------------------------------------------------------------ void ctkDICOMServer::setCallingAETitle( const QString& callingAETitle ) { @@ -170,6 +202,49 @@ ctkDICOMServer::RetrieveProtocol ctkDICOMServer::retrieveProtocol()const return d->RetrieveProtocol; } +//------------------------------------------------------------------------------ +void ctkDICOMServer::setRetrieveProtocolAsString(QString protocolString) +{ + Q_D(ctkDICOMServer); + + if (protocolString == "CGET") + { + d->RetrieveProtocol = RetrieveProtocol::CGET; + } + else if (protocolString == "CMOVE") + { + d->RetrieveProtocol = RetrieveProtocol::CMOVE; + } + /*else if (protocolString == "WADO") + { + d->RetrieveProtocol = RetrieveProtocol::WADO; + }*/ +} + +//------------------------------------------------------------------------------ +QString ctkDICOMServer::retrieveProtocolAsString() const +{ + Q_D(const ctkDICOMServer); + + QString protocolString = ""; + switch (d->RetrieveProtocol) + { + case RetrieveProtocol::CGET: + protocolString = "CGET"; + break; + case RetrieveProtocol::CMOVE: + protocolString = "CMOVE"; + break; + /*case RetrieveProtocol::WADO: + protocolString = "WADO"; + break; */ + default: + break; + } + + return protocolString; +} + //------------------------------------------------------------------------------ void ctkDICOMServer::setMoveDestinationAETitle(const QString& moveDestinationAETitle) { diff --git a/Libs/DICOM/Core/ctkDICOMServer.h b/Libs/DICOM/Core/ctkDICOMServer.h index fa593a0596..28fe6d6565 100644 --- a/Libs/DICOM/Core/ctkDICOMServer.h +++ b/Libs/DICOM/Core/ctkDICOMServer.h @@ -37,6 +37,8 @@ class CTK_DICOM_CORE_EXPORT ctkDICOMServer : public QObject Q_OBJECT Q_ENUMS(RetrieveProtocol) Q_PROPERTY(QString connectionName READ connectionName WRITE setConnectionName); + Q_PROPERTY(bool downloadEnabled READ downloadEnabled WRITE setDownloadEnabled); + Q_PROPERTY(bool uploadEnabled READ uploadEnabled WRITE setUploadEnabled); Q_PROPERTY(QString callingAETitle READ callingAETitle WRITE setCallingAETitle); Q_PROPERTY(QString calledAETitle READ calledAETitle WRITE setCalledAETitle); Q_PROPERTY(QString host READ host WRITE setHost); @@ -53,6 +55,14 @@ class CTK_DICOM_CORE_EXPORT ctkDICOMServer : public QObject /// Set methods for connectivity void setConnectionName(const QString& connectionName); QString connectionName() const; + /// downloadEnabled + /// true as default + void setDownloadEnabled(bool downloadEnabled); + bool downloadEnabled() const; + /// Enabled + /// true as default + void setUploadEnabled(bool uploadEnabled); + bool uploadEnabled() const; /// CTK_AE - the AE string by which the peer host might /// recognize your request void setCallingAETitle(const QString& callingAETitle); @@ -77,7 +87,9 @@ class CTK_DICOM_CORE_EXPORT ctkDICOMServer : public QObject // WADO // To Do }; void setRetrieveProtocol(RetrieveProtocol protocol); - RetrieveProtocol retrieveProtocol()const; + RetrieveProtocol retrieveProtocol() const; + Q_INVOKABLE void setRetrieveProtocolAsString(QString protocolString); + Q_INVOKABLE QString retrieveProtocolAsString() const; /// Typically CTK_STORE or similar - needs to be something that the /// peer host knows about and is able to move data into /// Only used when calling moveSeries or moveStudy diff --git a/Libs/DICOM/Core/ctkDICOMTaskPool.cpp b/Libs/DICOM/Core/ctkDICOMTaskPool.cpp index 04645f87fa..357067f8e6 100644 --- a/Libs/DICOM/Core/ctkDICOMTaskPool.cpp +++ b/Libs/DICOM/Core/ctkDICOMTaskPool.cpp @@ -59,6 +59,7 @@ ctkDICOMTaskPoolPrivate::~ctkDICOMTaskPoolPrivate() q->stopAllTasks(); QObject::disconnect(this->Indexer.data(), SIGNAL(progressTaskDetail(ctkDICOMTaskResults*)), q, SIGNAL(progressTaskDetail(ctkDICOMTaskResults*))); + q->removeAllServers(); } //------------------------------------------------------------------------------ @@ -102,6 +103,11 @@ void ctkDICOMTaskPool::queryStudies(QThread::Priority priority) foreach(QSharedPointer server, d->Servers) { + if (!server->downloadEnabled()) + { + continue; + } + ctkDICOMQueryTask *task = new ctkDICOMQueryTask(); task->setServer(*server); task->setFilters(d->Filters); @@ -128,6 +134,11 @@ void ctkDICOMTaskPool::querySeries(const QString& studyInstanceUID, foreach(QSharedPointer server, d->Servers) { + if (!server->downloadEnabled()) + { + continue; + } + ctkDICOMQueryTask *task = new ctkDICOMQueryTask(); task->setServer(*server); task->setFilters(d->Filters); @@ -156,6 +167,11 @@ void ctkDICOMTaskPool::queryInstances(const QString& studyInstanceUID, foreach(QSharedPointer server, d->Servers) { + if (!server->downloadEnabled()) + { + continue; + } + ctkDICOMQueryTask *task = new ctkDICOMQueryTask(); task->setServer(*server); task->setFilters(d->Filters); @@ -184,6 +200,11 @@ void ctkDICOMTaskPool::retrieveStudy(const QString &studyInstanceUID, foreach(QSharedPointer server, d->Servers) { + if (!server->downloadEnabled()) + { + continue; + } + ctkDICOMRetrieveTask *task = new ctkDICOMRetrieveTask(); task->setServer(*server); task->setRetrieveLevel(ctkDICOMRetrieveTask::DICOMLevel::Studies); @@ -211,6 +232,11 @@ void ctkDICOMTaskPool::retrieveSeries(const QString &studyInstanceUID, foreach(QSharedPointer server, d->Servers) { + if (!server->downloadEnabled()) + { + continue; + } + ctkDICOMRetrieveTask *task = new ctkDICOMRetrieveTask(); task->setServer(*server); task->setRetrieveLevel(ctkDICOMRetrieveTask::DICOMLevel::Series); @@ -242,6 +268,11 @@ void ctkDICOMTaskPool::retrieveSOPInstance(const QString &studyInstanceUID, foreach(QSharedPointer server, d->Servers) { + if (!server->downloadEnabled()) + { + continue; + } + ctkDICOMRetrieveTask *task = new ctkDICOMRetrieveTask(); task->setServer(*server); task->setRetrieveLevel(ctkDICOMRetrieveTask::DICOMLevel::Instances); @@ -348,6 +379,8 @@ ctkDICOMServer* ctkDICOMTaskPool::getServer(const char *connectionName) void ctkDICOMTaskPool::addServer(ctkDICOMServer* server) { Q_D(ctkDICOMTaskPool); + this->stopAllTasks(); + this->waitForFinish(); QSharedPointer QsharedServer = QSharedPointer(server); d->Servers.push_back(QsharedServer); } @@ -367,9 +400,20 @@ void ctkDICOMTaskPool::removeNthServer(int id) return; } + this->stopAllTasks(); + this->waitForFinish(); d->Servers.erase(d->Servers.begin() + id); } +//---------------------------------------------------------------------------- +void ctkDICOMTaskPool::removeAllServers() +{ + Q_D(ctkDICOMTaskPool); + this->stopAllTasks(); + this->waitForFinish(); + d->Servers.clear(); +} + //---------------------------------------------------------------------------- QString ctkDICOMTaskPool::getServerNameFromIndex(int id) { @@ -790,14 +834,13 @@ void ctkDICOMTaskPool::taskFinished() // 2) start a get operation to the proxy server. // if the task pool owns a storage listener -> ... To Do. - foreach (QSharedPointer taskResults, taskResultsList) { emit this->progressTaskDetail(taskResults.data()); } ctkDICOMServer* proxyServer = retrieveTask->server()->proxyServer(); - if (proxyServer) + if (proxyServer && proxyServer->downloadEnabled()) { QString newTaskUID = d->generateUniqueTaskUID(); ctkDICOMRetrieveTask* newRetrieveTask = new ctkDICOMRetrieveTask(); diff --git a/Libs/DICOM/Core/ctkDICOMTaskPool.h b/Libs/DICOM/Core/ctkDICOMTaskPool.h index 043243b3c2..abd2a585e9 100644 --- a/Libs/DICOM/Core/ctkDICOMTaskPool.h +++ b/Libs/DICOM/Core/ctkDICOMTaskPool.h @@ -124,6 +124,7 @@ class CTK_DICOM_CORE_EXPORT ctkDICOMTaskPool : public ctkAbstractTaskPool Q_INVOKABLE void addServer(ctkDICOMServer* server); Q_INVOKABLE void removeServer(const char* connectionName); Q_INVOKABLE void removeNthServer(int id); + Q_INVOKABLE void removeAllServers(); Q_INVOKABLE QString getServerNameFromIndex(int id); Q_INVOKABLE int getServerIndexFromName(const char* connectionName); diff --git a/Libs/DICOM/Widgets/CMakeLists.txt b/Libs/DICOM/Widgets/CMakeLists.txt index 63cab17ef0..283b312d27 100644 --- a/Libs/DICOM/Widgets/CMakeLists.txt +++ b/Libs/DICOM/Widgets/CMakeLists.txt @@ -39,6 +39,8 @@ set(KIT_SRCS ctkDICOMSeriesItemWidget.h ctkDICOMServerNodeWidget.cpp ctkDICOMServerNodeWidget.h + ctkDICOMServerNodeWidget2.cpp + ctkDICOMServerNodeWidget2.h ctkDICOMStudyItemWidget.cpp ctkDICOMStudyItemWidget.h ctkDICOMTableManager.h @@ -68,6 +70,7 @@ set(KIT_MOC_SRCS ctkDICOMPatientItemWidget.h ctkDICOMSeriesItemWidget.h ctkDICOMServerNodeWidget.h + ctkDICOMServerNodeWidget2.h ctkDICOMStudyItemWidget.h ctkDICOMTableManager.h ctkDICOMTableView.h @@ -89,6 +92,7 @@ set(KIT_UI_FORMS Resources/UI/ctkDICOMPatientItemWidget.ui Resources/UI/ctkDICOMSeriesItemWidget.ui Resources/UI/ctkDICOMServerNodeWidget.ui + Resources/UI/ctkDICOMServerNodeWidget2.ui Resources/UI/ctkDICOMStudyItemWidget.ui Resources/UI/ctkDICOMTableManager.ui Resources/UI/ctkDICOMTableView.ui diff --git a/Libs/DICOM/Widgets/Resources/UI/Icons/add.svg b/Libs/DICOM/Widgets/Resources/UI/Icons/add.svg new file mode 100644 index 0000000000..846383523a --- /dev/null +++ b/Libs/DICOM/Widgets/Resources/UI/Icons/add.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Libs/DICOM/Widgets/Resources/UI/Icons/dns.svg b/Libs/DICOM/Widgets/Resources/UI/Icons/dns.svg new file mode 100644 index 0000000000..c386420774 --- /dev/null +++ b/Libs/DICOM/Widgets/Resources/UI/Icons/dns.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Libs/DICOM/Widgets/Resources/UI/Icons/restore.svg b/Libs/DICOM/Widgets/Resources/UI/Icons/restore.svg new file mode 100644 index 0000000000..884575fd06 --- /dev/null +++ b/Libs/DICOM/Widgets/Resources/UI/Icons/restore.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Libs/DICOM/Widgets/Resources/UI/Icons/save.svg b/Libs/DICOM/Widgets/Resources/UI/Icons/save.svg new file mode 100644 index 0000000000..9cc945f49f --- /dev/null +++ b/Libs/DICOM/Widgets/Resources/UI/Icons/save.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Libs/DICOM/Widgets/Resources/UI/ctkDICOMServerNodeWidget2.ui b/Libs/DICOM/Widgets/Resources/UI/ctkDICOMServerNodeWidget2.ui new file mode 100644 index 0000000000..62796cc197 --- /dev/null +++ b/Libs/DICOM/Widgets/Resources/UI/ctkDICOMServerNodeWidget2.ui @@ -0,0 +1,300 @@ + + + ctkDICOMServerNodeWidget2 + + + + 0 + 0 + 1332 + 225 + + + + Server List + + + + 1 + + + 1 + + + 1 + + + 1 + + + 5 + + + + + Storage Port + + + + + + + + + + Storage AETitle + + + + + + + 3 + + + + + + 0 + 0 + + + + Add host + + + + :/Icons/add.svg:/Icons/add.svg + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + Verify host + + + + :/Icons/dns.svg:/Icons/dns.svg + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + Remove host + + + + :/Icons/delete.svg:/Icons/delete.svg + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + Qt::Vertical + + + QSizePolicy::MinimumExpanding + + + + 20 + 30 + + + + + + + + + 0 + 0 + + + + Discard changes + + + + :/Icons/restore.svg:/Icons/restore.svg + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + Save changes + + + + :/Icons/save.svg:/Icons/save.svg + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + + + + 0 + 0 + + + + false + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + Qt::ElideRight + + + 10 + + + true + + + false + + + 150 + + + 150 + + + true + + + false + + + true + + + false + + + false + + + + Name + + + + + Download + + + + + Upload + + + + + CallingAETitle + + + + + CalledAETitle + + + + + Address + + + + + Port + + + + + Timeout + + + + + Protocol + + + + + Proxy + + + + + + + + + + + Servers + + + Qt::AlignCenter + + + + + + + + ctkPushButton + QPushButton +
ctkPushButton.h
+
+
+ + + + +
diff --git a/Libs/DICOM/Widgets/Resources/UI/ctkDICOMVisualBrowserWidget.ui b/Libs/DICOM/Widgets/Resources/UI/ctkDICOMVisualBrowserWidget.ui index 0dd4d7b26b..a9cca8c888 100644 --- a/Libs/DICOM/Widgets/Resources/UI/ctkDICOMVisualBrowserWidget.ui +++ b/Libs/DICOM/Widgets/Resources/UI/ctkDICOMVisualBrowserWidget.ui @@ -884,6 +884,44 @@ Please set at least one filter to query the servers + + + + + 11 + + + + + + + Settings + + + false + + + true + + + + 0 + + + 2 + + + 0 + + + 2 + + + 2 + + + + diff --git a/Libs/DICOM/Widgets/Resources/UI/ctkDICOMWidget.qrc b/Libs/DICOM/Widgets/Resources/UI/ctkDICOMWidget.qrc index 71f133b113..9a54744637 100644 --- a/Libs/DICOM/Widgets/Resources/UI/ctkDICOMWidget.qrc +++ b/Libs/DICOM/Widgets/Resources/UI/ctkDICOMWidget.qrc @@ -13,5 +13,9 @@ Icons/text_document.svg Icons/delete.svg Icons/more_vert.svg + Icons/add.svg + Icons/dns.svg + Icons/restore.svg + Icons/save.svg diff --git a/Libs/DICOM/Widgets/ctkDICOMServerNodeWidget2.cpp b/Libs/DICOM/Widgets/ctkDICOMServerNodeWidget2.cpp new file mode 100644 index 0000000000..2e2b352e65 --- /dev/null +++ b/Libs/DICOM/Widgets/ctkDICOMServerNodeWidget2.cpp @@ -0,0 +1,966 @@ +/*========================================================================= + + Library: CTK + + Copyright (c) Kitware Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + This file was originally developed by Davide Punzo, punzodavide@hotmail.it, + and development was supported by the Center for Intelligent Image-guided Interventions (CI3). + +=========================================================================*/ + +// Qt includes +#include +#include +#include +#include +#include +#include +#include +#include + +// CTK includes +#include +#include +#include +#include + +// ctkDICOMCore includes +#include "ctkDICOMEcho.h" +#include "ctkDICOMServer.h" +#include "ctkDICOMTaskPool.h" + +// ctkDICOMWidgets includes +#include "ctkDICOMServerNodeWidget2.h" +#include "ui_ctkDICOMServerNodeWidget2.h" + +// STD includes +#include + +static ctkLogger logger("org.commontk.DICOM.Widgets.ctkDICOMServerNodeWidget2"); + +//---------------------------------------------------------------------------- +class SuffixDelegate : public QStyledItemDelegate +{ + Q_DISABLE_COPY(SuffixDelegate) + +public: + explicit SuffixDelegate(QObject* parent = nullptr) : QStyledItemDelegate(parent){} + QString displayText(const QVariant &value, const QLocale &locale) const override + { + return QStyledItemDelegate::displayText(value,locale) + m_suffix; + } + void setSuffix(const QString& val) { m_suffix = val; } + const QString& suffix() const {return m_suffix;} + +private: + QString m_suffix; +}; + +//---------------------------------------------------------------------------- +class ctkDICOMServerNodeWidget2Private: public Ui_ctkDICOMServerNodeWidget2 +{ + Q_DECLARE_PUBLIC(ctkDICOMServerNodeWidget2); + +protected: + ctkDICOMServerNodeWidget2* const q_ptr; + +public: + ctkDICOMServerNodeWidget2Private(ctkDICOMServerNodeWidget2& obj); + ~ctkDICOMServerNodeWidget2Private(); + + void init(); + /// Utility function that returns the storageAETitle and + /// storagePort in a map + QMap parameters()const; + + /// Return the list of server names + QStringList serverNodes()const; + /// Return all the information associated to a server defined by its name + QMap serverNodeParameters(const QString &connectionName) const; + QMap serverNodeParameters(int row) const; + QStringList getAllNodesName() const; + int getServerNodeRowFromConnectionName(const QString &connectionName) const; + QString getServerNodeConnectionNameFromRow(int row) const; + + /// Add a server node with the given parameters + /// Return the row index added into the table + int addServerNode(const QMap& parameters); + int addServerNode(ctkDICOMServer* server); + ctkDICOMServer* createServerFromServerNode(const QMap& node); + void updateProxyComboBoxes(const QString &connectionName, int rowCount) const; + + bool SettingsModified; + QSharedPointer TaskPool; +}; + +//---------------------------------------------------------------------------- +ctkDICOMServerNodeWidget2Private::ctkDICOMServerNodeWidget2Private(ctkDICOMServerNodeWidget2& obj) + : q_ptr(&obj) +{ + this->SettingsModified = false; +} + +//---------------------------------------------------------------------------- +ctkDICOMServerNodeWidget2Private::~ctkDICOMServerNodeWidget2Private() +{ +} + +//---------------------------------------------------------------------------- +void ctkDICOMServerNodeWidget2Private::init() +{ + Q_Q(ctkDICOMServerNodeWidget2); + + this->setupUi(q); + + // checkable headers. + this->NodeTable->model()->setHeaderData( + q->DownloadColumn, Qt::Horizontal, static_cast(Qt::Unchecked), Qt::CheckStateRole); + this->NodeTable->model()->setHeaderData( + q->UploadColumn, Qt::Horizontal, static_cast(Qt::Unchecked), Qt::CheckStateRole); + QHeaderView* previousHeaderView = this->NodeTable->horizontalHeader(); + ctkCheckableHeaderView* headerView = new ctkCheckableHeaderView(Qt::Horizontal, this->NodeTable); + headerView->setSectionsClickable(previousHeaderView->sectionsClickable()); + headerView->setSectionsMovable(previousHeaderView->sectionsMovable()); + headerView->setHighlightSections(previousHeaderView->highlightSections()); + headerView->checkableModelHelper()->setPropagateDepth(-1); + headerView->setStretchLastSection(previousHeaderView->stretchLastSection()); + headerView->setMinimumSectionSize(previousHeaderView->minimumSectionSize()); + headerView->setDefaultSectionSize(previousHeaderView->defaultSectionSize()); + this->NodeTable->setHorizontalHeader(headerView); + + SuffixDelegate *secDelegate = new SuffixDelegate(); + secDelegate->setSuffix(QStringLiteral(" s")); + this->NodeTable->setItemDelegateForColumn(ctkDICOMServerNodeWidget2::TimeoutColumn, secDelegate); + + this->TestButton->setEnabled(false); + this->RemoveButton->setEnabled(false); + + q->readSettings(); + + QObject::connect(this->StorageAETitle, SIGNAL(textChanged(QString)), + q, SLOT(onSettingsModified())); + QObject::connect(this->StoragePort, SIGNAL(textChanged(QString)), + q, SLOT(onSettingsModified())); + + QObject::connect(this->NodeTable, SIGNAL(cellChanged(int,int)), + q, SLOT(onSettingsModified())); + QObject::connect(this->NodeTable, SIGNAL(itemSelectionChanged()), + q, SLOT(updateGUIState())); + + QObject::connect(this->AddButton, SIGNAL(clicked()), + q, SLOT(addServerNode())); + QObject::connect(this->TestButton, SIGNAL(clicked()), + q, SLOT(testCurrentServerNode())); + QObject::connect(this->RemoveButton, SIGNAL(clicked()), + q, SLOT(removeCurrentServerNode())); + QObject::connect(this->RestoreButton, SIGNAL(clicked()), + q, SLOT(readSettings())); + QObject::connect(this->SaveButton, SIGNAL(clicked()), + q, SLOT(saveSettings())); +} + +//---------------------------------------------------------------------------- +QMap ctkDICOMServerNodeWidget2Private::parameters()const +{ + Q_Q(const ctkDICOMServerNodeWidget2); + QMap parameters; + + parameters["StorageAETitle"] = this->StorageAETitle->text(); + parameters["StoragePort"] = q->storagePort(); + + return parameters; +} + +//---------------------------------------------------------------------------- +QStringList ctkDICOMServerNodeWidget2Private::serverNodes()const +{ + QStringList nodes; + const int count = this->NodeTable->rowCount(); + for (int row = 0; row < count; ++row) + { + QTableWidgetItem* item = this->NodeTable->item(row, ctkDICOMServerNodeWidget2::NameColumn); + nodes << (item ? item->text() : QString("")); + } + // If there are duplicates, serverNodeParameters(QString) will behave + // strangely + Q_ASSERT(nodes.removeDuplicates() == 0); + return nodes; +} + +//---------------------------------------------------------------------------- +QMap ctkDICOMServerNodeWidget2Private::serverNodeParameters(const QString &connectionName)const +{ + QMap parameters; + const int count = this->NodeTable->rowCount(); + for (int row = 0; row < count; ++row) + { + if (this->NodeTable->item(row, 0)->text() == connectionName) + { + return this->serverNodeParameters(row); + } + } + + return parameters; +} + +//---------------------------------------------------------------------------- +QMap ctkDICOMServerNodeWidget2Private::serverNodeParameters(int row) const +{ + QMap node; + if (row < 0 || row >= this->NodeTable->rowCount()) + { + return node; + } + const int columnCount = this->NodeTable->columnCount(); + for (int column = 0; column < columnCount; ++column) + { + if (!this->NodeTable->item(row, column)) + { + continue; + } + QString label = this->NodeTable->horizontalHeaderItem(column)->text(); + node[label] = this->NodeTable->item(row, column)->data(Qt::DisplayRole); + } + node["DownloadCheckState"] = this->NodeTable->item(row, ctkDICOMServerNodeWidget2::DownloadColumn) ? + this->NodeTable->item(row, ctkDICOMServerNodeWidget2::DownloadColumn)->checkState() : + static_cast(Qt::Unchecked); + node["UploadCheckState"] = this->NodeTable->item(row, ctkDICOMServerNodeWidget2::UploadColumn) ? + this->NodeTable->item(row, ctkDICOMServerNodeWidget2::UploadColumn)->checkState() : + static_cast(Qt::Unchecked); + QComboBox *protocolComboBox = qobject_cast(this->NodeTable->cellWidget(row, ctkDICOMServerNodeWidget2::ProtocolColumn)); + if (protocolComboBox) + { + node["Protocol"] = protocolComboBox->currentText(); + } + QComboBox *proxyComboBox = qobject_cast(this->NodeTable->cellWidget(row, ctkDICOMServerNodeWidget2::ProxyColumn)); + if (proxyComboBox) + { + node["Proxy"] = proxyComboBox->currentText(); + } + + return node; +} + +//---------------------------------------------------------------------------- +QStringList ctkDICOMServerNodeWidget2Private::getAllNodesName() const +{ + QStringList nodesNames; + const int count = this->NodeTable->rowCount(); + for (int row = 0; row < count; ++row) + { + nodesNames.append(this->NodeTable->item(row, ctkDICOMServerNodeWidget2::NameColumn)->data(Qt::DisplayRole).toString()); + } + + return nodesNames; +} + +//---------------------------------------------------------------------------- +int ctkDICOMServerNodeWidget2Private::getServerNodeRowFromConnectionName(const QString &connectionName) const +{ + QMap parameters; + const int count = this->NodeTable->rowCount(); + for (int row = 0; row < count; ++row) + { + if (this->NodeTable->item(row, 0)->text() == connectionName) + { + return row; + } + } + + return -1; +} + +//---------------------------------------------------------------------------- +QString ctkDICOMServerNodeWidget2Private::getServerNodeConnectionNameFromRow(int row) const +{ + if (row < 0 || row >= this->NodeTable->rowCount()) + { + return ""; + } + + return this->NodeTable->item(row, 0)->text(); +} + +//---------------------------------------------------------------------------- +int ctkDICOMServerNodeWidget2Private::addServerNode(const QMap& node) +{ + Q_Q(ctkDICOMServerNodeWidget2); + + if (this->getServerNodeRowFromConnectionName(node["Name"].toString()) != -1) + { + logger.error("addServerNode failed: the server has a duplicate. The connection name has to be unique \n"); + return -1; + } + + const int rowCount = this->NodeTable->rowCount(); + this->NodeTable->setRowCount(rowCount + 1); + + QTableWidgetItem *newItem; + QString serverName = node["Name"].toString(); + newItem = new QTableWidgetItem(serverName); + this->NodeTable->setItem(rowCount, ctkDICOMServerNodeWidget2::NameColumn, newItem); + newItem = new QTableWidgetItem(QString("")); + newItem->setCheckState(Qt::CheckState(node["DownloadCheckState"].toInt())); + this->NodeTable->setItem(rowCount, ctkDICOMServerNodeWidget2::DownloadColumn, newItem); + newItem = new QTableWidgetItem(QString("")); + newItem->setCheckState(Qt::CheckState(node["UploadCheckState"].toInt())); + this->NodeTable->setItem(rowCount, ctkDICOMServerNodeWidget2::UploadColumn, newItem); + newItem = new QTableWidgetItem(node["CallingAETitle"].toString()); + this->NodeTable->setItem(rowCount, ctkDICOMServerNodeWidget2::CallingAETitleColumn, newItem); + newItem = new QTableWidgetItem(node["CalledAETitle"].toString()); + this->NodeTable->setItem(rowCount, ctkDICOMServerNodeWidget2::CalledAETitleColumn, newItem); + newItem = new QTableWidgetItem(node["Address"].toString()); + this->NodeTable->setItem(rowCount, ctkDICOMServerNodeWidget2::AddressColumn, newItem); + newItem = new QTableWidgetItem(node["Port"].toString()); + this->NodeTable->setItem(rowCount, ctkDICOMServerNodeWidget2::PortColumn, newItem); + newItem = new QTableWidgetItem(QString("")); + QComboBox *protocolComboBox = new QComboBox(); + protocolComboBox->addItem("CGET"); + protocolComboBox->addItem("CMOVE"); + // To Do: protocolComboBox->addItem("WADO"); + protocolComboBox->setCurrentIndex(protocolComboBox->findText(node["Protocol"].toString())); + QObject::connect(protocolComboBox, SIGNAL(currentIndexChanged(int)), + q, SLOT(onSettingsModified())); + this->NodeTable->setItem(rowCount, ctkDICOMServerNodeWidget2::ProtocolColumn, newItem); + this->NodeTable->setCellWidget(rowCount, ctkDICOMServerNodeWidget2::ProtocolColumn, protocolComboBox); + newItem = new QTableWidgetItem(node["Timeout"].toString()); + this->NodeTable->setItem(rowCount, ctkDICOMServerNodeWidget2::TimeoutColumn, newItem); + newItem = new QTableWidgetItem(QString("")); + QComboBox *proxyComboBox = new QComboBox(); + QStringListModel* cbModel = new QStringListModel(); + proxyComboBox->setModel(cbModel); + + proxyComboBox->addItem(""); + QStringList nodesNames = this->getAllNodesName(); + nodesNames.removeOne(serverName); + QString proxyName = node["Proxy"].toString(); + if (!nodesNames.contains(proxyName) && !proxyName.isEmpty()) + { + nodesNames.append(proxyName); + } + proxyComboBox->addItems(nodesNames); + proxyComboBox->setCurrentIndex(proxyComboBox->findText(node["Proxy"].toString())); + QObject::connect(proxyComboBox, SIGNAL(currentIndexChanged(int)), + q, SLOT(onSettingsModified())); + this->NodeTable->setCellWidget(rowCount, ctkDICOMServerNodeWidget2::ProxyColumn, proxyComboBox); + this->NodeTable->setItem(rowCount, ctkDICOMServerNodeWidget2::ProxyColumn, newItem); + + q->onSettingsModified(); + + this->updateProxyComboBoxes(serverName, rowCount); + + return rowCount; +} + +//---------------------------------------------------------------------------- +int ctkDICOMServerNodeWidget2Private::addServerNode(ctkDICOMServer *server) +{ + Q_Q(ctkDICOMServerNodeWidget2); + + if (!server) + { + return -1; + } + + if (this->getServerNodeRowFromConnectionName(server->connectionName()) != -1) + { + logger.error("addServerNode failed: the server has a duplicate. The connection name has to be unique \n"); + return -1; + } + + int rowCount = this->NodeTable->rowCount(); + this->NodeTable->setRowCount(rowCount + 1); + + QTableWidgetItem *newItem; + newItem = new QTableWidgetItem(server->connectionName()); + this->NodeTable->setItem(rowCount, ctkDICOMServerNodeWidget2::NameColumn, newItem); + newItem = new QTableWidgetItem(QString("")); + newItem->setCheckState(server->downloadEnabled() ? Qt::CheckState::Checked : Qt::CheckState::Unchecked); + this->NodeTable->setItem(rowCount, ctkDICOMServerNodeWidget2::DownloadColumn, newItem); + newItem = new QTableWidgetItem(QString("")); + newItem->setCheckState(server->uploadEnabled() ? Qt::CheckState::Checked : Qt::CheckState::Unchecked); + this->NodeTable->setItem(rowCount, ctkDICOMServerNodeWidget2::UploadColumn, newItem); + newItem = new QTableWidgetItem(server->callingAETitle()); + this->NodeTable->setItem(rowCount, ctkDICOMServerNodeWidget2::CallingAETitleColumn, newItem); + newItem = new QTableWidgetItem(server->calledAETitle()); + this->NodeTable->setItem(rowCount, ctkDICOMServerNodeWidget2::CalledAETitleColumn, newItem); + newItem = new QTableWidgetItem(server->host()); + this->NodeTable->setItem(rowCount, ctkDICOMServerNodeWidget2::AddressColumn, newItem); + newItem = new QTableWidgetItem(QString::number(server->port())); + this->NodeTable->setItem(rowCount, ctkDICOMServerNodeWidget2::PortColumn, newItem); + newItem = new QTableWidgetItem(QString("")); + QComboBox *protocolComboBox = new QComboBox(); + protocolComboBox->addItem("CGET"); + protocolComboBox->addItem("CMOVE"); + protocolComboBox->setCurrentIndex(protocolComboBox->findText(server->retrieveProtocolAsString())); + // To Do: protocolComboBox->addItem("WADO"); + QObject::connect(protocolComboBox, SIGNAL(currentIndexChanged(int)), + q, SLOT(onSettingsModified())); + this->NodeTable->setItem(rowCount, ctkDICOMServerNodeWidget2::ProtocolColumn, newItem); + this->NodeTable->setCellWidget(rowCount, ctkDICOMServerNodeWidget2::ProtocolColumn, protocolComboBox); + newItem = new QTableWidgetItem(QString::number(server->connectionTimeout())); + this->NodeTable->setItem(rowCount, ctkDICOMServerNodeWidget2::TimeoutColumn, newItem); + newItem = new QTableWidgetItem(QString("")); + QComboBox *proxyComboBox = new QComboBox(); + QStringListModel* cbModel = new QStringListModel(); + proxyComboBox->setModel(cbModel); + + proxyComboBox->addItem(""); + QStringList nodesNames = this->getAllNodesName(); + nodesNames.removeOne(server->connectionName()); + + if (server->proxyServer()) + { + QString proxyName = server->proxyServer()->connectionName(); + if (!nodesNames.contains(proxyName)) + { + nodesNames.append(proxyName); + } + } + proxyComboBox->addItems(nodesNames); + if (server->proxyServer()) + { + QString proxyName = server->proxyServer()->connectionName(); + proxyComboBox->setCurrentIndex(proxyComboBox->findText(proxyName)); + } + + QObject::connect(proxyComboBox, SIGNAL(currentIndexChanged(int)), + q, SLOT(onSettingsModified())); + this->NodeTable->setCellWidget(rowCount, ctkDICOMServerNodeWidget2::ProxyColumn, proxyComboBox); + this->NodeTable->setItem(rowCount, ctkDICOMServerNodeWidget2::ProxyColumn, newItem); + + this->updateProxyComboBoxes(server->connectionName(), rowCount); + + if (server->proxyServer()) + { + this->addServerNode(server->proxyServer()); + rowCount++; + } + + q->onSettingsModified(); + + return rowCount; +} + +//---------------------------------------------------------------------------- +ctkDICOMServer* ctkDICOMServerNodeWidget2Private::createServerFromServerNode(const QMap &node) +{ + ctkDICOMServer* server = new ctkDICOMServer(); + server->setConnectionName(node["Name"].toString()); + server->setDownloadEnabled(node["DownloadCheckState"].toInt() == 0 ? false : true); + server->setUploadEnabled(node["UploadCheckState"].toInt() == 0 ? false : true); + server->setCallingAETitle(node["CallingAETitle"].toString()); + server->setCalledAETitle(node["CalledAETitle"].toString()); + server->setHost(node["Address"].toString()); + server->setPort(node["Port"].toInt()); + server->setRetrieveProtocolAsString(node["Protocol"].toString()); + server->setConnectionTimeout(node["Timeout"].toInt()); + server->setMoveDestinationAETitle(this->StorageAETitle->text()); + + return server; +} + +//---------------------------------------------------------------------------- +void ctkDICOMServerNodeWidget2Private::updateProxyComboBoxes(const QString &connectionName, int rowCount) const +{ + for (int row = 0; row < rowCount; ++row) + { + QComboBox *proxyComboBox = qobject_cast(this->NodeTable->cellWidget(row, ctkDICOMServerNodeWidget2::ProxyColumn)); + if (proxyComboBox) + { + QStringListModel* cbModel = qobject_cast(proxyComboBox->model()); + if (cbModel) + { + QStringList nodesNames = cbModel->stringList(); + if (nodesNames.contains(connectionName)) + { + continue; + } + } + proxyComboBox->addItem(connectionName); + } + } +} + +//---------------------------------------------------------------------------- +ctkDICOMServerNodeWidget2::ctkDICOMServerNodeWidget2(QWidget* parentWidget) + : Superclass(parentWidget) + , d_ptr(new ctkDICOMServerNodeWidget2Private(*this)) +{ + Q_D(ctkDICOMServerNodeWidget2); + + d->init(); +} + + +//---------------------------------------------------------------------------- +ctkDICOMServerNodeWidget2::~ctkDICOMServerNodeWidget2() +{ +} + +//---------------------------------------------------------------------------- +int ctkDICOMServerNodeWidget2::addServerNode() +{ + Q_D(ctkDICOMServerNodeWidget2); + const int rowCount = d->NodeTable->rowCount(); + d->NodeTable->setRowCount(rowCount + 1); + + QTableWidgetItem *newItem = new QTableWidgetItem(QString::number(rowCount)); + d->NodeTable->setItem(rowCount, NameColumn, newItem); + + newItem = new QTableWidgetItem(QString("")); + newItem->setCheckState(Qt::Unchecked); + d->NodeTable->setItem(rowCount, ctkDICOMServerNodeWidget2::DownloadColumn, newItem); + newItem = new QTableWidgetItem(QString("")); + newItem->setCheckState(Qt::Unchecked); + d->NodeTable->setItem(rowCount, ctkDICOMServerNodeWidget2::UploadColumn, newItem); + + newItem = new QTableWidgetItem; + QComboBox *protocolComboBox = new QComboBox(); + protocolComboBox->addItem("CGET"); + protocolComboBox->addItem("CMOVE"); + // To Do: protocolComboBox->addItem("WADO"); + connect(protocolComboBox, SIGNAL(currentIndexChanged(int)), + this, SLOT(onSettingsModified())); + d->NodeTable->setItem(rowCount, ProtocolColumn, newItem); + d->NodeTable->setCellWidget(rowCount, ProtocolColumn, protocolComboBox); + + d->NodeTable->setCurrentCell(rowCount, NameColumn); + + this->onSettingsModified(); + + return rowCount; +} + +//---------------------------------------------------------------------------- +void ctkDICOMServerNodeWidget2::removeCurrentServerNode() +{ + Q_D(ctkDICOMServerNodeWidget2); + + QModelIndexList selection = d->NodeTable->selectionModel()->selectedRows(); + if (selection.count() == 0) + { + return; + } + + QModelIndex index = selection.at(0); + int row = index.row(); + d->NodeTable->removeRow(row); + this->onSettingsModified(); +} + +//---------------------------------------------------------------------------- +void ctkDICOMServerNodeWidget2::testCurrentServerNode() +{ + Q_D(ctkDICOMServerNodeWidget2); + + QModelIndexList selection = d->NodeTable->selectionModel()->selectedRows(); + if (selection.count() == 0) + { + return; + } + + QModelIndex index = selection.at(0); + QString serverName = d->getServerNodeConnectionNameFromRow(index.row()); + ctkDICOMServer* server = this->getServer(serverName.toStdString().c_str()); + if (!server) + { + return; + } + + ctkDICOMEcho echo; + echo.setConnectionName(server->connectionName()); + echo.setCalledAETitle(server->calledAETitle()); + echo.setCallingAETitle(server->callingAETitle()); + echo.setHost(server->host()); + echo.setPort(server->port()); + echo.setConnectionTimeout(server->connectionTimeout()); + + ctkMessageBox echoMessageBox(this); + QString messageString; + if (echo.echo()) + { + messageString = tr("Node response was positive."); + echoMessageBox.setIcon(QMessageBox::Information); + } + else + { + messageString = tr("Node response was negative."); + echoMessageBox.setIcon(QMessageBox::Warning); + } + + echoMessageBox.setText(messageString); + echoMessageBox.exec(); +} + +//---------------------------------------------------------------------------- +void ctkDICOMServerNodeWidget2::updateGUIState() +{ + Q_D(ctkDICOMServerNodeWidget2); + QList selectedItems = d->NodeTable->selectedItems(); + d->RemoveButton->setEnabled(selectedItems.count() > 0); + d->TestButton->setEnabled(selectedItems.count() > 0); + + d->RestoreButton->setEnabled(d->SettingsModified); + d->SaveButton->setEnabled(d->SettingsModified); +} + +//---------------------------------------------------------------------------- +void ctkDICOMServerNodeWidget2::onSettingsModified() +{ + Q_D(ctkDICOMServerNodeWidget2); + d->SettingsModified = true; + this->updateGUIState(); +} + +//---------------------------------------------------------------------------- +void ctkDICOMServerNodeWidget2::saveSettings() +{ + Q_D(ctkDICOMServerNodeWidget2); + + if (!d->TaskPool) + { + return; + } + + QSettings settings; + const int rowCount = d->NodeTable->rowCount(); + + settings.remove("DICOM/ServerNodes"); + this->removeAllServers(); + + settings.setValue("DICOM/ServerNodeCount", rowCount); + + QStringList proxyServers; + for (int row = 0; row < rowCount; ++row) + { + QMap node = d->serverNodeParameters(row); + QString proxyName = node["Proxy"].toString(); + if (!proxyName.isEmpty() && node["DownloadCheckState"].toInt() > 0) + { + proxyServers.append(proxyName); + } + + settings.setValue(QString("DICOM/ServerNodes/%1").arg(row), QVariant(node)); + } + + for (int row = 0; row < rowCount; ++row) + { + QMap node = d->serverNodeParameters(row); + QString serverName = node["Name"].toString(); + if (proxyServers.contains(serverName)) + { + continue; + } + + ctkDICOMServer* server = d->createServerFromServerNode(node); + d->TaskPool->addServer(server); + } + + for (int ii = 0; ii < rowCount; ++ii) + { + QMap node = d->serverNodeParameters(ii); + QString serverName = node["Name"].toString(); + if (!proxyServers.contains(serverName)) + { + continue; + } + + ctkDICOMServer* proxyServer = d->createServerFromServerNode(node); + for (int jj = 0; jj < rowCount; ++jj) + { + QMap tmpNode = d->serverNodeParameters(jj); + QString tmpServerName = tmpNode["Name"].toString(); + if (serverName == tmpServerName) + { + continue; + } + QString tmpProxyName = tmpNode["Proxy"].toString(); + if (serverName == tmpProxyName) + { + ctkDICOMServer* server = this->getServer(tmpServerName.toStdString().c_str()); + if (server) + { + server->setProxyServer(*proxyServer); + break; + } + } + } + } + + settings.setValue("DICOM/StorageAETitle", this->storageAETitle()); + settings.setValue("DICOM/StoragePort", this->storagePort()); + settings.sync(); + + d->SettingsModified = false; + this->updateGUIState(); +} + +//---------------------------------------------------------------------------- +void ctkDICOMServerNodeWidget2::readSettings() +{ + Q_D(ctkDICOMServerNodeWidget2); + + d->NodeTable->setRowCount(0); + + QSettings settings; + + QMap node; + if (settings.status() == QSettings::AccessError || + settings.value("DICOM/ServerNodeCount").toInt() == 0) + { + d->StorageAETitle->setText("CTKSTORE"); + d->StoragePort->setText("11112"); + + // a dummy example + QMap defaultServerNode; + defaultServerNode["Name"] = QString("ExampleHost"); + defaultServerNode["DownloadCheckState"] = static_cast(Qt::Unchecked); + defaultServerNode["UploadCheckState"] = static_cast(Qt::Unchecked); + defaultServerNode["CallingAETitle"] = QString("CTK"); + defaultServerNode["CalledAETitle"] = QString("AETITLE"); + defaultServerNode["Address"] = QString("dicom.example.com"); + defaultServerNode["Port"] = QString("11112"); + defaultServerNode["Protocol"] = QString("CGET"); + defaultServerNode["Timeout"] = QString("30"); + defaultServerNode["Proxy"] = QString(""); + d->addServerNode(defaultServerNode); + + // the uk example - see http://www.dicomserver.co.uk/ + // and http://www.medicalconnections.co.uk/ + defaultServerNode["Name"] = QString("MedicalConnections"); + defaultServerNode["DownloadCheckState"] = static_cast(Qt::Unchecked); + defaultServerNode["UploadCheckState"] = static_cast(Qt::Unchecked); + defaultServerNode["CallingAETitle"] = QString("CTK"); + defaultServerNode["CalledAETitle"] = QString("ANYAE"); + defaultServerNode["Address"] = QString("dicomserver.co.uk"); + defaultServerNode["Port"] = QString("11112"); + defaultServerNode["Protocol"] = QString("CGET"); + defaultServerNode["Timeout"] = QString("30"); + defaultServerNode["Proxy"] = QString(""); + d->addServerNode(defaultServerNode); + + d->SettingsModified = false; + d->NodeTable->clearSelection(); + this->updateGUIState(); + return; + } + + d->StorageAETitle->setText(settings.value("DICOM/StorageAETitle").toString()); + d->StoragePort->setText(settings.value("DICOM/StoragePort").toString()); + + const int count = settings.value("DICOM/ServerNodeCount").toInt(); + for (int row = 0; row < count; ++row) + { + node = settings.value(QString("DICOM/ServerNodes/%1").arg(row)).toMap(); + d->addServerNode(node); + } + + d->SettingsModified = false; + d->NodeTable->clearSelection(); + this->updateGUIState(); +} + + +//---------------------------------------------------------------------------- +void ctkDICOMServerNodeWidget2::setStorageAETitle(QString storageAETitle) +{ + Q_D(const ctkDICOMServerNodeWidget2); + d->StorageAETitle->setText(storageAETitle); + this->saveSettings(); +} + +//---------------------------------------------------------------------------- +QString ctkDICOMServerNodeWidget2::storageAETitle()const +{ + Q_D(const ctkDICOMServerNodeWidget2); + return d->StorageAETitle->text(); +} + +//---------------------------------------------------------------------------- +void ctkDICOMServerNodeWidget2::setStoragePort(int storagePort) +{ + Q_D(const ctkDICOMServerNodeWidget2); + d->StoragePort->setText(QString::number(storagePort)); + this->saveSettings(); +} + +//---------------------------------------------------------------------------- +int ctkDICOMServerNodeWidget2::storagePort()const +{ + Q_D(const ctkDICOMServerNodeWidget2); + bool ok = false; + int port = d->StoragePort->text().toInt(&ok); + Q_ASSERT(ok); + return port; +} + +//---------------------------------------------------------------------------- +static void skipDelete(QObject* obj) +{ + Q_UNUSED(obj); + // this deleter does not delete the object from memory + // useful if the pointer is not owned by the smart pointer +} + +//---------------------------------------------------------------------------- +ctkDICOMTaskPool* ctkDICOMServerNodeWidget2::taskPool()const +{ + Q_D(const ctkDICOMServerNodeWidget2); + return d->TaskPool.data(); +} + +//---------------------------------------------------------------------------- +QSharedPointer ctkDICOMServerNodeWidget2::taskPoolShared()const +{ + Q_D(const ctkDICOMServerNodeWidget2); + return d->TaskPool; +} + +//---------------------------------------------------------------------------- +void ctkDICOMServerNodeWidget2::setTaskPool(ctkDICOMTaskPool& taskPool) +{ + Q_D(ctkDICOMServerNodeWidget2); + d->TaskPool = QSharedPointer(&taskPool, skipDelete); +} + +//---------------------------------------------------------------------------- +void ctkDICOMServerNodeWidget2::setTaskPool(QSharedPointer taskPool) +{ + Q_D(ctkDICOMServerNodeWidget2); + d->TaskPool = taskPool; +} + +//---------------------------------------------------------------------------- +int ctkDICOMServerNodeWidget2::getNumberOfServers() +{ + Q_D(ctkDICOMServerNodeWidget2); + if (!d->TaskPool) + { + logger.error("getNumberOfServers failed, no task pool has been set. \n"); + return -1; + } + + return d->TaskPool->getNumberOfServers(); +} + +//---------------------------------------------------------------------------- +ctkDICOMServer* ctkDICOMServerNodeWidget2::getNthServer(int id) +{ + Q_D(ctkDICOMServerNodeWidget2); + if (!d->TaskPool) + { + logger.error("getNthServer failed, no task pool has been set. \n"); + return nullptr; + } + + return d->TaskPool->getNthServer(id); +} + +//---------------------------------------------------------------------------- +ctkDICOMServer* ctkDICOMServerNodeWidget2::getServer(const char *connectionName) +{ + Q_D(ctkDICOMServerNodeWidget2); + if (!d->TaskPool) + { + logger.error("getServer failed, no task pool has been set. \n"); + return nullptr; + } + + return d->TaskPool->getServer(connectionName); +} + +//---------------------------------------------------------------------------- +void ctkDICOMServerNodeWidget2::addServer(ctkDICOMServer* server) +{ + Q_D(ctkDICOMServerNodeWidget2); + if (!d->TaskPool) + { + logger.error("addServer failed, no task pool has been set. \n"); + return; + } + + d->addServerNode(server); + this->saveSettings(); +} + +//---------------------------------------------------------------------------- +void ctkDICOMServerNodeWidget2::removeServer(const char *connectionName) +{ + Q_D(ctkDICOMServerNodeWidget2); + if (!d->TaskPool) + { + logger.error("removeServer failed, no task pool has been set. \n"); + return; + } + + this->removeNthServer(this->getServerIndexFromName(connectionName)); +} + +//---------------------------------------------------------------------------- +void ctkDICOMServerNodeWidget2::removeNthServer(int id) +{ + Q_D(ctkDICOMServerNodeWidget2); + if (!d->TaskPool) + { + logger.error("removeNthServer failed, no task pool has been set. \n"); + return; + } + + QString connectionName = this->getServerNameFromIndex(id); + int row = d->getServerNodeRowFromConnectionName(connectionName); + d->NodeTable->removeRow(row); + this->saveSettings(); +} + +//---------------------------------------------------------------------------- +void ctkDICOMServerNodeWidget2::removeAllServers() +{ + Q_D(ctkDICOMServerNodeWidget2); + if (!d->TaskPool) + { + logger.error("removeAllServers failed, no task pool has been set. \n"); + return; + } + + d->TaskPool->removeAllServers(); +} + +//---------------------------------------------------------------------------- +QString ctkDICOMServerNodeWidget2::getServerNameFromIndex(int id) +{ + Q_D(ctkDICOMServerNodeWidget2); + if (!d->TaskPool) + { + logger.error("getServerNameFromIndex failed, no task pool has been set. \n"); + return ""; + } + + return d->TaskPool->getServerNameFromIndex(id); +} + +//---------------------------------------------------------------------------- +int ctkDICOMServerNodeWidget2::getServerIndexFromName(const char *connectionName) +{ + Q_D(ctkDICOMServerNodeWidget2); + if (!d->TaskPool) + { + logger.error("getServerIndexFromName failed, no task pool has been set. \n"); + return -1; + } + + return d->TaskPool->getServerIndexFromName(connectionName); +} diff --git a/Libs/DICOM/Widgets/ctkDICOMServerNodeWidget2.h b/Libs/DICOM/Widgets/ctkDICOMServerNodeWidget2.h new file mode 100644 index 0000000000..9c7ba72aa8 --- /dev/null +++ b/Libs/DICOM/Widgets/ctkDICOMServerNodeWidget2.h @@ -0,0 +1,117 @@ +/*========================================================================= + + Library: CTK + + Copyright (c) Kitware Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + This file was originally developed by Davide Punzo, punzodavide@hotmail.it, + and development was supported by the Center for Intelligent Image-guided Interventions (CI3). + +=========================================================================*/ + +#ifndef __ctkDICOMServerNodeWidget2_h +#define __ctkDICOMServerNodeWidget2_h + +// Qt includes +#include +#include +#include +#include + +#include "ctkDICOMWidgetsExport.h" + +class QTableWidgetItem; +class ctkDICOMServer; +class ctkDICOMServerNodeWidget2Private; +class ctkDICOMTaskPool; + +/// \ingroup DICOM_Widgets +class CTK_DICOM_WIDGETS_EXPORT ctkDICOMServerNodeWidget2 : public QWidget +{ + Q_OBJECT; + Q_PROPERTY(QString storageAETitle READ storageAETitle WRITE setStorageAETitle); + Q_PROPERTY(int storagePort READ storagePort WRITE setStoragePort); + +public: + typedef QWidget Superclass; + explicit ctkDICOMServerNodeWidget2(QWidget* parent=0); + virtual ~ctkDICOMServerNodeWidget2(); + + /// Storage AE title + /// "CTKSTORE" by default + void setStorageAETitle(QString storageAETitle); + QString storageAETitle() const; + + /// Storage port + /// 11112 by default + void setStoragePort(int storagePort); + int storagePort() const; + + /// Return the task pool. + Q_INVOKABLE ctkDICOMTaskPool* taskPool() const; + /// Return the task pool as a shared pointer + /// (not Python-wrappable). + QSharedPointer taskPoolShared() const; + /// Set the task pool. + Q_INVOKABLE void setTaskPool(ctkDICOMTaskPool& taskPool); + /// Set the task pool as a shared pointer + /// (not Python-wrappable). + void setTaskPool(QSharedPointer taskPool); + + /// Servers + Q_INVOKABLE int getNumberOfServers(); + Q_INVOKABLE ctkDICOMServer* getNthServer(int id); + Q_INVOKABLE ctkDICOMServer* getServer(const char* connectionName); + Q_INVOKABLE void addServer(ctkDICOMServer* server); + Q_INVOKABLE void removeServer(const char* connectionName); + Q_INVOKABLE void removeNthServer(int id); + Q_INVOKABLE void removeAllServers(); + Q_INVOKABLE QString getServerNameFromIndex(int id); + Q_INVOKABLE int getServerIndexFromName(const char* connectionName); + +public Q_SLOTS: + /// Add an empty server node and make it current + /// Return the row index added into the table + int addServerNode(); + /// Remove the current row (different from the checked rows) + void removeCurrentServerNode(); + /// Test the current row (different from the checked rows) + void testCurrentServerNode(); + + void readSettings(); + void saveSettings(); + void updateGUIState(); + void onSettingsModified(); + +protected: + QScopedPointer d_ptr; + enum ServerColumns{ + NameColumn = 0, + DownloadColumn, + UploadColumn, + CallingAETitleColumn, + CalledAETitleColumn, + AddressColumn, + PortColumn, + TimeoutColumn, + ProtocolColumn, + ProxyColumn + }; +private: + Q_DECLARE_PRIVATE(ctkDICOMServerNodeWidget2); + Q_DISABLE_COPY(ctkDICOMServerNodeWidget2); +}; + +#endif diff --git a/Libs/DICOM/Widgets/ctkDICOMVisualBrowserWidget.cpp b/Libs/DICOM/Widgets/ctkDICOMVisualBrowserWidget.cpp index eda5fa52e8..e2104cc04d 100644 --- a/Libs/DICOM/Widgets/ctkDICOMVisualBrowserWidget.cpp +++ b/Libs/DICOM/Widgets/ctkDICOMVisualBrowserWidget.cpp @@ -53,6 +53,8 @@ #include "ctkDICOMVisualBrowserWidget.h" #include "ctkDICOMStudyItemWidget.h" #include "ctkDICOMSeriesItemWidget.h" +#include "ctkDICOMServerNodeWidget2.h" +#include "ctkDICOMVisualBrowserWidget.h" #include "ui_ctkDICOMVisualBrowserWidget.h" static ctkLogger logger("org.commontk.DICOM.Widgets.ctkDICOMVisualBrowserWidget"); @@ -224,6 +226,8 @@ class ctkDICOMVisualBrowserWidgetPrivate: public Ui_ctkDICOMVisualBrowserWidget int MinimumThumbnailSize; bool SendActionVisible; bool IsGUIUpdating; + + ctkDICOMServerNodeWidget2* ServerNodeWidget; }; CTK_GET_CPP(ctkDICOMVisualBrowserWidget, QString, databaseDirectoryBase, DatabaseDirectoryBase); @@ -264,6 +268,8 @@ ctkDICOMVisualBrowserWidgetPrivate::ctkDICOMVisualBrowserWidgetPrivate(ctkDICOMV this->FilteringDate = ctkDICOMPatientItemWidget::DateType::Any; this->IsGUIUpdating = false; + + this->ServerNodeWidget = nullptr; } //---------------------------------------------------------------------------- @@ -301,6 +307,9 @@ void ctkDICOMVisualBrowserWidgetPrivate::init() QObject::connect(this->QueryPatientPushButton, SIGNAL(clicked()), q, SLOT(onQueryPatient())); + this->ServerNodeWidget = new ctkDICOMServerNodeWidget2(); + this->ServersSettingsCollapsibleGroupBox->layout()->addWidget(this->ServerNodeWidget); + QSize iconSize(28, 28); this->PatientsTabWidget->setIconSize(iconSize); this->PatientsTabWidget->clear(); @@ -1205,6 +1214,7 @@ void ctkDICOMVisualBrowserWidget::setTaskPool(ctkDICOMTaskPool& taskPool) Q_D(ctkDICOMVisualBrowserWidget); d->disconnectTaskPool(); d->TaskPool = QSharedPointer(&taskPool, skipDelete); + d->ServerNodeWidget->setTaskPool(d->TaskPool); d->connectTaskPool(); } @@ -1214,6 +1224,7 @@ void ctkDICOMVisualBrowserWidget::setTaskPool(QSharedPointer t Q_D(ctkDICOMVisualBrowserWidget); d->disconnectTaskPool(); d->TaskPool = taskPool; + d->ServerNodeWidget->setTaskPool(d->TaskPool); d->connectTaskPool(); } @@ -1279,108 +1290,95 @@ const QStringList ctkDICOMVisualBrowserWidget::tagsToPrecache() return d->DicomDatabase->tagsToPrecache(); } +//---------------------------------------------------------------------------- +void ctkDICOMVisualBrowserWidget::setStorageAETitle(QString storageAETitle) +{ + Q_D(const ctkDICOMVisualBrowserWidget); + d->ServerNodeWidget->setStorageAETitle(storageAETitle); +} + +//---------------------------------------------------------------------------- +QString ctkDICOMVisualBrowserWidget::storageAETitle()const +{ + Q_D(const ctkDICOMVisualBrowserWidget); + d->ServerNodeWidget->storageAETitle(); +} + +//---------------------------------------------------------------------------- +void ctkDICOMVisualBrowserWidget::setStoragePort(int storagePort) +{ + Q_D(const ctkDICOMVisualBrowserWidget); + d->ServerNodeWidget->setStoragePort(storagePort); +} + +//---------------------------------------------------------------------------- +int ctkDICOMVisualBrowserWidget::storagePort()const +{ + Q_D(const ctkDICOMVisualBrowserWidget); + d->ServerNodeWidget->storagePort(); +} + //---------------------------------------------------------------------------- int ctkDICOMVisualBrowserWidget::getNumberOfServers() { Q_D(ctkDICOMVisualBrowserWidget); - if (!d->TaskPool) - { - logger.error("getNumberOfServers failed, no task pool has been set. \n"); - return -1; - } - - return d->TaskPool->getNumberOfServers(); + return d->ServerNodeWidget->getNumberOfServers(); } //---------------------------------------------------------------------------- ctkDICOMServer* ctkDICOMVisualBrowserWidget::getNthServer(int id) { Q_D(ctkDICOMVisualBrowserWidget); - if (!d->TaskPool) - { - logger.error("getNthServer failed, no task pool has been set. \n"); - return nullptr; - } - - return d->TaskPool->getNthServer(id); + return d->ServerNodeWidget->getNthServer(id); } //---------------------------------------------------------------------------- ctkDICOMServer* ctkDICOMVisualBrowserWidget::getServer(const char *connectionName) { Q_D(ctkDICOMVisualBrowserWidget); - if (!d->TaskPool) - { - logger.error("getServer failed, no task pool has been set. \n"); - return nullptr; - } - - return d->TaskPool->getServer(connectionName); + return d->ServerNodeWidget->getServer(connectionName); } //---------------------------------------------------------------------------- void ctkDICOMVisualBrowserWidget::addServer(ctkDICOMServer* server) { Q_D(ctkDICOMVisualBrowserWidget); - if (!d->TaskPool) - { - logger.error("addServer failed, no task pool has been set. \n"); - return; - } - - return d->TaskPool->addServer(server); + return d->ServerNodeWidget->addServer(server); } //---------------------------------------------------------------------------- void ctkDICOMVisualBrowserWidget::removeServer(const char *connectionName) { Q_D(ctkDICOMVisualBrowserWidget); - if (!d->TaskPool) - { - logger.error("removeServer failed, no task pool has been set. \n"); - return; - } - - return d->TaskPool->removeServer(connectionName); + return d->ServerNodeWidget->removeServer(connectionName); } //---------------------------------------------------------------------------- void ctkDICOMVisualBrowserWidget::removeNthServer(int id) { Q_D(ctkDICOMVisualBrowserWidget); - if (!d->TaskPool) - { - logger.error("removeNthServer failed, no task pool has been set. \n"); - return; - } + return d->ServerNodeWidget->removeNthServer(id); +} - return d->TaskPool->removeNthServer(id); +//---------------------------------------------------------------------------- +void ctkDICOMVisualBrowserWidget::removeAllServers() +{ + Q_D(ctkDICOMVisualBrowserWidget); + return d->ServerNodeWidget->removeAllServers(); } //---------------------------------------------------------------------------- QString ctkDICOMVisualBrowserWidget::getServerNameFromIndex(int id) { Q_D(ctkDICOMVisualBrowserWidget); - if (!d->TaskPool) - { - logger.error("getServerNameFromIndex failed, no task pool has been set. \n"); - return ""; - } - - return d->TaskPool->getServerNameFromIndex(id); + return d->ServerNodeWidget->getServerNameFromIndex(id); } //---------------------------------------------------------------------------- int ctkDICOMVisualBrowserWidget::getServerIndexFromName(const char *connectionName) { Q_D(ctkDICOMVisualBrowserWidget); - if (!d->TaskPool) - { - logger.error("getServerIndexFromName failed, no task pool has been set. \n"); - return -1; - } - - return d->TaskPool->getServerIndexFromName(connectionName); + return d->ServerNodeWidget->getServerIndexFromName(connectionName); } //------------------------------------------------------------------------------ diff --git a/Libs/DICOM/Widgets/ctkDICOMVisualBrowserWidget.h b/Libs/DICOM/Widgets/ctkDICOMVisualBrowserWidget.h index 6ee8dec0b7..ea90d457a1 100644 --- a/Libs/DICOM/Widgets/ctkDICOMVisualBrowserWidget.h +++ b/Libs/DICOM/Widgets/ctkDICOMVisualBrowserWidget.h @@ -53,6 +53,8 @@ class CTK_DICOM_WIDGETS_EXPORT ctkDICOMVisualBrowserWidget : public QWidget Q_PROPERTY(int numberOfSeriesPerRow READ numberOfSeriesPerRow WRITE setNumberOfSeriesPerRow); Q_PROPERTY(int minimumThumbnailSize READ minimumThumbnailSize WRITE setMinimumThumbnailSize); Q_PROPERTY(bool sendActionVisible READ isSendActionVisible WRITE setSendActionVisible) + Q_PROPERTY(QString storageAETitle READ storageAETitle WRITE setStorageAETitle); + Q_PROPERTY(int storagePort READ storagePort WRITE setStoragePort); public: typedef QWidget Superclass; @@ -108,6 +110,16 @@ class CTK_DICOM_WIDGETS_EXPORT ctkDICOMVisualBrowserWidget : public QWidget Q_INVOKABLE void setTagsToPrecache(const QStringList tags); Q_INVOKABLE const QStringList tagsToPrecache(); + /// Storage AE title + /// "CTKSTORE" by default + void setStorageAETitle(QString storageAETitle); + QString storageAETitle() const; + + /// Storage port + /// 11112 by default + void setStoragePort(int storagePort); + int storagePort() const; + /// Servers Q_INVOKABLE int getNumberOfServers(); Q_INVOKABLE ctkDICOMServer* getNthServer(int id); @@ -115,6 +127,7 @@ class CTK_DICOM_WIDGETS_EXPORT ctkDICOMVisualBrowserWidget : public QWidget Q_INVOKABLE void addServer(ctkDICOMServer* server); Q_INVOKABLE void removeServer(const char* connectionName); Q_INVOKABLE void removeNthServer(int id); + Q_INVOKABLE void removeAllServers(); Q_INVOKABLE QString getServerNameFromIndex(int id); Q_INVOKABLE int getServerIndexFromName(const char* connectionName);