diff --git a/Modules/QtWidgets/include/QmitkAbstractNodeSelectionWidget.h b/Modules/QtWidgets/include/QmitkAbstractNodeSelectionWidget.h index b968153561..c014cc745a 100644 --- a/Modules/QtWidgets/include/QmitkAbstractNodeSelectionWidget.h +++ b/Modules/QtWidgets/include/QmitkAbstractNodeSelectionWidget.h @@ -1,234 +1,241 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef QMITK_ABSTRACT_NODE_SELECTION_WIDGET_H #define QMITK_ABSTRACT_NODE_SELECTION_WIDGET_H #include #include #include #include #include class QmitkAbstractDataStorageModel; class QAbstractItemVew; /** * \class QmitkAbstractNodeSelectionWidget * \brief Abstract base class for the selection of data from a data storage. */ class MITKQTWIDGETS_EXPORT QmitkAbstractNodeSelectionWidget : public QWidget { Q_OBJECT public: explicit QmitkAbstractNodeSelectionWidget(QWidget* parent = nullptr); virtual ~QmitkAbstractNodeSelectionWidget() override; /** * @brief Sets the data storage that will be used /monitored by widget. * * @par dataStorage A pointer to the data storage to set. */ void SetDataStorage(mitk::DataStorage* dataStorage); /** * Sets the node predicate and updates the widget, according to the node predicate. * Implement OnNodePredicateChange() for custom actualization of a derived widget class. * * @par nodePredicate A pointer to node predicate. */ void SetNodePredicate(const mitk::NodePredicateBase* nodePredicate); const mitk::NodePredicateBase* GetNodePredicate() const; QString GetInvalidInfo() const; QString GetEmptyInfo() const; QString GetPopUpTitel() const; QString GetPopUpHint() const; bool GetSelectionIsOptional() const; bool GetSelectOnlyVisibleNodes() const; using NodeList = QList; /** Returns the selected nodes, as emitted with CurrentSelectionChanged*/ NodeList GetSelectedNodes() const; Q_SIGNALS: /* * @brief A signal that will be emitted if the selected node has changed. * * @par nodes A list of data nodes that are newly selected. */ void CurrentSelectionChanged(NodeList 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 do not fullfill the predicate. * * @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(NodeList selectedNodes); /** Set the info text that should be displayed if no (valid) node is selected, * but a selection is mandatory. * The string can contain HTML code. if wanted*/ void SetInvalidInfo(QString info); /** Set the info text that should be displayed if no (valid) node is selected, * but a selection is optional. * The string can contain HTML code. if wanted*/ void SetEmptyInfo(QString info); /** Set the caption of the popup that is displayed to alter the selection. * The string can contain HTML code. if wanted*/ void SetPopUpTitel(QString info); /** Set the hint text of the popup that is displayed to alter the selection. * The string can contain HTML code. if wanted*/ void SetPopUpHint(QString info); /** Set the widget into an optional mode. Optional means that the selection of no valid node does not mean an invalid state. Thus no node is a valid "node" selection too.*/ void SetSelectionIsOptional(bool isOptional); protected Q_SLOTS: /** Call to remove a node from the current selection. If the node is part of the current selection, this will trigger ReviseSelectionChanged(), AllowEmissionOfSelection() and if there is really a change, will also emit CurrentSelectionChanged.*/ void RemoveNodeFromSelection(const mitk::DataNode* node); protected: /**Method is called if the display of the selected nodes should be updated (e.g. because the selection changed)*/ virtual void UpdateInfo() = 0; /**Method is called if the predicate has changed, before the selection will be updated according to the new predicate. The default implementation does nothing. @remark If you are only interested to know when the selection has changed, overwrite OnInternalSelectionChange().*/ virtual void OnNodePredicateChanged(); /**Method is called if the data storage has changed. The selection will be automatically be reseted afterwards. The default implementation does nothing.*/ virtual void OnDataStorageChanged(); /** This member function will called when ever a new internal selection has been determined. This can be used to update the state of internal widgets. The default implementation does nothing.*/ virtual void OnInternalSelectionChanged(); /**Method is called when a node is added to the storage. Default implementation does nothing. Derived widgets can override the method if they want to react on new nodes in the storage.*/ virtual void OnNodeAddedToStorage(const mitk::DataNode* node); /**Method is called when a node is removed from the storage. The removed node is passed as variable. This member is called directly before the node will be removed from the current selection if he was a part. Default implementation does nothing. */ virtual void OnNodeRemovedFromStorage(const mitk::DataNode* node); - /**Method is called if the internal selection has changed. It will call the methods ReviseSelectionChanged(), - OnInternalSelectionChanged(), UpdateInfo() and EmitSelection() with the new emission candidates.*/ + /**Method is called if the internal selection has changed. It will call following methods, that can be overriden to change + behavior in derived classes: + - pre internal selection change: ReviseSelectionChanged() + - post internal selection change: OnInternalSelectionChanged(), UpdateInfo() and AllowEmissionOfSelection() (via EmitSelection()) + . + If the emission is needed and allowed it will also trigger the emission via EmitSelection().*/ void HandleChangeOfInternalSelection(NodeList newInternalSelection); /**Compiles the list of node that would be emitted. It always contains the internal selection. Depending on SelectOnlyVisibleNodes it also adds all external select nodes that weren't visible (failed the predicate).*/ NodeList CompileEmitSelection() const; /** This member function is called if the internal selection is about to be changed by the base implementation. This is the slot where derived classes can revise and change the internal selection before widget updates, signal emissions and other things are triggered. Default implementation does nothing, thus it keeps the passed internal selection as compiled by the base implementation.*/ virtual void ReviseSelectionChanged(const NodeList& oldInternalSelection, NodeList& newInternalSelection); /** This function will be called before the CurrentSelectionChanged signal is emitted. The return value indicates if the signal should be emitted (true = emission; false = no emission). The default implementation always returns true. @param emissionCandidates The nodes that will be emitted if the function returns true.*/ virtual bool AllowEmissionOfSelection(const NodeList& emissionCandidates) const; /** Checks if the new emission differs from the last emission. If this is the case and AllowEmissionOfSelection() returns true the new selection will be emited. */ void EmitSelection(const NodeList& emissionCandidates); void SetCurrentInternalSelection(NodeList selectedNodes); const NodeList& GetCurrentInternalSelection() const; const NodeList& GetCurrentExternalSelection() const; mitk::WeakPointer m_DataStorage; mitk::NodePredicateBase::ConstPointer m_NodePredicate; QString m_InvalidInfo; QString m_EmptyInfo; QString m_PopUpTitel; QString m_PopUpHint; /** See documentation of SetSelectOnlyVisibleNodes for details*/ bool m_IsOptional; /** See documentation of SetSelectionIsOptional for details*/ bool m_SelectOnlyVisibleNodes; private: /** Helper triggered on the storage delete event */ void SetDataStorageDeleted(); /**Member is called when a node is added to the storage. Derived widgets can override the method OnNodeAddedToStorage if they want to react on new nodes in the storage.*/ void NodeAddedToStorage(const mitk::DataNode* node); /**Member is called when a node is removed from the storage. It calls OnNodeRemovedFromStorage() and afterwards it removes the removed node form the selection (if it is part of the current selection). Derived classes can override OnNodeRemovedFromStorage() to react on the fact that a node might be removed and their selection might change, because the removed node is part of there selection.*/ void NodeRemovedFromStorage(const mitk::DataNode* node); void OnNodeModified(const itk::Object * /*caller*/, const itk::EventObject &); void AddNodeObserver(mitk::DataNode* node); void RemoveNodeObserver(mitk::DataNode* node); unsigned long m_DataStorageDeletedTag; NodeList m_CurrentInternalSelection; NodeList m_CurrentExternalSelection; NodeList m_LastEmission; bool m_LastEmissionAllowance; using NodeObserverTagMapType = std::map; NodeObserverTagMapType m_NodeObserverTags; + + /** Help to prevent recursions due to signal loops when emitting selections.*/ + bool m_RecursionGuard; }; #endif // QmitkAbstractNodeSelectionWidget_H diff --git a/Modules/QtWidgets/src/QmitkAbstractNodeSelectionWidget.cpp b/Modules/QtWidgets/src/QmitkAbstractNodeSelectionWidget.cpp index 008660151c..c352fe31c4 100644 --- a/Modules/QtWidgets/src/QmitkAbstractNodeSelectionWidget.cpp +++ b/Modules/QtWidgets/src/QmitkAbstractNodeSelectionWidget.cpp @@ -1,405 +1,410 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "QmitkAbstractNodeSelectionWidget.h" #include "QmitkModelViewSelectionConnector.h" QmitkAbstractNodeSelectionWidget::QmitkAbstractNodeSelectionWidget(QWidget* parent) : QWidget(parent), m_InvalidInfo("Error. Select data."), m_EmptyInfo("Empty. Make a selection."), m_PopUpTitel("Select a data node"), m_PopUpHint(""), -m_IsOptional(false), m_SelectOnlyVisibleNodes(true), m_DataStorageDeletedTag(0), m_LastEmissionAllowance(true) +m_IsOptional(false), m_SelectOnlyVisibleNodes(true), m_DataStorageDeletedTag(0), m_LastEmissionAllowance(true), m_RecursionGuard(false) { } QmitkAbstractNodeSelectionWidget::~QmitkAbstractNodeSelectionWidget() { auto dataStorage = m_DataStorage.Lock(); if (dataStorage.IsNotNull()) { // remove Listener for the data storage itself dataStorage->RemoveObserver(m_DataStorageDeletedTag); // remove "add node listener" from data storage dataStorage->AddNodeEvent.RemoveListener( mitk::MessageDelegate1(this, &QmitkAbstractNodeSelectionWidget::NodeAddedToStorage)); // remove "remove node listener" from data storage dataStorage->RemoveNodeEvent.RemoveListener( mitk::MessageDelegate1(this, &QmitkAbstractNodeSelectionWidget::NodeRemovedFromStorage)); } for (auto& node : m_CurrentInternalSelection) { this->RemoveNodeObserver(node); } } QmitkAbstractNodeSelectionWidget::NodeList QmitkAbstractNodeSelectionWidget::GetSelectedNodes() const { return this->CompileEmitSelection(); } void QmitkAbstractNodeSelectionWidget::SetDataStorage(mitk::DataStorage* dataStorage) { if (m_DataStorage == dataStorage) { return; } auto oldStorage = m_DataStorage.Lock(); if (oldStorage.IsNotNull()) { // remove Listener for the data storage itself oldStorage->RemoveObserver(m_DataStorageDeletedTag); // remove "add node listener" from old data storage oldStorage->AddNodeEvent.RemoveListener( mitk::MessageDelegate1(this, &QmitkAbstractNodeSelectionWidget::NodeAddedToStorage)); // remove "remove node listener" from old data storage oldStorage->RemoveNodeEvent.RemoveListener( mitk::MessageDelegate1(this, &QmitkAbstractNodeSelectionWidget::NodeRemovedFromStorage)); } m_DataStorage = dataStorage; auto newStorage = m_DataStorage.Lock(); if (newStorage.IsNotNull()) { // add Listener for the data storage itself auto command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &QmitkAbstractNodeSelectionWidget::SetDataStorageDeleted); m_DataStorageDeletedTag = newStorage->AddObserver(itk::DeleteEvent(), command); // add "add node listener" for new data storage newStorage->AddNodeEvent.AddListener( mitk::MessageDelegate1(this, &QmitkAbstractNodeSelectionWidget::NodeAddedToStorage)); // add remove node listener for new data storage newStorage->RemoveNodeEvent.AddListener( mitk::MessageDelegate1(this, &QmitkAbstractNodeSelectionWidget::NodeRemovedFromStorage)); } this->OnDataStorageChanged(); this->HandleChangeOfInternalSelection({}); } void QmitkAbstractNodeSelectionWidget::SetNodePredicate(const mitk::NodePredicateBase* nodePredicate) { if (m_NodePredicate != nodePredicate) { m_NodePredicate = nodePredicate; this->OnNodePredicateChanged(); NodeList newInternalNodes; for (auto& node : m_CurrentInternalSelection) { if (m_NodePredicate.IsNull() || m_NodePredicate->CheckNode(node)) { newInternalNodes.append(node); } } if (!m_SelectOnlyVisibleNodes) { for (auto& node : m_CurrentExternalSelection) { if (!newInternalNodes.contains(node) && (m_NodePredicate.IsNull() || m_NodePredicate->CheckNode(node))) { newInternalNodes.append(node); } } } this->HandleChangeOfInternalSelection(newInternalNodes); } } void QmitkAbstractNodeSelectionWidget::HandleChangeOfInternalSelection(NodeList newInternalSelection) { this->ReviseSelectionChanged(m_CurrentInternalSelection, newInternalSelection); this->SetCurrentInternalSelection(newInternalSelection); this->OnInternalSelectionChanged(); auto newEmission = this->CompileEmitSelection(); this->EmitSelection(newEmission); this->UpdateInfo(); } void QmitkAbstractNodeSelectionWidget::SetCurrentSelection(NodeList selectedNodes) { - m_CurrentExternalSelection = selectedNodes; - - auto dataStorage = m_DataStorage.Lock(); - NodeList newInternalSelection; - for (auto node : selectedNodes) + if (!m_RecursionGuard) { - if (dataStorage.IsNotNull() && dataStorage->Exists(node) && (m_NodePredicate.IsNull() || m_NodePredicate->CheckNode(node))) + m_CurrentExternalSelection = selectedNodes; + + auto dataStorage = m_DataStorage.Lock(); + NodeList newInternalSelection; + for (auto node : selectedNodes) { - newInternalSelection.append(node); + if (dataStorage.IsNotNull() && dataStorage->Exists(node) && (m_NodePredicate.IsNull() || m_NodePredicate->CheckNode(node))) + { + newInternalSelection.append(node); + } } - } - this->HandleChangeOfInternalSelection(newInternalSelection); + this->HandleChangeOfInternalSelection(newInternalSelection); + } } const mitk::NodePredicateBase* QmitkAbstractNodeSelectionWidget::GetNodePredicate() const { return m_NodePredicate; } QString QmitkAbstractNodeSelectionWidget::GetInvalidInfo() const { return m_InvalidInfo; } QString QmitkAbstractNodeSelectionWidget::GetEmptyInfo() const { return m_EmptyInfo; } QString QmitkAbstractNodeSelectionWidget::GetPopUpTitel() const { return m_PopUpTitel; } QString QmitkAbstractNodeSelectionWidget::GetPopUpHint() const { return m_PopUpHint; } bool QmitkAbstractNodeSelectionWidget::GetSelectionIsOptional() const { return m_IsOptional; } bool QmitkAbstractNodeSelectionWidget::GetSelectOnlyVisibleNodes() const { return m_SelectOnlyVisibleNodes; } void QmitkAbstractNodeSelectionWidget::SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes) { if (m_SelectOnlyVisibleNodes != selectOnlyVisibleNodes) { m_SelectOnlyVisibleNodes = selectOnlyVisibleNodes; auto newEmission = this->CompileEmitSelection(); this->EmitSelection(newEmission); } } void QmitkAbstractNodeSelectionWidget::SetInvalidInfo(QString info) { m_InvalidInfo = info; this->UpdateInfo(); } void QmitkAbstractNodeSelectionWidget::SetEmptyInfo(QString info) { m_EmptyInfo = info; this->UpdateInfo(); } void QmitkAbstractNodeSelectionWidget::SetPopUpTitel(QString info) { m_PopUpTitel = info; } void QmitkAbstractNodeSelectionWidget::SetPopUpHint(QString info) { m_PopUpHint = info; } void QmitkAbstractNodeSelectionWidget::SetSelectionIsOptional(bool isOptional) { m_IsOptional = isOptional; this->UpdateInfo(); } void QmitkAbstractNodeSelectionWidget::SetDataStorageDeleted() { this->OnDataStorageChanged(); this->HandleChangeOfInternalSelection({}); } void QmitkAbstractNodeSelectionWidget::ReviseSelectionChanged(const NodeList& /*oldInternalSelection*/, NodeList& /*newInternalSelection*/) { } bool QmitkAbstractNodeSelectionWidget::AllowEmissionOfSelection(const NodeList& /*emissionCandidates*/) const { return true; } void QmitkAbstractNodeSelectionWidget::EmitSelection(const NodeList& emissionCandidates) { m_LastEmissionAllowance = this->AllowEmissionOfSelection(emissionCandidates); if (m_LastEmissionAllowance && !EqualNodeSelections(m_LastEmission, emissionCandidates)) { + m_RecursionGuard = true; emit CurrentSelectionChanged(emissionCandidates); + m_RecursionGuard = false; m_LastEmission = emissionCandidates; } } void QmitkAbstractNodeSelectionWidget::SetCurrentInternalSelection(NodeList selectedNodes) { for (auto& node : m_CurrentInternalSelection) { this->RemoveNodeObserver(node); } m_CurrentInternalSelection = selectedNodes; for (auto& node : m_CurrentInternalSelection) { this->AddNodeObserver(node); } } const QmitkAbstractNodeSelectionWidget::NodeList& QmitkAbstractNodeSelectionWidget::GetCurrentInternalSelection() const { return m_CurrentInternalSelection; } const QmitkAbstractNodeSelectionWidget::NodeList& QmitkAbstractNodeSelectionWidget::GetCurrentExternalSelection() const { return m_CurrentExternalSelection; } void QmitkAbstractNodeSelectionWidget::OnNodePredicateChanged() { } void QmitkAbstractNodeSelectionWidget::OnDataStorageChanged() { } void QmitkAbstractNodeSelectionWidget::OnInternalSelectionChanged() { } void QmitkAbstractNodeSelectionWidget::NodeAddedToStorage(const mitk::DataNode* node) { this->OnNodeAddedToStorage(node); } void QmitkAbstractNodeSelectionWidget::OnNodeAddedToStorage(const mitk::DataNode* /*node*/) { } void QmitkAbstractNodeSelectionWidget::NodeRemovedFromStorage(const mitk::DataNode* node) { this->OnNodeRemovedFromStorage(node); this->RemoveNodeFromSelection(node); } void QmitkAbstractNodeSelectionWidget::OnNodeRemovedFromStorage(const mitk::DataNode* /*node*/) { } QmitkAbstractNodeSelectionWidget::NodeList QmitkAbstractNodeSelectionWidget::CompileEmitSelection() const { NodeList result = m_CurrentInternalSelection; if (!m_SelectOnlyVisibleNodes) { for (auto node : m_CurrentExternalSelection) { if (!result.contains(node) && m_NodePredicate.IsNotNull() && !m_NodePredicate->CheckNode(node)) { result.append(node); } } } return result; } void QmitkAbstractNodeSelectionWidget::RemoveNodeFromSelection(const mitk::DataNode* node) { auto newSelection = m_CurrentInternalSelection; auto finding = std::find(std::begin(newSelection), std::end(newSelection), node); if (finding != std::end(newSelection)) { newSelection.erase(finding); this->HandleChangeOfInternalSelection(newSelection); } } void QmitkAbstractNodeSelectionWidget::OnNodeModified(const itk::Object * caller, const itk::EventObject & event) { if (itk::ModifiedEvent().CheckEvent(&event)) { auto node = dynamic_cast(caller); if (node) { if (m_NodePredicate.IsNotNull() && !m_NodePredicate->CheckNode(node)) { this->RemoveNodeFromSelection(node); } else { auto oldAllowance = m_LastEmissionAllowance; auto newEmission = this->CompileEmitSelection(); auto nonConstNode = const_cast(node); if (newEmission.contains(nonConstNode) && (oldAllowance != this->AllowEmissionOfSelection(newEmission))) { this->EmitSelection(newEmission); this->UpdateInfo(); } } } } } void QmitkAbstractNodeSelectionWidget::AddNodeObserver(mitk::DataNode* node) { if (node) { auto modifiedCommand = itk::MemberCommand::New(); modifiedCommand->SetCallbackFunction(this, &QmitkAbstractNodeSelectionWidget::OnNodeModified); auto nodeModifiedObserverTag = node->AddObserver(itk::ModifiedEvent(), modifiedCommand); m_NodeObserverTags.insert(std::make_pair(node, nodeModifiedObserverTag)); } } void QmitkAbstractNodeSelectionWidget::RemoveNodeObserver(mitk::DataNode* node) { if (node) { auto finding = m_NodeObserverTags.find(node); if (finding != std::end(m_NodeObserverTags)) { node->RemoveObserver(finding->second); } else { MITK_ERROR << "Selection widget is in a wrong state. A node should be removed from the internal selection but seems to have no observer. Node:" << node; } m_NodeObserverTags.erase(node); } } diff --git a/Modules/QtWidgets/test/QmitkAbstractNodeSelectionWidgetTest.cpp b/Modules/QtWidgets/test/QmitkAbstractNodeSelectionWidgetTest.cpp index b98c4ccaa7..dae23380ac 100644 --- a/Modules/QtWidgets/test/QmitkAbstractNodeSelectionWidgetTest.cpp +++ b/Modules/QtWidgets/test/QmitkAbstractNodeSelectionWidgetTest.cpp @@ -1,586 +1,624 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "QmitkAbstractNodeSelectionWidget.h" #include #include #include #include "QmitkModelViewSelectionConnector.h" #include #include class TestWidget : public QmitkAbstractNodeSelectionWidget { public: explicit TestWidget(QWidget* parent = nullptr) : QmitkAbstractNodeSelectionWidget(parent), m_UpdateInfo(0), m_OnNodePredicateChanged(0), m_OnDataStorageChanged(0), m_OnInternalSelectionChanged(0), m_OnNodeAddedToStorage(0), m_OnNodeRemovedFromStorage(0), m_ReviseSelectionChanged(0), m_AllowEmissionOfSelection(0), m_Allow(true), m_NewSelectionEmited(0) { connect(this, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, this, &TestWidget::NewSelectionEmited); }; int m_UpdateInfo; void UpdateInfo() override { m_UpdateInfo++; }; int m_OnNodePredicateChanged; void OnNodePredicateChanged() override { m_OnNodePredicateChanged++; }; int m_OnDataStorageChanged; void OnDataStorageChanged() override { m_OnDataStorageChanged++; }; int m_OnInternalSelectionChanged; void OnInternalSelectionChanged() override { m_OnInternalSelectionChanged++; }; int m_OnNodeAddedToStorage; void OnNodeAddedToStorage(const mitk::DataNode* /*node*/) override { m_OnNodeAddedToStorage++; }; int m_OnNodeRemovedFromStorage; void OnNodeRemovedFromStorage(const mitk::DataNode* /*node*/) override { m_OnNodeRemovedFromStorage++; }; int m_ReviseSelectionChanged; void ReviseSelectionChanged(const NodeList& /*oldInternalSelection*/, NodeList& /*newInternalSelection*/) override { m_ReviseSelectionChanged++; }; mutable int m_AllowEmissionOfSelection; bool m_Allow; bool AllowEmissionOfSelection(const NodeList& emissionCandidates) const override { m_AllowEmissionOfSelection++; if (m_Allow) return QmitkAbstractNodeSelectionWidget::AllowEmissionOfSelection(emissionCandidates); return false; }; int m_NewSelectionEmited; QmitkAbstractNodeSelectionWidget::NodeList m_LastNewEmision; void NewSelectionEmited(NodeList selection) { m_NewSelectionEmited++; m_LastNewEmision = selection; }; }; class QmitkAbstractNodeSelectionWidgetTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(QmitkAbstractNodeSelectionWidgetTestSuite); MITK_TEST(InstantiationTest); MITK_TEST(SetDataStorageTest); MITK_TEST(DataStorageEventTest); MITK_TEST(NodePredicateTest); MITK_TEST(SelectOnlyVisibleNodesTest); - MITK_TEST(OtherSetterAnsGetterTest); + MITK_TEST(OtherSetterAndGetterTest); MITK_TEST(AllowEmissionOfSelectionTest); MITK_TEST(OnNodeModifiedTest); + MITK_TEST(SignalRecursionTest); CPPUNIT_TEST_SUITE_END(); mitk::DataStorage::Pointer m_DataStorage; mitk::DataNode::Pointer m_Node1; mitk::DataNode::Pointer m_Node1_2; mitk::DataNode::Pointer m_Node2; mitk::DataNode::Pointer m_Node3; QApplication* m_TestApp; public: void setUp() override { m_DataStorage = mitk::StandaloneDataStorage::New(); m_Node1 = mitk::DataNode::New(); m_Node1->SetName("node1_1"); m_Node2 = mitk::DataNode::New(); m_Node2->SetName("node2"); m_Node3 = mitk::DataNode::New(); m_Node3->SetName("node3"); m_Node1_2 = mitk::DataNode::New(); m_Node1_2->SetName("node1_2"); m_DataStorage->Add(m_Node1); m_DataStorage->Add(m_Node2); m_DataStorage->Add(m_Node3); m_DataStorage->Add(m_Node1_2); int argc = 0; char** argv = nullptr; m_TestApp = new QApplication(argc, argv); } mitk::NodePredicateBase::Pointer GeneratTestPredicate(const std::string& name) { auto check = [name](const mitk::DataNode * node) { return node->GetName().find(name,0) == 0; }; auto predicate = mitk::NodePredicateFunction::New(check); return predicate.GetPointer(); } void tearDown() override { delete m_TestApp; } void InstantiationTest() { TestWidget* widget; CPPUNIT_ASSERT_NO_THROW_MESSAGE("Normal constructor fails", widget = new TestWidget()); CPPUNIT_ASSERT_NO_THROW_MESSAGE("Normal destructor fails", delete widget); } void SetDataStorageTest() { TestWidget widget; widget.SetDataStorage(nullptr); CPPUNIT_ASSERT_EQUAL(0, widget.m_UpdateInfo); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodePredicateChanged); CPPUNIT_ASSERT_EQUAL_MESSAGE("Set same data storage but triggered change", 0, widget.m_OnDataStorageChanged); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnInternalSelectionChanged); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodeAddedToStorage); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodeRemovedFromStorage); CPPUNIT_ASSERT_EQUAL(0, widget.m_ReviseSelectionChanged); CPPUNIT_ASSERT_EQUAL(0, widget.m_AllowEmissionOfSelection); CPPUNIT_ASSERT_EQUAL(0, widget.m_NewSelectionEmited); widget.SetDataStorage(m_DataStorage); CPPUNIT_ASSERT_EQUAL(1, widget.m_UpdateInfo); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodePredicateChanged); CPPUNIT_ASSERT_EQUAL(1, widget.m_OnDataStorageChanged); CPPUNIT_ASSERT_EQUAL(1, widget.m_OnInternalSelectionChanged); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodeAddedToStorage); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodeRemovedFromStorage); CPPUNIT_ASSERT_EQUAL(1, widget.m_ReviseSelectionChanged); CPPUNIT_ASSERT_EQUAL(1, widget.m_AllowEmissionOfSelection); CPPUNIT_ASSERT_EQUAL(0, widget.m_NewSelectionEmited); widget.SetCurrentSelection({ m_Node1 }); CPPUNIT_ASSERT_EQUAL(2, widget.m_UpdateInfo); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodePredicateChanged); CPPUNIT_ASSERT_EQUAL(1, widget.m_OnDataStorageChanged); CPPUNIT_ASSERT_EQUAL(2, widget.m_OnInternalSelectionChanged); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodeAddedToStorage); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodeRemovedFromStorage); CPPUNIT_ASSERT_EQUAL(2, widget.m_ReviseSelectionChanged); CPPUNIT_ASSERT_EQUAL(2, widget.m_AllowEmissionOfSelection); CPPUNIT_ASSERT_EQUAL(1, widget.m_NewSelectionEmited); CPPUNIT_ASSERT(EqualNodeSelections({ m_Node1 }, widget.m_LastNewEmision)); CPPUNIT_ASSERT(EqualNodeSelections({ m_Node1 }, widget.GetSelectedNodes())); widget.SetDataStorage(m_DataStorage); CPPUNIT_ASSERT_EQUAL(2, widget.m_UpdateInfo); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodePredicateChanged); CPPUNIT_ASSERT_EQUAL_MESSAGE("Set same data storage but triggered change", 1, widget.m_OnDataStorageChanged); CPPUNIT_ASSERT_EQUAL(2, widget.m_OnInternalSelectionChanged); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodeAddedToStorage); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodeRemovedFromStorage); CPPUNIT_ASSERT_EQUAL(2, widget.m_ReviseSelectionChanged); CPPUNIT_ASSERT_EQUAL(2, widget.m_AllowEmissionOfSelection); CPPUNIT_ASSERT_EQUAL(1, widget.m_NewSelectionEmited); CPPUNIT_ASSERT(EqualNodeSelections({ m_Node1 }, widget.GetSelectedNodes())); widget.SetDataStorage(nullptr); CPPUNIT_ASSERT_EQUAL(3, widget.m_UpdateInfo); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodePredicateChanged); CPPUNIT_ASSERT_EQUAL_MESSAGE("Set same data storage but triggered change", 2, widget.m_OnDataStorageChanged); CPPUNIT_ASSERT_EQUAL(3, widget.m_OnInternalSelectionChanged); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodeAddedToStorage); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodeRemovedFromStorage); CPPUNIT_ASSERT_EQUAL(3, widget.m_ReviseSelectionChanged); CPPUNIT_ASSERT_EQUAL(3, widget.m_AllowEmissionOfSelection); CPPUNIT_ASSERT_EQUAL(2, widget.m_NewSelectionEmited); CPPUNIT_ASSERT(EqualNodeSelections({}, widget.m_LastNewEmision)); CPPUNIT_ASSERT(EqualNodeSelections({}, widget.GetSelectedNodes())); } void DataStorageEventTest() { TestWidget widget; auto newNode = mitk::DataNode::New(); widget.SetDataStorage(m_DataStorage); m_DataStorage->Add(newNode); CPPUNIT_ASSERT_EQUAL(1, widget.m_UpdateInfo); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodePredicateChanged); CPPUNIT_ASSERT_EQUAL(1, widget.m_OnDataStorageChanged); CPPUNIT_ASSERT_EQUAL(1, widget.m_OnInternalSelectionChanged); CPPUNIT_ASSERT_EQUAL(1, widget.m_OnNodeAddedToStorage); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodeRemovedFromStorage); CPPUNIT_ASSERT_EQUAL(1, widget.m_ReviseSelectionChanged); CPPUNIT_ASSERT_EQUAL(1, widget.m_AllowEmissionOfSelection); CPPUNIT_ASSERT_EQUAL(0, widget.m_NewSelectionEmited); widget.SetCurrentSelection({ newNode }); m_DataStorage->Remove(m_Node1); CPPUNIT_ASSERT_EQUAL(2, widget.m_UpdateInfo); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodePredicateChanged); CPPUNIT_ASSERT_EQUAL(1, widget.m_OnDataStorageChanged); CPPUNIT_ASSERT_EQUAL(2, widget.m_OnInternalSelectionChanged); CPPUNIT_ASSERT_EQUAL(1, widget.m_OnNodeAddedToStorage); CPPUNIT_ASSERT_EQUAL(1, widget.m_OnNodeRemovedFromStorage); CPPUNIT_ASSERT_EQUAL(2, widget.m_ReviseSelectionChanged); CPPUNIT_ASSERT_EQUAL(2, widget.m_AllowEmissionOfSelection); CPPUNIT_ASSERT_EQUAL(1, widget.m_NewSelectionEmited); CPPUNIT_ASSERT(EqualNodeSelections({ newNode }, widget.m_LastNewEmision)); CPPUNIT_ASSERT(EqualNodeSelections({ newNode }, widget.GetSelectedNodes())); m_DataStorage->Remove(newNode); CPPUNIT_ASSERT_EQUAL(3, widget.m_UpdateInfo); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodePredicateChanged); CPPUNIT_ASSERT_EQUAL(1, widget.m_OnDataStorageChanged); CPPUNIT_ASSERT_EQUAL(3, widget.m_OnInternalSelectionChanged); CPPUNIT_ASSERT_EQUAL(1, widget.m_OnNodeAddedToStorage); CPPUNIT_ASSERT_EQUAL(2, widget.m_OnNodeRemovedFromStorage); CPPUNIT_ASSERT_EQUAL(3, widget.m_ReviseSelectionChanged); CPPUNIT_ASSERT_EQUAL(3, widget.m_AllowEmissionOfSelection); CPPUNIT_ASSERT_EQUAL(2, widget.m_NewSelectionEmited); CPPUNIT_ASSERT(EqualNodeSelections({}, widget.m_LastNewEmision)); CPPUNIT_ASSERT(EqualNodeSelections({}, widget.GetSelectedNodes())); widget.SetCurrentSelection({ m_Node2 }); m_DataStorage = nullptr; CPPUNIT_ASSERT_EQUAL(5, widget.m_UpdateInfo); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodePredicateChanged); CPPUNIT_ASSERT_EQUAL(2, widget.m_OnDataStorageChanged); CPPUNIT_ASSERT_EQUAL(5, widget.m_OnInternalSelectionChanged); CPPUNIT_ASSERT_EQUAL(1, widget.m_OnNodeAddedToStorage); CPPUNIT_ASSERT_EQUAL(2, widget.m_OnNodeRemovedFromStorage); CPPUNIT_ASSERT_EQUAL(5, widget.m_ReviseSelectionChanged); CPPUNIT_ASSERT_EQUAL(5, widget.m_AllowEmissionOfSelection); CPPUNIT_ASSERT_EQUAL(4, widget.m_NewSelectionEmited); CPPUNIT_ASSERT(EqualNodeSelections({}, widget.m_LastNewEmision)); CPPUNIT_ASSERT(EqualNodeSelections({}, widget.GetSelectedNodes())); } void NodePredicateTest() { TestWidget widget; CPPUNIT_ASSERT(nullptr == widget.GetNodePredicate()); auto testPred = GeneratTestPredicate("node2"); widget.SetNodePredicate(testPred); CPPUNIT_ASSERT(testPred == widget.GetNodePredicate()); CPPUNIT_ASSERT_EQUAL(1, widget.m_UpdateInfo); CPPUNIT_ASSERT_EQUAL(1, widget.m_OnNodePredicateChanged); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnDataStorageChanged); CPPUNIT_ASSERT_EQUAL(1, widget.m_OnInternalSelectionChanged); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodeAddedToStorage); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodeRemovedFromStorage); CPPUNIT_ASSERT_EQUAL(1, widget.m_ReviseSelectionChanged); CPPUNIT_ASSERT_EQUAL(1, widget.m_AllowEmissionOfSelection); CPPUNIT_ASSERT_EQUAL(0, widget.m_NewSelectionEmited); widget.SetDataStorage(m_DataStorage); widget.SetCurrentSelection({ m_Node3 }); CPPUNIT_ASSERT_EQUAL(3, widget.m_UpdateInfo); CPPUNIT_ASSERT_EQUAL(1, widget.m_OnNodePredicateChanged); CPPUNIT_ASSERT_EQUAL(1, widget.m_OnDataStorageChanged); CPPUNIT_ASSERT_EQUAL(3, widget.m_OnInternalSelectionChanged); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodeAddedToStorage); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodeRemovedFromStorage); CPPUNIT_ASSERT_EQUAL(3, widget.m_ReviseSelectionChanged); CPPUNIT_ASSERT_EQUAL(3, widget.m_AllowEmissionOfSelection); CPPUNIT_ASSERT_EQUAL(0, widget.m_NewSelectionEmited); CPPUNIT_ASSERT(EqualNodeSelections({}, widget.m_LastNewEmision)); CPPUNIT_ASSERT(EqualNodeSelections({}, widget.GetSelectedNodes())); widget.SetCurrentSelection({ m_Node2 }); CPPUNIT_ASSERT_EQUAL(4, widget.m_UpdateInfo); CPPUNIT_ASSERT_EQUAL(1, widget.m_OnNodePredicateChanged); CPPUNIT_ASSERT_EQUAL(1, widget.m_OnDataStorageChanged); CPPUNIT_ASSERT_EQUAL(4, widget.m_OnInternalSelectionChanged); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodeAddedToStorage); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodeRemovedFromStorage); CPPUNIT_ASSERT_EQUAL(4, widget.m_ReviseSelectionChanged); CPPUNIT_ASSERT_EQUAL(4, widget.m_AllowEmissionOfSelection); CPPUNIT_ASSERT_EQUAL(1, widget.m_NewSelectionEmited); CPPUNIT_ASSERT(EqualNodeSelections({ m_Node2 }, widget.m_LastNewEmision)); CPPUNIT_ASSERT(EqualNodeSelections({ m_Node2 }, widget.GetSelectedNodes())); //change predicate while nodes are selected widget.SetNodePredicate(GeneratTestPredicate("node1")); CPPUNIT_ASSERT_EQUAL(5, widget.m_UpdateInfo); CPPUNIT_ASSERT_EQUAL(2, widget.m_OnNodePredicateChanged); CPPUNIT_ASSERT_EQUAL(1, widget.m_OnDataStorageChanged); CPPUNIT_ASSERT_EQUAL(5, widget.m_OnInternalSelectionChanged); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodeAddedToStorage); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodeRemovedFromStorage); CPPUNIT_ASSERT_EQUAL(5, widget.m_ReviseSelectionChanged); CPPUNIT_ASSERT_EQUAL(5, widget.m_AllowEmissionOfSelection); CPPUNIT_ASSERT_EQUAL(2, widget.m_NewSelectionEmited); CPPUNIT_ASSERT(EqualNodeSelections({}, widget.m_LastNewEmision)); CPPUNIT_ASSERT(EqualNodeSelections({}, widget.GetSelectedNodes())); //change selection to mixed one (valid nodes and invalid ones) widget.SetCurrentSelection({ m_Node1, m_Node2, m_Node1_2 }); CPPUNIT_ASSERT_EQUAL(6, widget.m_UpdateInfo); CPPUNIT_ASSERT_EQUAL(2, widget.m_OnNodePredicateChanged); CPPUNIT_ASSERT_EQUAL(1, widget.m_OnDataStorageChanged); CPPUNIT_ASSERT_EQUAL(6, widget.m_OnInternalSelectionChanged); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodeAddedToStorage); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodeRemovedFromStorage); CPPUNIT_ASSERT_EQUAL(6, widget.m_ReviseSelectionChanged); CPPUNIT_ASSERT_EQUAL(6, widget.m_AllowEmissionOfSelection); CPPUNIT_ASSERT_EQUAL(3, widget.m_NewSelectionEmited); CPPUNIT_ASSERT(EqualNodeSelections({ m_Node1, m_Node1_2 }, widget.m_LastNewEmision)); CPPUNIT_ASSERT(EqualNodeSelections({ m_Node1, m_Node1_2 }, widget.GetSelectedNodes())); } void SelectOnlyVisibleNodesTest() { TestWidget widget; CPPUNIT_ASSERT_EQUAL(true, widget.GetSelectOnlyVisibleNodes()); CPPUNIT_ASSERT(nullptr == widget.GetNodePredicate()); auto testPred = GeneratTestPredicate("node2"); widget.SetNodePredicate(testPred); widget.SetDataStorage(m_DataStorage); widget.SetCurrentSelection({ m_Node3 }); CPPUNIT_ASSERT_EQUAL(3, widget.m_UpdateInfo); CPPUNIT_ASSERT_EQUAL(1, widget.m_OnNodePredicateChanged); CPPUNIT_ASSERT_EQUAL(1, widget.m_OnDataStorageChanged); CPPUNIT_ASSERT_EQUAL(3, widget.m_OnInternalSelectionChanged); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodeAddedToStorage); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodeRemovedFromStorage); CPPUNIT_ASSERT_EQUAL(3, widget.m_ReviseSelectionChanged); CPPUNIT_ASSERT_EQUAL(3, widget.m_AllowEmissionOfSelection); CPPUNIT_ASSERT_EQUAL(0, widget.m_NewSelectionEmited); CPPUNIT_ASSERT(EqualNodeSelections({}, widget.m_LastNewEmision)); CPPUNIT_ASSERT(EqualNodeSelections({}, widget.GetSelectedNodes())); widget.SetSelectOnlyVisibleNodes(false); CPPUNIT_ASSERT_EQUAL(false, widget.GetSelectOnlyVisibleNodes()); CPPUNIT_ASSERT_EQUAL(3, widget.m_UpdateInfo); CPPUNIT_ASSERT_EQUAL(1, widget.m_OnNodePredicateChanged); CPPUNIT_ASSERT_EQUAL(1, widget.m_OnDataStorageChanged); CPPUNIT_ASSERT_EQUAL(3, widget.m_OnInternalSelectionChanged); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodeAddedToStorage); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodeRemovedFromStorage); CPPUNIT_ASSERT_EQUAL(3, widget.m_ReviseSelectionChanged); CPPUNIT_ASSERT_EQUAL(4, widget.m_AllowEmissionOfSelection); CPPUNIT_ASSERT_EQUAL(1, widget.m_NewSelectionEmited); CPPUNIT_ASSERT(EqualNodeSelections({ m_Node3 }, widget.m_LastNewEmision)); CPPUNIT_ASSERT(EqualNodeSelections({ m_Node3 }, widget.GetSelectedNodes())); //change selection to mixed one (valid nodes and invalid ones) widget.SetCurrentSelection({ m_Node1, m_Node2, m_Node1_2 }); CPPUNIT_ASSERT_EQUAL(4, widget.m_UpdateInfo); CPPUNIT_ASSERT_EQUAL(1, widget.m_OnNodePredicateChanged); CPPUNIT_ASSERT_EQUAL(1, widget.m_OnDataStorageChanged); CPPUNIT_ASSERT_EQUAL(4, widget.m_OnInternalSelectionChanged); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodeAddedToStorage); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodeRemovedFromStorage); CPPUNIT_ASSERT_EQUAL(4, widget.m_ReviseSelectionChanged); CPPUNIT_ASSERT_EQUAL(5, widget.m_AllowEmissionOfSelection); CPPUNIT_ASSERT_EQUAL(2, widget.m_NewSelectionEmited); CPPUNIT_ASSERT(EqualNodeSelections({ m_Node1, m_Node2, m_Node1_2 }, widget.m_LastNewEmision)); CPPUNIT_ASSERT(EqualNodeSelections({ m_Node1, m_Node2, m_Node1_2 }, widget.GetSelectedNodes())); //change predicate while nodes are selected widget.SetNodePredicate(GeneratTestPredicate("node1")); CPPUNIT_ASSERT_EQUAL(5, widget.m_UpdateInfo); CPPUNIT_ASSERT_EQUAL(2, widget.m_OnNodePredicateChanged); CPPUNIT_ASSERT_EQUAL(1, widget.m_OnDataStorageChanged); CPPUNIT_ASSERT_EQUAL(5, widget.m_OnInternalSelectionChanged); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodeAddedToStorage); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodeRemovedFromStorage); CPPUNIT_ASSERT_EQUAL(5, widget.m_ReviseSelectionChanged); CPPUNIT_ASSERT_EQUAL(6, widget.m_AllowEmissionOfSelection); CPPUNIT_ASSERT_EQUAL(2, widget.m_NewSelectionEmited); CPPUNIT_ASSERT(EqualNodeSelections({ m_Node1, m_Node2, m_Node1_2 }, widget.m_LastNewEmision)); CPPUNIT_ASSERT(EqualNodeSelections({ m_Node1, m_Node2, m_Node1_2 }, widget.GetSelectedNodes())); widget.SetSelectOnlyVisibleNodes(true); CPPUNIT_ASSERT_EQUAL(true, widget.GetSelectOnlyVisibleNodes()); CPPUNIT_ASSERT_EQUAL(5, widget.m_UpdateInfo); CPPUNIT_ASSERT_EQUAL(2, widget.m_OnNodePredicateChanged); CPPUNIT_ASSERT_EQUAL(1, widget.m_OnDataStorageChanged); CPPUNIT_ASSERT_EQUAL(5, widget.m_OnInternalSelectionChanged); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodeAddedToStorage); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodeRemovedFromStorage); CPPUNIT_ASSERT_EQUAL(5, widget.m_ReviseSelectionChanged); CPPUNIT_ASSERT_EQUAL(7, widget.m_AllowEmissionOfSelection); CPPUNIT_ASSERT_EQUAL(3, widget.m_NewSelectionEmited); CPPUNIT_ASSERT(EqualNodeSelections({ m_Node1, m_Node1_2 }, widget.m_LastNewEmision)); CPPUNIT_ASSERT(EqualNodeSelections({ m_Node1, m_Node1_2 }, widget.GetSelectedNodes())); } - void OtherSetterAnsGetterTest() + void OtherSetterAndGetterTest() { TestWidget widget; CPPUNIT_ASSERT("Error. Select data." == widget.GetInvalidInfo()); CPPUNIT_ASSERT("Empty. Make a selection." == widget.GetEmptyInfo()); CPPUNIT_ASSERT("Select a data node" == widget.GetPopUpTitel()); CPPUNIT_ASSERT("" == widget.GetPopUpHint()); CPPUNIT_ASSERT(false == widget.GetSelectionIsOptional()); widget.SetInvalidInfo("SetInvalidInfo"); widget.SetEmptyInfo("SetEmptyInfo"); widget.SetPopUpTitel("SetPopUpTitel"); widget.SetPopUpHint("SetPopUpHint"); widget.SetSelectionIsOptional(true); CPPUNIT_ASSERT("SetInvalidInfo" == widget.GetInvalidInfo()); CPPUNIT_ASSERT("SetEmptyInfo" == widget.GetEmptyInfo()); CPPUNIT_ASSERT("SetPopUpTitel" == widget.GetPopUpTitel()); CPPUNIT_ASSERT("SetPopUpHint" == widget.GetPopUpHint()); CPPUNIT_ASSERT(true == widget.GetSelectionIsOptional()); } void AllowEmissionOfSelectionTest() { TestWidget widget; widget.SetDataStorage(m_DataStorage); widget.SetCurrentSelection({ m_Node3 }); CPPUNIT_ASSERT_EQUAL(2, widget.m_UpdateInfo); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodePredicateChanged); CPPUNIT_ASSERT_EQUAL(1, widget.m_OnDataStorageChanged); CPPUNIT_ASSERT_EQUAL(2, widget.m_OnInternalSelectionChanged); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodeAddedToStorage); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodeRemovedFromStorage); CPPUNIT_ASSERT_EQUAL(2, widget.m_ReviseSelectionChanged); CPPUNIT_ASSERT_EQUAL(2, widget.m_AllowEmissionOfSelection); CPPUNIT_ASSERT_EQUAL(1, widget.m_NewSelectionEmited); CPPUNIT_ASSERT(EqualNodeSelections({ m_Node3 }, widget.m_LastNewEmision)); CPPUNIT_ASSERT(EqualNodeSelections({ m_Node3 }, widget.GetSelectedNodes())); widget.m_Allow = false; widget.SetCurrentSelection({ m_Node1 }); CPPUNIT_ASSERT_EQUAL(3, widget.m_UpdateInfo); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodePredicateChanged); CPPUNIT_ASSERT_EQUAL(1, widget.m_OnDataStorageChanged); CPPUNIT_ASSERT_EQUAL(3, widget.m_OnInternalSelectionChanged); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodeAddedToStorage); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodeRemovedFromStorage); CPPUNIT_ASSERT_EQUAL(3, widget.m_ReviseSelectionChanged); CPPUNIT_ASSERT_EQUAL(3, widget.m_AllowEmissionOfSelection); CPPUNIT_ASSERT_EQUAL(1, widget.m_NewSelectionEmited); CPPUNIT_ASSERT(EqualNodeSelections({ m_Node3 }, widget.m_LastNewEmision)); CPPUNIT_ASSERT(EqualNodeSelections({ m_Node1 }, widget.GetSelectedNodes())); } void OnNodeModifiedTest() { TestWidget widget; widget.SetDataStorage(m_DataStorage); widget.SetCurrentSelection({ m_Node3 }); //Check OnNodeModified behavour without predicate m_Node3->SetName("NewName"); CPPUNIT_ASSERT_EQUAL(2, widget.m_UpdateInfo); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodePredicateChanged); CPPUNIT_ASSERT_EQUAL(1, widget.m_OnDataStorageChanged); CPPUNIT_ASSERT_EQUAL(2, widget.m_OnInternalSelectionChanged); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodeAddedToStorage); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodeRemovedFromStorage); CPPUNIT_ASSERT_EQUAL(2, widget.m_ReviseSelectionChanged); CPPUNIT_ASSERT_EQUAL(3, widget.m_AllowEmissionOfSelection); CPPUNIT_ASSERT_EQUAL(1, widget.m_NewSelectionEmited); CPPUNIT_ASSERT(EqualNodeSelections({ m_Node3 }, widget.m_LastNewEmision)); CPPUNIT_ASSERT(EqualNodeSelections({ m_Node3 }, widget.GetSelectedNodes())); //simulate behaviour if allowance is changed to true widget.m_Allow = false; m_Node3->SetName("NewName_temp"); widget.m_Allow = true; m_Node3->SetName("NewName"); CPPUNIT_ASSERT_EQUAL(4, widget.m_UpdateInfo); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodePredicateChanged); CPPUNIT_ASSERT_EQUAL(1, widget.m_OnDataStorageChanged); CPPUNIT_ASSERT_EQUAL(2, widget.m_OnInternalSelectionChanged); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodeAddedToStorage); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodeRemovedFromStorage); CPPUNIT_ASSERT_EQUAL(2, widget.m_ReviseSelectionChanged); CPPUNIT_ASSERT_EQUAL(7, widget.m_AllowEmissionOfSelection); CPPUNIT_ASSERT_EQUAL(1, widget.m_NewSelectionEmited); CPPUNIT_ASSERT(EqualNodeSelections({ m_Node3 }, widget.m_LastNewEmision)); CPPUNIT_ASSERT(EqualNodeSelections({ m_Node3 }, widget.GetSelectedNodes())); //change irrelevant node m_Node2->SetName("IrrelevantNode"); CPPUNIT_ASSERT_EQUAL(4, widget.m_UpdateInfo); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodePredicateChanged); CPPUNIT_ASSERT_EQUAL(1, widget.m_OnDataStorageChanged); CPPUNIT_ASSERT_EQUAL(2, widget.m_OnInternalSelectionChanged); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodeAddedToStorage); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodeRemovedFromStorage); CPPUNIT_ASSERT_EQUAL(2, widget.m_ReviseSelectionChanged); CPPUNIT_ASSERT_EQUAL(7, widget.m_AllowEmissionOfSelection); CPPUNIT_ASSERT_EQUAL(1, widget.m_NewSelectionEmited); CPPUNIT_ASSERT(EqualNodeSelections({ m_Node3 }, widget.m_LastNewEmision)); CPPUNIT_ASSERT(EqualNodeSelections({ m_Node3 }, widget.GetSelectedNodes())); //test with predicate set widget.SetNodePredicate(GeneratTestPredicate("node1")); m_Node3->SetName("NowAlsoIrrelevantNode"); CPPUNIT_ASSERT_EQUAL(5, widget.m_UpdateInfo); CPPUNIT_ASSERT_EQUAL(1, widget.m_OnNodePredicateChanged); CPPUNIT_ASSERT_EQUAL(1, widget.m_OnDataStorageChanged); CPPUNIT_ASSERT_EQUAL(3, widget.m_OnInternalSelectionChanged); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodeAddedToStorage); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodeRemovedFromStorage); CPPUNIT_ASSERT_EQUAL(3, widget.m_ReviseSelectionChanged); CPPUNIT_ASSERT_EQUAL(8, widget.m_AllowEmissionOfSelection); CPPUNIT_ASSERT_EQUAL(2, widget.m_NewSelectionEmited); CPPUNIT_ASSERT(EqualNodeSelections({ }, widget.m_LastNewEmision)); CPPUNIT_ASSERT(EqualNodeSelections({ }, widget.GetSelectedNodes())); widget.SetCurrentSelection({ m_Node1, m_Node1_2 }); CPPUNIT_ASSERT(EqualNodeSelections({ m_Node1, m_Node1_2 }, widget.m_LastNewEmision)); m_Node1->SetName("NodeSortedOutByPredicate"); CPPUNIT_ASSERT_EQUAL(7, widget.m_UpdateInfo); CPPUNIT_ASSERT_EQUAL(1, widget.m_OnNodePredicateChanged); CPPUNIT_ASSERT_EQUAL(1, widget.m_OnDataStorageChanged); CPPUNIT_ASSERT_EQUAL(5, widget.m_OnInternalSelectionChanged); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodeAddedToStorage); CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodeRemovedFromStorage); CPPUNIT_ASSERT_EQUAL(5, widget.m_ReviseSelectionChanged); CPPUNIT_ASSERT_EQUAL(10, widget.m_AllowEmissionOfSelection); CPPUNIT_ASSERT_EQUAL(4, widget.m_NewSelectionEmited); CPPUNIT_ASSERT(EqualNodeSelections({ m_Node1_2 }, widget.m_LastNewEmision)); CPPUNIT_ASSERT(EqualNodeSelections({ m_Node1_2 }, widget.GetSelectedNodes())); } + void SignalRecursionTest() + { + TestWidget widget; + widget.SetDataStorage(m_DataStorage); + + TestWidget widget2; + widget2.SetDataStorage(m_DataStorage); + + QmitkAbstractNodeSelectionWidget::connect(&widget, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, &widget2, &QmitkAbstractNodeSelectionWidget::SetCurrentSelection); + QmitkAbstractNodeSelectionWidget::connect(&widget2, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, &widget, &QmitkAbstractNodeSelectionWidget::SetCurrentSelection); + + widget.SetCurrentSelection({ m_Node1 }); + CPPUNIT_ASSERT_EQUAL(2, widget.m_UpdateInfo); + CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodePredicateChanged); + CPPUNIT_ASSERT_EQUAL(1, widget.m_OnDataStorageChanged); + CPPUNIT_ASSERT_EQUAL(2, widget.m_OnInternalSelectionChanged); + CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodeAddedToStorage); + CPPUNIT_ASSERT_EQUAL(0, widget.m_OnNodeRemovedFromStorage); + CPPUNIT_ASSERT_EQUAL(2, widget.m_ReviseSelectionChanged); + CPPUNIT_ASSERT_EQUAL(2, widget.m_AllowEmissionOfSelection); + CPPUNIT_ASSERT_EQUAL(1, widget.m_NewSelectionEmited); + CPPUNIT_ASSERT(EqualNodeSelections({ m_Node1 }, widget.m_LastNewEmision)); + CPPUNIT_ASSERT(EqualNodeSelections({ m_Node1 }, widget.GetSelectedNodes())); + + CPPUNIT_ASSERT_EQUAL(2, widget2.m_UpdateInfo); + CPPUNIT_ASSERT_EQUAL(0, widget2.m_OnNodePredicateChanged); + CPPUNIT_ASSERT_EQUAL(1, widget2.m_OnDataStorageChanged); + CPPUNIT_ASSERT_EQUAL(2, widget2.m_OnInternalSelectionChanged); + CPPUNIT_ASSERT_EQUAL(0, widget2.m_OnNodeAddedToStorage); + CPPUNIT_ASSERT_EQUAL(0, widget2.m_OnNodeRemovedFromStorage); + CPPUNIT_ASSERT_EQUAL(2, widget2.m_ReviseSelectionChanged); + CPPUNIT_ASSERT_EQUAL(2, widget2.m_AllowEmissionOfSelection); + CPPUNIT_ASSERT_EQUAL(1, widget2.m_NewSelectionEmited); + CPPUNIT_ASSERT(EqualNodeSelections({ m_Node1 }, widget2.m_LastNewEmision)); + CPPUNIT_ASSERT(EqualNodeSelections({ m_Node1 }, widget2.GetSelectedNodes())); + } + }; MITK_TEST_SUITE_REGISTRATION(QmitkAbstractNodeSelectionWidget) diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkSingleNodeSelectionWidget.cpp b/Plugins/org.mitk.gui.qt.common/src/QmitkSingleNodeSelectionWidget.cpp index 6275c5b19d..87bb9cd71a 100644 --- a/Plugins/org.mitk.gui.qt.common/src/QmitkSingleNodeSelectionWidget.cpp +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkSingleNodeSelectionWidget.cpp @@ -1,230 +1,230 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "QmitkSingleNodeSelectionWidget.h" #include #include "mitkNodePredicateFunction.h" #include "mitkNodePredicateAnd.h" #include #include "QmitkNodeSelectionDialog.h" #include "QmitkNodeDetailsDialog.h" QmitkSingleNodeSelectionWidget::QmitkSingleNodeSelectionWidget(QWidget* parent) : QmitkAbstractNodeSelectionWidget(parent), m_AutoSelectNewNodes(false) { m_Controls.setupUi(this); m_Controls.btnSelect->installEventFilter(this); m_Controls.btnSelect->setVisible(true); m_Controls.btnClear->setVisible(false); m_Controls.btnClear->setIcon(berry::QtStyleManager::ThemeIcon(QStringLiteral(":/org.mitk.gui.qt.common/times.svg"))); this->UpdateInfo(); connect(m_Controls.btnClear, SIGNAL(clicked(bool)), this, SLOT(OnClearSelection())); } void QmitkSingleNodeSelectionWidget::ReviseSelectionChanged(const NodeList& oldInternalSelection, NodeList& newInternalSelection) { if (newInternalSelection.empty()) { if (m_AutoSelectNewNodes) { - auto autoSelectedNode = this->DeterminAutoSelectNode(oldInternalSelection); + auto autoSelectedNode = this->DetermineAutoSelectNode(oldInternalSelection); if (autoSelectedNode.IsNotNull()) { newInternalSelection.append(autoSelectedNode); } } } else if (newInternalSelection.size()>1) { //this widget only allows one internal selected node. newInternalSelection = { newInternalSelection.front() }; } } void QmitkSingleNodeSelectionWidget::OnClearSelection() { if (m_IsOptional) { this->SetCurrentSelection({}); } this->UpdateInfo(); } mitk::DataNode::Pointer QmitkSingleNodeSelectionWidget::GetSelectedNode() const { mitk::DataNode::Pointer result; auto selection = GetCurrentInternalSelection(); if (!selection.empty()) { result = selection.front(); } return result; } bool QmitkSingleNodeSelectionWidget::eventFilter(QObject *obj, QEvent *ev) { if (obj == m_Controls.btnSelect) { if (ev->type() == QEvent::MouseButtonRelease) { auto mouseEv = dynamic_cast(ev); if (!mouseEv) { return false; } if (mouseEv->button() == Qt::LeftButton) { if (this->isEnabled()) { this->EditSelection(); return true; } } else { auto selection = this->CompileEmitSelection(); if (!selection.empty()) { QmitkNodeDetailsDialog infoDialog(selection, this); infoDialog.exec(); return true; } } } } return false; } void QmitkSingleNodeSelectionWidget::EditSelection() { QmitkNodeSelectionDialog* dialog = new QmitkNodeSelectionDialog(this, m_PopUpTitel, m_PopUpHint); dialog->SetDataStorage(m_DataStorage.Lock()); dialog->SetNodePredicate(m_NodePredicate); dialog->SetCurrentSelection(this->GetCurrentInternalSelection()); dialog->SetSelectOnlyVisibleNodes(m_SelectOnlyVisibleNodes); dialog->SetSelectionMode(QAbstractItemView::SingleSelection); m_Controls.btnSelect->setChecked(true); if (dialog->exec()) { this->HandleChangeOfInternalSelection(dialog->GetSelectedNodes()); } m_Controls.btnSelect->setChecked(false); delete dialog; } void QmitkSingleNodeSelectionWidget::UpdateInfo() { if (this->GetSelectedNode().IsNull()) { if (m_IsOptional) { m_Controls.btnSelect->SetNodeInfo(m_EmptyInfo); } else { m_Controls.btnSelect->SetNodeInfo(m_InvalidInfo); } m_Controls.btnSelect->SetSelectionIsOptional(m_IsOptional); m_Controls.btnClear->setVisible(false); } else { m_Controls.btnClear->setVisible(m_IsOptional); } m_Controls.btnSelect->SetSelectedNode(this->GetSelectedNode()); } -mitk::DataNode::Pointer QmitkSingleNodeSelectionWidget::DeterminAutoSelectNode(const NodeList& ignoreNodes) +mitk::DataNode::Pointer QmitkSingleNodeSelectionWidget::DetermineAutoSelectNode(const NodeList& ignoreNodes) { mitk::DataNode::Pointer result; auto storage = m_DataStorage.Lock(); if (storage.IsNotNull()) { auto ignoreCheck = [ignoreNodes](const mitk::DataNode * node) { bool result = true; for (const auto& ignoreNode : ignoreNodes) { if (node == ignoreNode) { result = false; break; } } return result; }; mitk::NodePredicateFunction::Pointer isNotIgnoredNode = mitk::NodePredicateFunction::New(ignoreCheck); mitk::NodePredicateBase::Pointer predicate = isNotIgnoredNode.GetPointer(); if (m_NodePredicate.IsNotNull()) { predicate = mitk::NodePredicateAnd::New(m_NodePredicate.GetPointer(), predicate.GetPointer()).GetPointer(); } result = storage->GetNode(predicate); } return result; } void QmitkSingleNodeSelectionWidget::SetCurrentSelectedNode(mitk::DataNode* selectedNode) { NodeList selection; if (selectedNode) { selection.append(selectedNode); } this->SetCurrentSelection(selection); }; void QmitkSingleNodeSelectionWidget::OnNodeAddedToStorage(const mitk::DataNode* /*node*/) { if (this->GetSelectedNode().IsNull() && m_AutoSelectNewNodes) { - auto autoNode = this->DeterminAutoSelectNode(); + auto autoNode = this->DetermineAutoSelectNode(); if (autoNode.IsNotNull()) { this->HandleChangeOfInternalSelection({ autoNode }); } } } bool QmitkSingleNodeSelectionWidget::GetAutoSelectNewNodes() const { return m_AutoSelectNewNodes; } void QmitkSingleNodeSelectionWidget::SetAutoSelectNewNodes(bool autoSelect) { m_AutoSelectNewNodes = autoSelect; this->OnNodeAddedToStorage(nullptr); } diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkSingleNodeSelectionWidget.h b/Plugins/org.mitk.gui.qt.common/src/QmitkSingleNodeSelectionWidget.h index dc70648d38..27635231ca 100644 --- a/Plugins/org.mitk.gui.qt.common/src/QmitkSingleNodeSelectionWidget.h +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkSingleNodeSelectionWidget.h @@ -1,80 +1,80 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef QMITK_SINGLE_NODE_SELECTION_WIDGET_H #define QMITK_SINGLE_NODE_SELECTION_WIDGET_H #include #include #include #include "org_mitk_gui_qt_common_Export.h" #include "ui_QmitkSingleNodeSelectionWidget.h" #include #include class QmitkAbstractDataStorageModel; /** * \class QmitkSingleNodeSelectionWidget * \brief Widget that represents a node selection of (max) one node. It acts like a button. Clicking on it * allows to change the selection. */ class MITK_QT_COMMON QmitkSingleNodeSelectionWidget : public QmitkAbstractNodeSelectionWidget { Q_OBJECT public: explicit QmitkSingleNodeSelectionWidget(QWidget* parent = nullptr); mitk::DataNode::Pointer GetSelectedNode() const; bool GetAutoSelectNewNodes() const; using NodeList = QmitkAbstractNodeSelectionWidget::NodeList; public Q_SLOTS: void SetCurrentSelectedNode(mitk::DataNode* selectedNode); /** Sets the auto selection mode (Default is false). If auto select is true and the following conditions are fullfilled, the widget will select a node automatically from the data storage: - a data storage is set - data storage contains at least one node that matches the given predicate - no selection is set.*/ void SetAutoSelectNewNodes(bool autoSelect); protected Q_SLOTS: virtual void OnClearSelection(); protected: void ReviseSelectionChanged(const NodeList& oldInternalSelection, NodeList& newInternalSelection) override; bool eventFilter(QObject *obj, QEvent *ev) override; void EditSelection(); void UpdateInfo() override; void OnNodeAddedToStorage(const mitk::DataNode* node) override; /** Helper function that gets a suitable auto selected node from the datastorage that fits to the predicate settings. @param ignoreNodes You may pass a list of nodes that must not be choosen as auto selected node. */ - mitk::DataNode::Pointer DeterminAutoSelectNode(const NodeList& ignoreNodes = {}); + mitk::DataNode::Pointer DetermineAutoSelectNode(const NodeList& ignoreNodes = {}); /** See documentation of SetAutoSelectNewNodes for details*/ bool m_AutoSelectNewNodes; Ui_QmitkSingleNodeSelectionWidget m_Controls; }; #endif // QmitkSingleNodeSelectionWidget_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 7ab9404e83..1ce16e51e0 100644 --- a/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/QmitkDataStorageViewerTestView.cpp +++ b/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/QmitkDataStorageViewerTestView.cpp @@ -1,277 +1,277 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // data storage viewer test plugin #include "QmitkDataStorageViewerTestView.h" #include "mitkNodePredicateDataType.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_Controls.singleSlot->SetDataStorage(GetDataStorage()); m_Controls.singleSlot->SetEmptyInfo(QStringLiteral("EmptyInfo: Set this to display info in empty state")); m_Controls.singleSlot->SetInvalidInfo(QStringLiteral("InvalidInfo: is displayed for invalid states")); m_Controls.singleSlot->SetPopUpTitel(QStringLiteral("This is the definable caption. Choose your data now!")); m_Controls.singleSlot->SetPopUpHint(QStringLiteral("I am an optional hint, that can be set by the developer

