Skip to content

Commit

Permalink
ENH: Improve DICOM query/retrieve widget
Browse files Browse the repository at this point in the history
* Retrieve only selected series (previously, all series of the selected studies were retrieved)
* Add collapsible button to hide query or retrieve section, to give more space for browsing query results
  • Loading branch information
Pierre Bour authored and lassoan committed Sep 11, 2021
1 parent 70ec660 commit 9492f0f
Show file tree
Hide file tree
Showing 8 changed files with 160 additions and 99 deletions.
6 changes: 3 additions & 3 deletions Libs/DICOM/Core/Testing/Cpp/ctkDICOMQueryTest1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ int ctkDICOMQueryTest1( int argc, char * argv [] )
!query.host().isEmpty() ||
query.port() != 0 ||
!query.filters().isEmpty() ||
!query.studyInstanceUIDQueried().isEmpty())
!query.studyAndSeriesInstanceUIDQueried().isEmpty())
{
std::cerr << "ctkDICOMQuery::ctkDICOMQuery() failed: "
<< qPrintable(query.callingAETitle()) << " "
Expand Down Expand Up @@ -102,10 +102,10 @@ int ctkDICOMQueryTest1( int argc, char * argv [] )
query.query(database);

// Queried studies should be empty because we use an empty database.
if (!query.studyInstanceUIDQueried().isEmpty())
if (!query.studyAndSeriesInstanceUIDQueried().isEmpty())
{
std::cerr << "ctkDICOMDatabase::query() failed: "
<< query.studyInstanceUIDQueried().count() << std::endl;
<< query.studyAndSeriesInstanceUIDQueried().count() << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
Expand Down
2 changes: 1 addition & 1 deletion Libs/DICOM/Core/Testing/Cpp/ctkDICOMQueryTest2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ int ctkDICOMQueryTest2( int argc, char * argv [] )
std::cout << "ctkDICOMQuery::query() failed" << std::endl;
return EXIT_FAILURE;
}
if (query.studyInstanceUIDQueried().count() == 0)
if (query.studyAndSeriesInstanceUIDQueried().count() == 0)
{
std::cout << "ctkDICOMQuery::query() failed."
<< "No study instance retrieved" << std::endl;
Expand Down
12 changes: 7 additions & 5 deletions Libs/DICOM/Core/Testing/Cpp/ctkDICOMRetrieveTest2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
// Qt includes
#include <QCoreApplication>
#include <QDebug>
#include <QPair>
#include <QString>
#include <QStringList>
#include <QVariant>

Expand Down Expand Up @@ -74,7 +76,7 @@ int ctkDICOMRetrieveTest2( int argc, char * argv [] )
std::cout << "ctkDICOMQuery::query() failed" << std::endl;
return EXIT_FAILURE;
}
if (query.studyInstanceUIDQueried().count() == 0)
if (query.studyAndSeriesInstanceUIDQueried().count() == 0)
{
std::cout << "ctkDICOMQuery::query() failed."
<< "No study instance retrieved" << std::endl;
Expand All @@ -95,14 +97,14 @@ int ctkDICOMRetrieveTest2( int argc, char * argv [] )
retrieve.setDatabase(retrieveDatabase);

std::cerr << "ctkDICOMRetrieveTest2: Retrieving\n";
foreach(const QString& study, query.studyInstanceUIDQueried())
foreach(auto studyAndSeriesInstanceUID, query.studyAndSeriesInstanceUIDQueried())
{
std::cerr << "ctkDICOMRetrieveTest2: Retrieving " << study.toStdString() << "\n";
bool res = retrieve.moveStudy(study);
std::cerr << "ctkDICOMRetrieveTest2: Retrieving " << studyAndSeriesInstanceUID.first.toStdString() << "\n";
bool res = retrieve.moveStudy(studyAndSeriesInstanceUID.first);
if (!res)
{
std::cout << "ctkDICOMRetrieve::retrieveStudy() failed. "
<< "Study " << qPrintable(study) << " can't be retrieved"
<< "Study " << qPrintable(studyAndSeriesInstanceUID.first) << " can't be retrieved"
<< std::endl;
return EXIT_FAILURE;
}
Expand Down
38 changes: 26 additions & 12 deletions Libs/DICOM/Core/ctkDICOMQuery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,17 @@
=========================================================================*/

// Qt includes
#include <QSqlQuery>
#include <QSqlRecord>
#include <QVariant>
#include <QDebug>
#include <QDate>
#include <QStringList>
#include <QSet>
#include <QFile>
#include <QDirIterator>
#include <QFile>
#include <QFileInfo>
#include <QDebug>
#include <QPair>
#include <QSet>
#include <QSqlQuery>
#include <QSqlRecord>
#include <QStringList>
#include <QVariant>

// ctkDICOMCore includes
#include "ctkDICOMQuery.h"
Expand Down Expand Up @@ -88,6 +89,8 @@ class ctkDICOMQueryPrivate

/// Add a StudyInstanceUID to be queried
void addStudyInstanceUIDAndDataset(const QString& StudyInstanceUID, DcmDataset* dataset );
/// Add StudyInstanceUID and SeriesInstanceUID that may be further retrieved
void addStudyAndSeriesInstanceUID( const QString& StudyInstanceUID, const QString& SeriesInstanceUID );

QString CallingAETitle;
QString CalledAETitle;
Expand All @@ -97,6 +100,7 @@ class ctkDICOMQueryPrivate
QMap<QString,QVariant> Filters;
ctkDICOMQuerySCUPrivate SCU;
DcmDataset* Query;
QList<QPair<QString,QString>> StudyAndSeriesInstanceUIDPairList;
QStringList StudyInstanceUIDList;
QList<DcmDataset*> StudyDatasetList;
bool Canceled;
Expand All @@ -121,9 +125,15 @@ ctkDICOMQueryPrivate::~ctkDICOMQueryPrivate()
}

//------------------------------------------------------------------------------
void ctkDICOMQueryPrivate::addStudyInstanceUIDAndDataset( const QString& s, DcmDataset* dataset )
void ctkDICOMQueryPrivate::addStudyAndSeriesInstanceUID( const QString& study, const QString& series )
{
this->StudyAndSeriesInstanceUIDPairList.push_back (qMakePair( study, series ) );
}

//------------------------------------------------------------------------------
void ctkDICOMQueryPrivate::addStudyInstanceUIDAndDataset( const QString& study, DcmDataset* dataset )
{
this->StudyInstanceUIDList.append ( s );
this->StudyInstanceUIDList.append ( study );
this->StudyDatasetList.append ( dataset );
}

Expand Down Expand Up @@ -230,10 +240,10 @@ QMap<QString,QVariant> ctkDICOMQuery::filters()const
}

//------------------------------------------------------------------------------
QStringList ctkDICOMQuery::studyInstanceUIDQueried()const
QList<QPair<QString,QString>> ctkDICOMQuery::studyAndSeriesInstanceUIDQueried()const
{
Q_D(const ctkDICOMQuery);
return d->StudyInstanceUIDList;
return d->StudyAndSeriesInstanceUIDPairList;
}

//------------------------------------------------------------------------------
Expand All @@ -260,6 +270,7 @@ bool ctkDICOMQuery::query(ctkDICOMDatabase& database )
emit progress(0);
if (d->Canceled) {return false;}

d->StudyAndSeriesInstanceUIDPairList.clear();
d->StudyInstanceUIDList.clear();
d->SCU.setAETitle ( OFString(this->callingAETitle().toStdString().c_str()) );
d->SCU.setPeerAETitle ( OFString(this->calledAETitle().toStdString().c_str()) );
Expand Down Expand Up @@ -453,7 +464,7 @@ bool ctkDICOMQuery::query(ctkDICOMDatabase& database )
int i = 0;

QListIterator<DcmDataset*> datasetIterator(d->StudyDatasetList);
foreach ( QString StudyInstanceUID, d->StudyInstanceUIDList )
for (const auto & StudyInstanceUID : d->StudyInstanceUIDList )
{
DcmDataset *studyDataset = datasetIterator.next();
DcmElement *patientName, *patientID;
Expand All @@ -475,6 +486,9 @@ bool ctkDICOMQuery::query(ctkDICOMDatabase& database )
DcmDataset *dataset = (*it)->m_dataset;
if ( dataset != NULL )
{
OFString SeriesInstanceUID;
dataset->findAndGetOFString ( DCM_SeriesInstanceUID, SeriesInstanceUID );
d->addStudyAndSeriesInstanceUID ( StudyInstanceUID.toStdString().c_str(), SeriesInstanceUID.c_str() );
// add the patient elements not provided for the series level query
dataset->insert( patientName, true );
dataset->insert( patientID, true );
Expand Down
6 changes: 3 additions & 3 deletions Libs/DICOM/Core/ctkDICOMQuery.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class CTK_DICOM_CORE_EXPORT ctkDICOMQuery : public QObject
Q_PROPERTY(QString host READ host WRITE setHost);
Q_PROPERTY(int port READ port WRITE setPort);
Q_PROPERTY(bool preferCGET READ preferCGET WRITE setPreferCGET);
Q_PROPERTY(QStringList studyInstanceUIDQueried READ studyInstanceUIDQueried);
Q_PROPERTY(QList<QPair<QString,QString>> studyAndSeriesInstanceUIDQueried READ studyAndSeriesInstanceUIDQueried);
Q_PROPERTY(QMap<QString, QVariant> filters READ filters WRITE setFilters);

public:
Expand Down Expand Up @@ -75,8 +75,8 @@ class CTK_DICOM_CORE_EXPORT ctkDICOMQuery : public QObject
/// You must at least set the host and port before calling query()
Q_INVOKABLE bool query(ctkDICOMDatabase& database);

/// Access the list of study instance UIDs from the last query
QStringList studyInstanceUIDQueried()const;
/// Access the list of study and series instance UIDs from the last query
QList<QPair<QString,QString>> studyAndSeriesInstanceUIDQueried()const;

///
/// Filters are keyword/value pairs as generated by
Expand Down
139 changes: 76 additions & 63 deletions Libs/DICOM/Widgets/Resources/UI/ctkDICOMQueryRetrieveWidget.ui
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,38 @@
<rect>
<x>0</x>
<y>0</y>
<width>843</width>
<height>815</height>
<width>840</width>
<height>501</height>
</rect>
</property>
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="windowTitle">
<string>DICOM Query/Retrieve</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QFrame" name="frame">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
<widget class="ctkCollapsibleButton" name="QueryCollapsibleButton">
<property name="text">
<string>Query</string>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
<property name="collapsed">
<bool>false</bool>
</property>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,0">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Data Sources</string>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QFrame" name="frame_2">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="ctkDICOMServerNodeWidget" name="ServerNodeWidget" native="true">
<property name="minimumSize">
Expand All @@ -39,82 +48,80 @@
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Search Options</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="ctkDICOMQueryWidget" name="QueryWidget" native="true"/>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Search Options</string>
<item row="1" column="0">
<widget class="QPushButton" name="QueryButton">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Query</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="ctkDICOMQueryWidget" name="QueryWidget" native="true"/>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="commandFrame" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<widget class="ctkCollapsibleButton" name="RetrieveCollapsibleButton">
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>Retrieve</string>
</property>
<property name="collapsed">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>90</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="QueryButton">
<property name="text">
<string>Query</string>
</property>
</widget>
<widget class="ctkDICOMTableManager" name="dicomTableManager"/>
</item>
<item>
<widget class="QPushButton" name="RetrieveButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Retrieve</string>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="CancelButton">
<property name="text">
<string>Close</string>
<string>Retrieve</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>90</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<widget class="ctkDICOMTableManager" name="dicomTableManager"/>
<widget class="QPushButton" name="CancelButton">
<property name="text">
<string>Close</string>
</property>
</widget>
</item>
</layout>
</widget>
Expand All @@ -125,6 +132,12 @@
<header>ctkDICOMTableManager.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>ctkCollapsibleButton</class>
<extends>QWidget</extends>
<header>ctkCollapsibleButton.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>ctkDICOMQueryWidget</class>
<extends>QWidget</extends>
Expand Down
Loading

0 comments on commit 9492f0f

Please sign in to comment.