Medical Imaging Interaction Toolkit  2016.11.0
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,
6 Division of Medical and Biological Informatics.
7 All rights reserved.
8 
9 This software is distributed WITHOUT ANY WARRANTY; without
10 even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE.
12 
13 See LICENSE.txt or http://www.mitk.org for details.
14 
15 ===================================================================*/
16 
18 
19 //# Own includes
20 #include "QmitkCustomVariants.h"
21 #include "QmitkEnums.h"
22 #include "mitkNodePredicateBase.h"
23 #include "mitkProperties.h"
24 #include "mitkRenderingManager.h"
26 
27 //# Toolkit includes
28 #include <QFile>
29 #include <QIcon>
30 #include <itkCommand.h>
31 
32 //#CTORS/DTOR
34  mitk::NodePredicateBase *_Predicate,
35  QObject *parent)
36  : QAbstractTableModel(parent),
37  m_DataStorage(nullptr),
38  m_Predicate(nullptr),
39  m_BlockEvents(false),
40  m_SortDescending(false)
41 {
42  this->SetPredicate(_Predicate);
43  this->SetDataStorage(_DataStorage);
44 }
45 
47 {
48  // set data storage 0 to remove event listeners
49  this->SetDataStorage(nullptr);
50 }
51 
52 //# Public GETTER
54 {
55  return m_DataStorage.GetPointer();
56 }
57 
59 {
60  return m_Predicate;
61 }
62 
64 {
66 
67  if (index.isValid())
68  {
69  node = m_NodeSet.at(index.row());
70  }
71 
72  return node;
73 }
74 
75 QVariant QmitkDataStorageTableModel::headerData(int section, Qt::Orientation orientation, int role) const
76 {
77  QVariant headerData;
78 
79  // show only horizontal header
80  if (role == Qt::DisplayRole)
81  {
82  if (orientation == Qt::Horizontal)
83  {
84  // first column: "Name"
85  if (section == 0)
86  headerData = "Name";
87  else if (section == 1)
88  headerData = "Data Type";
89  else if (section == 2)
90  headerData = "Visibility";
91  }
92  else if (orientation == Qt::Vertical)
93  {
94  // show numbers for rows
95  headerData = section + 1;
96  }
97  }
98 
99  return headerData;
100 }
101 
102 Qt::ItemFlags QmitkDataStorageTableModel::flags(const QModelIndex &index) const
103 {
104  Qt::ItemFlags flags = QAbstractItemModel::flags(index);
105 
106  // name & visibility is editable
107  if (index.column() == 0)
108  {
109  flags |= Qt::ItemIsEditable;
110  }
111  else if (index.column() == 2)
112  {
113  flags |= Qt::ItemIsUserCheckable;
114  }
115 
116  return flags;
117 }
118 
119 int QmitkDataStorageTableModel::rowCount(const QModelIndex &) const
120 {
121  return m_NodeSet.size();
122 }
123 
124 int QmitkDataStorageTableModel::columnCount(const QModelIndex &) const
125 {
126  // show name, type and visible columnn
127  int columns = 3;
128  return columns;
129 }
130 
131 QVariant QmitkDataStorageTableModel::data(const QModelIndex &index, int role) const
132 {
133  QVariant data;
134 
135  if (index.isValid() && !m_NodeSet.empty())
136  {
137  mitk::DataNode::Pointer node = m_NodeSet.at(index.row());
138 
139  std::string nodeName = node->GetName();
140  if (nodeName.empty())
141  nodeName = "unnamed";
142 
143  // get name
144  if (index.column() == 0)
145  {
146  // get name of node (may also be edited)
147  if (role == Qt::DisplayRole || role == Qt::EditRole)
148  {
149  data = QFile::encodeName(nodeName.c_str());
150  }
151  else if (role == QmitkDataNodeRole)
152  {
153  data = QVariant::fromValue(node);
154  }
155  }
156  else if (index.column() == 1)
157  {
159 
160  // get type property of mitk::BaseData
161  if (role == Qt::DisplayRole)
162  {
163  data = nodeDescriptor->GetNameOfClass();
164  }
165  // show some nice icons for datatype
166  else if (role == Qt::DecorationRole)
167  {
168  data = nodeDescriptor->GetIcon();
169  }
170  }
171  else if (index.column() == 2)
172  {
173  // get visible property of mitk::BaseData
174  bool visibility = false;
175 
176  if (node->GetVisibility(visibility, nullptr) && role == Qt::CheckStateRole)
177  {
178  data = (visibility ? Qt::Checked : Qt::Unchecked);
179  } // node->GetVisibility(visibility, 0) && role == Qt::CheckStateRole
180 
181  } // index.column() == 2
182 
183  } // index.isValid() && !m_NodeSet.empty()
184  return data;
185 }
186 
187 //# Public SETTERS
189 {
190  // ensure that a new predicate is set in order to avoid unnecessary changed events
191  if (m_Predicate != _Predicate)
192  {
193  m_Predicate = _Predicate;
194  this->Reset();
195  }
196 }
197 
199 {
200  // only proceed if we have a new datastorage
201  if (m_DataStorage.GetPointer() != _DataStorage.GetPointer())
202  {
203  // if a data storage was set before remove old event listeners
204  if (m_DataStorage.IsNotNull())
205  {
209 
213  }
214 
215  // set new data storage
216  m_DataStorage = _DataStorage.GetPointer();
217 
218  // if new storage is not 0 subscribe for events
219  if (m_DataStorage.IsNotNull())
220  {
221  // subscribe for node added/removed events
225 
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
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 {
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.IsNotNull())
419  {
420  if (m_Predicate.IsNotNull())
421  // get subset
422  _NodeSet = m_DataStorage->GetSubset(m_Predicate);
423  // if predicate is NULL, select all nodes
424  else
425  {
426  _NodeSet = m_DataStorage->GetAll();
427  // remove ghost root node
428  }
429 
430  // finally add all nodes to the model
431  for (auto it = _NodeSet->begin(); it != _NodeSet->end(); it++)
432  {
433  // save node
434  this->AddNode(*it);
435  }
436  }
437 }
438 
439 void QmitkDataStorageTableModel::sort(int column, Qt::SortOrder order /*= Qt::AscendingOrder */)
440 {
441  bool sortDescending = (order == Qt::DescendingOrder) ? true : false;
442 
443  // do not sort twice !!! (dont know why, but qt calls this func twice. STUPID!)
444  /*
445  if(sortDescending != m_SortDescending)
446  {*/
447 
448  // m_SortDescending = sortDescending;
449 
451 
454 
455  if (column == 1)
457 
458  else if (column == 2)
460 
461  DataNodeCompareFunction compareFunc(_CompareCriteria, _CompareOperator);
462  std::sort(m_NodeSet.begin(), m_NodeSet.end(), compareFunc);
463 
464  QAbstractTableModel::beginResetModel();
465  QAbstractTableModel::endResetModel();
466  //}
467 }
468 
469 std::vector<mitk::DataNode *> QmitkDataStorageTableModel::GetNodeSet() const
470 {
471  return m_NodeSet;
472 }
473 
475  CompareOperator _CompareOperator)
476  : m_CompareCriteria(_CompareCriteria), m_CompareOperator(_CompareOperator)
477 {
478 }
479 
481  const mitk::DataNode::Pointer &_Right) const
482 {
483  switch (m_CompareCriteria)
484  {
485  case CompareByClassName:
486  if (m_CompareOperator == Less)
487  return (_Left->GetData()->GetNameOfClass() < _Right->GetData()->GetNameOfClass());
488  else
489  return (_Left->GetData()->GetNameOfClass() > _Right->GetData()->GetNameOfClass());
490  break;
491 
492  case CompareByVisibility:
493  {
494  bool _LeftVisibility = false;
495  bool _RightVisibility = false;
496  _Left->GetVisibility(_LeftVisibility, nullptr);
497  _Right->GetVisibility(_RightVisibility, nullptr);
498 
499  if (m_CompareOperator == Less)
500  return (_LeftVisibility < _RightVisibility);
501  else
502  return (_LeftVisibility > _RightVisibility);
503  }
504  break;
505 
506  // CompareByName:
507  default:
508  if (m_CompareOperator == Less)
509  return (_Left->GetName() < _Right->GetName());
510  else
511  return (_Left->GetName() > _Right->GetName());
512  break;
513  }
514 }
void RemoveListener(const AbstractDelegate &delegate) const
Definition: mitkMessage.h:397
QmitkDataStorageTableModel(mitk::DataStorage::Pointer _DataStorage, mitk::NodePredicateBase *_Predicate=nullptr, QObject *parent=nullptr)
void AddListener(const AbstractDelegate &delegate) const
Definition: mitkMessage.h:378
bool setData(const QModelIndex &index, const QVariant &value, int role) override
itk::SmartPointer< Self > Pointer
QmitkNodeQmitkNodeDescriptor is Decorator class for the mitk::DataNode which enhances certain mitk::D...
CompareCriteria
Specifies field of the property with which it will be sorted.
virtual QVariant data(const QModelIndex &index, int role) const override
virtual int rowCount(const QModelIndex &parent) const override
virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const override
virtual std::vector< mitk::DataNode * > GetNodeSet() const
bool operator()(const mitk::DataNode::Pointer &_Left, const mitk::DataNode::Pointer &_Right) const
The reimplemented compare function.
bool IsNotNull() const
BaseData * GetData() const
Get the data object (instance of BaseData, e.g., an Image) managed by this DataNode.
std::vector< mitk::DataNode * > m_NodeSet
mitk::BaseProperty * GetProperty(const char *propertyKey, const mitk::BaseRenderer *renderer=nullptr) const
Get the property (instance of BaseProperty) with key propertyKey from the PropertyList of the rendere...
void sort(int column, Qt::SortOrder order=Qt::AscendingOrder) override
Reimplemented sort function from QAbstractTableModel to enable sorting on the table.
itk::SmartPointer< const Self > ConstPointer
void SetDataStorage(mitk::DataStorage::Pointer _DataStorage)
ObjectType * GetPointer() const
virtual SetOfObjects::ConstPointer GetAll() const =0
returns a set of all data objects that are stored in the data storage
Abstract base class for properties.
mitk::DataNode::Pointer GetNode(const QModelIndex &index) const
mitk::DataStorage::Pointer m_DataStorage
SetOfObjects::ConstPointer GetSubset(const NodePredicateBase *condition) const
returns a set of data objects that meet the given condition(s)
static RenderingManager * GetInstance()
virtual QIcon GetIcon() const
virtual QString GetNameOfClass() const
DataStorageEvent AddNodeEvent
AddEvent is emitted whenever a new node has been added to the DataStorage.
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...
QmitkNodeDescriptor * GetDescriptor(const mitk::DataNode *_Node) const
DataStorageEvent RemoveNodeEvent
RemoveEvent is emitted directly before a node is removed from the DataStorage.
const mitk::DataStorage::Pointer GetDataStorage() 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...
Interface for evaluation conditions used in the DataStorage class GetSubset() method.
mitk::NodePredicateBase::Pointer m_Predicate
mitk::NodePredicateBase::Pointer GetPredicate() const
virtual 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)
virtual Qt::ItemFlags flags(const QModelIndex &index) const override
static QmitkNodeDescriptorManager * GetInstance()
Class for nodes of the DataTree.
Definition: mitkDataNode.h:66
void SetPredicate(mitk::NodePredicateBase *_Predicate)
CompareOperator
Specifies Ascending/descending ordering.
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.