Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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.