ctkDICOMRetrieve.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661
  1. /*=========================================================================
  2. Library: CTK
  3. Copyright (c) Kitware Inc.
  4. Licensed under the Apache License, Version 2.0 (the "License");
  5. you may not use this file except in compliance with the License.
  6. You may obtain a copy of the License at
  7. http://www.apache.org/licenses/LICENSE-2.0.txt
  8. Unless required by applicable law or agreed to in writing, software
  9. distributed under the License is distributed on an "AS IS" BASIS,
  10. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. See the License for the specific language governing permissions and
  12. limitations under the License.
  13. =========================================================================*/
  14. #include <stdexcept>
  15. // Qt includes
  16. // ctkDICOMCore includes
  17. #include "ctkDICOMRetrieve.h"
  18. #include "ctkLogger.h"
  19. // DCMTK includes
  20. #include "dcmtk/dcmnet/dimse.h"
  21. #include "dcmtk/dcmnet/diutil.h"
  22. #include <dcmtk/dcmdata/dcfilefo.h>
  23. #include <dcmtk/dcmdata/dcfilefo.h>
  24. #include <dcmtk/dcmdata/dcdeftag.h>
  25. #include <dcmtk/dcmdata/dcdatset.h>
  26. #include <dcmtk/ofstd/ofcond.h>
  27. #include <dcmtk/ofstd/ofstring.h>
  28. #include <dcmtk/ofstd/ofstd.h> /* for class OFStandard */
  29. #include <dcmtk/dcmdata/dcddirif.h> /* for class DicomDirInterface */
  30. #include <dcmtk/dcmjpeg/djdecode.h> /* for dcmjpeg decoders */
  31. #include <dcmtk/dcmjpeg/djencode.h> /* for dcmjpeg encoders */
  32. #include <dcmtk/dcmdata/dcrledrg.h> /* for DcmRLEDecoderRegistration */
  33. #include <dcmtk/dcmdata/dcrleerg.h> /* for DcmRLEEncoderRegistration */
  34. // NOTE: using ctk stand-in class for now - switch back
  35. // to dcmtk's scu.h when cget support is in a release version
  36. //#include <dcmtk/dcmnet/scu.h>
  37. #include <ctkDcmSCU.h>
  38. #include "dcmtk/oflog/oflog.h"
  39. static ctkLogger logger("org.commontk.dicom.DICOMRetrieve");
  40. //------------------------------------------------------------------------------
  41. // A customized local implemenation of the DcmSCU so that Qt signals can be emitted
  42. // when retrieve results are obtained
  43. class ctkDICOMRetrieveSCUPrivate : public ctkDcmSCU
  44. {
  45. public:
  46. ctkDICOMRetrieve *retrieve;
  47. ctkDICOMRetrieveSCUPrivate()
  48. {
  49. this->retrieve = 0;
  50. };
  51. ~ctkDICOMRetrieveSCUPrivate() {};
  52. // called when a move reponse comes in: indicates that the
  53. // move request is being handled by the remote server.
  54. virtual OFCondition handleMOVEResponse(const T_ASC_PresentationContextID presID,
  55. RetrieveResponse *response,
  56. OFBool &waitForNextResponse)
  57. {
  58. if (this->retrieve)
  59. {
  60. emit this->retrieve->moveResponseHandled("Got one!");
  61. return this->ctkDcmSCU::handleMOVEResponse(
  62. presID, response, waitForNextResponse);
  63. }
  64. return false;
  65. };
  66. // called when a data set is coming in from a server in
  67. // response to a CGET
  68. virtual OFCondition handleSTORERequest(const T_ASC_PresentationContextID presID,
  69. DcmDataset *incomingObject,
  70. OFBool& continueCGETSession,
  71. Uint16& cStoreReturnStatus)
  72. {
  73. if (this->retrieve)
  74. {
  75. emit this->retrieve->storeRequested("Got a store request!");
  76. if (this->retrieve && this->retrieve->database())
  77. {
  78. this->retrieve->database()->insert(incomingObject);
  79. return ECC_Normal;
  80. }
  81. else
  82. {
  83. return this->ctkDcmSCU::handleSTORERequest(
  84. presID, incomingObject, continueCGETSession, cStoreReturnStatus);
  85. }
  86. }
  87. return false;
  88. };
  89. // called when status information from remote server
  90. // comes in from CGET
  91. virtual OFCondition handleCGETResponse(const T_ASC_PresentationContextID presID,
  92. RetrieveResponse* response,
  93. OFBool& continueCGETSession)
  94. {
  95. if (this->retrieve)
  96. {
  97. emit this->retrieve->retrieveStatusChanged("Got a cget response!");
  98. return this->ctkDcmSCU::handleCGETResponse(presID, response, continueCGETSession);
  99. }
  100. return false;
  101. };
  102. };
  103. //------------------------------------------------------------------------------
  104. class ctkDICOMRetrievePrivate
  105. {
  106. public:
  107. ctkDICOMRetrievePrivate();
  108. ~ctkDICOMRetrievePrivate();
  109. /// Keep the currently negotiated connection to the
  110. /// peer host open unless the connection parameters change
  111. bool KeepAssociationOpen;
  112. bool ConnectionParamsChanged;
  113. bool LastRetrieveType;
  114. QSharedPointer<ctkDICOMDatabase> Database;
  115. ctkDICOMRetrieveSCUPrivate SCU;
  116. QString MoveDestinationAETitle;
  117. // do the retrieve, handling both series and study retrieves
  118. enum RetrieveType { RetrieveNone, RetrieveSeries, RetrieveStudy };
  119. bool initializeSCU(const QString& studyInstanceUID,
  120. const QString& seriesInstanceUID,
  121. const RetrieveType retrieveType,
  122. DcmDataset *retrieveParameters);
  123. bool move ( const QString& studyInstanceUID,
  124. const QString& seriesInstanceUID,
  125. const RetrieveType retrieveType );
  126. bool get ( const QString& studyInstanceUID,
  127. const QString& seriesInstanceUID,
  128. const RetrieveType retrieveType );
  129. };
  130. //------------------------------------------------------------------------------
  131. // ctkDICOMRetrievePrivate methods
  132. //------------------------------------------------------------------------------
  133. ctkDICOMRetrievePrivate::ctkDICOMRetrievePrivate()
  134. {
  135. this->Database = QSharedPointer<ctkDICOMDatabase> (0);
  136. this->KeepAssociationOpen = true;
  137. this->ConnectionParamsChanged = false;
  138. this->LastRetrieveType = RetrieveNone;
  139. // Register the JPEG libraries in case we need them
  140. // (registration only happens once, so it's okay to call repeatedly)
  141. // register global JPEG decompression codecs
  142. DJDecoderRegistration::registerCodecs();
  143. // register global JPEG compression codecs
  144. DJEncoderRegistration::registerCodecs();
  145. // register RLE compression codec
  146. DcmRLEEncoderRegistration::registerCodecs();
  147. // register RLE decompression codec
  148. DcmRLEDecoderRegistration::registerCodecs();
  149. logger.info ( "Setting Transfer Syntaxes" );
  150. OFList<OFString> transferSyntaxes;
  151. transferSyntaxes.push_back ( UID_LittleEndianExplicitTransferSyntax );
  152. transferSyntaxes.push_back ( UID_BigEndianExplicitTransferSyntax );
  153. transferSyntaxes.push_back ( UID_LittleEndianImplicitTransferSyntax );
  154. this->SCU.addPresentationContext (
  155. UID_MOVEStudyRootQueryRetrieveInformationModel, transferSyntaxes );
  156. this->SCU.addPresentationContext (
  157. UID_GETStudyRootQueryRetrieveInformationModel, transferSyntaxes );
  158. for (Uint16 i = 0; i < numberOfDcmLongSCUStorageSOPClassUIDs; i++)
  159. {
  160. this->SCU.addPresentationContext(dcmLongSCUStorageSOPClassUIDs[i],
  161. transferSyntaxes, ASC_SC_ROLE_SCP);
  162. }
  163. }
  164. //------------------------------------------------------------------------------
  165. ctkDICOMRetrievePrivate::~ctkDICOMRetrievePrivate()
  166. {
  167. // At least now be kind to the server and release association
  168. this->SCU.closeAssociation(DCMSCU_RELEASE_ASSOCIATION);
  169. }
  170. //------------------------------------------------------------------------------
  171. bool ctkDICOMRetrievePrivate::initializeSCU( const QString& studyInstanceUID,
  172. const QString& seriesInstanceUID,
  173. const RetrieveType retrieveType,
  174. DcmDataset *retrieveParameters)
  175. {
  176. if ( !this->Database )
  177. {
  178. logger.error ( "No Database for retrieve transaction" );
  179. return false;
  180. }
  181. // If we like to query another server than before, be sure to disconnect first
  182. if (this->SCU.isConnected() && this->ConnectionParamsChanged)
  183. {
  184. this->SCU.closeAssociation(DCMSCU_RELEASE_ASSOCIATION);
  185. }
  186. // Connect to server if not already connected
  187. if (!this->SCU.isConnected())
  188. {
  189. // Check and initialize networking parameters in DCMTK
  190. if ( !this->SCU.initNetwork().good() )
  191. {
  192. logger.error ( "Error initializing the network" );
  193. return false;
  194. }
  195. // Negotiate (i.e. start the) association
  196. logger.debug ( "Negotiating Association" );
  197. if ( !this->SCU.negotiateAssociation().good() )
  198. {
  199. logger.error ( "Error negotiating association" );
  200. return false;;
  201. }
  202. }
  203. this->ConnectionParamsChanged = false;
  204. // Setup query about what to be received from the PACS
  205. logger.debug ( "Setting Retrieve Parameters" );
  206. if ( retrieveType == RetrieveSeries )
  207. {
  208. retrieveParameters->putAndInsertString ( DCM_QueryRetrieveLevel, "SERIES" );
  209. retrieveParameters->putAndInsertString ( DCM_SeriesInstanceUID,
  210. seriesInstanceUID.toStdString().c_str() );
  211. // Always required to send all highler level unique keys, so add study here (we are in Study Root)
  212. retrieveParameters->putAndInsertString ( DCM_StudyInstanceUID,
  213. studyInstanceUID.toStdString().c_str() ); //TODO
  214. }
  215. else
  216. {
  217. retrieveParameters->putAndInsertString ( DCM_QueryRetrieveLevel, "STUDY" );
  218. retrieveParameters->putAndInsertString ( DCM_StudyInstanceUID,
  219. studyInstanceUID.toStdString().c_str() );
  220. }
  221. return true;
  222. }
  223. //------------------------------------------------------------------------------
  224. bool ctkDICOMRetrievePrivate::move ( const QString& studyInstanceUID,
  225. const QString& seriesInstanceUID,
  226. const RetrieveType retrieveType )
  227. {
  228. DcmDataset *retrieveParameters = new DcmDataset();
  229. if (! this->initializeSCU(studyInstanceUID, seriesInstanceUID, retrieveType, retrieveParameters) )
  230. {
  231. delete retrieveParameters;
  232. return false;
  233. }
  234. // Issue request
  235. logger.debug ( "Sending Move Request" );
  236. OFList<RetrieveResponse*> responses;
  237. T_ASC_PresentationContextID presID = this->SCU.findPresentationContextID(
  238. UID_MOVEStudyRootQueryRetrieveInformationModel,
  239. "" /* don't care about transfer syntax */ );
  240. if (presID == 0)
  241. {
  242. logger.error ( "MOVE Request failed: No valid Study Root MOVE Presentation Context available" );
  243. if (!this->KeepAssociationOpen)
  244. {
  245. this->SCU.closeAssociation(DCMSCU_RELEASE_ASSOCIATION);
  246. }
  247. delete retrieveParameters;
  248. return false;
  249. }
  250. // do the actual move request
  251. OFCondition status = this->SCU.sendMOVERequest (
  252. presID, this->MoveDestinationAETitle.toStdString().c_str(),
  253. retrieveParameters, &responses );
  254. // Close association if we do not want to explicitly keep it open
  255. if (!this->KeepAssociationOpen)
  256. {
  257. this->SCU.closeAssociation(DCMSCU_RELEASE_ASSOCIATION);
  258. }
  259. // Free some (little) memory
  260. delete retrieveParameters;
  261. // If we do not receive a single response, something is fishy
  262. if ( responses.begin() == responses.end() )
  263. {
  264. logger.error ( "No responses received at all! (at least one empty response always expected)" );
  265. //throw std::runtime_error( std::string("No responses received from server!") );
  266. return false;
  267. }
  268. /* The server is permitted to acknowledge every image that was received, or
  269. * to send a single move response.
  270. * If there is only a single response, this can mean the following:
  271. * 1) No images to transfer (Status Success and Number of Completed Subops = 0)
  272. * 2) All images transferred (Status Success and Number of Completed Subops > 0)
  273. * 3) Error code, i.e. no images transferred
  274. * 4) Warning (one or more failures, i.e. some images transferred)
  275. */
  276. if ( responses.size() == 1 )
  277. {
  278. RetrieveResponse* rsp = *responses.begin();
  279. logger.debug ( "MOVE response receveid with status: " +
  280. QString(DU_cmoveStatusString(rsp->m_status)) );
  281. if ( (rsp->m_status == STATUS_Success)
  282. || (rsp->m_status == STATUS_MOVE_Warning_SubOperationsCompleteOneOrMoreFailures))
  283. {
  284. if (rsp->m_numberOfCompletedSubops == 0)
  285. {
  286. logger.error ( "No images transferred by PACS!" );
  287. //throw std::runtime_error( std::string("No images transferred by PACS!") );
  288. return false;
  289. }
  290. }
  291. else
  292. {
  293. logger.error("MOVE request failed, server does report error");
  294. QString statusDetail("No details");
  295. if (rsp->m_statusDetail != NULL)
  296. {
  297. std::ostringstream out;
  298. rsp->m_statusDetail->print(out);
  299. statusDetail = "Status Detail: " + statusDetail.fromStdString(out.str());
  300. }
  301. statusDetail.prepend("MOVE request failed: ");
  302. logger.error(statusDetail);
  303. //throw std::runtime_error( statusDetail.toStdString() );
  304. return false;
  305. }
  306. }
  307. // Select the last MOVE response to output meaningful status information
  308. OFIterator<RetrieveResponse*> it = responses.begin();
  309. Uint32 numResults = responses.size();
  310. for (Uint32 i = 1; i < numResults; i++)
  311. {
  312. it++;
  313. }
  314. logger.debug ( "MOVE responses report for study: " + studyInstanceUID +"\n"
  315. + QString::number(static_cast<unsigned int>((*it)->m_numberOfCompletedSubops))
  316. + " images transferred, and\n"
  317. + QString::number(static_cast<unsigned int>((*it)->m_numberOfWarningSubops))
  318. + " images transferred with warning, and\n"
  319. + QString::number(static_cast<unsigned int>((*it)->m_numberOfFailedSubops))
  320. + " images transfers failed");
  321. return true;
  322. }
  323. //------------------------------------------------------------------------------
  324. bool ctkDICOMRetrievePrivate::get ( const QString& studyInstanceUID,
  325. const QString& seriesInstanceUID,
  326. const RetrieveType retrieveType )
  327. {
  328. DcmDataset *retrieveParameters = new DcmDataset();
  329. if (! this->initializeSCU(studyInstanceUID, seriesInstanceUID, retrieveType, retrieveParameters) )
  330. {
  331. delete retrieveParameters;
  332. return false;
  333. }
  334. // Issue request
  335. logger.debug ( "Sending Get Request" );
  336. OFList<RetrieveResponse*> responses;
  337. T_ASC_PresentationContextID presID = this->SCU.findPresentationContextID(
  338. UID_GETStudyRootQueryRetrieveInformationModel,
  339. "" /* don't care about transfer syntax */ );
  340. if (presID == 0)
  341. {
  342. logger.error ( "GET Request failed: No valid Study Root GET Presentation Context available" );
  343. if (!this->KeepAssociationOpen)
  344. {
  345. this->SCU.closeAssociation(DCMSCU_RELEASE_ASSOCIATION);
  346. }
  347. delete retrieveParameters;
  348. return false;
  349. }
  350. // do the actual move request
  351. OFCondition status = this->SCU.sendCGETRequest (
  352. presID, retrieveParameters, &responses );
  353. // Close association if we do not want to explicitly keep it open
  354. if (!this->KeepAssociationOpen)
  355. {
  356. this->SCU.closeAssociation(DCMSCU_RELEASE_ASSOCIATION);
  357. }
  358. // Free some (little) memory
  359. delete retrieveParameters;
  360. // If we do not receive a single response, something is fishy
  361. if ( responses.begin() == responses.end() )
  362. {
  363. logger.error ( "No responses received at all! (at least one empty response always expected)" );
  364. //throw std::runtime_error( std::string("No responses received from server!") );
  365. return false;
  366. }
  367. /* The server is permitted to acknowledge every image that was received, or
  368. * to send a single move response.
  369. * If there is only a single response, this can mean the following:
  370. * 1) No images to transfer (Status Success and Number of Completed Subops = 0)
  371. * 2) All images transferred (Status Success and Number of Completed Subops > 0)
  372. * 3) Error code, i.e. no images transferred
  373. * 4) Warning (one or more failures, i.e. some images transferred)
  374. */
  375. if ( responses.size() == 1 )
  376. {
  377. RetrieveResponse* rsp = *responses.begin();
  378. logger.debug ( "GET response receveid with status: " +
  379. QString(DU_cmoveStatusString(rsp->m_status)) );
  380. if ( (rsp->m_status == STATUS_Success)
  381. || (rsp->m_status == STATUS_GET_Warning_SubOperationsCompleteOneOrMoreFailures))
  382. {
  383. if (rsp->m_numberOfCompletedSubops == 0)
  384. {
  385. logger.error ( "No images transferred by PACS!" );
  386. //throw std::runtime_error( std::string("No images transferred by PACS!") );
  387. return false;
  388. }
  389. }
  390. else
  391. {
  392. logger.error("GET request failed, server does report error");
  393. QString statusDetail("No details");
  394. if (rsp->m_statusDetail != NULL)
  395. {
  396. std::ostringstream out;
  397. rsp->m_statusDetail->print(out);
  398. statusDetail = "Status Detail: " + statusDetail.fromStdString(out.str());
  399. }
  400. statusDetail.prepend("GET request failed: ");
  401. logger.error(statusDetail);
  402. //throw std::runtime_error( statusDetail.toStdString() );
  403. return false;
  404. }
  405. }
  406. // Select the last GET response to output meaningful status information
  407. OFIterator<RetrieveResponse*> it = responses.begin();
  408. Uint32 numResults = responses.size();
  409. for (Uint32 i = 1; i < numResults; i++)
  410. {
  411. it++;
  412. }
  413. logger.debug ( "GET responses report for study: " + studyInstanceUID +"\n"
  414. + QString::number(static_cast<unsigned int>((*it)->m_numberOfCompletedSubops))
  415. + " images transferred, and\n"
  416. + QString::number(static_cast<unsigned int>((*it)->m_numberOfWarningSubops))
  417. + " images transferred with warning, and\n"
  418. + QString::number(static_cast<unsigned int>((*it)->m_numberOfFailedSubops))
  419. + " images transfers failed");
  420. return true;
  421. }
  422. //------------------------------------------------------------------------------
  423. // ctkDICOMRetrieve methods
  424. //------------------------------------------------------------------------------
  425. ctkDICOMRetrieve::ctkDICOMRetrieve()
  426. : d_ptr(new ctkDICOMRetrievePrivate)
  427. {
  428. Q_D(ctkDICOMRetrieve);
  429. d->SCU.retrieve = this; // give the dcmtk level access to this for emitting signals
  430. }
  431. //------------------------------------------------------------------------------
  432. ctkDICOMRetrieve::~ctkDICOMRetrieve()
  433. {
  434. }
  435. //------------------------------------------------------------------------------
  436. /// Set methods for connectivity
  437. void ctkDICOMRetrieve::setCallingAETitle( const QString& callingAETitle )
  438. {
  439. Q_D(ctkDICOMRetrieve);
  440. if (strcmp(callingAETitle.toStdString().c_str(), d->SCU.getAETitle().c_str()))
  441. {
  442. d->SCU.setAETitle(callingAETitle.toStdString().c_str());
  443. d->ConnectionParamsChanged = true;
  444. }
  445. }
  446. //------------------------------------------------------------------------------
  447. QString ctkDICOMRetrieve::callingAETitle() const
  448. {
  449. Q_D(const ctkDICOMRetrieve);
  450. return d->SCU.getAETitle().c_str();
  451. }
  452. //------------------------------------------------------------------------------
  453. void ctkDICOMRetrieve::setCalledAETitle( const QString& calledAETitle )
  454. {
  455. Q_D(ctkDICOMRetrieve);
  456. if (strcmp(calledAETitle.toStdString().c_str(),d->SCU.getPeerAETitle().c_str()))
  457. {
  458. d->SCU.setPeerAETitle(calledAETitle.toStdString().c_str());
  459. d->ConnectionParamsChanged = true;
  460. }
  461. }
  462. //------------------------------------------------------------------------------
  463. QString ctkDICOMRetrieve::calledAETitle()const
  464. {
  465. Q_D(const ctkDICOMRetrieve);
  466. return d->SCU.getPeerAETitle().c_str();
  467. }
  468. //------------------------------------------------------------------------------
  469. void ctkDICOMRetrieve::setHost( const QString& host )
  470. {
  471. Q_D(ctkDICOMRetrieve);
  472. if (strcmp(host.toStdString().c_str(), d->SCU.getPeerHostName().c_str()))
  473. {
  474. d->SCU.setPeerHostName(host.toStdString().c_str());
  475. d->ConnectionParamsChanged = true;
  476. }
  477. }
  478. //------------------------------------------------------------------------------
  479. QString ctkDICOMRetrieve::host()const
  480. {
  481. Q_D(const ctkDICOMRetrieve);
  482. return d->SCU.getPeerHostName().c_str();
  483. }
  484. //------------------------------------------------------------------------------
  485. void ctkDICOMRetrieve::setPort( int port )
  486. {
  487. Q_D(ctkDICOMRetrieve);
  488. if (d->SCU.getPeerPort() != port)
  489. {
  490. d->SCU.setPeerPort(port);
  491. d->ConnectionParamsChanged = true;
  492. }
  493. }
  494. //------------------------------------------------------------------------------
  495. int ctkDICOMRetrieve::port()const
  496. {
  497. Q_D(const ctkDICOMRetrieve);
  498. return d->SCU.getPeerPort();
  499. }
  500. //------------------------------------------------------------------------------
  501. void ctkDICOMRetrieve::setMoveDestinationAETitle( const QString& moveDestinationAETitle )
  502. {
  503. Q_D(ctkDICOMRetrieve);
  504. if (moveDestinationAETitle != d->MoveDestinationAETitle)
  505. {
  506. d->MoveDestinationAETitle = moveDestinationAETitle;
  507. d->ConnectionParamsChanged = true;
  508. }
  509. }
  510. //------------------------------------------------------------------------------
  511. QString ctkDICOMRetrieve::moveDestinationAETitle()const
  512. {
  513. Q_D(const ctkDICOMRetrieve);
  514. return d->MoveDestinationAETitle;
  515. }
  516. //------------------------------------------------------------------------------
  517. void ctkDICOMRetrieve::setDatabase(QSharedPointer<ctkDICOMDatabase> dicomDatabase)
  518. {
  519. Q_D(ctkDICOMRetrieve);
  520. d->Database = dicomDatabase;
  521. }
  522. //------------------------------------------------------------------------------
  523. QSharedPointer<ctkDICOMDatabase> ctkDICOMRetrieve::database()const
  524. {
  525. Q_D(const ctkDICOMRetrieve);
  526. return d->Database;
  527. }
  528. //------------------------------------------------------------------------------
  529. void ctkDICOMRetrieve::setKeepAssociationOpen(const bool keepOpen)
  530. {
  531. Q_D(ctkDICOMRetrieve);
  532. d->KeepAssociationOpen = keepOpen;
  533. }
  534. //------------------------------------------------------------------------------
  535. bool ctkDICOMRetrieve::keepAssociationOpen()
  536. {
  537. Q_D(const ctkDICOMRetrieve);
  538. return d->KeepAssociationOpen;
  539. }
  540. //------------------------------------------------------------------------------
  541. bool ctkDICOMRetrieve::moveStudy(const QString& studyInstanceUID)
  542. {
  543. if (studyInstanceUID.isEmpty())
  544. {
  545. logger.error("Cannot receive series: Study Instance UID empty.");
  546. return false;
  547. }
  548. Q_D(ctkDICOMRetrieve);
  549. logger.info ( "Starting moveStudy" );
  550. return d->move ( studyInstanceUID, "", ctkDICOMRetrievePrivate::RetrieveStudy );
  551. }
  552. //------------------------------------------------------------------------------
  553. bool ctkDICOMRetrieve::getStudy(const QString& studyInstanceUID)
  554. {
  555. if (studyInstanceUID.isEmpty())
  556. {
  557. logger.error("Cannot receive series: Study Instance UID empty.");
  558. return false;
  559. }
  560. Q_D(ctkDICOMRetrieve);
  561. logger.info ( "Starting getStudy" );
  562. return d->get ( studyInstanceUID, "", ctkDICOMRetrievePrivate::RetrieveStudy );
  563. }
  564. //------------------------------------------------------------------------------
  565. bool ctkDICOMRetrieve::moveSeries(const QString& studyInstanceUID,
  566. const QString& seriesInstanceUID)
  567. {
  568. if (studyInstanceUID.isEmpty() || seriesInstanceUID.isEmpty())
  569. {
  570. logger.error("Cannot receive series: Either Study or Series Instance UID empty.");
  571. return false;
  572. }
  573. Q_D(ctkDICOMRetrieve);
  574. logger.info ( "Starting moveSeries" );
  575. return d->move ( studyInstanceUID, seriesInstanceUID, ctkDICOMRetrievePrivate::RetrieveSeries );
  576. }
  577. //------------------------------------------------------------------------------
  578. bool ctkDICOMRetrieve::getSeries(const QString& studyInstanceUID,
  579. const QString& seriesInstanceUID)
  580. {
  581. if (studyInstanceUID.isEmpty() || seriesInstanceUID.isEmpty())
  582. {
  583. logger.error("Cannot receive series: Either Study or Series Instance UID empty.");
  584. return false;
  585. }
  586. Q_D(ctkDICOMRetrieve);
  587. logger.info ( "Starting getSeries" );
  588. return d->get ( studyInstanceUID, seriesInstanceUID, ctkDICOMRetrievePrivate::RetrieveSeries );
  589. }