CustusX  15.4.0-beta
An IGT application
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
cxDICOMAppWidget.cpp
Go to the documentation of this file.
1 /*=========================================================================
2 
3  Library: CTK
4 
5  Copyright (c) Kitware Inc.
6 
7  Licensed under the Apache License, Version 2.0 (the "License");
8  you may not use this file except in compliance with the License.
9  You may obtain a copy of the License at
10 
11  http://www.apache.org/licenses/LICENSE-2.0.txt
12 
13  Unless required by applicable law or agreed to in writing, software
14  distributed under the License is distributed on an "AS IS" BASIS,
15  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  See the License for the specific language governing permissions and
17  limitations under the License.
18 
19 =========================================================================*/
20 
21 // std includes
22 #include <iostream>
23 
24 #include <dcmimage.h>
25 
26 // Qt includes
27 #include <QAction>
28 #include <QCoreApplication>
29 #include <QCheckBox>
30 #include <QDebug>
31 #include <QMessageBox>
32 #include <QMetaType>
33 #include <QModelIndex>
34 #include <QPersistentModelIndex>
35 #include <QProgressDialog>
36 #include <QSettings>
37 #include <QSlider>
38 #include <QTabBar>
39 #include <QTimer>
40 #include <QTreeView>
41 #include <QLabel>
42 #include <QHBoxLayout>
43 #include <QSplitter>
44 
45 // ctkWidgets includes
46 #include "ctkDirectoryButton.h"
47 #include "ctkFileDialog.h"
48 
49 // ctkDICOMCore includes
50 #include "ctkDICOMDatabase.h"
51 #include "ctkDICOMFilterProxyModel.h"
52 #include "ctkDICOMIndexer.h"
53 #include "cxDICOMModel.h"
54 
55 // ctkDICOMWidgets includes
56 #include "cxDICOMAppWidget.h"
58 #include "ctkThumbnailLabel.h"
59 #include "ctkDICOMQueryResultsTabWidget.h"
60 #include "ctkDICOMQueryRetrieveWidget.h"
61 #include "ctkDICOMQueryWidget.h"
62 #include <QToolBar>
63 //#include "ctkDICOMThumbnailListWidget.h"
65 
66 
67 #include "cxDicomImporter.h"
68 #include "cxLogger.h"
69 
70 //#include "ui_DICOMAppWidget.h"
71 
72 //logger
73 #include <ctkLogger.h>
74 static ctkLogger logger("org.commontk.DICOM.Widgets.DICOMAppWidget");
75 
76 Q_DECLARE_METATYPE(QPersistentModelIndex);
77 
78 
79 namespace cx
80 {
82 
83 //----------------------------------------------------------------------------
84 class DICOMAppWidgetPrivate: public QWidget
85 {
86 public:
89 
92  void setupUi(DICOMAppWidget* parent);
93 
94  QVBoxLayout* TopLayout;
95  QTreeView* TreeView;
96  QToolBar* ToolBar;
97 // ctkDICOMThumbnailListWidget* ThumbnailsWidget;
100  QAction* ActionImport;
101  QAction* ActionQuery;
102  QAction* ActionRemove;
104 
105  ctkDICOMQueryRetrieveWidget* QueryRetrieveWidget;
106  ctkDICOMQueryRetrieveWidget* getQueryRetrieveWidget();
107 
108  QSharedPointer<ctkDICOMDatabase> DICOMDatabase;
109  QSharedPointer<ctkDICOMThumbnailGenerator> ThumbnailGenerator;
111  ctkDICOMFilterProxyModel DICOMProxyModel;
112  QProgressDialog *UpdateSchemaProgress;
113 
114  void showUpdateSchemaDialog();
115  std::map<ctkDICOMModel::IndexType, QStringList> getSelection() const;
116 
117  void removeSelection();
118 };
119 
120 //----------------------------------------------------------------------------
121 // DICOMAppWidgetPrivate methods
122 
124 {
125  QueryRetrieveWidget = NULL;
126  DICOMDatabase = QSharedPointer<ctkDICOMDatabase> (new ctkDICOMDatabase);
127  ThumbnailGenerator = QSharedPointer <ctkDICOMThumbnailGenerator> (new ctkDICOMThumbnailGenerator);
128  DICOMDatabase->setThumbnailGenerator(ThumbnailGenerator.data());
130 }
131 
133 {
134  if ( UpdateSchemaProgress )
135  {
136  delete UpdateSchemaProgress;
137  }
138 
140  QueryRetrieveWidget->deleteLater();
141 }
142 
144 {
145  Q_Q(DICOMAppWidget);
146 
147  TopLayout = new QVBoxLayout(parent);
148  TopLayout->setMargin(0);
149 
150  ToolBar = new QToolBar;
151  TopLayout->addWidget(ToolBar);
152 
153  ActionImport = new QAction("Open", this);
154  ActionImport->setToolTip("Open and load a DICOM file or folder");
155  q->connect(ActionImport, SIGNAL(triggered()), &Importer, SLOT(openImportDialog()));
156  ToolBar->addAction(ActionImport);
157 
158  ActionQuery = new QAction("Query", this);
159  ActionQuery->setToolTip("Query and Retrieve DICOM studies from a DICOM node");
160  q->connect(ActionQuery, SIGNAL(triggered()), q, SLOT(openQueryDialog()));
161  ToolBar->addAction(ActionQuery);
162 
163  ActionRemove = new QAction("Remove", this);
164  ActionRemove->setToolTip("Remove selection from database");
165  q->connect(ActionRemove, SIGNAL(triggered()), q, SLOT(onRemoveAction()));
166  ToolBar->addAction(ActionRemove);
167 
168  QSplitter* splitter = new QSplitter;
169  splitter->setOrientation(Qt::Vertical);
170  TopLayout->addWidget(splitter);
171 
172  TreeView = new QTreeView;
173  TreeView->setAlternatingRowColors(true);
174  splitter->addWidget(TreeView);
175 
176  QWidget* ThumbnailsFullWidget = new QWidget;
177  splitter->addWidget(ThumbnailsFullWidget);
178  QVBoxLayout* ThumbnailsFullWidgetLayout = new QVBoxLayout(ThumbnailsFullWidget);
179  ThumbnailsFullWidgetLayout->setMargin(0);
180 
182  ThumbnailsWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
183  ThumbnailsWidget->setMinimumSize(QSize(0,200));
184  ThumbnailsFullWidgetLayout->addWidget(ThumbnailsWidget);
185 
186  ThumbnailWidthSlider = new QSlider;
187  ThumbnailWidthSlider->setMinimum(64);
188  ThumbnailWidthSlider->setMaximum(256);
189  ThumbnailWidthSlider->setValue(64);
190  ThumbnailWidthSlider->setOrientation(Qt::Horizontal);
191  connect(ThumbnailWidthSlider, SIGNAL(valueChanged(int)), q, SLOT(onThumbnailWidthSliderValueChanged(int)));
192  ThumbnailsFullWidgetLayout->addWidget(ThumbnailWidthSlider);
193 }
194 
196 {
197  Q_Q(DICOMAppWidget);
198 
199  ctkDICOMDatabase* db = DICOMDatabase.data();
200  q->connect(db, SIGNAL(schemaUpdateStarted(int)), q, SLOT(schemaUpdateStarted(int)));
201  q->connect(db, SIGNAL(schemaUpdateProgress(int)), q, SLOT(schemaUpdateProgress(int)));
202  q->connect(db, SIGNAL(schemaUpdateProgress(QString)), q, SLOT(schemaUpdateProgress(QString)));
203  q->connect(db, SIGNAL(schemaUpdated()), q, SLOT(schemaUpdated()));
204 
205 // if (UpdateSchemaProgress == 0)
206 // {
207 // //
208 // // Set up the Update Schema Progress Dialog
209 // //
210 // UpdateSchemaProgress = new QProgressDialog(
211 // q->tr("DICOM Schema Update"), "Cancel", 0, 100, q,
212 // Qt::WindowTitleHint | Qt::WindowSystemMenuHint);
213 
214 // // We don't want the progress dialog to resize itself, so we bypass the label
215 // // by creating our own
216 // QLabel* progressLabel = new QLabel(q->tr("Initialization..."));
217 // UpdateSchemaProgress->setLabel(progressLabel);
218 // UpdateSchemaProgress->setWindowModality(Qt::ApplicationModal);
219 // UpdateSchemaProgress->setMinimumDuration(0);
220 // UpdateSchemaProgress->setValue(0);
221 
222 // //q->connect(UpdateSchemaProgress, SIGNAL(canceled()),
223 // // DICOMIndexer.data(), SLOT(cancel()));
224 // ctkDICOMDatabase* db = DICOMDatabase.data();
225 
226 // q->connect(db, SIGNAL(schemaUpdateStarted(int)), UpdateSchemaProgress, SLOT(setMaximum(int)));
227 // q->connect(db, SIGNAL(schemaUpdateProgress(int)), UpdateSchemaProgress, SLOT(setValue(int)));
228 // q->connect(db, SIGNAL(schemaUpdateProgress(QString)), progressLabel, SLOT(setText(QString)));
229 // // close the dialog
231 // // reset the database to show new data
232 // q->connect(db, SIGNAL(schemaUpdated()), &mDICOMModel, SLOT(reset()));
233 // // reset the database if canceled
234 // q->connect(UpdateSchemaProgress, SIGNAL(canceled()), &mDICOMModel, SLOT(reset()));
235 
236 
237 // q->connect(db, SIGNAL(schemaUpdateStarted(int)), q, SLOT(schemaUpdateStarted(int)));
238 // q->connect(db, SIGNAL(schemaUpdateProgress(int)), q, SLOT(schemaUpdateProgress(int)));
239 // q->connect(db, SIGNAL(schemaUpdateProgress(QString)), q, SLOT(schemaUpdateProgress(QString)));
240 // q->connect(db, SIGNAL(schemaUpdated()), q, SLOT(schemaUpdated()));
241 // }
242 // UpdateSchemaProgress->show();
243 }
244 
245 void DICOMAppWidget::schemaUpdateStarted(int)
246 {
247 // report("DICOM schema update started...");
248 }
249 void DICOMAppWidget::schemaUpdateProgress(QString val)
250 {
251 }
252 void DICOMAppWidget::schemaUpdateProgress(int val)
253 {
254 }
255 void DICOMAppWidget::schemaUpdated()
256 {
257 // report("DICOM schema updated");
258 }
259 
261 {
262  QModelIndexList selection = TreeView->selectionModel()->selectedIndexes();
263  QModelIndex index;
264 
265  foreach(index,selection)
266  {
267  if (index.column()!=0)
268  continue;
269  mDICOMModel.removeRows(index.row(), 1, index.parent());
270 // this->remove(index);
271  }
272 }
273 
274 std::map<ctkDICOMModel::IndexType, QStringList> DICOMAppWidgetPrivate::getSelection() const
275 {
276 // Q_Q(DICOMAppWidget);
277  std::map<ctkDICOMModel::IndexType, QStringList> retval;
278  QModelIndexList selection = TreeView->selectionModel()->selectedIndexes();
279  QModelIndex index;
280 
281  foreach(index,selection)
282  {
283  QModelIndex index0 = index.sibling(index.row(), 0);
285  QString uid = mDICOMModel.data(index0,ctkDICOMModel::UIDRole).toString();
286 
287  if (!retval.count(type))
288  retval[type] << uid;
289  }
290 
291  return retval;
292 }
293 
294 //----------------------------------------------------------------------------
295 ctkDICOMQueryRetrieveWidget* DICOMAppWidgetPrivate::getQueryRetrieveWidget()
296 {
297  if (!QueryRetrieveWidget)
298  {
299  Q_Q(DICOMAppWidget);
300  //Initialize Q/R widget
301  QueryRetrieveWidget = new ctkDICOMQueryRetrieveWidget();
302  QueryRetrieveWidget->setWindowModality(Qt::ApplicationModal);
303 
304  connect(QueryRetrieveWidget, SIGNAL(canceled()), QueryRetrieveWidget, SLOT(hide()) );
305  connect(QueryRetrieveWidget, SIGNAL(canceled()), q, SLOT(onQueryRetrieveFinished()) );
306 
307  QueryRetrieveWidget->setRetrieveDatabase(DICOMDatabase);
308  }
309 
310  return QueryRetrieveWidget;
311 }
312 
313 //----------------------------------------------------------------------------
314 // DICOMAppWidget methods
315 
316 //----------------------------------------------------------------------------
317 DICOMAppWidget::DICOMAppWidget(QWidget* _parent):Superclass(_parent),
318  d_ptr(new DICOMAppWidgetPrivate(this))
319 {
320  Q_D(DICOMAppWidget);
321 
322  d->setupUi(this);
323 
324  connect(&d->Importer, SIGNAL(indexingCompleted()),
325  &d->mDICOMModel, SLOT(reset()));
326  connect(&d->Importer, SIGNAL(directoryImported()),
327  this, SIGNAL(directoryImported()));
328 
329  //Enable sorting in tree view
330  d->TreeView->setSortingEnabled(true);
331  d->TreeView->setSelectionBehavior(QAbstractItemView::SelectRows);
332  d->DICOMProxyModel.setSourceModel(&d->mDICOMModel);
333  d->TreeView->setModel(&d->mDICOMModel);
334 
335  d->ThumbnailsWidget->setThumbnailSize(
336  QSize(d->ThumbnailWidthSlider->value(), d->ThumbnailWidthSlider->value()));
337 
338  // Treeview signals
339  connect(d->TreeView, SIGNAL(collapsed(QModelIndex)), this, SLOT(onTreeCollapsed(QModelIndex)));
340  connect(d->TreeView, SIGNAL(expanded(QModelIndex)), this, SLOT(onTreeExpanded(QModelIndex)));
341 
342  //Set ToolBar button style
343  d->ToolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
344 
345 // //Initialize Q/R widget
346 // d->QueryRetrieveWidget = new ctkDICOMQueryRetrieveWidget();
347 // d->QueryRetrieveWidget->setWindowModality ( Qt::ApplicationModal );
348 
349  connect(d->TreeView->selectionModel(),
350  SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
351  this,
352  SLOT(onSelectionChanged(const QItemSelection&, const QItemSelection&)));
353  connect(d->TreeView->selectionModel(),
354  SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)),
355  this,
356  SLOT(onCurrentChanged(const QModelIndex&, const QModelIndex&)));
357 
358  //connect signal and slots
359  connect(d->TreeView, SIGNAL(clicked(QModelIndex)), this, SLOT(onModelSelected(QModelIndex)));
360 
361 // connect(d->QueryRetrieveWidget, SIGNAL(canceled()), d->QueryRetrieveWidget, SLOT(hide()) );
362 // connect(d->QueryRetrieveWidget, SIGNAL(canceled()), this, SLOT(onQueryRetrieveFinished()) );
363 }
364 
365 //----------------------------------------------------------------------------
367 {
368  Q_D(DICOMAppWidget);
369 
370 // d->QueryRetrieveWidget->deleteLater();
371 }
372 
373 //----------------------------------------------------------------------------
375 {
376  Q_D(DICOMAppWidget);
377  return d->Importer.displayImportSummary();
378 }
379 
380 //----------------------------------------------------------------------------
382 {
383  Q_D(DICOMAppWidget);
384  return d->Importer.setDisplayImportSummary(onOff);
385 }
386 
387 //----------------------------------------------------------------------------
389 {
390  Q_D(DICOMAppWidget);
391  return d->Importer.patientsAddedDuringImport();
392 }
393 
394 //----------------------------------------------------------------------------
396 {
397  Q_D(DICOMAppWidget);
398  return d->Importer.studiesAddedDuringImport();
399 }
400 
401 //----------------------------------------------------------------------------
403 {
404  Q_D(DICOMAppWidget);
405  return d->Importer.seriesAddedDuringImport();
406 }
407 
408 //----------------------------------------------------------------------------
410 {
411  Q_D(DICOMAppWidget);
412  return d->Importer.instancesAddedDuringImport();
413 }
414 
415 //----------------------------------------------------------------------------
417 {
418  Q_D(DICOMAppWidget);
419 
420  d->showUpdateSchemaDialog();
421  d->DICOMDatabase->updateSchemaIfNeeded();
422 }
423 
424 //----------------------------------------------------------------------------
425 void DICOMAppWidget::setDatabaseDirectory(const QString& directory)
426 {
427  Q_D(DICOMAppWidget);
428 
429  QSettings settings;
430  settings.setValue("DatabaseDirectory", directory);
431  settings.sync();
432 
433  //close the active DICOM database
434  d->DICOMDatabase->closeDatabase();
435 
436  //open DICOM database on the directory
437  QString databaseFileName = directory + QString("/ctkDICOM.sql");
438  try
439  {
440  d->DICOMDatabase->openDatabase( databaseFileName );
441 
442  CX_LOG_CHANNEL_INFO("dicom") << "Open Database " << databaseFileName.toStdString() << ", open= " << d->DICOMDatabase->isOpen();
443 // std::cout << "open database " << databaseFileName.toStdString() << ", open= " << d->DICOMDatabase->isOpen() << std::endl;
444  }
445  catch (std::exception e)
446  {
447  CX_LOG_CHANNEL_ERROR("dicom") << "Database error: " << qPrintable(d->DICOMDatabase->lastError());
448 // std::cerr << "Database error: " << qPrintable(d->DICOMDatabase->lastError()) << "\n";
449  d->DICOMDatabase->closeDatabase();
450  return;
451  }
452 
453  // update the database schema if needed and provide progress
455 
456  d->mDICOMModel.setDatabase(d->DICOMDatabase);
457  d->mDICOMModel.setEndLevel(ctkDICOMModel::SeriesType);
458  d->TreeView->resizeColumnToContents(0);
459  d->Importer.setDatabase(d->DICOMDatabase);
460 
461 // d->getQueryRetrieveWidget()->setRetrieveDatabase(d->DICOMDatabase);
462  d->ThumbnailsWidget->setDatabaseDirectory(directory);
463  d->ThumbnailsWidget->setDatabase(d->DICOMDatabase);
464  emit databaseDirectoryChanged(directory);
465 }
466 
467 //----------------------------------------------------------------------------
469 {
470  QSettings settings;
471  return settings.value("DatabaseDirectory").toString();
472 }
473 
474 //------------------------------------------------------------------------------
475 void DICOMAppWidget::setTagsToPrecache( const QStringList tags)
476 {
477  Q_D(DICOMAppWidget);
478  d->DICOMDatabase->setTagsToPrecache(tags);
479 }
480 
481 //------------------------------------------------------------------------------
483 {
484  Q_D(DICOMAppWidget);
485  return d->DICOMDatabase->tagsToPrecache();
486 }
487 
488 //----------------------------------------------------------------------------
489 ctkDICOMDatabase* DICOMAppWidget::database(){
490  Q_D(DICOMAppWidget);
491  return d->DICOMDatabase.data();
492 }
493 
494 //----------------------------------------------------------------------------
496 {
497  Q_D(DICOMAppWidget);
498 
499  d->getQueryRetrieveWidget()->show();
500  d->getQueryRetrieveWidget()->raise();
501 
502 }
503 
504 //----------------------------------------------------------------------------
506 {
507  Q_D(DICOMAppWidget);
508  d->mDICOMModel.reset();
509  emit this->queryRetrieveFinished();
510 }
511 
513 {
514  Q_D(DICOMAppWidget);
515  return d->getSelection()[ctkDICOMModel::PatientType];
516 }
518 {
519  Q_D(DICOMAppWidget);
520  return d->getSelection()[ctkDICOMModel::StudyType];
521 }
523 {
524  Q_D(DICOMAppWidget);
525  return d->getSelection()[ctkDICOMModel::SeriesType];
526 }
527 
528 //----------------------------------------------------------------------------
530 {
531  Q_D(DICOMAppWidget);
532  d->removeSelection();
533 }
534 
535 //----------------------------------------------------------------------------
537 {
538  Q_D(DICOMAppWidget);
539  d->mDICOMModel.setDatabase(d->DICOMDatabase);
540 }
541 
542 //----------------------------------------------------------------------------
544 {
545  Q_D(DICOMAppWidget);
546  d->mDICOMModel.reset();
547 }
548 
550 void DICOMAppWidget::onImportDirectory(QString directory)
551 {
552  Q_D(DICOMAppWidget);
553  d->Importer.onImportDirectory(directory);
554 }
555 
556 void DICOMAppWidget::onSelectionChanged(const QItemSelection&, const QItemSelection&)
557 {
558 }
559 
560 void DICOMAppWidget::onCurrentChanged(const QModelIndex& next, const QModelIndex& last)
561 {
562  Q_D(DICOMAppWidget);
563  d->ThumbnailsWidget->addThumbnails(next);
564 }
565 
566 void DICOMAppWidget::onModelSelected(const QModelIndex &index)
567 {
568  Q_D(DICOMAppWidget);
569 
570  ctkDICOMModel* model = const_cast<ctkDICOMModel*>(qobject_cast<const ctkDICOMModel*>(index.model()));
571 
572  if(model)
573  {
574  QModelIndex index0 = index.sibling(index.row(), 0);
575 
576  d->ActionRemove->setEnabled(
577  model->data(index0,ctkDICOMModel::TypeRole) == static_cast<int>(ctkDICOMModel::SeriesType) ||
578  model->data(index0,ctkDICOMModel::TypeRole) == static_cast<int>(ctkDICOMModel::StudyType) ||
579  model->data(index0,ctkDICOMModel::TypeRole) == static_cast<int>(ctkDICOMModel::PatientType) );
580  }
581  else
582  {
583  d->ActionRemove->setEnabled(false);
584  }
585 }
586 
587 //----------------------------------------------------------------------------
588 void DICOMAppWidget::onTreeCollapsed(const QModelIndex &index){
589  Q_UNUSED(index);
590  Q_D(DICOMAppWidget);
591  d->TreeView->resizeColumnToContents(0);
592 }
593 
594 //----------------------------------------------------------------------------
595 void DICOMAppWidget::onTreeExpanded(const QModelIndex &index){
596  Q_UNUSED(index);
597  Q_D(DICOMAppWidget);
598  d->TreeView->resizeColumnToContents(0);
599  d->TreeView->resizeColumnToContents(1);
600 }
601 
602 //----------------------------------------------------------------------------
604 {
605  Q_D(DICOMAppWidget);
606  d->ThumbnailsWidget->setThumbnailSize(QSize(val, val));
607 }
608 
610 {
611  Q_D(DICOMAppWidget);
612  d->ToolBar->addAction(action);
613 }
614 
615 
616 
617 } // namespace cx
#define CX_LOG_CHANNEL_INFO(channel)
Definition: cxLogger.h:121
void onTreeCollapsed(const QModelIndex &index)
ctkDICOMQueryRetrieveWidget * getQueryRetrieveWidget()
QStringList getSelectedSeries()
ctkDICOMQueryRetrieveWidget * QueryRetrieveWidget
Q_DECLARE_PUBLIC(DICOMAppWidget)
void onTreeExpanded(const QModelIndex &index)
virtual bool removeRows(int row, int count, const QModelIndex &parent=QModelIndex())
DICOMAppWidgetPrivate(DICOMAppWidget *)
ctkDICOMDatabase * database()
ctkDICOMFilterProxyModel DICOMProxyModel
std::map< ctkDICOMModel::IndexType, QStringList > getSelection() const
void addActionToToolbar(QAction *action)
void setDisplayImportSummary(bool)
virtual QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const
void onSelectionChanged(const QItemSelection &, const QItemSelection &)
QVariant value(const QString &key, const QVariant &defaultValue=QVariant()) const
Definition: cxSettings.cpp:99
QSharedPointer< ctkDICOMDatabase > DICOMDatabase
QSharedPointer< ctkDICOMThumbnailGenerator > ThumbnailGenerator
void onImportDirectory(QString directory)
void setTagsToPrecache(const QStringList tags)
DICOMModel ctkDICOMModel
void setValue(const QString &key, const QVariant &value)
Definition: cxSettings.cpp:91
QStringList getSelectedPatients()
QStringList getSelectedStudies()
void onCurrentChanged(const QModelIndex &, const QModelIndex &)
void databaseDirectoryChanged(const QString &)
QProgressDialog * UpdateSchemaProgress
QString databaseDirectory() const
Directory being used to store the dicom database.
Settings * settings()
Shortcut for accessing the settings instance.
Definition: cxSettings.cpp:42
DICOMAppWidget(QWidget *parent=0)
void queryRetrieveFinished()
void onThumbnailWidthSliderValueChanged(int val)
void setupUi(DICOMAppWidget *parent)
const QStringList tagsToPrecache()
void onModelSelected(const QModelIndex &index)
DICOMAppWidget *const q_ptr
void setDatabaseDirectory(const QString &directory)
Q_DECLARE_METATYPE(QPersistentModelIndex)
int patientsAddedDuringImport()
Accessors to status of last directory import operation.
#define CX_LOG_CHANNEL_ERROR(channel)
Definition: cxLogger.h:124
DICOMThumbnailListWidget * ThumbnailsWidget