diff --git a/Modules/QtWidgets/include/QmitkDataStorageDefaultListModel.h b/Modules/QtWidgets/include/QmitkDataStorageDefaultListModel.h index 5e65a22cf2..7dbd119978 100644 --- a/Modules/QtWidgets/include/QmitkDataStorageDefaultListModel.h +++ b/Modules/QtWidgets/include/QmitkDataStorageDefaultListModel.h @@ -1,84 +1,81 @@ /*=================================================================== 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 -// qt -#include - /** -* @brief The 'QmitkDataStorageDefaultListModel' is a basic list model, that implements the 'QmitkIDataStorageViewModel'. +* @brief The 'QmitkDataStorageDefaultListModel' is a basic list model, derived from the 'QmitkAbstractDataStorageModel'. * 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 'QmitkDataStorageSelectionConnector'. */ class MITKQTWIDGETS_EXPORT QmitkDataStorageDefaultListModel : public QmitkAbstractDataStorageModel { public: QmitkDataStorageDefaultListModel(QObject *parent); // override from 'QmitkAbstractDataStorageModel' /* * @brief See 'QmitkAbstractDataStorageModel' */ void DataStorageChanged() override; /* * @brief See 'QmitkAbstractDataStorageModel' */ 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: void UpdateModelData(); std::vector m_DataNodes; }; #endif // QMITKDATASTORAGEDEFAULTLISTMODEL_H diff --git a/Plugins/org.mitk.gui.qt.common/files.cmake b/Plugins/org.mitk.gui.qt.common/files.cmake index 5dedec11be..a33682f411 100755 --- a/Plugins/org.mitk.gui.qt.common/files.cmake +++ b/Plugins/org.mitk.gui.qt.common/files.cmake @@ -1,40 +1,42 @@ set(SRC_CPP_FILES QmitkAbstractRenderEditor.cpp QmitkAbstractView.cpp QmitkDataNodeSelectionProvider.cpp QmitkDnDFrameWidget.cpp QmitkModelViewSelectionConnector.cpp + QmitkSelectionServiceConnector.cpp QmitkSliceNavigationListener.cpp ) set(INTERNAL_CPP_FILES QmitkCommonActivator.cpp QmitkDataNodeItemModel.cpp QmitkDataNodeSelection.cpp QmitkViewCoordinator.cpp ) set(MOC_H_FILES src/QmitkAbstractRenderEditor.h src/QmitkDnDFrameWidget.h src/QmitkModelViewSelectionConnector.h + src/QmitkSelectionServiceConnector.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/QmitkModelViewSelectionConnector.cpp b/Plugins/org.mitk.gui.qt.common/src/QmitkModelViewSelectionConnector.cpp index cc5792b8d6..46c0a27e7a 100644 --- a/Plugins/org.mitk.gui.qt.common/src/QmitkModelViewSelectionConnector.cpp +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkModelViewSelectionConnector.cpp @@ -1,280 +1,178 @@ /*=================================================================== 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(); + // nothing here } 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 index 12b199e15f..1b36021510 100644 --- a/Plugins/org.mitk.gui.qt.common/src/QmitkModelViewSelectionConnector.h +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkModelViewSelectionConnector.h @@ -1,199 +1,144 @@ /*=================================================================== 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.common/src/QmitkSelectionServiceConnector.cpp b/Plugins/org.mitk.gui.qt.common/src/QmitkSelectionServiceConnector.cpp new file mode 100644 index 0000000000..657460f461 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkSelectionServiceConnector.cpp @@ -0,0 +1,130 @@ +/*=================================================================== + +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 "QmitkSelectionServiceConnector.h" +#include "internal/QmitkDataNodeSelection.h" + +// qt widgets module +#include "QmitkCustomVariants.h" +#include "QmitkEnums.h" + +// blueberry ui qt plugin +#include + +QmitkSelectionServiceConnector::QmitkSelectionServiceConnector() + : m_SelectionService(nullptr) + , m_SelectionProvider(nullptr) +{ + m_DataNodeItemModel = std::make_shared(); + m_DataNodeSelectionModel = std::make_shared(m_DataNodeItemModel.get()); +} + +QmitkSelectionServiceConnector::~QmitkSelectionServiceConnector() +{ + RemovePostSelectionListener(); + RemoveAsSelectionProvider(); +} + +void QmitkSelectionServiceConnector::AddPostSelectionListener(berry::ISelectionService* selectionService) +{ + if (nullptr == selectionService) + { + return; + } + + m_SelectionService = selectionService; + m_BerrySelectionListener.reset(new berry::NullSelectionChangedAdapter(this, &QmitkSelectionServiceConnector::GlobalSelectionChanged)); + m_SelectionService->AddPostSelectionListener(m_BerrySelectionListener.get()); +} + +void QmitkSelectionServiceConnector::RemovePostSelectionListener() +{ + if (nullptr == m_SelectionService) + { + return; + } + + m_SelectionService->RemovePostSelectionListener(m_BerrySelectionListener.get()); + m_SelectionService = nullptr; +} + +void QmitkSelectionServiceConnector::SetAsSelectionProvider(QmitkDataNodeSelectionProvider* selectionProvider) +{ + m_SelectionProvider = selectionProvider; +} + +void QmitkSelectionServiceConnector::RemoveAsSelectionProvider() +{ + m_SelectionProvider = nullptr; +} + +void QmitkSelectionServiceConnector::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 QmitkSelectionServiceConnector::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()); + } + + // send new (possibly empty) list of selected nodes + emit GlobalSelectionChanged(nodes); +} diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkSelectionServiceConnector.h b/Plugins/org.mitk.gui.qt.common/src/QmitkSelectionServiceConnector.h new file mode 100644 index 0000000000..e93322b54c --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkSelectionServiceConnector.h @@ -0,0 +1,130 @@ +/*=================================================================== + +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 QMITKSELECTIONSERVICECONNECTOR_H +#define QMITKSELECTIONSERVICECONNECTOR_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 'QmitkSelectionServiceConnector' is used to handle the selections of the global selection bus (selection service). +* +* The selection service connector can listen to a selection service. This should be done by using 'AddPostSelectionListener' +* with the existing selection service of the surrounding 'QmitkAbstractView'. +* The selection service connector can provide selections. This should be done by using 'SetAsSelectionProvider' +* with the existing selection provider of the surrounding 'QmitkAbstractView'. +* +* The 'QmitkSelectionServiceConnector' offers a public slot and signal that can be used to propagate the selected +* nodes from or to the global selection bus: +* The 'FireGlobalSelectionChanged'-slot transforms the given list of selected nodes into a QItemSelection of a temporary +* data node selection model. This data node selection model is set as the item selection model of the member selection provider. +* So by temporary adding a new data node selection model and changing its selection the selection provider sends a new selection +* that can be received at any place in the workbench. +* +* The 'GlobalSelectionChanged'-signal sends a list of selected nodes to it's environment. +* The 'GlobalSelectionChanged'-signal is emitted by the 'GlobalSelectionChanged'-function, which transforms the +* berry selection of the selection into a data node list. The 'GlobalSelectionChanged'-function is called whenever +* the selection service sends a selection changed event. +* +* In order to connect the 'QmitkSelectionServiceConnector' with a model-view pair, a 'QmitkModelViewSelectionConnector' needs to be used: +* The 'QmitkModelViewSelectionConnector' offers a 'SetCurrentSelection'-slot that can be connected with the +* 'GlobalSelectionChanged'-signal of this class. +* The 'QmitkModelViewSelectionConnector' offers a 'CurrentSelectionChanged'-signal that can be connected with the +* 'FireGlobalSelectionChanged'-slot of this class. +*/ +class MITK_QT_COMMON QmitkSelectionServiceConnector : public QObject +{ + Q_OBJECT + +public: + + QmitkSelectionServiceConnector(); + ~QmitkSelectionServiceConnector(); + + /* + * @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 private 'GlobalSelectionChanged'-function. This happens if a selection is changed + * via the selection bus. + * + * @par nodes A list of data nodes that are newly selected. + */ + void GlobalSelectionChanged(QList nodes); + +public Q_SLOTS: + /* + * @brief Send global selections to the selection provider. + * + * This slot-function is called whenever a local selection is changed in the workbench and a selection provider was set. + * 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: + + 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); + +}; + +#endif // QMITKSELECTIONSERVICECONNECTOR_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 660ddfe423..f588bf3301 100644 --- a/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/QmitkDataStorageViewerTestView.cpp +++ b/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/QmitkDataStorageViewerTestView.cpp @@ -1,88 +1,96 @@ /*=================================================================== 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_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_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_SelectionServiceConnector = std::make_unique(); + m_SelectionServiceConnector->AddPostSelectionListener(GetSite()->GetWorkbenchWindow()->GetSelectionService()); + connect(m_SelectionServiceConnector.get(), SIGNAL(GlobalSelectionChanged(QList)), m_ModelViewSelectionConnector.get(), SLOT(SetCurrentSelection(QList))); m_ModelViewSelectionConnector2 = std::make_unique(); m_ModelViewSelectionConnector2->SetModel(m_DataStorageDefaultListModel2); m_ModelViewSelectionConnector2->SetView(m_Controls.selectionListView2); - m_ModelViewSelectionConnector2->AddPostSelectionListener(GetSite()->GetWorkbenchWindow()->GetSelectionService()); + m_SelectionServiceConnector2 = std::make_unique(); + m_SelectionServiceConnector2->AddPostSelectionListener(GetSite()->GetWorkbenchWindow()->GetSelectionService()); + connect(m_SelectionServiceConnector2.get(), SIGNAL(GlobalSelectionChanged(QList)), m_ModelViewSelectionConnector2.get(), SLOT(SetCurrentSelection(QList))); 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_ModelViewSelectionConnector->SetAsSelectionProvider(GetSite()->GetSelectionProvider().Cast().GetPointer()); + m_SelectionServiceConnector->SetAsSelectionProvider(GetSite()->GetSelectionProvider().Cast().GetPointer()); + connect(m_ModelViewSelectionConnector.get(), SIGNAL(CurrentSelectionChanged(QList)), m_SelectionServiceConnector.get(), SLOT(FireGlobalSelectionChanged(QList))); } else { - m_ModelViewSelectionConnector->RemoveAsSelectionProvider(); + m_SelectionServiceConnector->RemoveAsSelectionProvider(); + disconnect(m_ModelViewSelectionConnector.get(), SIGNAL(CurrentSelectionChanged(QList)), m_SelectionServiceConnector.get(), SLOT(FireGlobalSelectionChanged(QList))); } } void QmitkDataStorageViewerTestView::SetAsSelectionProvider2(bool checked) { if (checked) { - m_ModelViewSelectionConnector2->SetAsSelectionProvider(GetSite()->GetSelectionProvider().Cast().GetPointer()); + m_SelectionServiceConnector2->SetAsSelectionProvider(GetSite()->GetSelectionProvider().Cast().GetPointer()); + connect(m_ModelViewSelectionConnector2.get(), SIGNAL(CurrentSelectionChanged(QList)), m_SelectionServiceConnector2.get(), SLOT(FireGlobalSelectionChanged(QList))); } else { - m_ModelViewSelectionConnector2->RemoveAsSelectionProvider(); + m_SelectionServiceConnector2->RemoveAsSelectionProvider(); + disconnect(m_ModelViewSelectionConnector2.get(), SIGNAL(CurrentSelectionChanged(QList)), m_SelectionServiceConnector2.get(), SLOT(FireGlobalSelectionChanged(QList))); } } 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 536dbc4277..3e2f86faef 100644 --- a/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/QmitkDataStorageViewerTestView.h +++ b/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/QmitkDataStorageViewerTestView.h @@ -1,62 +1,65 @@ /*=================================================================== 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 "QmitkModelViewSelectionConnector.h" +#include "QmitkSelectionServiceConnector.h" // data storage viewer test plugin #include "ui_QmitkDataStorageViewerTestControls.h" // qt widgets module #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_ModelViewSelectionConnector; + std::unique_ptr m_SelectionServiceConnector; std::unique_ptr m_ModelViewSelectionConnector2; + std::unique_ptr m_SelectionServiceConnector2; }; #endif // QMITKDATASTORAGEVIEWERTESTVIEW_H