CustusX  15.8
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  retval[type] << uid;
288  retval[type].removeDuplicates();
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->TreeView->setSelectionMode(QAbstractItemView::ExtendedSelection);
333  d->DICOMProxyModel.setSourceModel(&d->mDICOMModel);
334  d->TreeView->setModel(&d->mDICOMModel);
335 
336  d->ThumbnailsWidget->setThumbnailSize(
337  QSize(d->ThumbnailWidthSlider->value(), d->ThumbnailWidthSlider->value()));
338 
339  // Treeview signals
340  connect(d->TreeView, SIGNAL(collapsed(QModelIndex)), this, SLOT(onTreeCollapsed(QModelIndex)));
341  connect(d->TreeView, SIGNAL(expanded(QModelIndex)), this, SLOT(onTreeExpanded(QModelIndex)));
342 
343  //Set ToolBar button style
344  d->ToolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
345 
346 // //Initialize Q/R widget
347 // d->QueryRetrieveWidget = new ctkDICOMQueryRetrieveWidget();
348 // d->QueryRetrieveWidget->setWindowModality ( Qt::ApplicationModal );
349 
350  connect(d->TreeView->selectionModel(),
351  SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
352  this,
353  SLOT(onSelectionChanged(const QItemSelection&, const QItemSelection&)));
354  connect(d->TreeView->selectionModel(),
355  SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)),
356  this,
357  SLOT(onCurrentChanged(const QModelIndex&, const QModelIndex&)));
358 
359  //connect signal and slots
360  connect(d->TreeView, SIGNAL(clicked(QModelIndex)), this, SLOT(onModelSelected(QModelIndex)));
361 
362 // connect(d->QueryRetrieveWidget, SIGNAL(canceled()), d->QueryRetrieveWidget, SLOT(hide()) );
363 // connect(d->QueryRetrieveWidget, SIGNAL(canceled()), this, SLOT(onQueryRetrieveFinished()) );
364 }
365 
366 //----------------------------------------------------------------------------
368 {
369  Q_D(DICOMAppWidget);
370 
371 // d->QueryRetrieveWidget->deleteLater();
372 }
373 
374 //----------------------------------------------------------------------------
376 {
377  Q_D(DICOMAppWidget);
378  return d->Importer.displayImportSummary();
379 }
380 
381 //----------------------------------------------------------------------------
383 {
384  Q_D(DICOMAppWidget);
385  return d->Importer.setDisplayImportSummary(onOff);
386 }
387 
388 //----------------------------------------------------------------------------
390 {
391  Q_D(DICOMAppWidget);
392  return d->Importer.patientsAddedDuringImport();
393 }
394 
395 //----------------------------------------------------------------------------
397 {
398  Q_D(DICOMAppWidget);
399  return d->Importer.studiesAddedDuringImport();
400 }
401 
402 //----------------------------------------------------------------------------
404 {
405  Q_D(DICOMAppWidget);
406  return d->Importer.seriesAddedDuringImport();
407 }
408 
409 //----------------------------------------------------------------------------
411 {
412  Q_D(DICOMAppWidget);
413  return d->Importer.instancesAddedDuringImport();
414 }
415 
416 //----------------------------------------------------------------------------
418 {
419  Q_D(DICOMAppWidget);
420 
421  d->showUpdateSchemaDialog();
422  d->DICOMDatabase->updateSchemaIfNeeded();
423 }
424 
425 //----------------------------------------------------------------------------
426 void DICOMAppWidget::setDatabaseDirectory(const QString& directory)
427 {
428  Q_D(DICOMAppWidget);
429 
430  QSettings settings;
431  settings.setValue("DatabaseDirectory", directory);
432  settings.sync();
433 
434  //close the active DICOM database
435  d->DICOMDatabase->closeDatabase();
436 
437  //open DICOM database on the directory
438  QString databaseFileName = directory + QString("/ctkDICOM.sql");
439  try
440  {
441  d->DICOMDatabase->openDatabase( databaseFileName );
442 
443  CX_LOG_CHANNEL_INFO("dicom") << "Open Database " << databaseFileName.toStdString() << ", open= " << d->DICOMDatabase->isOpen();
444 // std::cout << "open database " << databaseFileName.toStdString() << ", open= " << d->DICOMDatabase->isOpen() << std::endl;
445  }
446  catch (std::exception e)
447  {
448  CX_LOG_CHANNEL_ERROR("dicom") << "Database error: " << qPrintable(d->DICOMDatabase->lastError());
449 // std::cerr << "Database error: " << qPrintable(d->DICOMDatabase->lastError()) << "\n";
450  d->DICOMDatabase->closeDatabase();
451  return;
452  }
453 
454  // update the database schema if needed and provide progress
456 
457  d->mDICOMModel.setDatabase(d->DICOMDatabase);
458  d->mDICOMModel.setEndLevel(ctkDICOMModel::SeriesType);
459  d->TreeView->resizeColumnToContents(0);
460  d->Importer.setDatabase(d->DICOMDatabase);
461 
462 // d->getQueryRetrieveWidget()->setRetrieveDatabase(d->DICOMDatabase);
463  d->ThumbnailsWidget->setDatabaseDirectory(directory);
464  d->ThumbnailsWidget->setDatabase(d->DICOMDatabase);
465  emit databaseDirectoryChanged(directory);
466 }
467 
468 //----------------------------------------------------------------------------
470 {
471  QSettings settings;
472  return settings.value("DatabaseDirectory").toString();
473 }
474 
475 //------------------------------------------------------------------------------
476 void DICOMAppWidget::setTagsToPrecache( const QStringList tags)
477 {
478  Q_D(DICOMAppWidget);
479  d->DICOMDatabase->setTagsToPrecache(tags);
480 }
481 
482 //------------------------------------------------------------------------------
484 {
485  Q_D(DICOMAppWidget);
486  return d->DICOMDatabase->tagsToPrecache();
487 }
488 
489 //----------------------------------------------------------------------------
490 ctkDICOMDatabase* DICOMAppWidget::database(){
491  Q_D(DICOMAppWidget);
492  return d->DICOMDatabase.data();
493 }
494 
495 //----------------------------------------------------------------------------
497 {
498  Q_D(DICOMAppWidget);
499 
500  d->getQueryRetrieveWidget()->show();
501  d->getQueryRetrieveWidget()->raise();
502 
503 }
504 
505 //----------------------------------------------------------------------------
507 {
508  Q_D(DICOMAppWidget);
509  d->mDICOMModel.reset();
510  emit this->queryRetrieveFinished();
511 }
512 
514 {
515  Q_D(DICOMAppWidget);
516  return d->getSelection()[ctkDICOMModel::PatientType];
517 }
519 {
520  Q_D(DICOMAppWidget);
521  return d->getSelection()[ctkDICOMModel::StudyType];
522 }
524 {
525  Q_D(DICOMAppWidget);
526  return d->getSelection()[ctkDICOMModel::SeriesType];
527 }
528 
529 //----------------------------------------------------------------------------
531 {
532  Q_D(DICOMAppWidget);
533  d->removeSelection();
534 }
535 
536 //----------------------------------------------------------------------------
538 {
539  Q_D(DICOMAppWidget);
540  d->mDICOMModel.setDatabase(d->DICOMDatabase);
541 }
542 
543 //----------------------------------------------------------------------------
545 {
546  Q_D(DICOMAppWidget);
547  d->mDICOMModel.reset();
548 }
549 
551 void DICOMAppWidget::onImportDirectory(QString directory)
552 {
553  Q_D(DICOMAppWidget);
554  d->Importer.onImportDirectory(directory);
555 }
556 
557 void DICOMAppWidget::onSelectionChanged(const QItemSelection&, const QItemSelection&)
558 {
559 }
560 
561 void DICOMAppWidget::onCurrentChanged(const QModelIndex& next, const QModelIndex& last)
562 {
563  Q_D(DICOMAppWidget);
564  d->ThumbnailsWidget->addThumbnails(next);
565 }
566 
567 void DICOMAppWidget::onModelSelected(const QModelIndex &index)
568 {
569  Q_D(DICOMAppWidget);
570 
571  ctkDICOMModel* model = const_cast<ctkDICOMModel*>(qobject_cast<const ctkDICOMModel*>(index.model()));
572 
573  if(model)
574  {
575  QModelIndex index0 = index.sibling(index.row(), 0);
576 
577  d->ActionRemove->setEnabled(
578  model->data(index0,ctkDICOMModel::TypeRole) == static_cast<int>(ctkDICOMModel::SeriesType) ||
579  model->data(index0,ctkDICOMModel::TypeRole) == static_cast<int>(ctkDICOMModel::StudyType) ||
580  model->data(index0,ctkDICOMModel::TypeRole) == static_cast<int>(ctkDICOMModel::PatientType) );
581  }
582  else
583  {
584  d->ActionRemove->setEnabled(false);
585  }
586 }
587 
588 //----------------------------------------------------------------------------
589 void DICOMAppWidget::onTreeCollapsed(const QModelIndex &index){
590  Q_UNUSED(index);
591  Q_D(DICOMAppWidget);
592  d->TreeView->resizeColumnToContents(0);
593 }
594 
595 //----------------------------------------------------------------------------
596 void DICOMAppWidget::onTreeExpanded(const QModelIndex &index){
597  Q_UNUSED(index);
598  Q_D(DICOMAppWidget);
599  d->TreeView->resizeColumnToContents(0);
600  d->TreeView->resizeColumnToContents(1);
601 }
602 
603 //----------------------------------------------------------------------------
605 {
606  Q_D(DICOMAppWidget);
607  d->ThumbnailsWidget->setThumbnailSize(QSize(val, val));
608 }
609 
611 {
612  Q_D(DICOMAppWidget);
613  d->ToolBar->addAction(action);
614 }
615 
616 
617 
618 } // 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:87
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:79
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