diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkAbstractNodeSelectionWidget.cpp b/Plugins/org.mitk.gui.qt.common/src/QmitkAbstractNodeSelectionWidget.cpp index 673cdfd067..68c91e55f0 100644 --- a/Plugins/org.mitk.gui.qt.common/src/QmitkAbstractNodeSelectionWidget.cpp +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkAbstractNodeSelectionWidget.cpp @@ -1,113 +1,165 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkAbstractNodeSelectionWidget.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) { } +QmitkAbstractNodeSelectionWidget::~QmitkAbstractNodeSelectionWidget() +{ + if (!m_DataStorage.IsExpired()) + { + auto dataStorage = m_DataStorage.Lock(); + + // remove Listener for the data storage itself + dataStorage->RemoveObserver(m_DataStorageDeletedTag); + + // remove listener from data storage + dataStorage->RemoveNodeEvent.RemoveListener( + mitk::MessageDelegate1(this, &QmitkAbstractNodeSelectionWidget::NodeRemovedFromStorage)); + } +}; + + void QmitkAbstractNodeSelectionWidget::SetDataStorage(mitk::DataStorage* dataStorage) { - if (m_DataStorage != dataStorage) + if (m_DataStorage == dataStorage) { - m_DataStorage = dataStorage; - this->OnDataStorageChanged(); - this->UpdateInfo(); + return; } + + if (!m_DataStorage.IsExpired()) + { + auto oldStorage = m_DataStorage.Lock(); + + // remove Listener for the data storage itself + oldStorage->RemoveObserver(m_DataStorageDeletedTag); + + // remove listener from old data storage + oldStorage->RemoveNodeEvent.RemoveListener( + mitk::MessageDelegate1(this, &QmitkAbstractNodeSelectionWidget::NodeRemovedFromStorage)); + } + + m_DataStorage = dataStorage; + + if (!m_DataStorage.IsExpired()) + { + auto newStorage = m_DataStorage.Lock(); + + // 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 listener for new data storage + newStorage->RemoveNodeEvent.AddListener( + mitk::MessageDelegate1(this, &QmitkAbstractNodeSelectionWidget::NodeRemovedFromStorage)); + } + + // update model if the data storage has been changed + m_DataStorage = dataStorage; + this->OnDataStorageChanged(); + this->UpdateInfo(); }; void QmitkAbstractNodeSelectionWidget::SetNodePredicate(mitk::NodePredicateBase* nodePredicate) { if (m_NodePredicate != nodePredicate) { m_NodePredicate = nodePredicate; this->OnNodePredicateChanged(nodePredicate); this->UpdateInfo(); } }; 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) { m_SelectOnlyVisibleNodes = selectOnlyVisibleNodes; }; void QmitkAbstractNodeSelectionWidget::SetInvalidInfo(QString info) { m_InvalidInfo = QString("")+info+QString(""); this->UpdateInfo(); }; void QmitkAbstractNodeSelectionWidget::SetEmptyInfo(QString info) { m_EmptyInfo = QString("")+info+QString(""); 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->SetDataStorage(nullptr); +} diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkAbstractNodeSelectionWidget.h b/Plugins/org.mitk.gui.qt.common/src/QmitkAbstractNodeSelectionWidget.h index 4ec7267eb2..42b1c72a67 100644 --- a/Plugins/org.mitk.gui.qt.common/src/QmitkAbstractNodeSelectionWidget.h +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkAbstractNodeSelectionWidget.h @@ -1,151 +1,161 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. 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 QMITK_ABSTRACT_NODE_SELECTION_WIDGET_H #define QMITK_ABSTRACT_NODE_SELECTION_WIDGET_H #include #include #include #include "org_mitk_gui_qt_common_Export.h" #include class QmitkAbstractDataStorageModel; class QAbstractItemVew; /** * \class QmitkAbstractNodeSelectionWidget * \brief Abstract base class for the selection of data from a data storage. */ class MITK_QT_COMMON QmitkAbstractNodeSelectionWidget : public QWidget { Q_OBJECT public: explicit QmitkAbstractNodeSelectionWidget(QWidget* parent = nullptr); + virtual ~QmitkAbstractNodeSelectionWidget(); /** * @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(mitk::NodePredicateBase* nodePredicate); 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; 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(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. */ virtual 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. */ virtual void SetCurrentSelection(NodeList selectedNodes) = 0; /** 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: /**Member is called if the display of the selected nodes should be updated.*/ virtual void UpdateInfo() = 0; /**Member is called if the predicate has changed. Thus the selection might change to. The new (changed) predicate is passed with the function call. It is the same like this->GetNodePredicate() called in the function call.*/ virtual void OnNodePredicateChanged(mitk::NodePredicateBase* newPredicate) = 0; /**Member is called if the data storage has changed. Thus the selection might change to.*/ virtual void OnDataStorageChanged() = 0; + virtual void NodeRemovedFromStorage(const mitk::DataNode* node) = 0; + mitk::WeakPointer m_DataStorage; mitk::NodePredicateBase::Pointer m_NodePredicate; QString m_InvalidInfo; QString m_EmptyInfo; QString m_PopUpTitel; QString m_PopUpHint; bool m_IsOptional; bool m_SelectOnlyVisibleNodes; + +private: + /** Helper triggered on the storage delete event */ + void SetDataStorageDeleted(); + + unsigned long m_DataStorageDeletedTag; + }; #endif // QmitkAbstractNodeSelectionWidget_H diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkMultiNodeSelectionWidget.cpp b/Plugins/org.mitk.gui.qt.common/src/QmitkMultiNodeSelectionWidget.cpp index 26102b6d3e..5f94c42764 100644 --- a/Plugins/org.mitk.gui.qt.common/src/QmitkMultiNodeSelectionWidget.cpp +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkMultiNodeSelectionWidget.cpp @@ -1,244 +1,254 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkMultiNodeSelectionWidget.h" #include #include "QmitkNodeSelectionDialog.h" #include "QmitkCustomVariants.h" #include "internal/QmitkNodeSelectionListItemWidget.h" QmitkMultiNodeSelectionWidget::QmitkMultiNodeSelectionWidget(QWidget* parent) : QmitkAbstractNodeSelectionWidget(parent) { m_Controls.setupUi(this); m_Overlay = new QmitkSimpleTextOverlayWidget(m_Controls.list); m_Overlay->setVisible(false); m_CheckFunction = [](const NodeList &) { return ""; }; this->UpdateList(); this->UpdateInfo(); connect(m_Controls.btnChange, SIGNAL(clicked(bool)), this, SLOT(OnEditSelection())); } QmitkMultiNodeSelectionWidget::NodeList QmitkMultiNodeSelectionWidget::CompileEmitSelection() const { NodeList result; for (int i = 0; i < m_Controls.list->count(); ++i) { QListWidgetItem* item = m_Controls.list->item(i); auto node = item->data(Qt::UserRole).value(); result.append(node); } if (!m_SelectOnlyVisibleNodes) { for (auto node : m_CurrentSelection) { if (!result.contains(node)) { result.append(node); } } } return result; } void QmitkMultiNodeSelectionWidget::OnNodePredicateChanged(mitk::NodePredicateBase* /*newPredicate*/) { this->UpdateInfo(); this->UpdateList(); }; void QmitkMultiNodeSelectionWidget::OnDataStorageChanged() { this->UpdateInfo(); this->UpdateList(); }; QmitkMultiNodeSelectionWidget::NodeList QmitkMultiNodeSelectionWidget::GetSelectedNodes() const { return m_CurrentSelection; }; void QmitkMultiNodeSelectionWidget::SetSelectionCheckFunction(const SelectionCheckFunctionType &checkFunction) { m_CheckFunction = checkFunction; auto newEmission = this->CompileEmitSelection(); auto newCheckResponse = m_CheckFunction(newEmission); if (newCheckResponse.empty() && !m_CheckResponse.empty()) { emit CurrentSelectionChanged(newEmission); } m_CheckResponse = newCheckResponse; this->UpdateInfo(); }; void QmitkMultiNodeSelectionWidget::OnEditSelection() { QmitkNodeSelectionDialog* dialog = new QmitkNodeSelectionDialog(this, m_PopUpTitel, m_PopUpHint); dialog->SetDataStorage(m_DataStorage.Lock()); dialog->SetNodePredicate(m_NodePredicate); dialog->SetCurrentSelection(this->CompileEmitSelection()); dialog->SetSelectOnlyVisibleNodes(m_SelectOnlyVisibleNodes); dialog->SetSelectionMode(QAbstractItemView::MultiSelection); m_Controls.btnChange->setChecked(true); if (dialog->exec()) { auto lastEmission = this->CompileEmitSelection(); m_CurrentSelection = dialog->GetSelectedNodes(); this->UpdateList(); auto newEmission = this->CompileEmitSelection(); m_CheckResponse = m_CheckFunction(newEmission); this->UpdateInfo(); if (!EqualNodeSelections(lastEmission, newEmission)) { if (m_CheckResponse.empty()) { emit CurrentSelectionChanged(newEmission); } } } m_Controls.btnChange->setChecked(false); delete dialog; }; void QmitkMultiNodeSelectionWidget::UpdateInfo() { if (!m_Controls.list->count()) { if (m_IsOptional) { m_Overlay->SetOverlayText(m_EmptyInfo); } else { m_Overlay->SetOverlayText(m_InvalidInfo); } } else { if (!m_CheckResponse.empty()) { m_Overlay->SetOverlayText(QString::fromStdString(m_CheckResponse)); } } m_Overlay->setVisible(m_Controls.list->count() == 0 || !m_CheckResponse.empty()); for (auto i = 0; i < m_Controls.list->count(); ++i) { auto item = m_Controls.list->item(i); auto widget = qobject_cast(m_Controls.list->itemWidget(item)); widget->SetClearAllowed(m_IsOptional || m_CurrentSelection.size() > 1); } }; void QmitkMultiNodeSelectionWidget::UpdateList() { m_Controls.list->clear(); for (auto node : m_CurrentSelection) { if (m_NodePredicate.IsNull() || m_NodePredicate->CheckNode(node)) { QListWidgetItem *newItem = new QListWidgetItem; newItem->setSizeHint(QSize(0, 40)); QmitkNodeSelectionListItemWidget* widget = new QmitkNodeSelectionListItemWidget; widget->SetSelectedNode(node); widget->SetClearAllowed(m_IsOptional || m_CurrentSelection.size() > 1); connect(widget, SIGNAL(ClearSelection(mitk::DataNode*)), this, SLOT(OnClearSelection(mitk::DataNode*))); newItem->setData(Qt::UserRole, QVariant::fromValue(node)); m_Controls.list->addItem(newItem); m_Controls.list->setItemWidget(newItem, widget); } } }; void QmitkMultiNodeSelectionWidget::SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes) { auto lastEmission = this->CompileEmitSelection(); m_SelectOnlyVisibleNodes = selectOnlyVisibleNodes; auto newEmission = this->CompileEmitSelection(); if (!EqualNodeSelections(lastEmission, newEmission)) { m_CheckResponse = m_CheckFunction(newEmission); if (m_CheckResponse.empty()) { emit CurrentSelectionChanged(newEmission); } this->UpdateList(); this->UpdateInfo(); } }; void QmitkMultiNodeSelectionWidget::SetCurrentSelection(NodeList selectedNodes) { auto lastEmission = this->CompileEmitSelection(); m_CurrentSelection = selectedNodes; this->UpdateList(); auto newEmission = this->CompileEmitSelection(); if (!EqualNodeSelections(lastEmission, newEmission)) { m_CheckResponse = m_CheckFunction(newEmission); if (m_CheckResponse.empty()) { emit CurrentSelectionChanged(newEmission); } this->UpdateInfo(); } }; -void QmitkMultiNodeSelectionWidget::OnClearSelection(mitk::DataNode* node) +void QmitkMultiNodeSelectionWidget::OnClearSelection(const mitk::DataNode* node) { auto finding = std::find(std::begin(m_CurrentSelection), std::end(m_CurrentSelection), node); m_CurrentSelection.erase(finding); this->UpdateList(); auto newEmission = this->CompileEmitSelection(); m_CheckResponse = m_CheckFunction(newEmission); if (m_CheckResponse.empty()) { emit CurrentSelectionChanged(newEmission); } this->UpdateInfo(); }; + +void QmitkMultiNodeSelectionWidget::NodeRemovedFromStorage(const mitk::DataNode* node) +{ + auto finding = std::find(std::begin(m_CurrentSelection), std::end(m_CurrentSelection), node); + + if (finding != std::end(m_CurrentSelection)) + { + this->OnClearSelection(node); + } +} \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkMultiNodeSelectionWidget.h b/Plugins/org.mitk.gui.qt.common/src/QmitkMultiNodeSelectionWidget.h index 28cc17ed33..c3c3a23141 100644 --- a/Plugins/org.mitk.gui.qt.common/src/QmitkMultiNodeSelectionWidget.h +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkMultiNodeSelectionWidget.h @@ -1,88 +1,89 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. 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 QMITK_MULTI_NODE_SELECTION_WIDGET_H #define QMITK_MULTI_NODE_SELECTION_WIDGET_H #include #include #include #include "QmitkSimpleTextOverlayWidget.h" #include "org_mitk_gui_qt_common_Export.h" #include "ui_QmitkMultiNodeSelectionWidget.h" #include class QmitkAbstractDataStorageModel; class QAbstractItemVew; /** * \class QmitkMultiNodeSelectionWidget * \brief Widget that allows to perform and represents a multiple node selection. */ class MITK_QT_COMMON QmitkMultiNodeSelectionWidget : public QmitkAbstractNodeSelectionWidget { Q_OBJECT public: explicit QmitkMultiNodeSelectionWidget(QWidget* parent = nullptr); using NodeList = QmitkAbstractNodeSelectionWidget::NodeList; NodeList GetSelectedNodes() const; /**Helper function that is used to check the given selection for consistency. Returning an empty string assumes that everything is alright and the selection is valid. If the string is not empty, the content of the string will be used as error message in the overlay to indicate the problem.*/ using SelectionCheckFunctionType = std::function; /**A selection check function can be set. If set the widget uses this function to check the made/set selection. If the selection is valid, everything is fine. If selection is indicated as invalid, it will not be communicated by the widget (no signal emission.*/ void SetSelectionCheckFunction(const SelectionCheckFunctionType &checkFunction); public Q_SLOTS: virtual void SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes) override; virtual void SetCurrentSelection(NodeList selectedNodes) override; void OnEditSelection(); protected Q_SLOTS: - void OnClearSelection(mitk::DataNode* node); + void OnClearSelection(const mitk::DataNode* node); protected: NodeList CompileEmitSelection() const; - virtual void UpdateInfo() override; + void UpdateInfo() override; virtual void UpdateList(); - virtual void OnNodePredicateChanged(mitk::NodePredicateBase* newPredicate) override; - virtual void OnDataStorageChanged() override; + void OnNodePredicateChanged(mitk::NodePredicateBase* newPredicate) override; + void OnDataStorageChanged() override; + void NodeRemovedFromStorage(const mitk::DataNode* node) override; NodeList m_CurrentSelection; QmitkSimpleTextOverlayWidget* m_Overlay; SelectionCheckFunctionType m_CheckFunction; std::string m_CheckResponse; Ui_QmitkMultiNodeSelectionWidget m_Controls; }; #endif // QmitkMultiNodeSelectionWidget_H diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkSingleNodeSelectionWidget.cpp b/Plugins/org.mitk.gui.qt.common/src/QmitkSingleNodeSelectionWidget.cpp index 2ede8b2f0b..737924a397 100644 --- a/Plugins/org.mitk.gui.qt.common/src/QmitkSingleNodeSelectionWidget.cpp +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkSingleNodeSelectionWidget.cpp @@ -1,237 +1,249 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkSingleNodeSelectionWidget.h" #include #include #include "QmitkNodeSelectionDialog.h" #include "QmitkNodeDetailsDialog.h" QmitkSingleNodeSelectionWidget::QmitkSingleNodeSelectionWidget(QWidget* parent) : QmitkAbstractNodeSelectionWidget(parent) { 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())); } QmitkSingleNodeSelectionWidget::~QmitkSingleNodeSelectionWidget() { } mitk::DataNode::Pointer QmitkSingleNodeSelectionWidget::ExtractCurrentValidSelection(const NodeList& nodes) const { mitk::DataNode::Pointer result = nullptr; for (auto node : nodes) { bool valid = true; if (m_NodePredicate.IsNotNull()) { valid = m_NodePredicate->CheckNode(node); } if (valid) { result = node; break; } } return result; } QmitkSingleNodeSelectionWidget::NodeList QmitkSingleNodeSelectionWidget::CompileEmitSelection() const { NodeList result; if (!m_SelectOnlyVisibleNodes) { result = m_ExternalSelection; } if (m_SelectedNode.IsNotNull() && !result.contains(m_SelectedNode)) { result.append(m_SelectedNode); } return result; } void QmitkSingleNodeSelectionWidget::OnNodePredicateChanged(mitk::NodePredicateBase* /*newPredicate*/) { m_SelectedNode = this->ExtractCurrentValidSelection(m_ExternalSelection); }; void QmitkSingleNodeSelectionWidget::OnDataStorageChanged() { }; void QmitkSingleNodeSelectionWidget::OnClearSelection() { if (m_IsOptional) { NodeList emptyList; this->SetCurrentSelection(emptyList); } this->UpdateInfo(); } mitk::DataNode::Pointer QmitkSingleNodeSelectionWidget::GetSelectedNode() const { return m_SelectedNode; }; 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) { 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); NodeList list; if (m_SelectedNode.IsNotNull()) { list.append(m_SelectedNode); } dialog->SetCurrentSelection(list); dialog->SetSelectOnlyVisibleNodes(m_SelectOnlyVisibleNodes); dialog->SetSelectionMode(QAbstractItemView::SingleSelection); m_Controls.btnSelect->setChecked(true); if (dialog->exec()) { auto lastEmission = this->CompileEmitSelection(); auto nodes = dialog->GetSelectedNodes(); if (nodes.empty()) { m_SelectedNode = nullptr; } else { m_SelectedNode = nodes.first(); } auto newEmission = this->CompileEmitSelection(); if (!EqualNodeSelections(lastEmission, newEmission)) { emit CurrentSelectionChanged(newEmission); this->UpdateInfo(); } } m_Controls.btnSelect->setChecked(false); delete dialog; }; void QmitkSingleNodeSelectionWidget::UpdateInfo() { if (m_SelectedNode.IsNull()) { if (m_IsOptional) { m_Controls.btnSelect->SetNodeInfo(m_EmptyInfo); } else { m_Controls.btnSelect->SetNodeInfo(m_InvalidInfo); } m_Controls.btnClear->setVisible(false); } else { m_Controls.btnClear->setVisible(m_IsOptional); } m_Controls.btnSelect->SetSelectedNode(m_SelectedNode); }; void QmitkSingleNodeSelectionWidget::SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes) { auto lastEmission = this->CompileEmitSelection(); m_SelectOnlyVisibleNodes = selectOnlyVisibleNodes; auto newEmission = this->CompileEmitSelection(); if (!EqualNodeSelections(lastEmission, newEmission)) { emit CurrentSelectionChanged(newEmission); this->UpdateInfo(); } }; void QmitkSingleNodeSelectionWidget::SetCurrentSelection(NodeList selectedNodes) { auto lastEmission = this->CompileEmitSelection(); m_ExternalSelection = selectedNodes; m_SelectedNode = this->ExtractCurrentValidSelection(selectedNodes); auto newEmission = this->CompileEmitSelection(); if (!EqualNodeSelections(lastEmission, newEmission)) { this->UpdateInfo(); emit CurrentSelectionChanged(newEmission); } }; + +void QmitkSingleNodeSelectionWidget::NodeRemovedFromStorage(const mitk::DataNode* node) +{ + if (m_SelectedNode == node && node != nullptr) + { + m_SelectedNode = nullptr; + auto newEmission = this->CompileEmitSelection(); + + emit CurrentSelectionChanged(newEmission); + this->UpdateInfo(); + } +} \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkSingleNodeSelectionWidget.h b/Plugins/org.mitk.gui.qt.common/src/QmitkSingleNodeSelectionWidget.h index 4f67d11568..3cb7f8f079 100644 --- a/Plugins/org.mitk.gui.qt.common/src/QmitkSingleNodeSelectionWidget.h +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkSingleNodeSelectionWidget.h @@ -1,76 +1,76 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. 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 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. 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); ~QmitkSingleNodeSelectionWidget(); mitk::DataNode::Pointer GetSelectedNode() const; using NodeList = QmitkAbstractNodeSelectionWidget::NodeList; public Q_SLOTS: virtual void SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes) override; virtual void SetCurrentSelection(NodeList selectedNodes) override; protected Q_SLOTS: virtual void OnClearSelection(); protected: mitk::DataNode::Pointer ExtractCurrentValidSelection(const NodeList& nodes) const; NodeList CompileEmitSelection() const; - virtual bool eventFilter(QObject *obj, QEvent *ev) override; + bool eventFilter(QObject *obj, QEvent *ev) override; void EditSelection(); - virtual void UpdateInfo() override; - - virtual void OnNodePredicateChanged(mitk::NodePredicateBase* newPredicate) override; - virtual void OnDataStorageChanged() override; + void UpdateInfo() override; + void OnNodePredicateChanged(mitk::NodePredicateBase* newPredicate) override; + void OnDataStorageChanged() override; + void NodeRemovedFromStorage(const mitk::DataNode* node) override; NodeList m_ExternalSelection; mitk::DataNode::Pointer m_SelectedNode; Ui_QmitkSingleNodeSelectionWidget m_Controls; }; #endif // QmitkSingleNodeSelectionWidget_H