diff --git a/Modules/QtWidgets/include/QmitkDataStorageComboBox.h b/Modules/QtWidgets/include/QmitkDataStorageComboBox.h index 39456c492a..e271d0215d 100644 --- a/Modules/QtWidgets/include/QmitkDataStorageComboBox.h +++ b/Modules/QtWidgets/include/QmitkDataStorageComboBox.h @@ -1,227 +1,229 @@ /*=================================================================== 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 QmitkDataStorageComboBox_h #define QmitkDataStorageComboBox_h #include // Own Includes #include "mitkDataNode.h" #include "mitkDataStorage.h" #include "mitkNodePredicateBase.h" #include "mitkWeakPointer.h" // Toolkit Includes #include #include /// /// \ingroup QmitkModule /// \class QmitkDataStorageComboBox /// \author Michael Mueller /// \version 4.0 /// \date 2009-02-09 /// \ingroup Widgets /// \brief Displays all or a subset (defined by a predicate) of nodes of the Data Storage. /// /// class MITKQTWIDGETS_EXPORT QmitkDataStorageComboBox : public QComboBox { Q_OBJECT public: /// /// \brief Ctor for an empty combobox. Use setDataStorage and setPredicate afterwards. /// QmitkDataStorageComboBox(QWidget *parent = nullptr, bool autoSelectNewNodes = false); /// /// \brief Ctor for constructing QmitkDataStorageComboBox with given DataStorageComboBox and given predicate. /// QmitkDataStorageComboBox(mitk::DataStorage *dataStorage, const mitk::NodePredicateBase *predicate, QWidget *parent = nullptr, bool autoSelectNewNodes = false); /// /// \brief Standard Dtor. Nothing to do here. /// ~QmitkDataStorageComboBox() override; /// /// \brief Searches for a given node and returns a valid index or -1 if the node was not found. /// virtual int Find(const mitk::DataNode *dataNode) const; public: /// /// \brief Get the DataStorage this ComboBox listens to. /// mitk::DataStorage::Pointer GetDataStorage() const; /// /// \brief Return the predicate (may be nullptr) that is responsible for the dataNode selection of this ComboBox. /// const mitk::NodePredicateBase::ConstPointer GetPredicate() const; /// /// \brief Returns the dataNode at Index index or 0 if the index is out of bounds. /// virtual mitk::DataNode::Pointer GetNode(int index) const; /// /// \brief Returns the selected dataNode or 0 if there is none. /// virtual mitk::DataNode::Pointer GetSelectedNode() const; /// /// \brief Returns all nodes that are stored in this combobox. /// mitk::DataStorage::SetOfObjects::ConstPointer GetNodes() const; /// /// Returns the AutoSelectNewItems. /// \see SetAutoSelectNewItems /// virtual bool GetAutoSelectNewItems(); public: /// /// \brief Set the DataStorage this ComboBox should listen to. /// /// If DataStorage is 0 nothing will be shown. If DataStorage is reset the combobox will be reset. void SetDataStorage(mitk::DataStorage *dataStorage); /// /// \brief Set the predicate for this ComboBox. (QmitkDataStorageComboBox is now owner of the predicate) /// /// If predicate is nullptr all nodes will be selected. If predicate changes the whole combobox will be reset. void SetPredicate(const mitk::NodePredicateBase *predicate); /// /// Adds a node to the ComboBox. Gets called every time a DataStorage Add Event was thrown. /// virtual void AddNode(const mitk::DataNode *dataNode); /// /// Removes a node from the ComboBox at a specified index (if the index exists). Gets called when a DataStorage Remove /// Event was thrown. /// virtual void RemoveNode(int index); /// /// Removes a node from the ComboBox. Gets called when a DataStorage Remove Event was thrown. /// virtual void RemoveNode(const mitk::DataNode *dataNode); /// /// Set a dataNode in the ComboBox at the specified index (if the index exists). /// Internally the method just calls RemoveNode(unsigned int) /// virtual void SetNode(int index, const mitk::DataNode *dataNode); /// /// Replaces a dataNode in the combobox by an otherDataNode. /// Internally the method just calls SetNode(unsigned int, mitk::DataNode*) /// virtual void SetNode(const mitk::DataNode *dataNode, const mitk::DataNode *otherDataNode); /// /// Sets AutoSelectNewItems flag. If set to true new Nodes will be automatically selected. Default is false. /// virtual void SetAutoSelectNewItems(bool autoSelectNewItems); /// /// \brief Called when the name property of the node was modified. /// virtual void OnPropertyListChanged(const itk::Object *caller, const itk::EventObject &event); signals: /// /// \brief Throw a signal when the data node selection changed. /// void OnSelectionChanged(const mitk::DataNode *); protected: /// /// \brief Checks if the given index is within the range of the m_Nodes vector. /// bool HasIndex(unsigned int index) const; protected slots: /// /// \brief Slot for signal when the user selects another item. /// void OnCurrentIndexChanged(int); public slots: /// /// \brief Slot for signal when user wants to set a node as current selected node. /// - void SetSelectedNode(mitk::DataNode::Pointer item); + void SetSelectedNode(const mitk::DataNode::Pointer& node); protected: /// /// \brief Inserts a new node at the given index. If the index does not exist, /// the data node is simply appended to the combobox. /// /// This function is used by AddNode() and SetNode() because they just to the same: /// 1. If node is replaced (that is when index exists), /// the itk::Event observer will be removed /// 2. Check Node against Predicate /// 3. Register for itk::Events on the node /// 4. Insert Node and show in combobox virtual void InsertNode(int index, const mitk::DataNode *dataNode); /// /// \brief Init-function this class with the given data storage and predicate. This function is called by all ctors. /// void Init(); /// /// \brief Reset function whenever data storage or predicate changes. /// virtual void Reset(); + void RemoveNodeAndPropertyLists(int index); + virtual void UpdateComboBoxText(const mitk::PropertyList*); protected: /// /// Pointer to the DataStorage from which the nodes are selected (remember: in BlueBerry there /// might be more than one DataStorage). /// mitk::WeakPointer m_DataStorage; /// /// \brief Holds the predicate that is responsible for the dataNode selection of this ComboBox. /// If the predicate is 0, every dataNode will be selected. /// mitk::NodePredicateBase::ConstPointer m_Predicate; /// /// Holds all selected Nodes. Don't hold smart pointer as we are in a GUI class. /// std::vector m_Nodes; /// /// \brief Holds the tags of the data node property observers. /// std::vector m_DataNodePropertyListObserverTags; /// /// \brief Holds the tags of the base data property observers. /// std::vector m_BaseDatapropertyListObserverTags; /// /// \brief Event function guard. Each function which is called by an event mechanism /// first checks if this is true in order to avoid endless loops. bool m_BlockEvents; /// /// \brief If set to "true" new Nodes will be automatically selected. bool m_AutoSelectNewNodes; }; #endif // QmitkDataStorageComboBox_h diff --git a/Modules/QtWidgets/include/QmitkDataStorageComboBoxWithSelectNone.h b/Modules/QtWidgets/include/QmitkDataStorageComboBoxWithSelectNone.h index a80673b07a..2ee588a200 100644 --- a/Modules/QtWidgets/include/QmitkDataStorageComboBoxWithSelectNone.h +++ b/Modules/QtWidgets/include/QmitkDataStorageComboBoxWithSelectNone.h @@ -1,151 +1,151 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) University College London (UCL). 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 QmitkDataStorageComboBoxWithSelectNone_h #define QmitkDataStorageComboBoxWithSelectNone_h #include #include "QmitkDataStorageComboBox.h" #include "QmitkCustomVariants.h" #include "mitkDataNode.h" /** * \class QmitkDataStorageComboBoxWithSelectNone * \brief Displays all or a subset (defined by a predicate) of nodes of the Data Storage, * and additionally, index 0 is always "please select", indicating no selection, and will * hence always return a nullptr mitk::DataNode* if asked for the node at index 0. * * \author Matt Clarkson (m.clarkson@ucl.ac.uk) * \ingroup org_mitk_gui_qt_cmdlinemodules_internal * \sa QmitkDataStorageComboBox */ class MITKQTWIDGETS_EXPORT QmitkDataStorageComboBoxWithSelectNone : public QmitkDataStorageComboBox { Q_OBJECT Q_PROPERTY(mitkDataNodePtr SelectedNode READ GetSelectedNode WRITE SetSelectedNode) Q_PROPERTY(QString currentValue READ currentValue WRITE setCurrentValue) public: /** * \brief Calls base class constructor. * \see QmitkDataStorageComboBox */ QmitkDataStorageComboBoxWithSelectNone(QWidget* parent = nullptr, bool autoSelectNewNodes=false); /** * \brief Calls base class constructor. * \see QmitkDataStorageComboBox */ - QmitkDataStorageComboBoxWithSelectNone( mitk::DataStorage* _DataStorage, + QmitkDataStorageComboBoxWithSelectNone( mitk::DataStorage* dataStorage, const mitk::NodePredicateBase* predicate, QWidget* parent = nullptr, - bool autoSelectNewNodes=false); + bool autoSelectNewNodes = false); /** * \brief Nothing to do. * \see QmitkDataStorageComboBox */ ~QmitkDataStorageComboBoxWithSelectNone() override; /** * \brief Stores the string that will be present on index 0, currently equal to "please select". */ static const QString ZERO_ENTRY_STRING; /** * \brief Searches for a given node, returning the index if found. * \param dataNode an mitk::DataNode, can be nullptr. * \return int -1 if not found, and compared to base class, will add 1 onto the retrieved index. */ - int Find( const mitk::DataNode* dataNode ) const override; + int Find(const mitk::DataNode* dataNode) const override; /** * \brief Retrieves the node at a given index, where if index is zero, will always return nullptr. * \param index An integer between 0 and n = number of nodes. * \return mitk::DataNode::Pointer nullptr or a data node pointer. */ mitk::DataNode::Pointer GetNode(int index) const override; /** * \brief Returns the selected DataNode or nullptr if there is none, or the current index is zero. */ mitk::DataNode::Pointer GetSelectedNode() const override; /** * \brief Sets the combo box to the index that contains the specified node, or 0 if the node cannot be found. */ virtual void SetSelectedNode(const mitk::DataNode::Pointer& node); using QmitkDataStorageComboBox::RemoveNode; /** * \brief Removes a node from the ComboBox at a specified index (if the index exists). * Gets called when a DataStorage Remove Event was thrown. */ void RemoveNode(int index) override; using QmitkDataStorageComboBox::SetNode; /** * \brief Set a DataNode in the ComboBox at the specified index (if the index exists). * Internally the method just calls InsertNode(unsigned int) */ void SetNode(int index, const mitk::DataNode* dataNode) override; /** * \brief Get the current file path. */ virtual QString currentValue() const; /** * \brief Set the current file path. */ virtual void setCurrentValue(const QString& path); /** * \brief Set the string that will be present on index 0. */ void SetZeroEntryText(const QString& zeroEntryString); protected: /** * \brief Checks if the given index is within range. */ bool HasIndex(unsigned int index) const; /** * \brief Inserts a new node at the given index, unless index is 0, which is silently ignored. */ void InsertNode(int index, const mitk::DataNode* dataNode) override; /** * \brief Reset function whenever datastorage or predicate changes. */ void Reset() override; private: /** * \brief This should store the current file path of the current image. * * * The reason is so that we can store and retrieve a temporary file name. */ QString m_CurrentPath; }; #endif // QmitkDataStorageComboBoxWithSelectNone_h diff --git a/Modules/QtWidgets/src/QmitkDataStorageComboBox.cpp b/Modules/QtWidgets/src/QmitkDataStorageComboBox.cpp index a9f01a34e8..e4cdf666dd 100644 --- a/Modules/QtWidgets/src/QmitkDataStorageComboBox.cpp +++ b/Modules/QtWidgets/src/QmitkDataStorageComboBox.cpp @@ -1,458 +1,471 @@ /*=================================================================== 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 "QmitkDataStorageComboBox.h" #include QmitkDataStorageComboBox::QmitkDataStorageComboBox(QWidget *parent, bool autoSelectNewNodes) : QComboBox(parent), m_DataStorage(nullptr), m_Predicate(nullptr), m_BlockEvents(false), m_AutoSelectNewNodes(autoSelectNewNodes) { this->Init(); } QmitkDataStorageComboBox::QmitkDataStorageComboBox(mitk::DataStorage *dataStorage, const mitk::NodePredicateBase *predicate, QWidget *parent, bool autoSelectNewNodes) : QComboBox(parent), m_DataStorage(nullptr), m_Predicate(predicate), m_BlockEvents(false), m_AutoSelectNewNodes(autoSelectNewNodes) { // make connections, fill combobox this->Init(); this->SetDataStorage(dataStorage); } QmitkDataStorageComboBox::~QmitkDataStorageComboBox() { // if there was an old storage, remove listeners if (!m_DataStorage.IsExpired()) { auto dataStorage = m_DataStorage.Lock(); dataStorage->AddNodeEvent.RemoveListener( mitk::MessageDelegate1(this, &QmitkDataStorageComboBox::AddNode)); dataStorage->RemoveNodeEvent.RemoveListener( mitk::MessageDelegate1(this, &QmitkDataStorageComboBox::RemoveNode)); } // we have lots of observers to nodes and their name properties, this gets ugly if nodes live longer than the box while (m_Nodes.size() > 0) RemoveNode(0); } int QmitkDataStorageComboBox::Find(const mitk::DataNode *dataNode) const { int index = -1; auto nodeIt = std::find(m_Nodes.begin(), m_Nodes.end(), dataNode); if (nodeIt != m_Nodes.end()) index = std::distance(m_Nodes.begin(), nodeIt); return index; } mitk::DataStorage::Pointer QmitkDataStorageComboBox::GetDataStorage() const { return m_DataStorage.Lock(); } const mitk::NodePredicateBase::ConstPointer QmitkDataStorageComboBox::GetPredicate() const { return m_Predicate.GetPointer(); } mitk::DataNode::Pointer QmitkDataStorageComboBox::GetNode(int index) const { return (this->HasIndex(index)) ? m_Nodes.at(index) : nullptr; } mitk::DataNode::Pointer QmitkDataStorageComboBox::GetSelectedNode() const { if (this->count() == 0) return nullptr; int currentIndex = this->currentIndex(); return currentIndex >= 0 ? this->GetNode(currentIndex) : nullptr; } mitk::DataStorage::SetOfObjects::ConstPointer QmitkDataStorageComboBox::GetNodes() const { mitk::DataStorage::SetOfObjects::Pointer setOfObjects = mitk::DataStorage::SetOfObjects::New(); for (auto it = m_Nodes.begin(); it != m_Nodes.end(); ++it) { setOfObjects->push_back(*it); } return setOfObjects.GetPointer(); } bool QmitkDataStorageComboBox::GetAutoSelectNewItems() { return m_AutoSelectNewNodes; } void QmitkDataStorageComboBox::SetDataStorage(mitk::DataStorage *dataStorage) { auto currentDataStorage = m_DataStorage.Lock(); // reset only if datastorage really changed if (currentDataStorage.GetPointer() != dataStorage) { // if there was an old storage, remove listeners if (currentDataStorage.IsNotNull()) { currentDataStorage->AddNodeEvent.RemoveListener( mitk::MessageDelegate1(this, &QmitkDataStorageComboBox::AddNode)); currentDataStorage->RemoveNodeEvent.RemoveListener( mitk::MessageDelegate1(this, &QmitkDataStorageComboBox::RemoveNode)); } // set new storage m_DataStorage = dataStorage; // if there is a new storage, add listeners if (!m_DataStorage.IsExpired()) { currentDataStorage = m_DataStorage.Lock(); currentDataStorage->AddNodeEvent.AddListener( mitk::MessageDelegate1(this, &QmitkDataStorageComboBox::AddNode)); currentDataStorage->RemoveNodeEvent.AddListener( mitk::MessageDelegate1(this, &QmitkDataStorageComboBox::RemoveNode)); } // reset predicate to reset the combobox this->Reset(); } } void QmitkDataStorageComboBox::SetPredicate(const mitk::NodePredicateBase *predicate) { if (m_Predicate != predicate) { m_Predicate = predicate; this->Reset(); } } void QmitkDataStorageComboBox::AddNode(const mitk::DataNode *dataNode) { // this is an event function, make sure that we didn't call ourself if (!m_BlockEvents) { m_BlockEvents = true; // pass a -1 to the InsertNode function in order to append the datatree node to the end this->InsertNode(-1, dataNode); m_BlockEvents = false; } } void QmitkDataStorageComboBox::RemoveNode(int index) { if (this->HasIndex(index)) { - // remove itk::Event observer - mitk::DataNode *dataNode = m_Nodes.at(index); - - // remove observer from data node property list - mitk::PropertyList* dataNodePropertyList = dataNode->GetPropertyList(); - if (nullptr != dataNodePropertyList) - { - dataNodePropertyList->RemoveObserver(m_DataNodePropertyListObserverTags[index]); - // remove observer tags from lists - m_DataNodePropertyListObserverTags.erase(m_DataNodePropertyListObserverTags.begin() + index); - } - - // remove observer from base data property list - mitk::BaseData* baseData = dynamic_cast(dataNode->GetData()); - if (nullptr != baseData) - { - mitk::PropertyList* baseDataPropertyList = baseData->GetPropertyList(); - if (nullptr != dataNodePropertyList) - { - baseDataPropertyList->RemoveObserver(m_BaseDatapropertyListObserverTags[index]); - // remove observer tags from lists - m_BaseDatapropertyListObserverTags.erase(m_BaseDatapropertyListObserverTags.begin() + index); - } - } - - // remove node from node vector - m_Nodes.erase(m_Nodes.begin() + index); + RemoveNodeAndPropertyLists(index); // remove node name from combobox this->removeItem(index); } } void QmitkDataStorageComboBox::RemoveNode(const mitk::DataNode *dataNode) { // this is an event function, make sure that we didn't call ourself if (!m_BlockEvents) { m_BlockEvents = true; this->RemoveNode(this->Find(dataNode)); m_BlockEvents = false; } } void QmitkDataStorageComboBox::SetNode(int index, const mitk::DataNode *dataNode) { if (this->HasIndex(index)) { - this->InsertNode(index, dataNode); + // if node is identical, we only update the name in the QComboBoxItem + if (dataNode == m_Nodes.at(index)) + { + this->setItemText(index, QString::fromStdString(dataNode->GetName())); + } + else + { + this->InsertNode(index, dataNode); + } } } void QmitkDataStorageComboBox::SetNode(const mitk::DataNode *dataNode, const mitk::DataNode *otherDataNode) { this->SetNode(this->Find(dataNode), otherDataNode); } void QmitkDataStorageComboBox::SetAutoSelectNewItems(bool autoSelectNewItems) { m_AutoSelectNewNodes = autoSelectNewItems; } void QmitkDataStorageComboBox::OnPropertyListChanged(const itk::Object *caller, const itk::EventObject &event) { if (!m_BlockEvents) { m_BlockEvents = true; // check if we have a modified event const itk::ModifiedEvent *modifiedEvent = dynamic_cast(&event); if (modifiedEvent) { const mitk::PropertyList *propertyList = dynamic_cast(caller); UpdateComboBoxText(propertyList); } m_BlockEvents = false; } } bool QmitkDataStorageComboBox::HasIndex(unsigned int index) const { return (m_Nodes.size() > 0 && index < m_Nodes.size()); } void QmitkDataStorageComboBox::OnCurrentIndexChanged(int index) { if (index >= 0 && index < this->count()) emit OnSelectionChanged(this->GetSelectedNode()); if (index == -1) emit OnSelectionChanged(nullptr); } -void QmitkDataStorageComboBox::SetSelectedNode(mitk::DataNode::Pointer item) +void QmitkDataStorageComboBox::SetSelectedNode(const mitk::DataNode::Pointer& node) { - int index = this->Find(item); + int index = this->Find(node); if (index == -1) { MITK_INFO << "QmitkDataStorageComboBox: item not available"; } else { this->setCurrentIndex(index); } } void QmitkDataStorageComboBox::InsertNode(int index, const mitk::DataNode *dataNode) { // check new or updated node first if (m_Predicate.IsNotNull() && !m_Predicate->CheckNode(dataNode)) return; bool addNewNode = false; bool insertNewNode = false; bool changedNode = false; // if this->HasIndex(index), then a node shall be updated if (this->HasIndex(index)) { // if we really have another node at this position then ... if (dataNode != m_Nodes.at(index)) { // ... remove node, then proceed as usual this->RemoveNode(index); insertNewNode = true; } else changedNode = true; } // otherwise a new node shall be added, let index point to the element after the last element else { index = m_Nodes.size(); addNewNode = true; } // const cast because we need non const nodes mitk::DataNode *nonConstDataNode = const_cast(dataNode); if (!changedNode) { // break on duplicated nodes (that doesn't make sense to have duplicates in the combobox) if (this->Find(dataNode) != -1) return; // add modified observer itk::MemberCommand::Pointer propertyListChangedCommand = itk::MemberCommand::New(); propertyListChangedCommand->SetCallbackFunction(this, &QmitkDataStorageComboBox::OnPropertyListChanged); // add observer for the data node property list mitk::PropertyList* dataNodePropertyList = nonConstDataNode->GetPropertyList(); if (nullptr != dataNodePropertyList) { m_DataNodePropertyListObserverTags.push_back(dataNodePropertyList->AddObserver(itk::ModifiedEvent(), propertyListChangedCommand)); } else { // fill vector with invalid value m_DataNodePropertyListObserverTags.push_back(-1); } mitk::PropertyList* baseDataPropertyList; //add observer for the base data property list mitk::BaseData* baseData = dynamic_cast(nonConstDataNode->GetData()); if (nullptr != baseData) { baseDataPropertyList = baseData->GetPropertyList(); if (nullptr != baseDataPropertyList) { m_BaseDatapropertyListObserverTags.push_back(baseDataPropertyList->AddObserver(itk::ModifiedEvent(), propertyListChangedCommand)); } else { // fill vector with invalid value m_BaseDatapropertyListObserverTags.push_back(-1); } } else { // fill vector with invalid value m_BaseDatapropertyListObserverTags.push_back(-1); } } // add node to the vector if (addNewNode) m_Nodes.push_back(nonConstDataNode); else if (insertNewNode) m_Nodes.insert(m_Nodes.begin() + index, nonConstDataNode); if (addNewNode) { this->addItem(QString::fromStdString(nonConstDataNode->GetName())); // select new node if m_AutoSelectNewNodes is true or if we have just added the first node if (m_AutoSelectNewNodes || m_Nodes.size() == 1) this->setCurrentIndex(index); } else { // update text in combobox this->setItemText(index, QString::fromStdString(nonConstDataNode->GetName())); } } void QmitkDataStorageComboBox::Init() { connect(this, SIGNAL(currentIndexChanged(int)), this, SLOT(OnCurrentIndexChanged(int))); } void QmitkDataStorageComboBox::Reset() { // remove all nodes first while (!m_Nodes.empty()) { // remove last node // explicitly calling RemoveNode of QmitkDataStorageComboBox since derived classes may prevent the removal of all // nodes in their respective RemoveNode implementation. This is happening for example in // QmitkDataStorageComboBoxWithSelectNone. QmitkDataStorageComboBox::RemoveNode(m_Nodes.size() - 1); } // clear combobox this->clear(); if (!m_DataStorage.IsExpired()) { auto dataStorage = m_DataStorage.Lock(); mitk::DataStorage::SetOfObjects::ConstPointer setOfObjects; // select all if predicate == nullptr if (m_Predicate.IsNotNull()) setOfObjects = dataStorage->GetSubset(m_Predicate); else setOfObjects = dataStorage->GetAll(); // add all found nodes for (mitk::DataStorage::SetOfObjects::ConstIterator nodeIt = setOfObjects->Begin(); nodeIt != setOfObjects->End(); ++nodeIt) // for each dataNode { // add node to the node vector and to the combobox this->AddNode(nodeIt.Value().GetPointer()); } } } +void QmitkDataStorageComboBox::RemoveNodeAndPropertyLists(int index) +{ + // remove itk::Event observer + mitk::DataNode *dataNode = m_Nodes.at(index); + + // remove observer from data node property list + mitk::PropertyList* dataNodePropertyList = dataNode->GetPropertyList(); + if (nullptr != dataNodePropertyList) + { + dataNodePropertyList->RemoveObserver(m_DataNodePropertyListObserverTags[index]); + // remove observer tags from lists + m_DataNodePropertyListObserverTags.erase(m_DataNodePropertyListObserverTags.begin() + index); + } + + // remove observer from base data property list + mitk::BaseData* baseData = dynamic_cast(dataNode->GetData()); + if (nullptr != baseData) + { + mitk::PropertyList* baseDataPropertyList = baseData->GetPropertyList(); + if (nullptr != dataNodePropertyList) + { + baseDataPropertyList->RemoveObserver(m_BaseDatapropertyListObserverTags[index]); + // remove observer tags from lists + m_BaseDatapropertyListObserverTags.erase(m_BaseDatapropertyListObserverTags.begin() + index); + } + } + + // remove node from node vector + m_Nodes.erase(m_Nodes.begin() + index); +} + void QmitkDataStorageComboBox::UpdateComboBoxText(const mitk::PropertyList* propertyList) { mitk::PropertyList* dataNodePropertyList; mitk::PropertyList* baseDataPropertyList; mitk::BaseData* baseData; for (const auto& node : m_Nodes) { dataNodePropertyList = node->GetPropertyList(); baseData = dynamic_cast(node->GetData()); if (nullptr != baseData) { baseDataPropertyList = baseData->GetPropertyList(); } if (propertyList == dataNodePropertyList || propertyList == baseDataPropertyList) { // if one of the property list is the one that has just been modified // get the node's index and set its text to the node name // the node name might have been changed, depending on the modified property list auto index = Find(node); // update text in combobox this->setItemText(index, QString::fromStdString(node->GetName())); return; } } } diff --git a/Modules/QtWidgets/src/QmitkDataStorageComboBoxWithSelectNone.cpp b/Modules/QtWidgets/src/QmitkDataStorageComboBoxWithSelectNone.cpp index e1a99a0007..488d7ac3ab 100644 --- a/Modules/QtWidgets/src/QmitkDataStorageComboBoxWithSelectNone.cpp +++ b/Modules/QtWidgets/src/QmitkDataStorageComboBoxWithSelectNone.cpp @@ -1,206 +1,139 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) University College London (UCL). 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 "QmitkDataStorageComboBoxWithSelectNone.h" #include const QString QmitkDataStorageComboBoxWithSelectNone::ZERO_ENTRY_STRING = "--"; -//----------------------------------------------------------------------------- -QmitkDataStorageComboBoxWithSelectNone::QmitkDataStorageComboBoxWithSelectNone( - QWidget* parent, - bool autoSelectNewNodes ) -: QmitkDataStorageComboBox(parent, autoSelectNewNodes) -, m_CurrentPath("") +QmitkDataStorageComboBoxWithSelectNone::QmitkDataStorageComboBoxWithSelectNone(QWidget* parent, bool autoSelectNewNodes) + : QmitkDataStorageComboBox(parent, autoSelectNewNodes) + , m_CurrentPath("") { } - -//----------------------------------------------------------------------------- -QmitkDataStorageComboBoxWithSelectNone::QmitkDataStorageComboBoxWithSelectNone( - mitk::DataStorage* dataStorage, - const mitk::NodePredicateBase* predicate, - QWidget* parent, bool autoSelectNewNodes ) -: QmitkDataStorageComboBox(dataStorage, predicate, parent, autoSelectNewNodes) +QmitkDataStorageComboBoxWithSelectNone::QmitkDataStorageComboBoxWithSelectNone(mitk::DataStorage* dataStorage, + const mitk::NodePredicateBase* predicate, + QWidget* parent, + bool autoSelectNewNodes) + : QmitkDataStorageComboBox(dataStorage, predicate, parent, autoSelectNewNodes) { } - -//----------------------------------------------------------------------------- QmitkDataStorageComboBoxWithSelectNone::~QmitkDataStorageComboBoxWithSelectNone() { } - -//----------------------------------------------------------------------------- -int QmitkDataStorageComboBoxWithSelectNone::Find( const mitk::DataNode* dataNode ) const +int QmitkDataStorageComboBoxWithSelectNone::Find(const mitk::DataNode* dataNode) const { int index = QmitkDataStorageComboBox::Find(dataNode); if (index != -1) { index += 1; } return index; } - -//----------------------------------------------------------------------------- -mitk::DataNode::Pointer QmitkDataStorageComboBoxWithSelectNone::GetNode( int index ) const +mitk::DataNode::Pointer QmitkDataStorageComboBoxWithSelectNone::GetNode(int index) const { mitk::DataNode::Pointer result = nullptr; if (this->HasIndex(index)) { if (index != 0) { result = m_Nodes.at(index - 1); } } return result; } - -//----------------------------------------------------------------------------- mitk::DataNode::Pointer QmitkDataStorageComboBoxWithSelectNone::GetSelectedNode() const { return this->GetNode(this->currentIndex()); } - -//----------------------------------------------------------------------------- void QmitkDataStorageComboBoxWithSelectNone::SetSelectedNode(const mitk::DataNode::Pointer& node) { - int currentIndex = -1; - for (int i = 0; i < static_cast(m_Nodes.size()); i++) - { - if (m_Nodes[i] == node.GetPointer()) - { - currentIndex = i; - break; - } - } - if (currentIndex == -1) + int index = Find(node); + if (index == -1) { // didn't find it, so set the value to 0. - currentIndex = 0; - } - else - { - currentIndex += 1; // because the combo box contains "please select" at position zero. + index = 0; } - this->setCurrentIndex(currentIndex); + + this->setCurrentIndex(index); } -//----------------------------------------------------------------------------- -void QmitkDataStorageComboBoxWithSelectNone::RemoveNode( int index ) +void QmitkDataStorageComboBoxWithSelectNone::RemoveNode(int index) { if(index > 0 && this->HasIndex(index)) { - - // remove itk::Event observer - mitk::DataNode* dataNode = m_Nodes.at(index - 1); - - // get name property first - mitk::BaseProperty* nameProperty = dataNode->GetProperty("name"); - - // if prop exists remove modified listener - if(nameProperty) - { - nameProperty->RemoveObserver(m_NodesModifiedObserverTags[index-1]); - - // remove name property map - m_PropertyToNode.erase(dataNode); - } - - // then remove delete listener on the node itself - dataNode->RemoveObserver(m_NodesDeleteObserverTags[index-1]); - - // remove observer tags from lists - m_NodesModifiedObserverTags.erase(m_NodesModifiedObserverTags.begin()+index-1); - m_NodesDeleteObserverTags.erase(m_NodesDeleteObserverTags.begin()+index-1); - + RemoveNodeAndPropertyLists(index - 1); // remove node name from combobox this->removeItem(index); - - // remove node from node vector - m_Nodes.erase(m_Nodes.begin()+index-1); } } - -//----------------------------------------------------------------------------- void QmitkDataStorageComboBoxWithSelectNone::SetNode(int index, const mitk::DataNode* dataNode) { - if(index > 0 && this->HasIndex(index)) + if (index > 0 && this->HasIndex(index)) { - // if node identical, we only update the name in the QComboBoxItem - if( dataNode == this->m_Nodes.at(index-1 ) ) + // if node is identical, we only update the name in the QComboBoxItem + if (dataNode == m_Nodes.at(index - 1)) { - mitk::BaseProperty* nameProperty = dataNode->GetProperty("name"); - std::string dataNodeNameStr = nameProperty->GetValueAsString(); - - this->setItemText(index, QString::fromStdString( dataNodeNameStr) ); + this->setItemText(index, QString::fromStdString(dataNode->GetName())); } else + { QmitkDataStorageComboBox::InsertNode(index - 1, dataNode); + } } } - -//----------------------------------------------------------------------------- bool QmitkDataStorageComboBoxWithSelectNone::HasIndex(unsigned int index) const { return (m_Nodes.size() > 0 && index <= m_Nodes.size()); } - -//----------------------------------------------------------------------------- void QmitkDataStorageComboBoxWithSelectNone::InsertNode(int index, const mitk::DataNode* dataNode) { if (index != 0) { QmitkDataStorageComboBox::InsertNode(index - 1, dataNode); } } - -//----------------------------------------------------------------------------- void QmitkDataStorageComboBoxWithSelectNone::Reset() { QmitkDataStorageComboBox::Reset(); this->insertItem(0, ZERO_ENTRY_STRING); } - -//----------------------------------------------------------------------------- void QmitkDataStorageComboBoxWithSelectNone::SetZeroEntryText(const QString& zeroEntryString) { this->setItemText(0, zeroEntryString); this->setCurrentIndex(0); } - -//----------------------------------------------------------------------------- QString QmitkDataStorageComboBoxWithSelectNone::currentValue() const { return m_CurrentPath; } - -//----------------------------------------------------------------------------- void QmitkDataStorageComboBoxWithSelectNone::setCurrentValue(const QString& path) { m_CurrentPath = path; }