diff --git a/Modules/QtWidgets/include/QmitkDataStorageDefaultListModel.h b/Modules/QtWidgets/include/QmitkDataStorageDefaultListModel.h index 908e445e51..5e65a22cf2 100644 --- a/Modules/QtWidgets/include/QmitkDataStorageDefaultListModel.h +++ b/Modules/QtWidgets/include/QmitkDataStorageDefaultListModel.h @@ -1,74 +1,84 @@ /*=================================================================== 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. ===================================================================*/ #ifndef QMITKDATASTORAGEDEFAULTLISTMODEL_H #define QMITKDATASTORAGEDEFAULTLISTMODEL_H #include // qt widgets module -#include +#include // qt #include /** * @brief The 'QmitkDataStorageDefaultListModel' is a basic list model, that implements the 'QmitkIDataStorageViewModel'. * It provides functions to accept a data storage and a node predicate in order to customize the model data nodes. * Furthermore it overrides the functions of 'QAbstractItemModel' to create a simple qt list model. -* This model can be used inside a concrete implementation of the 'QmitkDataStorageAbstractView' and therefore be -* connected to the data storage and the signals and slots of a concrete data storage viewer. +* This model can be used inside a 'QmitkDataStorageSelectionConnector'. */ -class MITKQTWIDGETS_EXPORT QmitkDataStorageDefaultListModel : public QmitkIDataStorageViewModel +class MITKQTWIDGETS_EXPORT QmitkDataStorageDefaultListModel : public QmitkAbstractDataStorageModel { public: QmitkDataStorageDefaultListModel(QObject *parent); - // override from 'QmitkIDataStorageViewModel' + // override from 'QmitkAbstractDataStorageModel' /* - * @brief See 'QmitkIDataStorageViewModel' + * @brief See 'QmitkAbstractDataStorageModel' */ - void SetDataStorage(mitk::DataStorage* dataStorage) override; + void DataStorageChanged() override; /* - * @brief See 'QmitkIDataStorageViewModel' + * @brief See 'QmitkAbstractDataStorageModel' */ - void SetNodePredicate(mitk::NodePredicateBase* nodePredicate) override; + void NodePredicateChanged() override; + /* + * @brief See 'QmitkAbstractDataStorageModel' + */ + void NodeAdded(const mitk::DataNode* node) override; + /* + * @brief See 'QmitkAbstractDataStorageModel' + */ + void NodeChanged(const mitk::DataNode* node) override; + /* + * @brief See 'QmitkAbstractDataStorageModel' + */ + void NodeRemoved(const mitk::DataNode* node) override; // override pure virtual from 'QAbstractItemModel' QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; QModelIndex parent(const QModelIndex &child) const override; int rowCount(const QModelIndex &parent = QModelIndex()) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; // override for customization QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; Qt::ItemFlags flags(const QModelIndex &index) const override; private: - mitk::DataStorage::Pointer m_DataStorage; - std::vector m_DataNodes; + void UpdateModelData(); - mitk::NodePredicateBase::Pointer m_NodePredicate; + std::vector m_DataNodes; }; #endif // QMITKDATASTORAGEDEFAULTLISTMODEL_H diff --git a/Modules/QtWidgets/src/QmitkDataStorageDefaultListModel.cpp b/Modules/QtWidgets/src/QmitkDataStorageDefaultListModel.cpp index 14dcf39e03..dee1fb6be7 100644 --- a/Modules/QtWidgets/src/QmitkDataStorageDefaultListModel.cpp +++ b/Modules/QtWidgets/src/QmitkDataStorageDefaultListModel.cpp @@ -1,147 +1,158 @@ /*=================================================================== 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. ===================================================================*/ #include // qt widgets module #include "QmitkCustomVariants.h" #include "QmitkEnums.h" QmitkDataStorageDefaultListModel::QmitkDataStorageDefaultListModel(QObject *parent) - : m_DataStorage(nullptr) - , m_NodePredicate(nullptr) { // nothing here } -void QmitkDataStorageDefaultListModel::SetDataStorage(mitk::DataStorage* dataStorage) +void QmitkDataStorageDefaultListModel::DataStorageChanged() { - /* TEMPORARY - if (m_DataStorage == dataStorage) - { - return; - } - */ - m_DataStorage = dataStorage; + UpdateModelData(); +} - mitk::DataStorage::SetOfObjects::ConstPointer dataNodes; - if (m_DataStorage != nullptr) - { - if (m_NodePredicate != nullptr) - { - dataNodes = m_DataStorage->GetSubset(m_NodePredicate); - } - else - { - dataNodes = m_DataStorage->GetAll(); - } - } +void QmitkDataStorageDefaultListModel::NodePredicateChanged() +{ + UpdateModelData(); +} - // update the model, so that it will be filled with the nodes of the new data storage - beginResetModel(); - m_DataNodes.clear(); +void QmitkDataStorageDefaultListModel::NodeAdded(const mitk::DataNode* node) +{ + UpdateModelData(); +} - // add all (filtered) nodes to the vector of nodes - if (dataNodes != nullptr) - { - for (auto& node : *dataNodes) - { - m_DataNodes.push_back(node); - } - } - endResetModel(); +void QmitkDataStorageDefaultListModel::NodeChanged(const mitk::DataNode* node) +{ + // nothing here, since the "'NodeChanged'-event is currently sent far too often + //UpdateModelData(); } -void QmitkDataStorageDefaultListModel::SetNodePredicate(mitk::NodePredicateBase* nodePredicate) +void QmitkDataStorageDefaultListModel::NodeRemoved(const mitk::DataNode* node) { - m_NodePredicate = nodePredicate; + UpdateModelData(); } QModelIndex QmitkDataStorageDefaultListModel::index(int row, int column, const QModelIndex &parent) const { bool hastIndex = hasIndex(row, column, parent); if (hastIndex) { return createIndex(row, column); } return QModelIndex(); } QModelIndex QmitkDataStorageDefaultListModel::parent(const QModelIndex &child) const { return QModelIndex(); } int QmitkDataStorageDefaultListModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) { return 0; } return m_DataNodes.size(); } int QmitkDataStorageDefaultListModel::columnCount(const QModelIndex &parent) const { if (parent.isValid()) { return 0; } return 1; } QVariant QmitkDataStorageDefaultListModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return QVariant(); } if(index.row() < 0 || index.row() >= m_DataNodes.size()) { return QVariant(); } mitk::DataNode::Pointer dataNode = m_DataNodes.at(index.row()); if (Qt::DisplayRole == role) { return QVariant(QString::fromStdString(dataNode->GetName())); } else if (QmitkDataNodeRole == role) { return QVariant::fromValue(dataNode); } return QVariant(); } QVariant QmitkDataStorageDefaultListModel::headerData(int section, Qt::Orientation orientation, int role) const { return QVariant(tr("Nodes")); } Qt::ItemFlags QmitkDataStorageDefaultListModel::flags(const QModelIndex &index) const { if (index.isValid()) { return Qt::ItemIsEnabled | Qt::ItemIsSelectable; } return Qt::NoItemFlags; } + +void QmitkDataStorageDefaultListModel::UpdateModelData() +{ + mitk::DataStorage::SetOfObjects::ConstPointer dataNodes; + if (m_DataStorage != nullptr) + { + if (m_NodePredicate != nullptr) + { + dataNodes = m_DataStorage->GetSubset(m_NodePredicate); + } + else + { + dataNodes = m_DataStorage->GetAll(); + } + } + + // update the model, so that it will be filled with the nodes of the new data storage + beginResetModel(); + m_DataNodes.clear(); + + // add all (filtered) nodes to the vector of nodes + if (dataNodes != nullptr) + { + for (auto& node : *dataNodes) + { + m_DataNodes.push_back(node); + } + } + endResetModel(); +} diff --git a/Plugins/org.mitk.gui.qt.common/files.cmake b/Plugins/org.mitk.gui.qt.common/files.cmake index 4a2ae184c9..5dedec11be 100755 --- a/Plugins/org.mitk.gui.qt.common/files.cmake +++ b/Plugins/org.mitk.gui.qt.common/files.cmake @@ -1,40 +1,40 @@ set(SRC_CPP_FILES QmitkAbstractRenderEditor.cpp QmitkAbstractView.cpp QmitkDataNodeSelectionProvider.cpp - QmitkDataStorageSelectionConnector.cpp QmitkDnDFrameWidget.cpp + QmitkModelViewSelectionConnector.cpp QmitkSliceNavigationListener.cpp ) set(INTERNAL_CPP_FILES QmitkCommonActivator.cpp QmitkDataNodeItemModel.cpp QmitkDataNodeSelection.cpp QmitkViewCoordinator.cpp ) set(MOC_H_FILES src/QmitkAbstractRenderEditor.h - src/QmitkDataStorageSelectionConnector.h src/QmitkDnDFrameWidget.h + src/QmitkModelViewSelectionConnector.h src/QmitkSliceNavigationListener.h src/internal/QmitkCommonActivator.h ) set(CACHED_RESOURCE_FILES ) set(QRC_FILES ) set(CPP_FILES ) foreach(file ${SRC_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/${file}) endforeach(file ${SRC_CPP_FILES}) foreach(file ${INTERNAL_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/internal/${file}) endforeach(file ${INTERNAL_CPP_FILES}) diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkDataStorageSelectionConnector.cpp b/Plugins/org.mitk.gui.qt.common/src/QmitkDataStorageSelectionConnector.cpp deleted file mode 100644 index e0adceb0b1..0000000000 --- a/Plugins/org.mitk.gui.qt.common/src/QmitkDataStorageSelectionConnector.cpp +++ /dev/null @@ -1,128 +0,0 @@ -/*=================================================================== - -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 "QmitkDataStorageSelectionConnector.h" -#include "internal/QmitkDataNodeSelection.h" - -// org.blueberry.ui.qt -#include - -QmitkDataStorageSelectionConnector::QmitkDataStorageSelectionConnector(QmitkDataStorageAbstractView* dataStorageAbstractView) - : m_DataStorageAbstractView(dataStorageAbstractView) - , m_SelectionService(nullptr) - , m_SelectionProvider(nullptr) -{ - m_DataNodeItemModel = std::make_shared(); - m_DataNodeSelectionModel = std::make_shared(m_DataNodeItemModel.get()); -} - -QmitkDataStorageSelectionConnector::~QmitkDataStorageSelectionConnector() -{ - RemovePostSelectionListener(); - RemoveAsSelectionProvider(); -} - -void QmitkDataStorageSelectionConnector::AddPostSelectionListener(berry::ISelectionService* selectionService) -{ - if (nullptr == selectionService) - { - return; - } - - m_SelectionService = selectionService; - m_BerrySelectionListener.reset(new berry::NullSelectionChangedAdapter(this, &QmitkDataStorageSelectionConnector::GlobalSelectionChanged)); - m_SelectionService->AddPostSelectionListener(m_BerrySelectionListener.get()); -} - -void QmitkDataStorageSelectionConnector::RemovePostSelectionListener() -{ - if (nullptr == m_SelectionService) - { - return; - } - - m_SelectionService->RemovePostSelectionListener(m_BerrySelectionListener.get()); - m_SelectionService = nullptr; -} - -void QmitkDataStorageSelectionConnector::SetAsSelectionProvider(QmitkDataNodeSelectionProvider* selectionProvider) -{ - m_SelectionProvider = selectionProvider; - connect(m_DataStorageAbstractView, SIGNAL(CurrentSelectionChanged(QList)), SLOT(FireGlobalSelectionChanged(QList))); -} - -void QmitkDataStorageSelectionConnector::RemoveAsSelectionProvider() -{ - disconnect(m_DataStorageAbstractView, SIGNAL(CurrentSelectionChanged(QList)), this, SLOT(FireGlobalSelectionChanged(QList))); -} - -void QmitkDataStorageSelectionConnector::GlobalSelectionChanged(const berry::IWorkbenchPart::Pointer& sourcePart, const berry::ISelection::ConstPointer& selection) -{ - if (sourcePart.IsNull()) - { - return; - } - - QList nodes; - if (selection.IsNull()) - { - // propagate an empty list - nodes = QList(); - } - - // transform valid selection to DataNodeSelection, which allows to retrieve the selected nodes - mitk::DataNodeSelection::ConstPointer dataNodeSelection = selection.Cast(); - if (dataNodeSelection.IsNull()) - { - // propagate an empty list - nodes = QList(); - } - else - { - nodes = QList::fromStdList(dataNodeSelection->GetSelectedDataNodes()); - } - - // set new (possibly empty) selection in the given data storage view - m_DataStorageAbstractView->SetCurrentSelection(nodes); -} - -void QmitkDataStorageSelectionConnector::FireGlobalSelectionChanged(QList nodes) -{ - if (nullptr == m_SelectionProvider) - { - return; - } - - m_SelectionProvider->SetItemSelectionModel(m_DataNodeSelectionModel.get()); - - if (nodes.empty()) - { - m_DataNodeSelectionModel->clearSelection(); - m_DataNodeItemModel->clear(); - } - else - { - m_DataNodeItemModel->clear(); - // fill the temporary helper data node item model with the nodes to select - for(const auto& node : nodes) - { - m_DataNodeItemModel->AddDataNode(node); - } - - m_DataNodeSelectionModel->select(QItemSelection(m_DataNodeItemModel->index(0, 0), m_DataNodeItemModel->index(nodes.size() - 1, 0)), QItemSelectionModel::ClearAndSelect); - } -} \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkDataStorageSelectionConnector.h b/Plugins/org.mitk.gui.qt.common/src/QmitkDataStorageSelectionConnector.h deleted file mode 100644 index 4ad2f26a74..0000000000 --- a/Plugins/org.mitk.gui.qt.common/src/QmitkDataStorageSelectionConnector.h +++ /dev/null @@ -1,103 +0,0 @@ -/*=================================================================== - -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. - -===================================================================*/ - -#ifndef QMITKDATASTORAGESELECTIONCONNECTOR_H -#define QMITKDATASTORAGESELECTIONCONNECTOR_H - -#include - -// qt widgets module -#include - -// mitk gui qt common plugin -#include "QmitkDataNodeSelectionProvider.h" -#include "internal/QmitkDataNodeItemModel.h" - - // blueberry ui qt plugin -#include - - /* - * @brief The QmitkDataStorageSelectionConnector is used to connect a given 'QmitkDataStorageAbstractView' with the global selection bus. - * The data storage view can be added as a selection listener to a selection service. This should be done by using 'AddPostSelectionListener' - * with the existing selection service of the surrounding 'QmitkAbstractView'. - * The data storage view can be set as a selection provider. This should be done by using 'SetAsSelectionProvider' with the existing - * selection provider of the surrounding 'QmitkAbstractView'. - */ -class MITK_QT_COMMON QmitkDataStorageSelectionConnector : public QObject -{ - Q_OBJECT - -public: - - QmitkDataStorageSelectionConnector(QmitkDataStorageAbstractView* dataStorageAbstractView); - ~QmitkDataStorageSelectionConnector(); - - /* - * @brief Create a selection listener and add it to the list of selection listener of the given selection service. - * The selection listener is connected with the 'GlobalSelectionChanged' member function, which is - * called if a berry selection is changed in the workbench. - */ - void AddPostSelectionListener(berry::ISelectionService* selectionService); - /* - * @brief Remove a selection listener from the list of selection listener of the selection service member. - */ - void RemovePostSelectionListener(); - /* - * @brief Connect the 'CurrentSelectionChanged'-slot from the member 'QmitkDataStorageAbstractView' with the - * private 'FireSelectionChanged'-function of this class. The 'FireSelectionChanged'-function transforms the - * list of selected nodes and propagates the changed selection. - */ - void SetAsSelectionProvider(QmitkDataNodeSelectionProvider* selectionProvider); - /* - * @brief Disconnect the 'CurrentSelectionChanged'-slot of the member 'QmitkDataStorageAbstractView' from the - * private 'FireSelectionChanged'-function of this class. - */ - void RemoveAsSelectionProvider(); - -private Q_SLOTS: - - /* - * @brief Send global selections to the selection provider. - * - * This function is called whenever a local selection is changed in the workbench and the 'QmitkDataStorageAbstractView' - * is set as selection provider. - * The newly selected data nodes are added temporary to the 'QmitkDataNodeItemModel', which is then used to define - * the indices to select. - * The 'QItemSelectionModel' is set for the selection provider and its items are selected by the indices previously defined. - */ - void FireGlobalSelectionChanged(QList nodes); - -private: - - QmitkDataStorageAbstractView* m_DataStorageAbstractView; - std::unique_ptr m_BerrySelectionListener; - berry::ISelectionService* m_SelectionService; - QmitkDataNodeSelectionProvider* m_SelectionProvider; - std::shared_ptr m_DataNodeItemModel; - std::shared_ptr m_DataNodeSelectionModel; - - /* - * @brief Handle global selection received from the selection service. - * - * This function is called whenever a global berry selection is changed in the workbench. - * The new selection is transformed into a data node selection and the contained data nodes are propagated - * as the new current selection of the data storage view member. - */ - void GlobalSelectionChanged(const berry::IWorkbenchPart::Pointer& sourcePart, const berry::ISelection::ConstPointer& selection); - -}; - -#endif // QMITKDATASTORAGESELECTIONCONNECTOR_H diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkModelViewSelectionConnector.cpp b/Plugins/org.mitk.gui.qt.common/src/QmitkModelViewSelectionConnector.cpp new file mode 100644 index 0000000000..cc5792b8d6 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkModelViewSelectionConnector.cpp @@ -0,0 +1,280 @@ +/*=================================================================== + +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) + , m_SelectionService(nullptr) + , m_SelectionProvider(nullptr) +{ + m_DataNodeItemModel = std::make_shared(); + m_DataNodeSelectionModel = std::make_shared(m_DataNodeItemModel.get()); +} + +QmitkModelViewSelectionConnector::~QmitkModelViewSelectionConnector() +{ + RemovePostSelectionListener(); + RemoveAsSelectionProvider(); +} + +void QmitkModelViewSelectionConnector::SetModel(QmitkAbstractDataStorageModel* model) +{ + m_Model = model; +} + +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&))); + } + + m_View = view; + if (nullptr != m_View) + { + connect(m_View->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), SLOT(ChangeModelSelection(const QItemSelection&, const QItemSelection&))); + } +} + +void QmitkModelViewSelectionConnector::AddPostSelectionListener(berry::ISelectionService* selectionService) +{ + if (nullptr == selectionService + || nullptr == m_Model + || nullptr == m_View) + { + return; + } + + m_SelectionService = selectionService; + m_BerrySelectionListener.reset(new berry::NullSelectionChangedAdapter(this, &QmitkModelViewSelectionConnector::GlobalSelectionChanged)); + m_SelectionService->AddPostSelectionListener(m_BerrySelectionListener.get()); +} + +void QmitkModelViewSelectionConnector::RemovePostSelectionListener() +{ + if (nullptr == m_SelectionService) + { + return; + } + + m_SelectionService->RemovePostSelectionListener(m_BerrySelectionListener.get()); + m_SelectionService = nullptr; +} + +void QmitkModelViewSelectionConnector::SetAsSelectionProvider(QmitkDataNodeSelectionProvider* selectionProvider) +{ + m_SelectionProvider = selectionProvider; + connect(this, SIGNAL(CurrentSelectionChanged(QList)), SLOT(FireGlobalSelectionChanged(QList))); +} + +void QmitkModelViewSelectionConnector::RemoveAsSelectionProvider() +{ + disconnect(this, SIGNAL(CurrentSelectionChanged(QList)), this, SLOT(FireGlobalSelectionChanged(QList))); +} + +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); +} + +void QmitkModelViewSelectionConnector::FireGlobalSelectionChanged(QList nodes) +{ + if (nullptr == m_SelectionProvider) + { + return; + } + + m_SelectionProvider->SetItemSelectionModel(m_DataNodeSelectionModel.get()); + + if (nodes.empty()) + { + m_DataNodeSelectionModel->clearSelection(); + m_DataNodeItemModel->clear(); + } + else + { + m_DataNodeItemModel->clear(); + // fill the temporary helper data node item model with the nodes to select + for (const auto& node : nodes) + { + m_DataNodeItemModel->AddDataNode(node); + } + + m_DataNodeSelectionModel->select(QItemSelection(m_DataNodeItemModel->index(0, 0), m_DataNodeItemModel->index(nodes.size() - 1, 0)), QItemSelectionModel::ClearAndSelect); + } +} + +void QmitkModelViewSelectionConnector::GlobalSelectionChanged(const berry::IWorkbenchPart::Pointer& sourcePart, const berry::ISelection::ConstPointer& selection) +{ + if (sourcePart.IsNull()) + { + return; + } + + QList nodes; + if (selection.IsNull()) + { + // propagate an empty list + nodes = QList(); + } + + // transform valid selection to DataNodeSelection, which allows to retrieve the selected nodes + mitk::DataNodeSelection::ConstPointer dataNodeSelection = selection.Cast(); + if (dataNodeSelection.IsNull()) + { + // propagate an empty list + nodes = QList(); + } + else + { + nodes = QList::fromStdList(dataNodeSelection->GetSelectedDataNodes()); + } + + // set new (possibly empty) selection in the given data storage view + SetCurrentSelection(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; }; + //bool equal = std::equal(filteredNodes.begin(), filteredNodes.end(), currentlySelectedNodes.begin(), currentlySelectedNodes.end(), lambda); + return std::is_permutation(selectedNodes.begin(), selectedNodes.end(), currentlySelectedNodes.begin(), currentlySelectedNodes.end(), lambda); + } + + return false; +} diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkModelViewSelectionConnector.h b/Plugins/org.mitk.gui.qt.common/src/QmitkModelViewSelectionConnector.h new file mode 100644 index 0000000000..12b199e15f --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkModelViewSelectionConnector.h @@ -0,0 +1,199 @@ +/*=================================================================== + +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. + +===================================================================*/ + +#ifndef QMITKMODELVIEWSELECTIONCONNECTOR_H +#define QMITKMODELVIEWSELECTIONCONNECTOR_H + +#include + +// qt widgets module +#include + +// mitk gui qt common plugin +#include "QmitkDataNodeSelectionProvider.h" +#include "internal/QmitkDataNodeItemModel.h" + + // blueberry ui qt plugin +#include + + // qt +#include + +/* +* @brief The 'QmitkModelViewSelectionConnector' is used to handle the selections of a model-view-pair. +* +* The class accepts a view and a model, which are used to react to selection changes. This class is able to propagate selection changes +* to and receive from its surrounding class. +* +* The model-view-pair can be added as a selection listener to a selection service. This should be done by using 'AddPostSelectionListener' +* with the existing selection service of the surrounding 'QmitkAbstractView'. +* The model-view-pair can be set as a selection provider. This should be done by using 'SetAsSelectionProvider' with the existing +* selection provider of the surrounding 'QmitkAbstractView'. +* +* The 'QmitkModelViewSelectionConnector' offers a public slot and signal that can be used to set / propagate the selected +* nodes in the current view: +* The 'SetCurrentSelection'-slot finds the indices of the given selected nodes in its internal data storage model and +* changes the selection of the accordingly. +* The 'CurrentSelectionChanged'-signal sends a list of selected nodes to it's environment. +* The 'CurrentSelectionChanged'-signal is emitted by the 'ChangeModelSelection'-function, which transforms the internal item view's +* selection into a data node list. The 'ChangeModelSelection'-function is called whenever the selection of the item view's +* selection model changes. +*/ +class MITK_QT_COMMON QmitkModelViewSelectionConnector : public QObject +{ + Q_OBJECT + +public: + + QmitkModelViewSelectionConnector(); + ~QmitkModelViewSelectionConnector(); + + /* + * @brief Set the model that should be used to transform selected nodes into model indexes and vice versa. + * + * This model must return mitk::DataNode::Pointer objects for model indexes + * if the role is QmitkDataNodeRole. + * + * @par model The model to set. + */ + void SetModel(QmitkAbstractDataStorageModel* model); + /* + * @brief Set the view whose selection model is used to propagate or receive selection changes. + * + * @par view The view to set. + */ + void SetView(QAbstractItemView* view); + /* + * @brief Create a selection listener and add it to the list of selection listener of the given selection service. + * The selection listener is connected with the 'GlobalSelectionChanged' member function, which is + * called if a berry selection is changed in the workbench. + */ + void AddPostSelectionListener(berry::ISelectionService* selectionService); + /* + * @brief Remove a selection listener from the list of selection listener of the selection service member. + */ + void RemovePostSelectionListener(); + /* + * @brief Connect the local 'CurrentSelectionChanged'-slot with the private 'FireSelectionChanged'-function of this class. + * The 'FireSelectionChanged'-function transforms the list of selected nodes and propagates the changed selection. + */ + void SetAsSelectionProvider(QmitkDataNodeSelectionProvider* selectionProvider); + /* + * @brief Disconnect the local 'CurrentSelectionChanged'-slot from the private 'FireSelectionChanged'-function of this class. + */ + void RemoveAsSelectionProvider(); + +Q_SIGNALS: + /* + * @brief A signal that will be emitted by the 'ChangeModelSelection'-function. This happens if the selection model + * of the private member item view has changed. + * + * @par nodes A list of data nodes that are newly selected. + */ + void CurrentSelectionChanged(QList nodes); + +public Q_SLOTS: + /* + * @brief Change the selection modus of the item view's selection model. + * + * If true, an incoming selection will be filtered (reduced) to only those nodes that are visible by the current view. + * An outgoing selection can then at most contain the filtered nodes. + * If false, the incoming non-visible selection will be stored and later added to the outgoing selection, + * to include the original selection that could not be modified. + * The part of the original selection, that is non-visible are the nodes that are not + * + * @par selectOnlyVisibleNodes The bool value to define the selection modus. + */ + void SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes); + /* + * @brief Transform a list of data nodes into a model selection and set this as a new selection of the + * selection model of the private member item view. + * + * The function filters the given list of nodes according to the 'm_SelectOnlyVisibleNodes' member variable. If + * necessary, the non-visible nodes are stored. This is done if 'm_SelectOnlyVisibleNodes' is false: In this case + * the selection may be filtered and only a subset of the selected nodes may be visible and therefore (de-)selectable + * in the data storage viewer. By storing the non-visible nodes it is possible to send the new, modified selection + * but also include the selected nodes from the original selection that could not be modified (see 'SetSelectOnlyVisibleNodes'). + * + * @par nodes A list of data nodes that should be newly selected. + */ + void SetCurrentSelection(QList selectedNodes); + +private Q_SLOTS: + /* + * @brief Transform a model selection into a data node list and emit the 'CurrentSelectionChanged'-signal. + * + * The function adds the selected nodes from the original selection that could not be modified, if + * 'm_SelectOnlyVisibleNodes' is false. + * This slot is internally connected to the 'selectionChanged'-signal of the selection model of the private member item view. + * + * @par selected The newly selected items. + * @par deselected The newly deselected items. + */ + void ChangeModelSelection(const QItemSelection& selected, const QItemSelection& deselected); + /* + * @brief Send global selections to the selection provider. + * + * This slot-function is called whenever a local selection is changed in the workbench and the model-view-pair was set + * as a selection provider. + * The newly selected data nodes are added temporary to the 'QmitkDataNodeItemModel', which is then used to define + * the indices to select. + * The 'QItemSelectionModel' is set as the item selection model of the selection provider and its items are selected + * by the indices previously defined by the 'QmitkDataNodeItemModel'. + */ + void FireGlobalSelectionChanged(QList nodes); + +private: + + QmitkAbstractDataStorageModel* m_Model; + QAbstractItemView* m_View; + + bool m_SelectOnlyVisibleNodes; + QList m_NonVisibleSelection; + + std::unique_ptr m_BerrySelectionListener; + berry::ISelectionService* m_SelectionService; + QmitkDataNodeSelectionProvider* m_SelectionProvider; + std::shared_ptr m_DataNodeItemModel; + std::shared_ptr m_DataNodeSelectionModel; + + /* + * @brief Handle a global selection received from the selection service. + * + * This function is called whenever a global berry selection is changed in the workbench. + * The new selection is transformed into a data node selection and the contained data nodes are propagated + * as the new current selection of the item view member. + * + * @par sourcePart The workbench part containing the selection. + * @par selection The current selection. + */ + void GlobalSelectionChanged(const berry::IWorkbenchPart::Pointer& sourcePart, const berry::ISelection::ConstPointer& selection); + /* + * @brief Retrieve the currently selected nodes from the selection model of the private member item view by + * transforming the selection indexes into a data node list. + * + * In order to transform the indices into data nodes, the private data storage model must return + * mitk::DataNode::Pointer objects for model indexes if the role is QmitkDataNodeRole. + */ + QList GetSelectedNodes() const; + + QList FilterNodeList(const QList& nodes) const; + + bool IsEqualToCurrentSelection(QList& selectedNodes) const; + +}; + +#endif // QMITKMODELVIEWSELECTIONCONNECTOR_H diff --git a/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/QmitkDataStorageViewerTestControls.ui b/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/QmitkDataStorageViewerTestControls.ui index dc0ada0f0e..53f33becde 100644 --- a/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/QmitkDataStorageViewerTestControls.ui +++ b/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/QmitkDataStorageViewerTestControls.ui @@ -1,57 +1,48 @@ QmitkDataStorageViewerTestControls 0 0 386 572 0 0 Data storage viewer test - - + + - + Set as selection provider Set as selection provider - - - QmitkDataStorageDefaultView - QWidget -
QmitkDataStorageDefaultView.h
-
-
- - QmitkDataStorageDefaultView.h - +
diff --git a/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/QmitkDataStorageViewerTestView.cpp b/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/QmitkDataStorageViewerTestView.cpp index 73ec7a4eba..32e5bce559 100644 --- a/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/QmitkDataStorageViewerTestView.cpp +++ b/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/QmitkDataStorageViewerTestView.cpp @@ -1,72 +1,88 @@ /*=================================================================== 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. ===================================================================*/ // data storage viewer test plugin #include "QmitkDataStorageViewerTestView.h" // berry #include // qt #include const std::string QmitkDataStorageViewerTestView::VIEW_ID = "org.mitk.views.datastorageviewertest"; void QmitkDataStorageViewerTestView::SetFocus() { // nothing here } void QmitkDataStorageViewerTestView::CreateQtPartControl(QWidget* parent) { // create GUI widgets m_Controls.setupUi(parent); - m_Controls.dataStorageDefaultView->SetDataStorage(GetDataStorage()); - m_DataStorageSelectionConnector = std::make_unique(m_Controls.dataStorageDefaultView); - m_DataStorageSelectionConnector->AddPostSelectionListener(GetSite()->GetWorkbenchWindow()->GetSelectionService()); + m_DataStorageDefaultListModel = new QmitkDataStorageDefaultListModel(this); + m_DataStorageDefaultListModel->SetDataStorage(GetDataStorage()); + m_Controls.selectionListView->setSelectionMode(QAbstractItemView::ExtendedSelection); + m_Controls.selectionListView->setSelectionBehavior(QAbstractItemView::SelectRows); + m_Controls.selectionListView->setAlternatingRowColors(true); + m_Controls.selectionListView->setModel(m_DataStorageDefaultListModel); - m_Controls.dataStorageDefaultView2->SetDataStorage(GetDataStorage()); - m_DataStorageSelectionConnector2 = std::make_unique(m_Controls.dataStorageDefaultView2); - m_DataStorageSelectionConnector2->AddPostSelectionListener(GetSite()->GetWorkbenchWindow()->GetSelectionService()); + m_DataStorageDefaultListModel2 = new QmitkDataStorageDefaultListModel(this); + m_DataStorageDefaultListModel2->SetDataStorage(GetDataStorage()); + m_Controls.selectionListView2->setSelectionMode(QAbstractItemView::ExtendedSelection); + m_Controls.selectionListView2->setSelectionBehavior(QAbstractItemView::SelectRows); + m_Controls.selectionListView2->setAlternatingRowColors(true); + m_Controls.selectionListView2->setModel(m_DataStorageDefaultListModel2); + + m_ModelViewSelectionConnector = std::make_unique(); + m_ModelViewSelectionConnector->SetModel(m_DataStorageDefaultListModel); + m_ModelViewSelectionConnector->SetView(m_Controls.selectionListView); + m_ModelViewSelectionConnector->AddPostSelectionListener(GetSite()->GetWorkbenchWindow()->GetSelectionService()); + + m_ModelViewSelectionConnector2 = std::make_unique(); + m_ModelViewSelectionConnector2->SetModel(m_DataStorageDefaultListModel2); + m_ModelViewSelectionConnector2->SetView(m_Controls.selectionListView2); + m_ModelViewSelectionConnector2->AddPostSelectionListener(GetSite()->GetWorkbenchWindow()->GetSelectionService()); connect(m_Controls.selectionProviderCheckBox, SIGNAL(toggled(bool)), this, SLOT(SetAsSelectionProvider1(bool))); connect(m_Controls.selectionProviderCheckBox2, SIGNAL(toggled(bool)), this, SLOT(SetAsSelectionProvider2(bool))); } void QmitkDataStorageViewerTestView::SetAsSelectionProvider1(bool checked) { if (checked) { - m_DataStorageSelectionConnector->SetAsSelectionProvider(GetSite()->GetSelectionProvider().Cast().GetPointer()); + m_ModelViewSelectionConnector->SetAsSelectionProvider(GetSite()->GetSelectionProvider().Cast().GetPointer()); } else { - m_DataStorageSelectionConnector->RemoveAsSelectionProvider(); + m_ModelViewSelectionConnector->RemoveAsSelectionProvider(); } } void QmitkDataStorageViewerTestView::SetAsSelectionProvider2(bool checked) { if (checked) { - m_DataStorageSelectionConnector2->SetAsSelectionProvider(GetSite()->GetSelectionProvider().Cast().GetPointer()); + m_ModelViewSelectionConnector2->SetAsSelectionProvider(GetSite()->GetSelectionProvider().Cast().GetPointer()); } else { - m_DataStorageSelectionConnector2->RemoveAsSelectionProvider(); + m_ModelViewSelectionConnector2->RemoveAsSelectionProvider(); } } diff --git a/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/QmitkDataStorageViewerTestView.h b/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/QmitkDataStorageViewerTestView.h index d2bd0bb84b..536dbc4277 100644 --- a/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/QmitkDataStorageViewerTestView.h +++ b/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/QmitkDataStorageViewerTestView.h @@ -1,61 +1,62 @@ /*=================================================================== 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. ===================================================================*/ #ifndef QMITKDATASTORAGEVIEWERTESTVIEW_H #define QMITKDATASTORAGEVIEWERTESTVIEW_H // mitk gui qt common plugin #include -#include "QmitkDataStorageSelectionConnector.h" +#include "QmitkModelViewSelectionConnector.h" // data storage viewer test plugin - #include "ui_QmitkDataStorageViewerTestControls.h" // qt widgets module -#include "QmitkDataStorageDefaultView.h" +#include "QmitkDataStorageDefaultListModel.h" /** * @brief DataStorageViewerTestView */ class QmitkDataStorageViewerTestView : public QmitkAbstractView { Q_OBJECT public: static const std::string VIEW_ID; protected: virtual void SetFocus() override; virtual void CreateQtPartControl(QWidget* parent) override; private Q_SLOTS: void SetAsSelectionProvider1(bool checked); void SetAsSelectionProvider2(bool checked); private: Ui::QmitkDataStorageViewerTestControls m_Controls; + QmitkDataStorageDefaultListModel* m_DataStorageDefaultListModel; + QmitkDataStorageDefaultListModel* m_DataStorageDefaultListModel2; - std::unique_ptr m_DataStorageSelectionConnector; - std::unique_ptr m_DataStorageSelectionConnector2; + std::unique_ptr m_ModelViewSelectionConnector; + std::unique_ptr m_ModelViewSelectionConnector2; }; #endif // QMITKDATASTORAGEVIEWERTESTVIEW_H