Fraxinus  17.12
An IGT application
cxDicomWidget.cpp
Go to the documentation of this file.
1 /*=========================================================================
2 This file is part of CustusX, an Image Guided Therapy Application.
3 
4 Copyright (c) 2008-2014, SINTEF Department of Medical Technology
5 All rights reserved.
6 
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9 
10 1. Redistributions of source code must retain the above copyright notice,
11  this list of conditions and the following disclaimer.
12 
13 2. Redistributions in binary form must reproduce the above copyright notice,
14  this list of conditions and the following disclaimer in the documentation
15  and/or other materials provided with the distribution.
16 
17 3. Neither the name of the copyright holder nor the names of its contributors
18  may be used to endorse or promote products derived from this software
19  without specific prior written permission.
20 
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 =========================================================================*/
32 
33 #include <QApplication>
34 #include <QDesktopWidget>
35 #include <QDir>
36 #undef REGISTERED
37 #include "ctkServiceTracker.h"
38 #include "ctkDICOMBrowser.h"
39 #include "ctkDICOMAppWidget.h"
40 #include "cxDICOMAppWidget.h"
41 #include "ctkDICOMTableManager.h"
42 #include "ctkDICOMObjectListWidget.h"
43 #include "ctkPluginContext.h"
44 #include "cxDicomWidget.h"
45 #include "cxProfile.h"
46 #include "cxTypeConversions.h"
47 #include "cxDicomConverter.h"
48 #include "cxLogger.h"
49 
50 #include "cxPatientModelService.h"
51 #include "cxDicomImageReader.h"
52 #include "cxVisServices.h"
53 #include "cxViewService.h"
54 #include "cxSettings.h"
55 
56 namespace cx
57 {
58 
59 DicomWidget::DicomWidget(ctkPluginContext *context, QWidget *parent) :
60  BaseWidget(parent, "dicom_widget", "DICOM"),
61  mVerticalLayout(new QVBoxLayout(this)),
62  mBrowser(NULL),
63  mContext(context),
64  mDicomShowAdvancedSettingsString("Dicom/ShowAdvanced")
65 {
66  this->setModified();
67 
68 }
69 
71 {
72  this->deleteDICOMDB();
73 }
74 
76 {
77  if (!mBrowser)
78  {
79  this->createUI();
80  }
81 }
82 
83 void DicomWidget::createUI()
84 {
85  if (mBrowser)
86  return;
87 
88  this->setToolTip("Import DICOM data");
89 
90  mViewHeaderAction = this->createAction(this,
91  QIcon(":/icons/open_icon_library/eye.png.png"),
92  "View info", "View the header info for the first selected series",
93  SLOT(onViewHeader()));
94 
95  mImportIntoCustusXAction = this->createAction(this,
96  QIcon(":/icons/open_icon_library/arrow-right-3.png"),
97  "Import selected", "Import the selected DICOM series into the application as a volume",
98  SLOT(onImportIntoCustusXAction()));
99 
100  mDetailsAction = this->createAction(this,
101  QIcon(":/icons/open_icon_library/system-run-5.png"),
102  "Advanced", "Toggle advanced options",
103  SLOT(toggleDetailsSlot()));
104 
105  mBrowser = new DICOMAppWidget;
106  mBrowser->addActionToToolbar(mViewHeaderAction);
107  mBrowser->addActionToToolbar(mImportIntoCustusXAction);
108  mBrowser->addActionToToolbar(mDetailsAction);
109  this->showOrHideDetails();
110 
111  mVerticalLayout->setMargin(0);
112  mVerticalLayout->addWidget(mBrowser);
113 
114  this->setupDatabaseDirectory();
115 }
116 
117 void DicomWidget::toggleDetailsSlot()
118 {
119  bool newShowAdvancedValue = !settings()->value(mDicomShowAdvancedSettingsString, "true").toBool();
120  settings()->setValue(mDicomShowAdvancedSettingsString, newShowAdvancedValue);
121  this->showOrHideDetails();
122 }
123 
124 void DicomWidget::showOrHideDetails()
125 {
126  bool showAdvanced = settings()->value(mDicomShowAdvancedSettingsString).toBool();
127 
128  mViewHeaderAction->setVisible(showAdvanced);
129  foreach (QAction* action, mBrowser->getAdvancedActions())
130  {
131  action->setVisible(showAdvanced);
132  }
133 }
134 
135 
137 {
138  QString databaseDirectory = profile()->getSettingsPath() + "/DICOMDatabase";
139 
140  return databaseDirectory;
141 }
142 
143 void DicomWidget::setupDatabaseDirectory()
144 {
145  QString databaseDirectory = this->getDICOMDatabaseDirectory();
146 
147  QDir qdir(databaseDirectory);
148  if ( !qdir.exists(databaseDirectory) )
149  {
150  if ( !qdir.mkpath(databaseDirectory) )
151  {
152  CX_LOG_CHANNEL_ERROR("dicom") << "Could not create database directory \"" << databaseDirectory;
153  }
154  }
155 
156  CX_LOG_CHANNEL_INFO("dicom") << "DatabaseDirectory set to: " << databaseDirectory;
157  mBrowser->setDatabaseDirectory(databaseDirectory);
158 }
159 
160 QStringList DicomWidget::currentSeriesSelection()
161 {
162  return mBrowser->getSelectedSeries();
163 }
164 
165 void DicomWidget::onViewHeader()
166 {
167  QStringList series = this->currentSeriesSelection();
168  std::cout << series.join("\n").toStdString() << std::endl;
169 
170  QStringList files;
171  for (int i=0; i<series.size(); ++i)
172  {
173  QStringList current = this->getDatabase()->filesForSeries(series[i]);
174  files.append(current);
175  }
176  files.sort();
177 
178  ctkDICOMObjectListWidget* window = new ctkDICOMObjectListWidget;
179  window->setWindowTitle("DICOM File Header");
180  window->setFileList(files);
181 
182  QWidget* screen = qApp->desktop()->screen(qApp->desktop()->screenNumber(this));
183  QRect rect = screen->geometry();
184  rect.setWidth(rect.width()*0.66);
185  window->setGeometry(rect);
186 
187  window->show();
188 }
189 
190 void DicomWidget::onImportIntoCustusXAction()
191 {
192  QStringList series = this->currentSeriesSelection();
193 
194  if (series.empty())
195  CX_LOG_CHANNEL_WARNING("dicom") << "No DICOM series selected, import failed.";
196 
197  for (unsigned i=0; i<series.size(); ++i)
198  {
199  this->importSeries(series[i]);
200  }
201 }
202 
203 void DicomWidget::deleteDICOMDB()
204 {
205  CX_LOG_CHANNEL_INFO("dicom") << "Deleting DICOM database: " << this->getDICOMDatabaseDirectory();
206  bool autoDeleteDICOMDB = settings()->value("Automation/autoDeleteDICOMDatabase").toBool();
207  if(autoDeleteDICOMDB)
208  {
209  ctkDICOMDatabase* database = this->getDatabase();
210  if(database)
211  {
212  QStringList patients = database->patients();
213  foreach(QString patient , patients)
214  {
215  this->getDatabase()->removePatient(patient);
216  }
217  }
218  }
219 }
220 
221 void DicomWidget::importSeries(QString seriesUid)
222 {
223  cx::DicomConverter converter;
224  converter.setDicomDatabase(this->getDatabase());
225  cx::ImagePtr convertedImage = converter.convertToImage(seriesUid);
226 
227  if (!convertedImage)
228  {
229  reportError(QString("Failed to convert DICOM series %1").arg(seriesUid));
230  return;
231  }
232 
233  this->loadIntoPatientModel(convertedImage, seriesUid);
234 }
235 
236 void DicomWidget::loadIntoPatientModel(ImagePtr image, QString seriesUid)
237 {
238  VisServicesPtr services = VisServices::create(mContext);
239 
240  if (!services->patient()->isNull())
241  {
242  services->patient()->insertData(image);
243  services->view()->autoShowData(image);
244  report(QString("Loaded DICOM series %1 as %2").arg(seriesUid).arg(image->getName()));
245  }
246  else
247  {
248  reportWarning(QString("Failed to load DICOM series %1 as %2: no PatientModelService.").arg(seriesUid).arg(image->getName()));
249  }
250 }
251 
252 ctkDICOMDatabase* DicomWidget::getDatabase() const
253 {
254  if(mBrowser)
255  return mBrowser->database();
256  else
257  return NULL;
258 }
259 
260 } /* namespace cx */
#define CX_LOG_CHANNEL_INFO(channel)
Definition: cxLogger.h:129
cxResource_EXPORT ProfilePtr profile()
Definition: cxProfile.cpp:181
QStringList getSelectedSeries()
void reportError(QString msg)
Definition: cxLogger.cpp:92
boost::shared_ptr< class VisServices > VisServicesPtr
Definition: cxMainWindow.h:61
ctkDICOMDatabase * database()
virtual void prePaintEvent()
boost::shared_ptr< class Image > ImagePtr
Definition: cxDicomWidget.h:48
void setDicomDatabase(ctkDICOMDatabase *database)
static VisServicesPtr create(ctkPluginContext *context)
void addActionToToolbar(QAction *action)
#define CX_LOG_CHANNEL_WARNING(channel)
Definition: cxLogger.h:131
QVariant value(const QString &key, const QVariant &defaultValue=QVariant()) const
Definition: cxSettings.cpp:87
DicomWidget(ctkPluginContext *context, QWidget *parent=0)
QAction * createAction(QObject *parent, QIcon iconName, QString text, QString tip, T slot, QLayout *layout=NULL, QToolButton *button=new QToolButton())
Definition: cxBaseWidget.h:150
void setValue(const QString &key, const QVariant &value)
Definition: cxSettings.cpp:79
ImagePtr convertToImage(QString seriesUid)
void reportWarning(QString msg)
Definition: cxLogger.cpp:91
Settings * settings()
Shortcut for accessing the settings instance.
Definition: cxSettings.cpp:42
QString getDICOMDatabaseDirectory()
ctkDICOMDatabase * getDatabase() const
Interface for QWidget which handles widgets uniformly for the system.
Definition: cxBaseWidget.h:109
void report(QString msg)
Definition: cxLogger.cpp:90
QList< QAction * > getAdvancedActions() const
virtual ~DicomWidget()
void setDatabaseDirectory(const QString &directory)
#define CX_LOG_CHANNEL_ERROR(channel)
Definition: cxLogger.h:132
Namespace for all CustusX production code.