Medical Imaging Interaction Toolkit  2018.4.99-389bf124
Medical Imaging Interaction Toolkit
QmitkDataStorageTableModel.cpp
Go to the documentation of this file.
1 /*============================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center (DKFZ)
6 All rights reserved.
7 
8 Use of this source code is governed by a 3-clause BSD license that can be
9 found in the LICENSE file.
10 
11 ============================================================================*/
12 
14 
15 //# Own includes
16 #include "QmitkCustomVariants.h"
17 #include "QmitkEnums.h"
18 #include "mitkNodePredicateBase.h"
19 #include "mitkProperties.h"
20 #include "mitkRenderingManager.h"
22 
23 //# Toolkit includes
24 #include <QFile>
25 #include <QIcon>
26 #include <itkCommand.h>
27 
28 //#CTORS/DTOR
30  mitk::NodePredicateBase *_Predicate,
31  QObject *parent)
32  : QAbstractTableModel(parent),
33  m_DataStorage(nullptr),
34  m_Predicate(nullptr),
35  m_BlockEvents(false),
36  m_SortDescending(false)
37 {
38  this->SetPredicate(_Predicate);
39  this->SetDataStorage(_DataStorage);
40 }
41 
43 {
44  // set data storage 0 to remove event listeners
45  this->SetDataStorage(nullptr);
46 }
47 
48 //# Public GETTER
50 {
51  return m_DataStorage.Lock();
52 }
53 
55 {
56  return m_Predicate;
57 }
58 
60 {
62 
63  if (index.isValid())
64  {
65  node = m_NodeSet.at(index.row());
66  }
67 
68  return node;
69 }
70 
71 QVariant QmitkDataStorageTableModel::headerData(int section, Qt::Orientation orientation, int role) const
72 {
73  QVariant headerData;
74 
75  // show only horizontal header
76  if (role == Qt::DisplayRole)
77  {
78  if (orientation == Qt::Horizontal)
79  {
80  // first column: "Name"
81  if (section == 0)
82  headerData = "Name";
83  else if (section == 1)
84  headerData = "Data Type";
85  else if (section == 2)
86  headerData = "Visibility";
87  }
88  else if (orientation == Qt::Vertical)
89  {
90  // show numbers for rows
91  headerData = section + 1;
92  }
93  }
94 
95  return headerData;
96 }
97 
98 Qt::ItemFlags QmitkDataStorageTableModel::flags(const QModelIndex &index) const
99 {
100  Qt::ItemFlags flags = QAbstractItemModel::flags(index);
101 
102  // name & visibility is editable
103  if (index.column() == 0)
104  {
105  flags |= Qt::ItemIsEditable;
106  }
107  else if (index.column() == 2)
108  {
109  flags |= Qt::ItemIsUserCheckable;
110  }
111 
112  return flags;
113 }
114 
115 int QmitkDataStorageTableModel::rowCount(const QModelIndex &) const
116 {
117  return m_NodeSet.size();
118 }
119 
120 int QmitkDataStorageTableModel::columnCount(const QModelIndex &) const
121 {
122  // show name, type and visible columnn
123  int columns = 3;
124  return columns;
125 }
126 
127 QVariant QmitkDataStorageTableModel::data(const QModelIndex &index, int role) const
128 {
129  QVariant data;
130 
131  if (index.isValid() && !m_NodeSet.empty())
132  {
133  mitk::DataNode::Pointer node = m_NodeSet.at(index.row());
134 
135  std::string nodeName = node->GetName();
136  if (nodeName.empty())
137  nodeName = "unnamed";
138 
139  // get name
140  if (index.column() == 0)
141  {
142  // get name of node (may also be edited)
143  if (role == Qt::DisplayRole || role == Qt::EditRole)
144  {
145  data = QString::fromStdString(nodeName);
146  }
147  else if (role == QmitkDataNodeRole)
148  {
149  data = QVariant::fromValue(node);
150  }
151  }
152  else if (index.column() == 1)
153  {
155 
156  // get type property of mitk::BaseData
157  if (role == Qt::DisplayRole)
158  {
159  data = nodeDescriptor->GetNameOfClass();
160  }
161  // show some nice icons for datatype
162  else if (role == Qt::DecorationRole)
163  {
164  data = nodeDescriptor->GetIcon(node);
165  }
166  }
167  else if (index.column() == 2)
168  {
169  // get visible property of mitk::BaseData
170  bool visibility = false;
171 
172  if (node->GetVisibility(visibility, nullptr) && role == Qt::CheckStateRole)
173  {
174  data = (visibility ? Qt::Checked : Qt::Unchecked);
175  } // node->GetVisibility(visibility, 0) && role == Qt::CheckStateRole
176 
177  } // index.column() == 2
178 
179  } // index.isValid() && !m_NodeSet.empty()
180  return data;
181 }
182 
183 //# Public SETTERS
185 {
186  // ensure that a new predicate is set in order to avoid unnecessary changed events
187  if (m_Predicate != _Predicate)
188  {
189  m_Predicate = _Predicate;
190  this->Reset();
191  }
192 }
193 
195 {
196  // only proceed if we have a new datastorage
197  if (m_DataStorage != _DataStorage)
198  {
199  // if a data storage was set before remove old event listeners
200  if (!m_DataStorage.IsExpired())
201  {
202  auto dataStorage = m_DataStorage.Lock();
203 
204  dataStorage->AddNodeEvent.RemoveListener(
207 
208  dataStorage->RemoveNodeEvent.RemoveListener(
211  }
212 
213  // set new data storage
214  m_DataStorage = _DataStorage;
215 
216  // if new storage is not 0 subscribe for events
217  if (!m_DataStorage.IsExpired())
218  {
219  auto dataStorage = m_DataStorage.Lock();
220 
221  // subscribe for node added/removed events
222  dataStorage->AddNodeEvent.AddListener(
225 
226  dataStorage->RemoveNodeEvent.AddListener(
229  }
230 
231  // Reset model (even if datastorage is 0->will be checked in Reset())
232  this->Reset();
233  }
234 }
235 
237 {
238  // garantuee no recursions when a new node event is thrown
239  if (!m_BlockEvents)
240  {
241  // if we have a predicate, check node against predicate first
242  if (m_Predicate.IsNotNull() && !m_Predicate->CheckNode(node))
243  return;
244 
245  // dont add nodes without data (formerly known as helper objects)
246  if (node->GetData() == nullptr)
247  return;
248 
249  // create listener commands to listen to changes in the name or the visibility of the node
250  itk::MemberCommand<QmitkDataStorageTableModel>::Pointer propertyModifiedCommand =
251  itk::MemberCommand<QmitkDataStorageTableModel>::New();
252  propertyModifiedCommand->SetCallbackFunction(this, &QmitkDataStorageTableModel::PropertyModified);
253 
254  mitk::BaseProperty *tempProperty = nullptr;
255 
256  // add listener for properties
257  tempProperty = node->GetProperty("visible");
258  if (tempProperty)
260  tempProperty->AddObserver(itk::ModifiedEvent(), propertyModifiedCommand);
261 
262  tempProperty = node->GetProperty("name");
263  if (tempProperty)
264  m_NamePropertyModifiedObserverTags[tempProperty] =
265  tempProperty->AddObserver(itk::ModifiedEvent(), propertyModifiedCommand);
266 
267  // emit beginInsertRows event
268  beginInsertRows(QModelIndex(), m_NodeSet.size(), m_NodeSet.size());
269 
270  // add node
271  m_NodeSet.push_back(const_cast<mitk::DataNode *>(node));
272 
273  // emit endInsertRows event
274  endInsertRows();
275  }
276 }
277 
279 {
280  // garantuee no recursions when a new node event is thrown
281  if (!m_BlockEvents)
282  {
283  // find corresponding node
284  auto nodeIt = std::find(m_NodeSet.begin(), m_NodeSet.end(), node);
285 
286  if (nodeIt != m_NodeSet.end())
287  {
288  // now: remove listeners for name property ...
289  mitk::BaseProperty *tempProperty = nullptr;
290 
291  tempProperty = (*nodeIt)->GetProperty("visible");
292  if (tempProperty)
293  tempProperty->RemoveObserver(m_VisiblePropertyModifiedObserverTags[tempProperty]);
294  m_VisiblePropertyModifiedObserverTags.erase(tempProperty);
295 
296  // ... and visibility property
297  tempProperty = (*nodeIt)->GetProperty("name");
298  if (tempProperty)
299  tempProperty->RemoveObserver(m_NamePropertyModifiedObserverTags[tempProperty]);
300  m_NamePropertyModifiedObserverTags.erase(tempProperty);
301 
302  // get an index from iterator
303  int row = std::distance(m_NodeSet.begin(), nodeIt);
304 
305  // emit beginRemoveRows event (QModelIndex is empty because we dont have a tree model)
306  this->beginRemoveRows(QModelIndex(), row, row);
307 
308  // remove node
309  m_NodeSet.erase(nodeIt);
310 
311  // emit endRemoveRows event
312  endRemoveRows();
313  }
314  }
315 }
316 
317 void QmitkDataStorageTableModel::PropertyModified(const itk::Object *caller, const itk::EventObject &)
318 {
319  if (!m_BlockEvents)
320  {
321  // get modified property
322  const mitk::BaseProperty *modifiedProperty = dynamic_cast<const mitk::BaseProperty *>(caller);
323 
324  if (modifiedProperty)
325  {
326  // find node that holds the modified property
327  int row = -1;
328  int column = -1;
329 
330  std::vector<mitk::DataNode *>::iterator it;
331  mitk::BaseProperty *visibilityProperty = nullptr;
332  mitk::BaseProperty *nameProperty = nullptr;
333 
334  // search for property that changed and emit datachanged on the corresponding ModelIndex
335  for (it = m_NodeSet.begin(); it != m_NodeSet.end(); it++)
336  {
337  // check for the visible property or the name property
338  visibilityProperty = (*it)->GetProperty("visible");
339  if (modifiedProperty == visibilityProperty)
340  {
341  column = 2;
342  break;
343  }
344 
345  nameProperty = (*it)->GetProperty("name");
346  if (modifiedProperty == nameProperty)
347  {
348  column = 0;
349  break;
350  }
351  }
352 
353  // if we have the property we have a valid iterator
354  if (it != m_NodeSet.end())
355  row = std::distance(m_NodeSet.begin(), it);
356 
357  // now emit the dataChanged signal
358  QModelIndex indexOfChangedProperty = index(row, column);
359  emit dataChanged(indexOfChangedProperty, indexOfChangedProperty);
360  }
361  }
362 }
363 
364 bool QmitkDataStorageTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
365 {
366  bool noErr = false;
367 
368  if (index.isValid() && (role == Qt::EditRole || role == Qt::CheckStateRole))
369  {
370  // any change events produced here should not be caught in this class
371  // --> set m_BlockEvents to true
372  m_BlockEvents = true;
373 
374  mitk::DataNode::Pointer node = m_NodeSet.at(index.row());
375 
376  if (index.column() == 0)
377  {
378  node->SetStringProperty("name", value.toString().toStdString().c_str());
379  }
380  else if (index.column() == 2)
381  {
382  node->SetBoolProperty("visible", (value.toInt() == Qt::Checked ? true : false));
384  }
385 
386  // inform listeners about changes
387  emit dataChanged(index, index);
388 
389  m_BlockEvents = false;
390  noErr = true;
391  }
392 
393  return noErr;
394 }
395 
396 //#Protected SETTER
398 {
399  mitk::DataStorage::SetOfObjects::ConstPointer _NodeSet;
400 
401  // remove all nodes now (dont use iterators because removing elements
402  // would invalidate the iterator)
403  // start at the last element: first in, last out
404  unsigned int i = m_NodeSet.size();
405  while (!m_NodeSet.empty())
406  {
407  --i;
408  this->RemoveNode(m_NodeSet.at(i));
409  }
410 
411  // normally now everything should be empty->just to be sure
412  // erase all arrays again
415  m_NodeSet.clear();
416 
417  // the whole reset depends on the fact if a data storage is set or not
418  if (!m_DataStorage.IsExpired())
419  {
420  auto dataStorage = m_DataStorage.Lock();
421 
422  if (m_Predicate.IsNotNull())
423  // get subset
424  _NodeSet = dataStorage->GetSubset(m_Predicate);
425  // if predicate is nullptr, select all nodes
426  else
427  {
428  _NodeSet = dataStorage->GetAll();
429  // remove ghost root node
430  }
431 
432  // finally add all nodes to the model
433  for (auto it = _NodeSet->begin(); it != _NodeSet->end(); it++)
434  {
435  // save node
436  this->AddNode(*it);
437  }
438  }
439 }
440 
441 void QmitkDataStorageTableModel::sort(int column, Qt::SortOrder order /*= Qt::AscendingOrder */)
442 {
443  bool sortDescending = (order == Qt::DescendingOrder) ? true : false;
444 
445  // do not sort twice !!! (dont know why, but qt calls this func twice. STUPID!)
446  /*
447  if(sortDescending != m_SortDescending)
448  {*/
449 
450  // m_SortDescending = sortDescending;
451 
453 
456 
457  if (column == 1)
459 
460  else if (column == 2)
462 
463  DataNodeCompareFunction compareFunc(_CompareCriteria, _CompareOperator);
464  std::sort(m_NodeSet.begin(), m_NodeSet.end(), compareFunc);
465 
466  QAbstractTableModel::beginResetModel();
467  QAbstractTableModel::endResetModel();
468  //}
469 }
470 
471 std::vector<mitk::DataNode *> QmitkDataStorageTableModel::GetNodeSet() const
472 {
473  return m_NodeSet;
474 }
475 
477  CompareOperator _CompareOperator)
478  : m_CompareCriteria(_CompareCriteria), m_CompareOperator(_CompareOperator)
479 {
480 }
481 
483  const mitk::DataNode::Pointer &_Right) const
484 {
485  switch (m_CompareCriteria)
486  {
487  case CompareByClassName:
488  if (m_CompareOperator == Less)
489  return (_Left->GetData()->GetNameOfClass() < _Right->GetData()->GetNameOfClass());
490  else
491  return (_Left->GetData()->GetNameOfClass() > _Right->GetData()->GetNameOfClass());
492  break;
493 
494  case CompareByVisibility:
495  {
496  bool _LeftVisibility = false;
497  bool _RightVisibility = false;
498  _Left->GetVisibility(_LeftVisibility, nullptr);
499  _Right->GetVisibility(_RightVisibility, nullptr);
500 
501  if (m_CompareOperator == Less)
502  return (_LeftVisibility < _RightVisibility);
503  else
504  return (_LeftVisibility > _RightVisibility);
505  }
506  break;
507 
508  // CompareByName:
509  default:
510  if (m_CompareOperator == Less)
511  return (_Left->GetName() < _Right->GetName());
512  else
513  return (_Left->GetName() > _Right->GetName());
514  break;
515  }
516 }
mitk::BaseProperty * GetProperty(const char *propertyKey, const mitk::BaseRenderer *renderer=nullptr, bool fallBackOnDataProperties=true) const
Get the property (instance of BaseProperty) with key propertyKey from the PropertyList of the rendere...
QmitkDataStorageTableModel(mitk::DataStorage::Pointer _DataStorage, mitk::NodePredicateBase *_Predicate=nullptr, QObject *parent=nullptr)
bool setData(const QModelIndex &index, const QVariant &value, int role) override
itk::SmartPointer< T > Lock() const
mitk::DataNode::Pointer GetNode(const QModelIndex &index) const
Decorator class for mitk::DataNode.
CompareCriteria
Specifies field of the property with which it will be sorted.
QVariant data(const QModelIndex &index, int role) const override
int rowCount(const QModelIndex &parent) const override
const mitk::DataStorage::Pointer GetDataStorage() const
QVariant headerData(int section, Qt::Orientation orientation, int role) const override
std::vector< mitk::DataNode * > m_NodeSet
virtual std::vector< mitk::DataNode * > GetNodeSet() const
void sort(int column, Qt::SortOrder order=Qt::AscendingOrder) override
Reimplemented sort function from QAbstractTableModel to enable sorting on the table.
void SetDataStorage(mitk::DataStorage::Pointer _DataStorage)
QmitkNodeDescriptor * GetDescriptor(const mitk::DataNode *node) const
BaseData * GetData() const
Get the data object (instance of BaseData, e.g., an Image) managed by this DataNode.
Abstract base class for properties.
mitk::DataStorage::Pointer m_DataStorage
static RenderingManager * GetInstance()
bool IsExpired() const noexcept
mitk::WeakPointer< mitk::DataStorage > m_DataStorage
virtual void RemoveNode(const mitk::DataNode *node)
std::map< mitk::BaseProperty *, unsigned long > m_VisiblePropertyModifiedObserverTags
Maps a property to an observer tag.
A struct that inherits from std::binary_function. You can use it in std::sort algorithm for sorting t...
virtual QString GetNameOfClass() const
std::map< mitk::BaseProperty *, unsigned long > m_NamePropertyModifiedObserverTags
Maps a property to an observer tag.
DataNodeCompareFunction(CompareCriteria _CompareCriteria=CompareByName, CompareOperator _CompareOperator=Less)
Creates a PropertyDataSetCompareFunction. A CompareCriteria and a CompareOperator must be given...
mitk::NodePredicateBase::Pointer GetPredicate() const
Interface for evaluation conditions used in the DataStorage class GetSubset() method.
mitk::NodePredicateBase::Pointer m_Predicate
virtual QIcon GetIcon(const mitk::DataNode *node) const
int columnCount(const QModelIndex &parent) const override
virtual void AddNode(const mitk::DataNode *node)
virtual void PropertyModified(const itk::Object *caller, const itk::EventObject &event)
Called when a single property was changed. The function searches through the list of nodes in this mo...
void RequestUpdateAll(RequestType type=REQUEST_UPDATE_ALL)
Qt::ItemFlags flags(const QModelIndex &index) const override
static QmitkNodeDescriptorManager * GetInstance()
bool operator()(const mitk::DataNode::Pointer &_Left, const mitk::DataNode::Pointer &_Right) const
The reimplemented compare function.
Class for nodes of the DataTree.
Definition: mitkDataNode.h:57
void SetPredicate(mitk::NodePredicateBase *_Predicate)
CompareOperator
Specifies Ascending/descending ordering.