Medical Imaging Interaction Toolkit  2018.4.99-3e3f1a6e
Medical Imaging Interaction Toolkit
QmitkModelViewSelectionConnector.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 
13 // mitk gui qt common plugin
15 
16 // qt widgets module
17 #include "QmitkCustomVariants.h"
18 #include "QmitkEnums.h"
19 
21  : m_Model(nullptr)
22  , m_View(nullptr)
23  , m_SelectOnlyVisibleNodes(false)
24 {
25  // nothing here
26 }
27 
28 void QmitkModelViewSelectionConnector::SetView(QAbstractItemView* view)
29 {
30  if (nullptr != m_View)
31  {
32  disconnect(m_View->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), this, SLOT(ChangeModelSelection(const QItemSelection&, const QItemSelection&)));
33  }
34 
35  // reset model-view pair and check for valid function argument
36  m_View = nullptr;
37  if (nullptr == view)
38  {
39  mitkThrow() << "Invalid item view. To use the model-view selection connector please specify a valid 'QAbstractItemView'.";
40  }
41 
42  auto storageModel = dynamic_cast<QmitkAbstractDataStorageModel*>(view->model());
43 
44  if (storageModel == nullptr)
45  {
46  mitkThrow() << "Invalid data model. To use the model-view selection connector please set a valid 'QmitkAbstractDataStorageModel' for the given item view.";
47  }
48 
49  // a valid item view and a valid data model was found
50  m_View = view;
51  m_Model = storageModel;
52  connect(m_View->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), SLOT(ChangeModelSelection(const QItemSelection&, const QItemSelection&)));
53 }
54 
56 {
57  m_SelectOnlyVisibleNodes = selectOnlyVisibleNodes;
58 }
59 
60 void QmitkModelViewSelectionConnector::SetCurrentSelection(QList<mitk::DataNode::Pointer> selectedNodes)
61 {
62  if (nullptr == m_Model || nullptr == m_View)
63  {
64  return;
65  }
66 
67  // filter input nodes and return the modified input node list
68  QList<mitk::DataNode::Pointer> filteredNodes = FilterNodeList(selectedNodes);
69 
70  bool equal = EqualNodeSelections(this->GetInternalSelectedNodes(), filteredNodes);
71  if (equal)
72  {
73  return;
74  }
75 
76  if (!m_SelectOnlyVisibleNodes)
77  {
78  // store the unmodified selection
79  m_NonVisibleSelection = selectedNodes;
80  // remove the nodes in the original selection that are already contained in the filtered input node list
81  // this will keep the selection of the original nodes that are not presented by the current view unmodified, but allows to change the selection of the filtered nodes
82  // later, the nodes of the 'm_NonVisibleSelection' member have to be added again to the list of selected (filtered) nodes, if a selection is sent from the current view (see 'ModelSelectionChanged')
83  auto lambda = [&filteredNodes](mitk::DataNode::Pointer original) { return filteredNodes.contains(original); };
84  m_NonVisibleSelection.erase(std::remove_if(m_NonVisibleSelection.begin(), m_NonVisibleSelection.end(), lambda), m_NonVisibleSelection.end());
85  }
86 
87  // create new selection by retrieving the corresponding indices of the (filtered) nodes
88  QItemSelection newCurrentSelection;
89  for (const auto& node : filteredNodes)
90  {
91  QModelIndexList matched = m_Model->match(m_Model->index(0, 0), QmitkDataNodeRole, QVariant::fromValue<mitk::DataNode::Pointer>(node), 1, Qt::MatchRecursive);
92  if (!matched.empty())
93  {
94  newCurrentSelection.select(matched.front(), matched.front());
95  }
96  }
97 
98  m_View->selectionModel()->select(newCurrentSelection, QItemSelectionModel::ClearAndSelect);
99 }
100 
101 void QmitkModelViewSelectionConnector::ChangeModelSelection(const QItemSelection& /*selected*/, const QItemSelection& /*deselected*/)
102 {
104 }
105 
107 {
108  return m_SelectOnlyVisibleNodes;
109 }
110 
111 QList<mitk::DataNode::Pointer> QmitkModelViewSelectionConnector::GetSelectedNodes() const
112 {
113  auto nodes = GetInternalSelectedNodes();
114 
115  if (!m_SelectOnlyVisibleNodes)
116  {
117  // add the non-visible nodes from the original selection
118  nodes.append(m_NonVisibleSelection);
119  }
120 
121  return nodes;
122 }
123 
124 QList<mitk::DataNode::Pointer> QmitkModelViewSelectionConnector::GetInternalSelectedNodes() const
125 {
126  if (nullptr == m_Model || nullptr == m_View)
127  {
128  return QList<mitk::DataNode::Pointer>();
129  }
130 
131  QList<mitk::DataNode::Pointer> nodes;
132  QModelIndexList selectedIndexes = m_View->selectionModel()->selectedIndexes();
133  for (const auto& index : selectedIndexes)
134  {
135  QVariant qvariantDataNode = m_Model->data(index, QmitkDataNodeRole);
136  if (qvariantDataNode.canConvert<mitk::DataNode::Pointer>())
137  {
138  nodes.push_back(qvariantDataNode.value<mitk::DataNode::Pointer>());
139  }
140  }
141  return nodes;
142 }
143 
144 QList<mitk::DataNode::Pointer> QmitkModelViewSelectionConnector::FilterNodeList(const QList<mitk::DataNode::Pointer>& nodes) const
145 {
146  if (nodes.isEmpty())
147  {
148  return QList<mitk::DataNode::Pointer>();
149  }
150 
151  if (nullptr == m_Model)
152  {
153  return nodes;
154  }
155 
156  auto nodePredicate = m_Model->GetNodePredicate();
157  if (nullptr == nodePredicate)
158  {
159  // no filter set
160  return nodes;
161  }
162 
163  QList<mitk::DataNode::Pointer> result;
164  for (const auto& node : nodes)
165  {
166  if (true == nodePredicate->CheckNode(node))
167  {
168  result.push_back(node);
169  }
170  }
171 
172  return result;
173 }
174 
175 bool MITKQTWIDGETS_EXPORT EqualNodeSelections(const QList<mitk::DataNode::Pointer>& selection1, const QList<mitk::DataNode::Pointer>& selection2)
176 {
177  if (selection1.size() == selection2.size())
178  {
179  // lambda to compare node pointer inside both lists
180  auto lambda = [](mitk::DataNode::Pointer lhs, mitk::DataNode::Pointer rhs) { return lhs == rhs; };
181  return std::is_permutation(selection1.begin(), selection1.end(), selection2.begin(), selection2.end(), lambda);
182  }
183 
184  return false;
185 }
void SetView(QAbstractItemView *view)
Set the view whose selection model is used to propagate or receive selection changes. Use the view&#39;s data model to transform selected nodes into model indexes and vice versa.
QList< mitk::DataNode::Pointer > GetSelectedNodes() const
Retrieve the currently selected nodes (equals the last CurrentSelectionChanged values).
#define MITKQTWIDGETS_EXPORT
void SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes)
Change the selection mode of the item view&#39;s selection model.
#define mitkThrow()
void CurrentSelectionChanged(QList< mitk::DataNode::Pointer > nodes)
A signal that will be emitted by the &#39;ChangeModelSelection&#39;-function. This happens if the selection m...
const mitk::NodePredicateBase * GetNodePredicate() const
void SetCurrentSelection(QList< mitk::DataNode::Pointer > selectedNodes)
Transform a list of data nodes into a model selection and set this as a new selection of the selectio...
bool MITKQTWIDGETS_EXPORT EqualNodeSelections(const QList< mitk::DataNode::Pointer > &selection1, const QList< mitk::DataNode::Pointer > &selection2)