diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkModelViewSelectionConnector.cpp b/Plugins/org.mitk.gui.qt.common/src/QmitkModelViewSelectionConnector.cpp index faec889ebf..f5a0ccbee4 100644 --- a/Plugins/org.mitk.gui.qt.common/src/QmitkModelViewSelectionConnector.cpp +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkModelViewSelectionConnector.cpp @@ -1,179 +1,184 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical Image Computing. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // mitk gui qt common plugin #include "QmitkModelViewSelectionConnector.h" #include "internal/QmitkDataNodeSelection.h" // qt widgets module #include "QmitkCustomVariants.h" #include "QmitkEnums.h" // blueberry ui qt plugin #include QmitkModelViewSelectionConnector::QmitkModelViewSelectionConnector() : m_Model(nullptr) , m_View(nullptr) , m_SelectOnlyVisibleNodes(false) { // nothing here } void QmitkModelViewSelectionConnector::SetView(QAbstractItemView* view) { if (nullptr != m_View) { disconnect(m_View->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), this, SLOT(ChangeModelSelection(const QItemSelection&, const QItemSelection&))); } - if (nullptr != view && nullptr != dynamic_cast(view->model())) + // reset model-view pair and check for valid function argument + m_View = nullptr; + m_Model = nullptr; + if (nullptr == view) { - m_View = view; - m_Model = dynamic_cast(m_View->model()); - connect(m_View->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), SLOT(ChangeModelSelection(const QItemSelection&, const QItemSelection&))); + mitkThrow() << "Invalid item view. To use the model-view selection connector please specify a valid 'QAbstractItemView'."; } - else + + if (nullptr == dynamic_cast(view->model())) { - m_View = nullptr; - m_Model = nullptr; - mitkThrow() << "Invalid item view or data model."; + mitkThrow() << "Invalid data model. To use the model-view selection connector please set a valid 'QmitkAbstractDataStorageModel' for the given item view."; } + + // a valid item view and a valid data model was found + m_View = view; + m_Model = dynamic_cast(m_View->model()); + connect(m_View->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), SLOT(ChangeModelSelection(const QItemSelection&, const QItemSelection&))); } void QmitkModelViewSelectionConnector::SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes) { m_SelectOnlyVisibleNodes = selectOnlyVisibleNodes; } void QmitkModelViewSelectionConnector::SetCurrentSelection(QList selectedNodes) { if (nullptr == m_Model || nullptr == m_View) { return; } // filter input nodes and return the modified input node list QList filteredNodes = FilterNodeList(selectedNodes); bool equal = IsEqualToCurrentSelection(filteredNodes); if (equal) { return; } if (!m_SelectOnlyVisibleNodes) { // store the unmodified selection m_NonVisibleSelection = selectedNodes; // remove the nodes in the original selection that are already contained in the filtered input node list // 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 // 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') auto lambda = [&filteredNodes](mitk::DataNode::Pointer original) { return filteredNodes.contains(original); }; m_NonVisibleSelection.erase(std::remove_if(m_NonVisibleSelection.begin(), m_NonVisibleSelection.end(), lambda), m_NonVisibleSelection.end()); } // create new selection by retrieving the corresponding indices of the (filtered) nodes QItemSelection newCurrentSelection; for (const auto& node : filteredNodes) { QModelIndexList matched = m_Model->match(m_Model->index(0, 0), QmitkDataNodeRole, QVariant::fromValue(node), 1, Qt::MatchRecursive); if (!matched.empty()) { newCurrentSelection.select(matched.front(), matched.front()); } } m_View->selectionModel()->select(newCurrentSelection, QItemSelectionModel::ClearAndSelect); } void QmitkModelViewSelectionConnector::ChangeModelSelection(const QItemSelection& /*selected*/, const QItemSelection& /*deselected*/) { QList nodes = GetSelectedNodes(); if (!m_SelectOnlyVisibleNodes) { // add the non-visible nodes from the original selection nodes.append(m_NonVisibleSelection); } emit CurrentSelectionChanged(nodes); } QList QmitkModelViewSelectionConnector::GetSelectedNodes() const { if (nullptr == m_Model || nullptr == m_View) { return QList(); } QList nodes; QModelIndexList selectedIndexes = m_View->selectionModel()->selectedIndexes(); for (const auto& index : selectedIndexes) { QVariant qvariantDataNode = m_Model->data(index, QmitkDataNodeRole); if (qvariantDataNode.canConvert()) { nodes.push_back(qvariantDataNode.value()); } } return nodes; } QList QmitkModelViewSelectionConnector::FilterNodeList(const QList& nodes) const { if (nodes.isEmpty()) { return QList(); } if (nullptr == m_Model) { return nodes; } mitk::NodePredicateBase* nodePredicate = m_Model->GetNodePredicate(); if (nullptr == nodePredicate) { // no filter set return nodes; } QList result; for (const auto& node : nodes) { if (true == nodePredicate->CheckNode(node)) { result.push_back(node); } } return result; } bool QmitkModelViewSelectionConnector::IsEqualToCurrentSelection(QList& selectedNodes) const { // get the currently selected nodes from the model QList currentlySelectedNodes = GetSelectedNodes(); if (currentlySelectedNodes.size() == selectedNodes.size()) { // lambda to compare node pointer inside both lists auto lambda = [](mitk::DataNode::Pointer lhs, mitk::DataNode::Pointer rhs) { return lhs == rhs; }; return std::is_permutation(selectedNodes.begin(), selectedNodes.end(), currentlySelectedNodes.begin(), currentlySelectedNodes.end(), lambda); } return false; }