7 #include "ioDicomWeb/SQueryEditor.hpp" 9 #include <fwGui/dialog/MessageDialog.hpp> 11 #include <fwGuiQt/container/QtContainer.hpp> 13 #include <fwMedData/DicomSeries.hpp> 15 #include <fwMedDataTools/helper/SeriesDB.hpp> 17 #include <fwNetworkIO/helper/Series.hpp> 19 #include <fwPreferences/helper.hpp> 21 #include <fwServices/macros.hpp> 23 #include <boost/filesystem/operations.hpp> 24 #include <boost/foreach.hpp> 26 #include <dcmtk/dcmnet/scu.h> 28 #include <QGridLayout> 29 #include <QHBoxLayout> 50 ::fwServices::IService::ConfigType configuration = this->
getConfigTree();
52 if(configuration.count(
"server"))
54 const std::string serverInfo = configuration.get(
"server",
"");
55 const std::string::size_type splitPosition = serverInfo.find(
':');
56 SLM_ASSERT(
"Server info not formatted correctly", splitPosition != std::string::npos);
58 const std::string hostnameStr = serverInfo.substr(0, splitPosition);
59 const std::string portStr = serverInfo.substr(splitPosition + 1, serverInfo.size());
61 m_serverHostnameKey = this->getPreferenceKey(hostnameStr);
62 m_serverPortKey = this->getPreferenceKey(portStr);
63 if(m_serverHostnameKey.empty())
65 m_serverHostname = hostnameStr;
67 if(m_serverPortKey.empty())
69 m_serverPort = std::stoi(portStr);
74 throw ::fwTools::Failed(
"'server' element not found");
82 std::string SQueryEditor::getPreferenceKey(
const std::string& key)
const 84 std::string keyResult;
85 const size_t first = key.find(
'%');
86 const size_t last = key.rfind(
'%');
87 if (first == 0 && last == key.size() - 1)
89 keyResult = key.substr(1, key.size() - 2);
100 ::fwGuiQt::container::QtContainer::sptr qtContainer = fwGuiQt::container::QtContainer::dynamicCast(getContainer());
103 QGridLayout* layout =
new QGridLayout();
105 m_patientNameLineEdit =
new QLineEdit();
106 m_patientNameQueryButton =
new QPushButton(
"Send");
107 layout->addWidget(
new QLabel(
"Patient name:"), 0, 0);
108 layout->addWidget(m_patientNameLineEdit, 0, 1);
109 layout->addWidget(m_patientNameQueryButton, 0, 2);
111 m_beginStudyDateEdit =
new QDateEdit();
112 m_beginStudyDateEdit->setDate(QDate::currentDate());
113 m_beginStudyDateEdit->setDisplayFormat(
"dd.MM.yyyy");
114 m_endStudyDateEdit =
new QDateEdit();
115 m_endStudyDateEdit->setDate(QDate::currentDate());
116 m_endStudyDateEdit->setDisplayFormat(
"dd.MM.yyyy");
117 m_studyDateQueryButton =
new QPushButton(
"Send");
118 QHBoxLayout* dateLayout =
new QHBoxLayout();
119 layout->addWidget(
new QLabel(
"Study date:"), 1, 0);
120 layout->addLayout(dateLayout, 1, 1);
121 layout->addWidget(m_studyDateQueryButton, 1, 2);
122 dateLayout->addWidget(m_beginStudyDateEdit);
123 dateLayout->addWidget(m_endStudyDateEdit);
126 qtContainer->setLayout(layout);
129 QObject::connect(m_patientNameLineEdit, SIGNAL(returnPressed()),
this, SLOT(queryPatientName()));
130 QObject::connect(m_patientNameQueryButton, SIGNAL(clicked()),
this, SLOT(queryPatientName()));
131 QObject::connect(m_studyDateQueryButton, SIGNAL(clicked()),
this, SLOT(queryStudyDate()));
132 QObject::connect(m_beginStudyDateEdit, SIGNAL(dateChanged(QDate)),
this, SLOT(queryStudyDate()));
133 QObject::connect(m_endStudyDateEdit, SIGNAL(dateChanged(QDate)),
this, SLOT(queryStudyDate()));
143 QObject::disconnect(m_patientNameLineEdit, SIGNAL(returnPressed()),
this, SLOT(queryPatientName()));
144 QObject::disconnect(m_patientNameQueryButton, SIGNAL(clicked()),
this, SLOT(queryPatientName()));
145 QObject::disconnect(m_studyDateQueryButton, SIGNAL(clicked()),
this, SLOT(queryStudyDate()));
146 QObject::disconnect(m_beginStudyDateEdit, SIGNAL(dateChanged(QDate)),
this, SLOT(queryStudyDate()));
147 QObject::disconnect(m_endStudyDateEdit, SIGNAL(dateChanged(QDate)),
this, SLOT(queryStudyDate()));
161 void SQueryEditor::queryPatientName()
163 if(!m_serverHostnameKey.empty())
165 const std::string hostname = ::fwPreferences::getPreference(m_serverHostnameKey);
166 if(!hostname.empty())
168 m_serverHostname = hostname;
171 if(!m_serverPortKey.empty())
173 const std::string port = ::fwPreferences::getPreference(m_serverPortKey);
176 m_serverPort = std::stoi(port);
183 ::fwMedData::SeriesDB::ContainerType allSeries;
187 query.insert(
"PatientName", m_patientNameLineEdit->text().toStdString().c_str());
190 body.insert(
"Level",
"Series");
191 body.insert(
"Query", query);
192 body.insert(
"Limit", 0);
195 const std::string pacsServer(
"http://" + m_serverHostname +
":" + std::to_string(m_serverPort));
199 const QByteArray& seriesAnswer = m_clientQt.
post(request, QJsonDocument(body).toJson());
200 QJsonDocument jsonResponse = QJsonDocument::fromJson(seriesAnswer);
201 QJsonArray seriesArray = jsonResponse.array();
202 const int seriesArraySize = seriesArray.count();
204 for(
int i = 0; i < seriesArraySize; ++i)
207 const std::string& seriesUID = seriesArray.at(i).toString().toStdString();
208 const std::string instancesListUrl(pacsServer +
"/series/" + seriesUID);
210 jsonResponse = QJsonDocument::fromJson(instancesAnswer);
211 const QJsonObject& jsonObj = jsonResponse.object();
212 const QJsonArray& instanceArray = jsonObj[
"Instances"].toArray();
215 const std::string& instanceUID = instanceArray.at(0).toString().toStdString();
216 const std::string instanceUrl(pacsServer +
"/instances/" + instanceUID +
"/simplified-tags");
219 QJsonObject seriesJson = QJsonDocument::fromJson(instance).object();
220 seriesJson.insert(
"NumberOfSeriesRelatedInstances", instanceArray.count() );
225 allSeries.insert(std::end(allSeries), std::begin(series), std::end(series));
226 this->updateSeriesDB(allSeries);
231 this->displayErrorMessage(exception.what());
238 void SQueryEditor::queryStudyDate()
240 if(!m_serverHostnameKey.empty())
242 const std::string hostname = ::fwPreferences::getPreference(m_serverHostnameKey);
243 if(!hostname.empty())
245 m_serverHostname = hostname;
248 if(!m_serverPortKey.empty())
250 const std::string port = ::fwPreferences::getPreference(m_serverPortKey);
253 m_serverPort = std::stoi(port);
260 ::fwMedData::SeriesDB::ContainerType allSeries;
264 const std::string& beginDate = m_beginStudyDateEdit->date().toString(
"yyyyMMdd").toStdString();
265 const std::string& endDate = m_endStudyDateEdit->date().toString(
"yyyyMMdd").toStdString();
266 const std::string& dateRange = beginDate +
"-" + endDate;
267 query.insert(
"StudyDate", dateRange.c_str());
270 body.insert(
"Level",
"Studies");
271 body.insert(
"Query", query);
272 body.insert(
"Limit", 0);
275 const std::string pacsServer(
"http://" + m_serverHostname +
":" + std::to_string(m_serverPort));
279 QByteArray studiesListAnswer;
282 studiesListAnswer = m_clientQt.
post(request, QJsonDocument(body).toJson());
286 std::stringstream ss;
287 ss <<
"Host not found:\n" 288 <<
" Please check your configuration: \n" 289 <<
"Pacs host name: " << m_serverHostname <<
"\n" 290 <<
"Pacs port: " << m_serverPort <<
"\n";
292 this->displayErrorMessage(ss.str());
295 QJsonDocument jsonResponse = QJsonDocument::fromJson(studiesListAnswer);
296 const QJsonArray& studiesListArray = jsonResponse.array();
297 const int studiesListArraySize = studiesListArray.count();
299 for(
int i = 0; i < studiesListArraySize; ++i)
301 const std::string& studiesUID = studiesListArray.at(i).toString().toStdString();
302 const std::string studiesUrl(pacsServer +
"/studies/" + studiesUID);
305 jsonResponse = QJsonDocument::fromJson(studiesAnswer);
306 const QJsonObject& jsonObj = jsonResponse.object();
307 const QJsonArray& seriesArray = jsonObj[
"Series"].toArray();
308 const int seriesArraySize = seriesArray.count();
310 for(
int i = 0; i < seriesArraySize; ++i)
312 const std::string& seriesUID = seriesArray.at(i).toString().toStdString();
313 const std::string instancesUrl(pacsServer +
"/series/" + seriesUID);
315 jsonResponse = QJsonDocument::fromJson(instancesAnswer);
316 const QJsonObject& jsonObj = jsonResponse.object();
317 const QJsonArray& instanceArray = jsonObj[
"Instances"].toArray();
320 const std::string& instanceUID = instanceArray.at(0).toString().toStdString();
321 const std::string instanceUrl(pacsServer +
"/instances/" + instanceUID +
"/simplified-tags");
324 QJsonObject seriesJson = QJsonDocument::fromJson(instance).object();
325 seriesJson.insert(
"NumberOfSeriesRelatedInstances", instanceArray.count() );
330 allSeries.insert(std::end(allSeries), std::begin(series), std::end(series));
331 this->updateSeriesDB(allSeries);
337 std::stringstream ss;
338 ss <<
"Unknown error.";
339 this->displayErrorMessage(ss.str());
346 void SQueryEditor::updateSeriesDB(::fwMedData::SeriesDB::ContainerType series)
348 ::fwMedData::SeriesDB::sptr seriesDB = this->getInOut< ::fwMedData::SeriesDB >(
"seriesDB");
352 seriesDBHelper.clear();
355 for(const ::fwMedData::Series::sptr& s: series)
357 ::fwMedData::DicomSeries::sptr dicomSeries = ::fwMedData::DicomSeries::dynamicCast(s);
358 seriesDBHelper.add(dicomSeries);
362 seriesDBHelper.notify();
368 void SQueryEditor::displayErrorMessage(
const std::string& message)
const 373 messageBox.
setIcon(::fwGui::dialog::IMessageDialog::CRITICAL);
374 messageBox.
addButton(::fwGui::dialog::IMessageDialog::OK);
FWNETWORKIO_API QByteArray post(Request::sptr request, const QByteArray &body)
Performs POST request.
Base class of fwNetworkIO Exception.
static FWNETWORKIO_API Request::sptr New(const std::string &url)
Creates a new Request with given url.
#define SLM_TRACE_FUNC()
Trace contextual function signature.
virtual FWGUI_API void setMessage(const std::string &msg) override
Set the message.
Defines the generic message box for IHM. Use the Delegate design pattern.
FWGUI_API void destroy()
Stops sub-views and toobar services. Destroys view, sub-views and toolbar containers.
virtual IODICOMWEB_API void starting() override
Creates the widgets & connect the signals.
IODICOMWEB_API void updating() override
Does nothing.
virtual IODICOMWEB_API void stopping() override
Disconnect the signals and destroy the widgets.
virtual IODICOMWEB_API void configuring() override
Gets the configurations.
#define SLM_WARN(message)
virtual FWGUI_API void addButton(IMessageDialog::Buttons button) override
Add a button (OK, YES_NO, YES, NO, CANCEL)
static FWNETWORKIO_API DicomSeriesContainer toFwMedData(const QJsonObject &answer)
Convert HTTP series response to fwMedData::DicomSeries.
FWNETWORKIO_API QByteArray get(Request::sptr request)
Retrieves data over network.
virtual FWGUI_API IMessageDialog::Buttons show() override
Show the message box and return the clicked button.
#define SLM_ASSERT(message, cond)
work like 'assert' from 'cassert', with in addition a message logged by spylog (with FATAL loglevel) ...
virtual IODICOMWEB_API ~SQueryEditor() noexcept
Destructor.
IODICOMWEB_API SQueryEditor() noexcept
Constructor.
FWGUI_API void create()
Creates view, sub-views and toolbar containers. Manages sub-views and toobar services.
virtual FWGUI_API void setIcon(IMessageDialog::Icons icon) override
Set the icon (CRITICAL, WARNING, INFO or QUESTION)
Implements exception for an HTTP host not found errors.
ioDicomWeb contains services use to deal with PACS through HTTP.
virtual FWGUI_API void setTitle(const std::string &title) override
Set the title of the message box.
FWGUI_API void initialize()
Initialize managers.
FWSERVICES_API ConfigType getConfigTree() const
Return the configuration, in an boost property tree.