If not set the widget is invisible.")); m_Controls.multiSlot->SetDataStorage(GetDataStorage()); m_Controls.multiSlot->SetEmptyInfo(QStringLiteral("EmptyInfo: Set this to display info in empty state")); m_Controls.multiSlot->SetInvalidInfo(QStringLiteral("InvalidInfo: is displayed for invalid states")); m_Controls.multiSlot->SetPopUpTitel(QStringLiteral("This is the definable caption. Choose your data now!")); m_Controls.multiSlot->SetPopUpHint(QStringLiteral("I am an optional hint, that can be set by the developer

If not set the widget is invisible.")); m_ModelViewSelectionConnector = std::make_unique(); try { m_ModelViewSelectionConnector->SetView(m_Controls.selectionListView); } catch (mitk::Exception& e) { mitkReThrow(e) << "Cannot connect the model-view pair signals and slots."; } m_SelectionServiceConnector = std::make_unique(); m_ModelViewSelectionConnector2 = std::make_unique(); try { m_ModelViewSelectionConnector2->SetView(m_Controls.selectionListView2); } catch (mitk::Exception& e) { mitkReThrow(e) << "Cannot connect the model-view pair signals and slots."; } m_SelectionServiceConnector2 = std::make_unique(); m_SelectionServiceConnector3 = std::make_unique(); m_SelectionServiceConnector4 = std::make_unique(); connect(m_Controls.selectionProviderCheckBox, SIGNAL(toggled(bool)), this, SLOT(SetAsSelectionProvider1(bool))); connect(m_Controls.selectionProviderCheckBox2, SIGNAL(toggled(bool)), this, SLOT(SetAsSelectionProvider2(bool))); connect(m_Controls.selectionListenerCheckBox, SIGNAL(toggled(bool)), this, SLOT(SetAsSelectionListener1(bool))); connect(m_Controls.selectionListenerCheckBox2, SIGNAL(toggled(bool)), this, SLOT(SetAsSelectionListener2(bool))); connect(m_Controls.selectionProviderCheckBox3, SIGNAL(toggled(bool)), this, SLOT(SetAsSelectionProvider3(bool))); connect(m_Controls.selectionListenerCheckBox3, SIGNAL(toggled(bool)), this, SLOT(SetAsSelectionListener3(bool))); connect(m_Controls.checkOnlyVisible, SIGNAL(toggled(bool)), m_Controls.singleSlot, SLOT(SetSelectOnlyVisibleNodes(bool))); connect(m_Controls.checkOptional, SIGNAL(toggled(bool)), m_Controls.singleSlot, SLOT(SetSelectionIsOptional(bool))); connect(m_Controls.checkAuto, SIGNAL(toggled(bool)), m_Controls.singleSlot, SLOT(SetAutoSelectNewNodes(bool))); connect(m_Controls.checkOnlyImages, SIGNAL(toggled(bool)), this, SLOT(OnOnlyImages(bool))); connect(m_Controls.checkEnabled, SIGNAL(toggled(bool)), m_Controls.singleSlot, SLOT(setEnabled(bool))); connect(m_Controls.selectionProviderCheckBox4, SIGNAL(toggled(bool)), this, SLOT(SetAsSelectionProvider4(bool))); connect(m_Controls.selectionListenerCheckBox4, SIGNAL(toggled(bool)), this, SLOT(SetAsSelectionListener4(bool))); connect(m_Controls.checkOnlyVisible_2, SIGNAL(toggled(bool)), m_Controls.multiSlot, SLOT(SetSelectOnlyVisibleNodes(bool))); connect(m_Controls.checkOptional_2, SIGNAL(toggled(bool)), m_Controls.multiSlot, SLOT(SetSelectionIsOptional(bool))); connect(m_Controls.checkOnlyImages_2, SIGNAL(toggled(bool)), this, SLOT(OnOnlyImages2(bool))); connect(m_Controls.checkOnlyUneven, SIGNAL(toggled(bool)), this, SLOT(OnOnlyUneven(bool))); connect(m_Controls.checkEnabled_2, SIGNAL(toggled(bool)), m_Controls.multiSlot, SLOT(setEnabled(bool))); } void QmitkDataStorageViewerTestView::SetAsSelectionProvider1(bool checked) { if (checked) { m_SelectionServiceConnector->SetAsSelectionProvider(GetSite()->GetSelectionProvider().Cast().GetPointer()); connect(m_ModelViewSelectionConnector.get(), SIGNAL(CurrentSelectionChanged(QList)), m_SelectionServiceConnector.get(), SLOT(ChangeServiceSelection(QList))); } else { m_SelectionServiceConnector->RemoveAsSelectionProvider(); disconnect(m_ModelViewSelectionConnector.get(), SIGNAL(CurrentSelectionChanged(QList)), m_SelectionServiceConnector.get(), SLOT(ChangeServiceSelection(QList))); } } void QmitkDataStorageViewerTestView::SetAsSelectionListener1(bool checked) { if (checked) { m_SelectionServiceConnector->AddPostSelectionListener(GetSite()->GetWorkbenchWindow()->GetSelectionService()); connect(m_SelectionServiceConnector.get(), SIGNAL(ServiceSelectionChanged(QList)), m_ModelViewSelectionConnector.get(), SLOT(SetCurrentSelection(QList))); } else { m_SelectionServiceConnector->RemovePostSelectionListener(); disconnect(m_SelectionServiceConnector.get(), SIGNAL(ServiceSelectionChanged(QList)), m_ModelViewSelectionConnector.get(), SLOT(SetCurrentSelection(QList))); } } void QmitkDataStorageViewerTestView::SetAsSelectionProvider2(bool checked) { if (checked) { m_SelectionServiceConnector2->SetAsSelectionProvider(GetSite()->GetSelectionProvider().Cast().GetPointer()); connect(m_ModelViewSelectionConnector2.get(), SIGNAL(CurrentSelectionChanged(QList)), m_SelectionServiceConnector2.get(), SLOT(ChangeServiceSelection(QList))); } else { m_SelectionServiceConnector2->RemoveAsSelectionProvider(); disconnect(m_ModelViewSelectionConnector2.get(), SIGNAL(CurrentSelectionChanged(QList)), m_SelectionServiceConnector2.get(), SLOT(ChangeServiceSelection(QList))); } } void QmitkDataStorageViewerTestView::SetAsSelectionListener2(bool checked) { if (checked) { m_SelectionServiceConnector2->AddPostSelectionListener(GetSite()->GetWorkbenchWindow()->GetSelectionService()); connect(m_SelectionServiceConnector2.get(), SIGNAL(ServiceSelectionChanged(QList)), m_ModelViewSelectionConnector2.get(), SLOT(SetCurrentSelection(QList))); } else { m_SelectionServiceConnector2->RemovePostSelectionListener(); disconnect(m_SelectionServiceConnector2.get(), SIGNAL(ServiceSelectionChanged(QList)), m_ModelViewSelectionConnector2.get(), SLOT(SetCurrentSelection(QList))); } } void QmitkDataStorageViewerTestView::SetAsSelectionProvider3(bool checked) { if (checked) { m_SelectionServiceConnector3->SetAsSelectionProvider(GetSite()->GetSelectionProvider().Cast().GetPointer()); - connect(m_Controls.singleSlot, SIGNAL(CurrentSelectionChanged(QList)), m_SelectionServiceConnector3.get(), SLOT(ChangeServiceSelection(QList))); + connect(m_Controls.singleSlot, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, m_SelectionServiceConnector3.get(), &QmitkSelectionServiceConnector::ChangeServiceSelection); } else { m_SelectionServiceConnector3->RemoveAsSelectionProvider(); - disconnect(m_Controls.singleSlot, SIGNAL(CurrentSelectionChanged(QList)), m_SelectionServiceConnector3.get(), SLOT(ChangeServiceSelection(QList))); + disconnect(m_Controls.singleSlot, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, m_SelectionServiceConnector3.get(), &QmitkSelectionServiceConnector::ChangeServiceSelection); } } void QmitkDataStorageViewerTestView::SetAsSelectionListener3(bool checked) { if (checked) { m_SelectionServiceConnector3->AddPostSelectionListener(GetSite()->GetWorkbenchWindow()->GetSelectionService()); connect(m_SelectionServiceConnector3.get(), &QmitkSelectionServiceConnector::ServiceSelectionChanged, m_Controls.singleSlot, &QmitkSingleNodeSelectionWidget::SetCurrentSelection); } else { m_SelectionServiceConnector3->RemovePostSelectionListener(); disconnect(m_SelectionServiceConnector3.get(), &QmitkSelectionServiceConnector::ServiceSelectionChanged, m_Controls.singleSlot, &QmitkSingleNodeSelectionWidget::SetCurrentSelection); } } void QmitkDataStorageViewerTestView::SetAsSelectionProvider4(bool checked) { if (checked) { m_SelectionServiceConnector4->SetAsSelectionProvider(GetSite()->GetSelectionProvider().Cast().GetPointer()); - connect(m_Controls.multiSlot, SIGNAL(CurrentSelectionChanged(QList)), m_SelectionServiceConnector4.get(), SLOT(ChangeServiceSelection(QList))); + connect(m_Controls.multiSlot, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, m_SelectionServiceConnector4.get(), &QmitkSelectionServiceConnector::ChangeServiceSelection); } else { m_SelectionServiceConnector4->RemoveAsSelectionProvider(); - disconnect(m_Controls.multiSlot, SIGNAL(CurrentSelectionChanged(QList)), m_SelectionServiceConnector4.get(), SLOT(ChangeServiceSelection(QList))); + disconnect(m_Controls.multiSlot, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, m_SelectionServiceConnector4.get(), &QmitkSelectionServiceConnector::ChangeServiceSelection); } } void QmitkDataStorageViewerTestView::SetAsSelectionListener4(bool checked) { if (checked) { m_SelectionServiceConnector4->AddPostSelectionListener(GetSite()->GetWorkbenchWindow()->GetSelectionService()); connect(m_SelectionServiceConnector4.get(), &QmitkSelectionServiceConnector::ServiceSelectionChanged, m_Controls.multiSlot, &QmitkMultiNodeSelectionWidget::SetCurrentSelection); } else { m_SelectionServiceConnector4->RemovePostSelectionListener(); disconnect(m_SelectionServiceConnector4.get(), &QmitkSelectionServiceConnector::ServiceSelectionChanged, m_Controls.multiSlot, &QmitkMultiNodeSelectionWidget::SetCurrentSelection); } } void QmitkDataStorageViewerTestView::OnOnlyImages(bool checked) { if (checked) { m_Controls.singleSlot->SetNodePredicate(mitk::NodePredicateDataType::New("Image")); } else { m_Controls.singleSlot->SetNodePredicate(nullptr); } }; void QmitkDataStorageViewerTestView::OnOnlyImages2(bool checked) { if (checked) { m_Controls.multiSlot->SetNodePredicate(mitk::NodePredicateDataType::New("Image")); m_Controls.multiSlot->SetInvalidInfo(QStringLiteral("InvalidInfo: is displayed for invalid states. Only images allowed!")); } else { m_Controls.multiSlot->SetNodePredicate(nullptr); m_Controls.multiSlot->SetInvalidInfo(QStringLiteral("InvalidInfo: is displayed for invalid states")); } }; void QmitkDataStorageViewerTestView::OnOnlyUneven(bool checked) { if (checked) { auto checkFunction = [](const QmitkMultiNodeSelectionWidget::NodeList & nodes) { if (!(nodes.size() % 2)) { std::stringstream ss; ss << "

Invalid selection.

The number of selected nodes must be uneven! the current number is " << nodes.size() << ".

"; return ss.str(); } return std::string(); }; m_Controls.multiSlot->SetSelectionCheckFunction(checkFunction); } else { auto checkFunction = [](const QmitkMultiNodeSelectionWidget::NodeList & /*nodes*/) { return std::string(); }; m_Controls.multiSlot->SetSelectionCheckFunction(checkFunction); } };