ctkDICOMAppWidget.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  1. // std includes
  2. #include <iostream>
  3. #include <dcmimage.h>
  4. // Qt includes
  5. #include <QDebug>
  6. #include <QTreeView>
  7. #include <QTabBar>
  8. #include <QSettings>
  9. #include <QAction>
  10. #include <QModelIndex>
  11. #include <QCheckBox>
  12. // ctkDICOMCore includes
  13. #include "ctkDICOMDatabase.h"
  14. #include "ctkDICOMIndexer.h"
  15. // ctkDICOMWidgets includes
  16. #include "ctkDICOMImage.h"
  17. #include "ctkDICOMModel.h"
  18. #include "ctkDICOMAppWidget.h"
  19. #include "ctkDICOMQueryResultsTabWidget.h"
  20. #include "ui_ctkDICOMAppWidget.h"
  21. #include "ctkDirectoryButton.h"
  22. #include "ctkFileDialog.h"
  23. #include "ctkDICOMQueryRetrieveWidget.h"
  24. #include "ctkDICOMImportWidget.h"
  25. #include "ctkDICOMThumbnailWidget.h"
  26. //logger
  27. #include <ctkLogger.h>
  28. static ctkLogger logger("org.commontk.DICOM.Widgets.ctkDICOMAppWidget");
  29. //----------------------------------------------------------------------------
  30. class ctkDICOMAppWidgetPrivate: public Ui_ctkDICOMAppWidget
  31. {
  32. public:
  33. ctkDICOMAppWidgetPrivate();
  34. ctkFileDialog* ImportDialog;
  35. ctkDICOMQueryRetrieveWidget* QueryRetrieveWidget;
  36. QSharedPointer<ctkDICOMDatabase> DICOMDatabase;
  37. ctkDICOMModel DICOMModel;
  38. QSharedPointer<ctkDICOMIndexer> DICOMIndexer;
  39. };
  40. //----------------------------------------------------------------------------
  41. // ctkDICOMAppWidgetPrivate methods
  42. ctkDICOMAppWidgetPrivate::ctkDICOMAppWidgetPrivate(){
  43. DICOMDatabase = QSharedPointer<ctkDICOMDatabase> (new ctkDICOMDatabase);
  44. DICOMIndexer = QSharedPointer<ctkDICOMIndexer> (new ctkDICOMIndexer);
  45. }
  46. //----------------------------------------------------------------------------
  47. // ctkDICOMAppWidget methods
  48. //----------------------------------------------------------------------------
  49. ctkDICOMAppWidget::ctkDICOMAppWidget(QWidget* _parent):Superclass(_parent),
  50. d_ptr(new ctkDICOMAppWidgetPrivate)
  51. {
  52. Q_D(ctkDICOMAppWidget);
  53. d->setupUi(this);
  54. //Hide image previewer buttons
  55. d->nextImageButton->hide();
  56. d->prevImageButton->hide();
  57. d->nextSeriesButton->hide();
  58. d->prevSeriesButton->hide();
  59. d->nextStudyButton->hide();
  60. d->prevStudyButton->hide();
  61. //Enable sorting in tree view
  62. d->treeView->setSortingEnabled(true);
  63. d->treeView->setSelectionBehavior(QAbstractItemView::SelectRows);
  64. connect(d->treeView, SIGNAL(collapsed(QModelIndex)), this, SLOT(onTreeCollapsed(QModelIndex)));
  65. connect(d->treeView, SIGNAL(expanded(QModelIndex)), this, SLOT(onTreeExpanded(QModelIndex)));
  66. //Set toolbar button style
  67. d->toolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
  68. //Initialize Q/R widget
  69. d->QueryRetrieveWidget = new ctkDICOMQueryRetrieveWidget();
  70. d->QueryRetrieveWidget->setWindowModality ( Qt::ApplicationModal );
  71. //initialize directory from settings, then listen for changes
  72. QSettings settings;
  73. if ( settings.value("DatabaseDirectory", "") == "" )
  74. {
  75. QString directory = QString("./ctkDICOM-Database");
  76. settings.setValue("DatabaseDirectory", directory);
  77. settings.sync();
  78. }
  79. QString databaseDirectory = settings.value("DatabaseDirectory").toString();
  80. this->setDatabaseDirectory(databaseDirectory);
  81. d->directoryButton->setDirectory(databaseDirectory);
  82. connect(d->directoryButton, SIGNAL(directoryChanged(const QString&)), this, SLOT(setDatabaseDirectory(const QString&)));
  83. //Initialize import widget
  84. d->ImportDialog = new ctkFileDialog();
  85. QCheckBox* importCheckbox = new QCheckBox("Copy on import", d->ImportDialog);
  86. d->ImportDialog->setBottomWidget(importCheckbox);
  87. d->ImportDialog->setFileMode(QFileDialog::Directory);
  88. d->ImportDialog->setLabelText(QFileDialog::Accept,"Import");
  89. d->ImportDialog->setWindowTitle("Import DICOM files from directory ...");
  90. d->ImportDialog->setWindowModality(Qt::ApplicationModal);
  91. //connect signal and slots
  92. connect(d->treeView, SIGNAL(clicked(const QModelIndex&)), d->thumbnailsWidget, SLOT(onModelSelected(const QModelIndex &)));
  93. connect(d->treeView, SIGNAL(clicked(const QModelIndex&)), d->imagePreview, SLOT(onModelSelected(const QModelIndex &)));
  94. connect(d->treeView, SIGNAL(clicked(const QModelIndex&)), this, SLOT(onModelSelected(const QModelIndex &)));
  95. connect(d->thumbnailsWidget, SIGNAL(selected(const ctkDICOMThumbnailWidget&)), this, SLOT(onThumbnailSelected(const ctkDICOMThumbnailWidget&)));
  96. connect(d->ImportDialog, SIGNAL(fileSelected(QString)),this,SLOT(onImportDirectory(QString)));
  97. connect(d->DICOMDatabase.data(), SIGNAL( databaseChanged() ), &(d->DICOMModel), SLOT( reset() ) );
  98. connect(d->QueryRetrieveWidget, SIGNAL( canceled() ), d->QueryRetrieveWidget, SLOT( hide() ) );
  99. connect(d->imagePreview, SIGNAL(requestNextImage()), this, SLOT(onNextImage()));
  100. connect(d->imagePreview, SIGNAL(requestPreviousImage()), this, SLOT(onPreviousImage()));
  101. }
  102. //----------------------------------------------------------------------------
  103. ctkDICOMAppWidget::~ctkDICOMAppWidget()
  104. {
  105. Q_D(ctkDICOMAppWidget);
  106. d->QueryRetrieveWidget->deleteLater();
  107. d->ImportDialog->deleteLater();
  108. }
  109. //----------------------------------------------------------------------------
  110. void ctkDICOMAppWidget::setDatabaseDirectory(const QString& directory)
  111. {
  112. Q_D(ctkDICOMAppWidget);
  113. QSettings settings;
  114. settings.setValue("DatabaseDirectory", directory);
  115. settings.sync();
  116. //close the active DICOM database
  117. d->DICOMDatabase->closeDatabase();
  118. //open DICOM database on the directory
  119. QString databaseFileName = directory + QString("/ctkDICOM.sql");
  120. try { d->DICOMDatabase->openDatabase( databaseFileName ); }
  121. catch (std::exception e)
  122. {
  123. std::cerr << "Database error: " << qPrintable(d->DICOMDatabase->lastError()) << "\n";
  124. d->DICOMDatabase->closeDatabase();
  125. return;
  126. }
  127. d->DICOMModel.setDatabase(d->DICOMDatabase->database());
  128. d->DICOMModel.setDisplayLevel(ctkDICOMModel::SeriesType);
  129. d->treeView->setModel(&d->DICOMModel);
  130. d->treeView->resizeColumnToContents(0);
  131. //pass DICOM database instance to Import widget
  132. // d->ImportDialog->setDICOMDatabase(d->DICOMDatabase);
  133. d->QueryRetrieveWidget->setRetrieveDatabase(d->DICOMDatabase);
  134. // update the button and let any connected slots know about the change
  135. d->directoryButton->setDirectory(directory);
  136. d->thumbnailsWidget->setDatabaseDirectory(directory);
  137. d->imagePreview->setDatabaseDirectory(directory);
  138. emit databaseDirectoryChanged(directory);
  139. }
  140. //----------------------------------------------------------------------------
  141. QString ctkDICOMAppWidget::databaseDirectory() const
  142. {
  143. QSettings settings;
  144. return settings.value("DatabaseDirectory").toString();
  145. }
  146. void ctkDICOMAppWidget::onAddToDatabase()
  147. {
  148. //Q_D(ctkDICOMAppWidget);
  149. //d->
  150. }
  151. //----------------------------------------------------------------------------
  152. void ctkDICOMAppWidget::openImportDialog()
  153. {
  154. Q_D(ctkDICOMAppWidget);
  155. d->ImportDialog->show();
  156. d->ImportDialog->raise();
  157. }
  158. //----------------------------------------------------------------------------
  159. void ctkDICOMAppWidget::openExportDialog()
  160. {
  161. }
  162. //----------------------------------------------------------------------------
  163. void ctkDICOMAppWidget::openQueryDialog()
  164. {
  165. Q_D(ctkDICOMAppWidget);
  166. d->QueryRetrieveWidget->show();
  167. d->QueryRetrieveWidget->raise();
  168. }
  169. //----------------------------------------------------------------------------
  170. void ctkDICOMAppWidget::onThumbnailSelected(const ctkDICOMThumbnailWidget& widget)
  171. {
  172. Q_D(ctkDICOMAppWidget);
  173. d->imagePreview->onModelSelected(widget.sourceIndex());
  174. }
  175. //----------------------------------------------------------------------------
  176. void ctkDICOMAppWidget::onImportDirectory(QString directory)
  177. {
  178. Q_D(ctkDICOMAppWidget);
  179. if (QDir(directory).exists())
  180. {
  181. QCheckBox* copyOnImport = qobject_cast<QCheckBox*>(d->ImportDialog->bottomWidget());
  182. QString targetDirectory;
  183. if (copyOnImport->isEnabled())
  184. {
  185. targetDirectory = d->DICOMDatabase->databaseDirectory();
  186. }
  187. d->DICOMIndexer->addDirectory(*d->DICOMDatabase,directory,targetDirectory);
  188. d->DICOMModel.reset();
  189. }
  190. }
  191. //----------------------------------------------------------------------------
  192. void ctkDICOMAppWidget::onModelSelected(const QModelIndex &index){
  193. Q_D(ctkDICOMAppWidget);
  194. ctkDICOMModel* model = const_cast<ctkDICOMModel*>(qobject_cast<const ctkDICOMModel*>(index.model()));
  195. if(model){
  196. QModelIndex index0 = index.sibling(index.row(), 0);
  197. if ( model->data(index0,ctkDICOMModel::TypeRole) == ctkDICOMModel::PatientType ){
  198. d->nextImageButton->show();
  199. d->prevImageButton->show();
  200. d->nextSeriesButton->show();
  201. d->prevSeriesButton->show();
  202. d->nextStudyButton->show();
  203. d->prevStudyButton->show();
  204. }else if ( model->data(index0,ctkDICOMModel::TypeRole) == ctkDICOMModel::StudyType ){
  205. d->nextImageButton->show();
  206. d->prevImageButton->show();
  207. d->nextSeriesButton->show();
  208. d->prevSeriesButton->show();
  209. d->nextStudyButton->hide();
  210. d->prevStudyButton->hide();
  211. }else if ( model->data(index0,ctkDICOMModel::TypeRole) == ctkDICOMModel::SeriesType ){
  212. d->nextImageButton->show();
  213. d->prevImageButton->show();
  214. d->nextSeriesButton->hide();
  215. d->prevSeriesButton->hide();
  216. d->nextStudyButton->hide();
  217. d->prevStudyButton->hide();
  218. }else{
  219. d->nextImageButton->hide();
  220. d->prevImageButton->hide();
  221. d->nextSeriesButton->hide();
  222. d->prevSeriesButton->hide();
  223. d->nextStudyButton->hide();
  224. d->prevStudyButton->hide();
  225. }
  226. }else{
  227. d->nextImageButton->hide();
  228. d->prevImageButton->hide();
  229. d->nextSeriesButton->hide();
  230. d->prevSeriesButton->hide();
  231. d->nextStudyButton->hide();
  232. d->prevStudyButton->hide();
  233. }
  234. }
  235. //----------------------------------------------------------------------------
  236. void ctkDICOMAppWidget::onNextImage(){
  237. Q_D(ctkDICOMAppWidget);
  238. QModelIndex currentIndex = d->imagePreview->currentImageIndex();
  239. if(currentIndex.isValid()){
  240. ctkDICOMModel* model = const_cast<ctkDICOMModel*>(qobject_cast<const ctkDICOMModel*>(currentIndex.model()));
  241. if(model){
  242. QModelIndex seriesIndex = currentIndex.parent();
  243. int imageCount = model->rowCount(seriesIndex);
  244. int imageID = currentIndex.row();
  245. imageID = (imageID+1)%imageCount;
  246. QModelIndex nextIndex = currentIndex.sibling(imageID, 0);
  247. d->imagePreview->onModelSelected(nextIndex);
  248. }
  249. }
  250. }
  251. //----------------------------------------------------------------------------
  252. void ctkDICOMAppWidget::onPreviousImage(){
  253. Q_D(ctkDICOMAppWidget);
  254. QModelIndex currentIndex = d->imagePreview->currentImageIndex();
  255. if(currentIndex.isValid()){
  256. ctkDICOMModel* model = const_cast<ctkDICOMModel*>(qobject_cast<const ctkDICOMModel*>(currentIndex.model()));
  257. if(model){
  258. QModelIndex seriesIndex = currentIndex.parent();
  259. int imageCount = model->rowCount(seriesIndex);
  260. int imageID = currentIndex.row();
  261. imageID--;
  262. if(imageID < 0) imageID += imageCount;
  263. QModelIndex prevIndex = currentIndex.sibling(imageID, 0);
  264. d->imagePreview->onModelSelected(prevIndex);
  265. }
  266. }
  267. }
  268. //----------------------------------------------------------------------------
  269. void ctkDICOMAppWidget::onNextSeries(){
  270. Q_D(ctkDICOMAppWidget);
  271. QModelIndex currentIndex = d->imagePreview->currentImageIndex();
  272. if(currentIndex.isValid()){
  273. ctkDICOMModel* model = const_cast<ctkDICOMModel*>(qobject_cast<const ctkDICOMModel*>(currentIndex.model()));
  274. if(model){
  275. QModelIndex seriesIndex = currentIndex.parent();
  276. QModelIndex studyIndex = seriesIndex.parent();
  277. int seriesCount = model->rowCount(studyIndex);
  278. int seriesID = seriesIndex.row();
  279. seriesID = (seriesID + 1)%seriesCount;
  280. QModelIndex nextIndex = seriesIndex.sibling(seriesID, 0);
  281. d->imagePreview->onModelSelected(nextIndex);
  282. }
  283. }
  284. }
  285. //----------------------------------------------------------------------------
  286. void ctkDICOMAppWidget::onPreviousSeries(){
  287. Q_D(ctkDICOMAppWidget);
  288. QModelIndex currentIndex = d->imagePreview->currentImageIndex();
  289. if(currentIndex.isValid()){
  290. ctkDICOMModel* model = const_cast<ctkDICOMModel*>(qobject_cast<const ctkDICOMModel*>(currentIndex.model()));
  291. if(model){
  292. QModelIndex seriesIndex = currentIndex.parent();
  293. QModelIndex studyIndex = seriesIndex.parent();
  294. int seriesCount = model->rowCount(studyIndex);
  295. int seriesID = seriesIndex.row();
  296. seriesID--;
  297. if(seriesID < 0) seriesID += seriesCount;
  298. QModelIndex nextIndex = seriesIndex.sibling(seriesID, 0);
  299. d->imagePreview->onModelSelected(nextIndex);
  300. }
  301. }
  302. }
  303. //----------------------------------------------------------------------------
  304. void ctkDICOMAppWidget::onNextStudy(){
  305. Q_D(ctkDICOMAppWidget);
  306. QModelIndex currentIndex = d->imagePreview->currentImageIndex();
  307. if(currentIndex.isValid()){
  308. ctkDICOMModel* model = const_cast<ctkDICOMModel*>(qobject_cast<const ctkDICOMModel*>(currentIndex.model()));
  309. if(model){
  310. QModelIndex seriesIndex = currentIndex.parent();
  311. QModelIndex studyIndex = seriesIndex.parent();
  312. QModelIndex patientIndex = studyIndex.parent();
  313. int studyCount = model->rowCount(patientIndex);
  314. int studyID = studyIndex.row();
  315. studyID = (studyID + 1)%studyCount;
  316. QModelIndex nextIndex = studyIndex.sibling(studyID, 0);
  317. d->imagePreview->onModelSelected(nextIndex);
  318. }
  319. }
  320. }
  321. //----------------------------------------------------------------------------
  322. void ctkDICOMAppWidget::onPreviousStudy(){
  323. Q_D(ctkDICOMAppWidget);
  324. QModelIndex currentIndex = d->imagePreview->currentImageIndex();
  325. if(currentIndex.isValid()){
  326. ctkDICOMModel* model = const_cast<ctkDICOMModel*>(qobject_cast<const ctkDICOMModel*>(currentIndex.model()));
  327. if(model){
  328. QModelIndex seriesIndex = currentIndex.parent();
  329. QModelIndex studyIndex = seriesIndex.parent();
  330. QModelIndex patientIndex = studyIndex.parent();
  331. int studyCount = model->rowCount(patientIndex);
  332. int studyID = studyIndex.row();
  333. studyID--;
  334. if(studyID < 0) studyID += studyCount;
  335. QModelIndex nextIndex = studyIndex.sibling(studyID, 0);
  336. d->imagePreview->onModelSelected(nextIndex);
  337. }
  338. }
  339. }
  340. //----------------------------------------------------------------------------
  341. void ctkDICOMAppWidget::onTreeCollapsed(const QModelIndex &index){
  342. Q_D(ctkDICOMAppWidget);
  343. d->treeView->resizeColumnToContents(0);
  344. }
  345. //----------------------------------------------------------------------------
  346. void ctkDICOMAppWidget::onTreeExpanded(const QModelIndex &index){
  347. Q_D(ctkDICOMAppWidget);
  348. d->treeView->resizeColumnToContents(0);
  349. }