Medical Imaging Interaction Toolkit  2018.4.99-389bf124
Medical Imaging Interaction Toolkit
QmitkDataStorageListModel.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 // mitk
17 #include "mitkStringProperty.h"
18 
19 //# Toolkit includes
20 // itk
21 #include "itkCommand.h"
22 
25  QObject *parent)
26  : QAbstractListModel(parent), m_NodePredicate(nullptr), m_DataStorage(nullptr), m_BlockEvents(false)
27 {
28  this->SetPredicate(pred);
29  this->SetDataStorage(dataStorage);
30 }
31 
33 {
34  // set data storage to nullptr so that the event listener gets removed
35  this->SetDataStorage(nullptr);
36 }
37 
39 {
40  if (m_DataStorage == dataStorage)
41  {
42  return;
43  }
44 
45  // remove old listeners
46  if (m_DataStorage != nullptr)
47  {
48  m_DataStorage->AddNodeEvent.RemoveListener(
51 
52  m_DataStorage->RemoveNodeEvent.RemoveListener(
55 
56  m_DataStorage->RemoveObserver(m_DataStorageDeleteObserverTag);
57  m_DataStorageDeleteObserverTag = 0;
58  }
59 
60  m_DataStorage = dataStorage;
61 
62  if (m_DataStorage != nullptr)
63  {
64  // subscribe for node added/removed events
67 
68  m_DataStorage->RemoveNodeEvent.AddListener(
71 
72  // add ITK delete listener on data storage
73  itk::MemberCommand<QmitkDataStorageListModel>::Pointer deleteCommand =
74  itk::MemberCommand<QmitkDataStorageListModel>::New();
75  deleteCommand->SetCallbackFunction(this, &QmitkDataStorageListModel::OnDataStorageDeleted);
76  m_DataStorageDeleteObserverTag = m_DataStorage->AddObserver(itk::DeleteEvent(), deleteCommand);
77  }
78 
79  // reset/rebuild model
80  reset();
81 }
82 
83 Qt::ItemFlags QmitkDataStorageListModel::flags(const QModelIndex &) const
84 {
85  return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
86 }
87 
88 QVariant QmitkDataStorageListModel::data(const QModelIndex &index, int role) const
89 {
90  if (role == Qt::DisplayRole && index.isValid())
91  {
92  const mitk::DataNode *node = std::get<NODE>(m_NodesAndObserverTags.at(index.row()));
93  return QVariant(QString::fromStdString(node->GetName()));
94  }
95  else
96  {
97  return QVariant();
98  }
99 }
100 
101 QVariant QmitkDataStorageListModel::headerData(int /*section*/, Qt::Orientation /*orientation*/, int /*role*/) const
102 {
103  return QVariant(tr("Nodes"));
104 }
105 
106 int QmitkDataStorageListModel::rowCount(const QModelIndex & /*parent*/) const
107 {
108  return m_NodesAndObserverTags.size();
109 }
110 
111 std::vector<mitk::DataNode *> QmitkDataStorageListModel::GetDataNodes() const
112 {
113  auto size = m_NodesAndObserverTags.size();
114  std::vector<mitk::DataNode *> result(size);
115  for (std::size_t i = 0; i < size; ++i)
116  {
117  result[i] = std::get<NODE>(m_NodesAndObserverTags[i]);
118  }
119  return result;
120 }
121 
123 {
124  return m_DataStorage;
125 }
126 
128 {
129  m_NodePredicate = pred;
130 
131  // in a prior implementation the call to beginResetModel() been after reset().
132  // Should this actually be the better order of calls, please document!
133  QAbstractListModel::beginResetModel();
134  reset();
135  QAbstractListModel::endResetModel();
136 }
137 
139 {
140  return m_NodePredicate;
141 }
142 
144 {
145  mitk::DataStorage::SetOfObjects::ConstPointer modelNodes;
146 
147  if (m_DataStorage != nullptr)
148  {
149  if (m_NodePredicate != nullptr)
150  {
151  modelNodes = m_DataStorage->GetSubset(m_NodePredicate);
152  }
153  else
154  {
155  modelNodes = m_DataStorage->GetAll();
156  }
157  }
158 
160 
161  // add all filtered nodes to our list
162  if (modelNodes != nullptr)
163  {
164  for (auto &node : *modelNodes)
165  {
166  AddNodeToInternalList(node);
167  }
168  }
169 }
170 
172 {
173  if (m_DataStorage != nullptr)
174  {
175  itk::MemberCommand<QmitkDataStorageListModel>::Pointer nodeModifiedCommand;
176  // add modified observer
177  nodeModifiedCommand = itk::MemberCommand<QmitkDataStorageListModel>::New();
178  nodeModifiedCommand->SetCallbackFunction(this, &QmitkDataStorageListModel::OnDataNodeModified);
179  unsigned long nodeObserverTag = node->AddObserver(itk::ModifiedEvent(), nodeModifiedCommand);
180 
181  itk::MemberCommand<QmitkDataStorageListModel>::Pointer dataModifiedCommand;
182  unsigned long dataObserverTag = 0;
183  // add modified observer
184  if (node->GetData() != nullptr)
185  {
186  dataModifiedCommand = itk::MemberCommand<QmitkDataStorageListModel>::New();
187  dataModifiedCommand->SetCallbackFunction(this, &QmitkDataStorageListModel::OnDataModified);
188  dataObserverTag = node->GetData()->AddObserver(itk::ModifiedEvent(), dataModifiedCommand);
189  }
190 
191  m_NodesAndObserverTags.push_back(std::make_tuple(node, nodeObserverTag, dataObserverTag));
192  }
193 }
194 
196 {
197  for (auto &iter : m_NodesAndObserverTags)
198  {
199  auto node = std::get<NODE>(iter);
200  if (node != nullptr)
201  {
202  node->RemoveObserver(std::get<NODE_OBSERVER>(iter));
203  if (node->GetData() != nullptr)
204  {
205  node->GetData()->RemoveObserver(std::get<DATA_OBSERVER>(iter));
206  }
207  }
208  }
209  m_NodesAndObserverTags.clear();
210 }
211 
213 {
214  for (auto iter = m_NodesAndObserverTags.begin(); iter != m_NodesAndObserverTags.end(); ++iter)
215  {
216  if (std::get<NODE>(*iter) == node)
217  {
218  node->RemoveObserver(std::get<NODE_OBSERVER>(*iter));
219  if (node->GetData() != nullptr)
220  {
221  node->GetData()->RemoveObserver(std::get<DATA_OBSERVER>(*iter));
222  }
223  m_NodesAndObserverTags.erase(iter); // invalidate iter
224  break;
225  }
226  }
227 }
228 
230 {
231  // guarantee no recursions when a new node event is thrown
232  if (!m_BlockEvents)
233  {
234  m_BlockEvents = true;
235 
236  // check if node should be added to the model
237  bool addNode = true;
238  if (m_NodePredicate && !m_NodePredicate->CheckNode(node))
239  addNode = false;
240 
241  if (addNode)
242  {
243  int newIndex = m_NodesAndObserverTags.size();
244  beginInsertRows(QModelIndex(), newIndex, newIndex);
245  AddNodeToInternalList(const_cast<mitk::DataNode *>(node));
246  endInsertRows();
247  }
248 
249  m_BlockEvents = false;
250  }
251 }
252 
254 {
255  // guarantee no recursions when a new node event is thrown
256  if (!m_BlockEvents)
257  {
258  m_BlockEvents = true;
259 
260  int row = 0;
261  for (auto iter = m_NodesAndObserverTags.begin(); iter != m_NodesAndObserverTags.end(); ++iter, ++row)
262  {
263  if (std::get<NODE>(*iter) == node)
264  {
265  // node found, remove it
266  beginRemoveRows(QModelIndex(), row, row);
267  RemoveNodeFromInternalList(std::get<NODE>(*iter));
268  endRemoveRows();
269  break;
270  }
271  }
272  }
273 
274  m_BlockEvents = false;
275 }
276 
277 void QmitkDataStorageListModel::OnDataNodeModified(const itk::Object *caller, const itk::EventObject & /*event*/)
278 {
279  if (m_BlockEvents)
280  return;
281 
282  const mitk::DataNode *modifiedNode = dynamic_cast<const mitk::DataNode *>(caller);
283  if (modifiedNode)
284  {
285  QModelIndex changedIndex = getIndex(modifiedNode);
286  if (changedIndex.isValid())
287  {
288  emit dataChanged(changedIndex, changedIndex);
289  }
290  }
291 }
292 
293 void QmitkDataStorageListModel::OnDataModified(const itk::Object *caller, const itk::EventObject &event)
294 {
295  OnDataNodeModified(caller, event); // until different implementation
296 }
297 
298 void QmitkDataStorageListModel::OnDataStorageDeleted(const itk::Object *, const itk::EventObject &)
299 {
300  if (m_BlockEvents)
301  return;
302 
303  this->SetDataStorage(nullptr);
304 }
305 
307 {
308  if (index.isValid())
309  {
310  return std::get<NODE>(m_NodesAndObserverTags.at(index.row()));
311  }
312  else
313  {
314  return nullptr;
315  }
316 }
317 
319 {
320  int row = 0;
321  for (auto iter = m_NodesAndObserverTags.begin(); iter != m_NodesAndObserverTags.end(); ++iter, ++row)
322  {
323  if (std::get<NODE>(*iter) == node)
324  {
325  return index(row);
326  }
327  }
328  return QModelIndex();
329 }
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override
Implements QAbstractListModel.
void reset()
Resets the whole model. Get all nodes matching the predicate from the data storage.
Data management class that handles &#39;was created by&#39; relations.
int rowCount(const QModelIndex &parent=QModelIndex()) const override
Implements QAbstractListModel.
virtual void OnDataStorageDeleted(const itk::Object *caller, const itk::EventObject &event)
mitk::DataStorage * GetDataStorage() const
Get the represented data storage.
void SetPredicate(mitk::NodePredicateBase *pred)
Change the filter predicate.
mitk::DataNode::Pointer getNode(const QModelIndex &index) const
Return the node for given model index.
void SetDataStorage(mitk::DataStorage::Pointer dataStorage)
Change the data storage to represent.
virtual void OnDataNodeModified(const itk::Object *caller, const itk::EventObject &event)
void AddNodeToInternalList(mitk::DataNode *node)
Internal helper: adds given node to end of list.
QModelIndex getIndex(const mitk::DataNode *node) const
Return the model index of the given node.
virtual SetOfObjects::ConstPointer GetAll() const =0
returns a set of all data objects that are stored in the data storage
BaseData * GetData() const
Get the data object (instance of BaseData, e.g., an Image) managed by this DataNode.
mitk::DataStorage::Pointer m_DataStorage
Qt::ItemFlags flags(const QModelIndex &index) const override
Implements QAbstractListModel.
std::vector< mitk::DataNode * > GetDataNodes() const
Get all current data nodes.
QmitkDataStorageListModel(mitk::DataStorage *dataStorage=nullptr, mitk::NodePredicateBase::Pointer pred=nullptr, QObject *parent=nullptr)
void RemoveNodeFromInternalList(mitk::DataNode *node)
Internal helper: remove given node.
SetOfObjects::ConstPointer GetSubset(const NodePredicateBase *condition) const
returns a set of data objects that meet the given condition(s)
virtual void OnDataStorageNodeAdded(const mitk::DataNode *node)
void AddListener(const AbstractDelegate &delegate) const
Definition: mitkMessage.h:374
DataStorageEvent AddNodeEvent
AddEvent is emitted whenever a new node has been added to the DataStorage.
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
Implements QAbstractListModel.
DataStorageEvent RemoveNodeEvent
RemoveEvent is emitted directly before a node is removed from the DataStorage.
mitk::NodePredicateBase * GetPredicate() const
Get the filter predicate in use.
void RemoveListener(const AbstractDelegate &delegate) const
Definition: mitkMessage.h:393
virtual void OnDataStorageNodeRemoved(const mitk::DataNode *node)
Interface for evaluation conditions used in the DataStorage class GetSubset() method.
void ClearInternalNodeList()
Internal helper: Clear complete model list.
Class for nodes of the DataTree.
Definition: mitkDataNode.h:57
virtual void OnDataModified(const itk::Object *caller, const itk::EventObject &event)
bool GetName(std::string &nodeName, const mitk::BaseRenderer *renderer=nullptr, const char *propertyKey="name") const
Convenience access method for accessing the name of an object (instance of StringProperty with proper...
Definition: mitkDataNode.h:369