CustusX  2023.01.05-dev+develop.0da12
An IGT application
cxDICOMModel.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 // Qt includes
22 #include <QStringList>
23 #include <QSqlDriver>
24 #include <QSqlError>
25 #include <QSqlQuery>
26 #include <QSqlRecord>
27 #include <QSqlResult>
28 
29 #include <QTime>
30 #include <QDebug>
31 
32 // dcmtk includes
33 #include "dcvrpn.h"
34 
35 // ctkDICOMCore includes
36 #include "cxDICOMModel.h"
37 #include "ctkLogger.h"
38 #include "boost/shared_ptr.hpp"
39 #include "ctkDICOMDatabase.h"
40 //#include "cxDicomImageReader.h"
41 #include "cxDicomModelNode.h"
42 
43 static ctkLogger logger ( "org.commontk.dicom.DICOMModel" );
44 
45 Q_DECLARE_METATYPE(Qt::CheckState);
46 Q_DECLARE_METATYPE(QStringList);
47 
48 namespace cx
49 {
50 
51 //------------------------------------------------------------------------------
53 {
54  Q_DECLARE_PUBLIC(DICOMModel);
55 protected:
56  DICOMModel* const q_ptr;
57 
58 public:
60  virtual ~DICOMModelPrivate();
61  void fetchChildren(const QModelIndex& indexValue);
62  NodePtr createNode(int row, const QModelIndex& parentValue)const;
63  DicomModelNode* nodeFromIndex(const QModelIndex& indexValue)const;
64  void remove(const QModelIndex& index);
65 
67  QSharedPointer<ctkDICOMDatabase> DataBase;
68 };
69 
71 {
73 }
74 
76 {
77 }
78 
79 DicomModelNode* DICOMModelPrivate::nodeFromIndex(const QModelIndex& indexValue)const
80 {
81  if (!indexValue.isValid())
82  return this->RootNode.get();
83  DicomModelNode* retval = reinterpret_cast<DicomModelNode*>(indexValue.internalPointer());
84  if (retval)
85  return retval;
86  return DicomModelNode::getNullNode().get();
87 }
88 
89 NodePtr DICOMModelPrivate::createNode(int row, const QModelIndex& parentValue)const
90 {
91  DicomModelNode* parent = this->nodeFromIndex(parentValue);
92  return DicomModelNode::createNode(row, parent, DataBase);
93 }
94 
95 void DICOMModelPrivate::fetchChildren(const QModelIndex& indexValue)
96 {
97  Q_Q(DICOMModel);
98 
99  DicomModelNode* node = this->nodeFromIndex(indexValue);
100 
101  if (!node->canFetchMore())
102  return;
103  if (!node->hasChildren())
104  return;
105 
106  q->beginInsertRows(indexValue, std::max<int>(0, node->getFetchedChildren().size()-1), node->getChildrenUID().size()-1);
107 
108  for (int i=node->getFetchedChildren().size(); i<node->getChildrenUID().size(); ++i)
109  {
110  this->createNode(i, indexValue);
111  }
112 
113  q->endInsertRows();
114 }
115 
116 void DICOMModelPrivate::remove(const QModelIndex& index)
117 {
118  DicomModelNode* node = this->nodeFromIndex(index);
119 
120  qDebug() << "Remove DICOM node " << node->getValue(0).toString();
121 
122  switch (node->getType())
123  {
125  DataBase->removeSeries(node->getUid());
126  break;
127  case DICOMModel::StudyType :
128  DataBase->removeStudy(node->getUid());
129  break;
131  DataBase->removePatient(node->getUid());
132  break;
133  default:
134  break;
135  }
136 
137  node->getParent()->removeChild(node->getRow());
138 }
139 
140 
141 //------------------------------------------------------------------------------
142 //------------------------------------------------------------------------------
143 
144 //------------------------------------------------------------------------------
145 //------------------------------------------------------------------------------
146 
147 DICOMModel::DICOMModel(QObject* parentObject)
148  : Superclass(parentObject)
149  , d_ptr(new DICOMModelPrivate(*this))
150 {
151  Q_D(DICOMModel);
152 }
153 
154 //------------------------------------------------------------------------------
156 {
157 }
158 
159 //------------------------------------------------------------------------------
160 bool DICOMModel::canFetchMore ( const QModelIndex & parentValue ) const
161 {
162  Q_D(const DICOMModel);
163  DicomModelNode* node = d->nodeFromIndex(parentValue);
164  return node->canFetchMore();
165 }
166 
167 //------------------------------------------------------------------------------
168 int DICOMModel::columnCount ( const QModelIndex & _parent ) const
169 {
170  Q_D(const DICOMModel);
171  Q_UNUSED(_parent);
172  return d->RootNode->getHeaders().size();
173 }
174 
175 //------------------------------------------------------------------------------
176 QVariant DICOMModel::data ( const QModelIndex & dataIndex, int role ) const
177 {
178  Q_D(const DICOMModel);
179 
180  if ( role == UIDRole )
181  {
182  DicomModelNode* node = d->nodeFromIndex(dataIndex);
183  return node->getUid();
184  }
185  else if ( role == TypeRole )
186  {
187  DicomModelNode* node = d->nodeFromIndex(dataIndex);
188  return node->getType();
189  }
190  else if (( role==Qt::DisplayRole )||( role==Qt::EditRole ))
191  {
192  DicomModelNode* node = d->nodeFromIndex(dataIndex);
193  return node->getValue(dataIndex.column());
194  }
195 
196  return QVariant();
197 }
198 
199 //------------------------------------------------------------------------------
200 void DICOMModel::fetchMore ( const QModelIndex & parentValue )
201 {
202  Q_D(DICOMModel);
203  d->fetchChildren(parentValue);
204 }
205 
206 //------------------------------------------------------------------------------
207 bool DICOMModel::hasChildren ( const QModelIndex & parentIndex ) const
208 {
209  Q_D(const DICOMModel);
210  // only items in the first columns have index, shortcut the following for speed issues.
211  if (parentIndex.column() > 0)
212  return false;
213 
214  DicomModelNode* node = d->nodeFromIndex(parentIndex);
215  return node->hasChildren();
216 }
217 
218 //------------------------------------------------------------------------------
219 QVariant DICOMModel::headerData(int section, Qt::Orientation orientation, int role)const
220 {
221  Q_D(const DICOMModel);
222 
223  if (role != Qt::DisplayRole)
224  return QVariant();
225 
226  if (orientation == Qt::Horizontal)
227  {
228  QStringList headers = d->RootNode->getHeaders();
229 
230  if (section < 0 || section >= headers.size())
231  return QVariant();
232 
233  return headers[section];
234  }
235 
236  return QVariant("");
237 }
238 
239 //------------------------------------------------------------------------------
240 QModelIndex DICOMModel::index ( int row, int column, const QModelIndex & parentIndex ) const
241 {
242  Q_D(const DICOMModel);
243 
244  if (parentIndex.column() > 0) // only the first column has children
245  return QModelIndex();
246 
247  DicomModelNode* parentNode = d->nodeFromIndex(parentIndex);
248  NodePtr node = parentNode->getFetchedChildForRow(row);
249 
250  if (node->isNull())
251  {
252  qDebug() << "DICOMModel::index() failed to get node for index";
253  return QModelIndex();
254  }
255 
256  return this->createIndex(row, column, node.get());
257 }
258 
259 //------------------------------------------------------------------------------
260 QModelIndex DICOMModel::parent ( const QModelIndex & indexValue ) const
261 {
262  Q_D(const DICOMModel);
263  if (!indexValue.isValid())
264  return QModelIndex();
265 
266  DicomModelNode* node = d->nodeFromIndex(indexValue);
267  DicomModelNode* parentNode = node->getParent();
268 
269  if (parentNode->isNull())
270  return QModelIndex(); // node is root
271  if (parentNode == d->RootNode.get())
272  return QModelIndex();
273 
274  return this->createIndex(parentNode->getRow(), 0, parentNode);
275 }
276 
277 //------------------------------------------------------------------------------
278 int DICOMModel::rowCount ( const QModelIndex & parentValue ) const
279 {
280  Q_D(const DICOMModel);
281  if (parentValue.column() > 0)
282  return 0;
283  DicomModelNode* node = d->nodeFromIndex(parentValue);
284  // Returns the amount of rows currently cached on the client.
285  return node->getFetchedChildren().size();
286 }
287 
288 //------------------------------------------------------------------------------
289 void DICOMModel::setDatabase(QSharedPointer<ctkDICOMDatabase> db)
290 {
291  Q_D(DICOMModel);
292 
293  this->beginResetModel();
294 
295  d->DataBase = db;
296  d->RootNode.reset();
297  d->RootNode = d->createNode(-1, QModelIndex());
298 
299  this->endResetModel();
300 }
301 
302 
303 //------------------------------------------------------------------------------
305 {
306  Q_D(const DICOMModel);
307  // deprecated
308  return SeriesType;
309 }
310 
311 //------------------------------------------------------------------------------
313 {
314  Q_D(DICOMModel);
315  // deprecated
316 }
317 
318 //------------------------------------------------------------------------------
320 {
321  Q_D(DICOMModel);
322  // this could probably be done in a more elegant way
323  this->setDatabase(d->DataBase);
324 }
325 
326 bool DICOMModel::removeRows(int row, int count, const QModelIndex& parent)
327 {
328  Q_D(DICOMModel);
329 
330  if (count==0)
331  return false;
332 
333  this->beginRemoveRows(parent, row, row+count-1);
334 
335  for (int i=row; i<row+count; ++i)
336  {
337  QModelIndex index = this->index(i, 0, parent);
338  d->remove(index);
339  }
340 
341  this->endRemoveRows();
342 
343  return true;
344 }
345 
346 //------------------------------------------------------------------------------
347 } //namespace cx
348 
349 
DicomModelNode * nodeFromIndex(const QModelIndex &indexValue) const
virtual int rowCount(const QModelIndex &parent=QModelIndex()) const
bool isNull() const
NodePtr createNode(int row, const QModelIndex &parentValue) const
void setEndLevel(DICOMModel::IndexType level)
virtual bool removeRows(int row, int count, const QModelIndex &parent=QModelIndex())
virtual void fetchMore(const QModelIndex &parent)
QString getUid() const
QStringList getChildrenUID() const
uids of all loaded and unloaded children.
void setDatabase(QSharedPointer< ctkDICOMDatabase > dataBase)
boost::shared_ptr< class DicomModelNode > NodePtr
virtual QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const
void removeChild(int index)
DicomModelNode * getParent() const
void remove(const QModelIndex &index)
virtual ~DICOMModelPrivate()
DICOMModelPrivate(DICOMModel &)
DICOMModel(QObject *parent=0)
DICOMModel *const q_ptr
void fetchChildren(const QModelIndex &indexValue)
bool hasChildren() const
virtual ~DICOMModel()
const std::vector< NodePtr > & getFetchedChildren() const
all children currently loaded (filled by fetchMore())
Q_DECLARE_METATYPE(Qt::CheckState)
static NodePtr createNode(int row, DicomModelNode *parent, QSharedPointer< ctkDICOMDatabase > dataBase)
virtual DICOMModel::IndexType getType() const =0
QSharedPointer< ctkDICOMDatabase > DataBase
virtual QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const
virtual bool hasChildren(const QModelIndex &parent=QModelIndex()) const
virtual QModelIndex parent(const QModelIndex &index) const
DICOMModel::IndexType endLevel() const
Set it before populating the model.
virtual bool canFetchMore(const QModelIndex &parent) const
static NodePtr getNullNode()
NodePtr getFetchedChildForRow(int row) const
bool canFetchMore() const
QVariant getValue(int column) const
virtual QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const
virtual int columnCount(const QModelIndex &parent=QModelIndex()) const
Namespace for all CustusX production code.
virtual void reset()