diff --git a/Modules/QtWidgets/include/QmitkDataStorageComboBox.h b/Modules/QtWidgets/include/QmitkDataStorageComboBox.h index 1dd4cbc7a9..e271d0215d 100644 --- a/Modules/QtWidgets/include/QmitkDataStorageComboBox.h +++ b/Modules/QtWidgets/include/QmitkDataStorageComboBox.h @@ -1,243 +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 -// Forward Declartions - /// /// \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. /// -/// Dont forget that this class inherits from QComboBox and you can therefore use the whole API of QComboBox. /// class MITKQTWIDGETS_EXPORT QmitkDataStorageComboBox : public QComboBox { - //#CLASS-MACROS,FRIENDS Q_OBJECT - //#CTORS/DTOR public: /// /// \brief Ctor for an empty combobox. Use setDataStorage and setPredicate afterwards. /// - QmitkDataStorageComboBox(QWidget *parent = nullptr, bool _AutoSelectNewNodes = false); + QmitkDataStorageComboBox(QWidget *parent = nullptr, bool autoSelectNewNodes = false); /// - /// \brief Ctor for constructing QmitkDataStorageComboBox with given DataStorageComboBox and given _Predicate. + /// \brief Ctor for constructing QmitkDataStorageComboBox with given DataStorageComboBox and given predicate. /// - QmitkDataStorageComboBox(mitk::DataStorage *_DataStorage, - const mitk::NodePredicateBase *_Predicate, + QmitkDataStorageComboBox(mitk::DataStorage *dataStorage, + const mitk::NodePredicateBase *predicate, QWidget *parent = nullptr, - bool _AutoSelectNewNodes = false); + bool autoSelectNewNodes = false); /// /// \brief Standard Dtor. Nothing to do here. /// ~QmitkDataStorageComboBox() override; /// - /// \brief Seaches for a given node and returns a valid index or -1 if the node was not found. + /// \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; + virtual int Find(const mitk::DataNode *dataNode) const; - //#PUBLIC GETTER 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. + /// \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. + /// \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. + /// \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 SETTER public: /// /// \brief Set the DataStorage this ComboBox should listen to. /// - /// If DataStorage is 0 nothing will be shown. If DataStorage is re-set the combobox will be resetted. + /// 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 resetted. - void SetPredicate(const mitk::NodePredicateBase *_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 everytime a DataStorage Add Event was thrown. + /// Adds a node to the ComboBox. Gets called every time a DataStorage Add Event was thrown. /// - virtual void AddNode(const mitk::DataNode *_DataNode); + 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); + virtual void RemoveNode(const mitk::DataNode *dataNode); /// - /// Set a _DataNode in the ComboBox at the specified index (if the index exists). + /// 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); + virtual void SetNode(int index, const mitk::DataNode *dataNode); /// - /// Replaces a _DataNode in the combobox by an _OtherDataNode. + /// 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); + 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); + virtual void SetAutoSelectNewItems(bool autoSelectNewItems); /// - /// \brief Called when a node is deleted or the name property of the node was modified. Calls RemoveNode or SetNode - /// then. + /// \brief Called when the name property of the node was modified. /// - virtual void OnDataNodeDeleteOrModified(const itk::Object *caller, const itk::EventObject &event); + virtual void OnPropertyListChanged(const itk::Object *caller, const itk::EventObject &event); signals: /// - /// \brief Throw a signal when the _DataNode selection changed. + /// \brief Throw a signal when the data node selection changed. /// void OnSelectionChanged(const mitk::DataNode *); - //#PROTECTED GETTER protected: /// /// \brief Checks if the given index is within the range of the m_Nodes vector. /// bool HasIndex(unsigned int index) const; - //#PROTECTED SETTER protected slots: /// /// \brief Slot for signal when the user selects another item. /// void OnCurrentIndexChanged(int); - //#PUBLIC SETTER 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 _DataNode is simply appended to the - /// combobox. + /// \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); + virtual void InsertNode(int index, const mitk::DataNode *dataNode); /// - /// \brief Init-function this class with the given dataStorage and _Predicate. This function is called by all ctors. + /// \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 datastorage or predicate changes. + /// \brief Reset function whenever data storage or predicate changes. /// virtual void Reset(); + void RemoveNodeAndPropertyLists(int index); + + virtual void UpdateComboBoxText(const mitk::PropertyList*); + protected: - //#PROTECTED MEMBER VARS /// /// 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. + /// \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. Dont hold smart pointer as we are in a GUI class. + /// 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 node-modified observers. (must be updated everytime m_Nodes changes) - /// - std::vector m_NodesModifiedObserverTags; - - /// - /// \brief Holds the tags of the node-modified observers. (must be updated everytime m_Nodes changes) + /// \brief Holds the tags of the data node property observers. /// - std::vector m_NodesDeleteObserverTags; + std::vector m_DataNodePropertyListObserverTags; /// - /// \brief Maps a a specific node to (Name-)property. This is needed because we have to find the assiociated node - /// whenever the name property of a node changed. + /// \brief Holds the tags of the base data property observers. /// - std::map m_PropertyToNode; + 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 9a498c94df..c286ba1238 100644 --- a/Modules/QtWidgets/src/QmitkDataStorageComboBox.cpp +++ b/Modules/QtWidgets/src/QmitkDataStorageComboBox.cpp @@ -1,435 +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 -//#CTORS/DTOR - -QmitkDataStorageComboBox::QmitkDataStorageComboBox(QWidget *parent, bool _AutoSelectNewNodes) +QmitkDataStorageComboBox::QmitkDataStorageComboBox(QWidget *parent, bool autoSelectNewNodes) : QComboBox(parent), m_DataStorage(nullptr), m_Predicate(nullptr), m_BlockEvents(false), - m_AutoSelectNewNodes(_AutoSelectNewNodes) + m_AutoSelectNewNodes(autoSelectNewNodes) { this->Init(); } -QmitkDataStorageComboBox::QmitkDataStorageComboBox(mitk::DataStorage *_DataStorage, - const mitk::NodePredicateBase *_Predicate, +QmitkDataStorageComboBox::QmitkDataStorageComboBox(mitk::DataStorage *dataStorage, + const mitk::NodePredicateBase *predicate, QWidget *parent, - bool _AutoSelectNewNodes) + bool autoSelectNewNodes) : QComboBox(parent), m_DataStorage(nullptr), - m_Predicate(_Predicate), + m_Predicate(predicate), m_BlockEvents(false), - m_AutoSelectNewNodes(_AutoSelectNewNodes) + m_AutoSelectNewNodes(autoSelectNewNodes) { // make connections, fill combobox this->Init(); - this->SetDataStorage(_DataStorage); + 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 get's ugly if nodes live longer than the box + // 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); } -//#PUBLIC GETTER +int QmitkDataStorageComboBox::Find(const mitk::DataNode *dataNode) const +{ + std::iterator_traits::difference_type 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 static_cast(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(); + mitk::DataStorage::SetOfObjects::Pointer setOfObjects = mitk::DataStorage::SetOfObjects::New(); for (auto it = m_Nodes.begin(); it != m_Nodes.end(); ++it) { - _SetOfObjects->push_back(*it); + setOfObjects->push_back(*it); } - return _SetOfObjects.GetPointer(); + return setOfObjects.GetPointer(); } bool QmitkDataStorageComboBox::GetAutoSelectNewItems() { return m_AutoSelectNewNodes; } -//#PUBLIC SETTER -void QmitkDataStorageComboBox::SetDataStorage(mitk::DataStorage *_DataStorage) +void QmitkDataStorageComboBox::SetDataStorage(mitk::DataStorage *dataStorage) { - auto dataStorage = m_DataStorage.Lock(); + auto currentDataStorage = m_DataStorage.Lock(); // reset only if datastorage really changed - if (dataStorage.GetPointer() != _DataStorage) + if (currentDataStorage.GetPointer() != dataStorage) { // if there was an old storage, remove listeners - if (dataStorage.IsNotNull()) + if (currentDataStorage.IsNotNull()) { - dataStorage->AddNodeEvent.RemoveListener( + currentDataStorage->AddNodeEvent.RemoveListener( mitk::MessageDelegate1(this, - &QmitkDataStorageComboBox::AddNode)); + &QmitkDataStorageComboBox::AddNode)); - dataStorage->RemoveNodeEvent.RemoveListener( - mitk::MessageDelegate1( - this, &QmitkDataStorageComboBox::RemoveNode)); + currentDataStorage->RemoveNodeEvent.RemoveListener( + mitk::MessageDelegate1(this, + &QmitkDataStorageComboBox::RemoveNode)); } // set new storage - m_DataStorage = _DataStorage; + m_DataStorage = dataStorage; // if there is a new storage, add listeners if (!m_DataStorage.IsExpired()) { - dataStorage = m_DataStorage.Lock(); + currentDataStorage = m_DataStorage.Lock(); - dataStorage->AddNodeEvent.AddListener( + currentDataStorage->AddNodeEvent.AddListener( mitk::MessageDelegate1(this, - &QmitkDataStorageComboBox::AddNode)); + &QmitkDataStorageComboBox::AddNode)); - dataStorage->RemoveNodeEvent.AddListener( - mitk::MessageDelegate1( - this, &QmitkDataStorageComboBox::RemoveNode)); + currentDataStorage->RemoveNodeEvent.AddListener( + mitk::MessageDelegate1(this, + &QmitkDataStorageComboBox::RemoveNode)); } // reset predicate to reset the combobox this->Reset(); } } -void QmitkDataStorageComboBox::SetPredicate(const mitk::NodePredicateBase *_Predicate) +void QmitkDataStorageComboBox::SetPredicate(const mitk::NodePredicateBase *predicate) { - if (m_Predicate != _Predicate) + if (m_Predicate != predicate) { - m_Predicate = _Predicate; + m_Predicate = predicate; this->Reset(); } } -void QmitkDataStorageComboBox::AddNode(const mitk::DataNode *_DataNode) +void QmitkDataStorageComboBox::AddNode(const mitk::DataNode *dataNode) { - // this is an event function, make sure that we didnt call ourself + // 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 datatreenode to the end - this->InsertNode(-1, _DataNode); + // 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); - // get name property first - mitk::BaseProperty *nameProperty = _DataNode->GetProperty("name"); - // if prop exists remove modified listener - if (nameProperty) - { - nameProperty->RemoveObserver(m_NodesModifiedObserverTags[index]); - // remove name property map - m_PropertyToNode.erase(_DataNode); - } - // then remove delete listener on the node itself - _DataNode->RemoveObserver(m_NodesDeleteObserverTags[index]); - // remove observer tags from lists - m_NodesModifiedObserverTags.erase(m_NodesModifiedObserverTags.begin() + index); - m_NodesDeleteObserverTags.erase(m_NodesDeleteObserverTags.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) +void QmitkDataStorageComboBox::RemoveNode(const mitk::DataNode *dataNode) { - // this is an event function, make sure that we didnt call ourself + // this is an event function, make sure that we didn't call ourself if (!m_BlockEvents) { m_BlockEvents = true; - this->RemoveNode(this->Find(_DataNode)); + this->RemoveNode(this->Find(dataNode)); m_BlockEvents = false; } } -void QmitkDataStorageComboBox::SetNode(int index, const mitk::DataNode *_DataNode) +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) +void QmitkDataStorageComboBox::SetNode(const mitk::DataNode *dataNode, const mitk::DataNode *otherDataNode) { - this->SetNode(this->Find(_DataNode), _OtherDataNode); + this->SetNode(this->Find(dataNode), otherDataNode); } -void QmitkDataStorageComboBox::SetAutoSelectNewItems(bool _AutoSelectNewItems) +void QmitkDataStorageComboBox::SetAutoSelectNewItems(bool autoSelectNewItems) { - m_AutoSelectNewNodes = _AutoSelectNewItems; + m_AutoSelectNewNodes = autoSelectNewItems; } -void QmitkDataStorageComboBox::OnDataNodeDeleteOrModified(const itk::Object *caller, const itk::EventObject &event) +void QmitkDataStorageComboBox::OnPropertyListChanged(const itk::Object *caller, const itk::EventObject &event) { if (!m_BlockEvents) { m_BlockEvents = true; - // check if we have a modified event (if not it is a delete event) + // check if we have a modified event const itk::ModifiedEvent *modifiedEvent = dynamic_cast(&event); - - // when node was modified reset text if (modifiedEvent) { - const mitk::BaseProperty *_NameProperty = dynamic_cast(caller); - - // node name changed, set it - // but first of all find associated node - for (auto it = m_PropertyToNode.begin(); it != m_PropertyToNode.end(); ++it) - { - // property is found take node - if (it->second == _NameProperty) - { - // looks strange but when calling setnode with the same node, that means the node gets updated - this->SetNode(it->first, it->first); - break; - } - } - } - else - { - const mitk::DataNode *_ConstDataNode = dynamic_cast(caller); - if (_ConstDataNode) - // node will be deleted, remove it - this->RemoveNode(_ConstDataNode); + const mitk::PropertyList *propertyList = dynamic_cast(caller); + UpdateComboBoxText(propertyList); } m_BlockEvents = false; } } -void QmitkDataStorageComboBox::SetSelectedNode(mitk::DataNode::Pointer item) -{ - int index = this->Find(item); - if (index == -1) - { - MITK_INFO << "QmitkDataStorageComboBox: item not available"; - } - else - { - this->setCurrentIndex(index); - } -} - -//#PROTECTED GETTER bool QmitkDataStorageComboBox::HasIndex(unsigned int index) const { return (m_Nodes.size() > 0 && index < m_Nodes.size()); } -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; -} - -//#PROTECTED SETTER void QmitkDataStorageComboBox::OnCurrentIndexChanged(int index) { if (index >= 0 && index < this->count()) emit OnSelectionChanged(this->GetSelectedNode()); if (index == -1) emit OnSelectionChanged(nullptr); } -void QmitkDataStorageComboBox::InsertNode(int index, const mitk::DataNode *_DataNode) +void QmitkDataStorageComboBox::SetSelectedNode(const mitk::DataNode::Pointer& node) +{ + 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)) + 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)) + 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); - mitk::BaseProperty *nameProperty = _NonConstDataNode->GetProperty("name"); - + mitk::DataNode *nonConstDataNode = const_cast(dataNode); if (!changedNode) { - // break on duplicated nodes (that doesnt make sense to have duplicates in the combobox) - if (this->Find(_DataNode) != -1) + // 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 modifiedCommand = + itk::MemberCommand::Pointer propertyListChangedCommand = itk::MemberCommand::New(); - modifiedCommand->SetCallbackFunction(this, &QmitkDataStorageComboBox::OnDataNodeDeleteOrModified); - // !!!! add modified observer for the name - /// property of the node because this is the only thing we are interested in !!!!! - if (nameProperty) + propertyListChangedCommand->SetCallbackFunction(this, &QmitkDataStorageComboBox::OnPropertyListChanged); + + // add observer for the data node property list + mitk::PropertyList* dataNodePropertyList = nonConstDataNode->GetPropertyList(); + if (nullptr != dataNodePropertyList) { - m_NodesModifiedObserverTags.push_back(nameProperty->AddObserver(itk::ModifiedEvent(), modifiedCommand)); - m_PropertyToNode[_NonConstDataNode] = nameProperty; + m_DataNodePropertyListObserverTags.push_back(dataNodePropertyList->AddObserver(itk::ModifiedEvent(), + propertyListChangedCommand)); } - // if there is no name node save an invalid value for the observer tag (-1) else - m_NodesModifiedObserverTags.push_back(-1); + { + // fill vector with invalid value + m_DataNodePropertyListObserverTags.push_back(-1); + } - // add delete observer - itk::MemberCommand::Pointer deleteCommand = - itk::MemberCommand::New(); - deleteCommand->SetCallbackFunction(this, &QmitkDataStorageComboBox::OnDataNodeDeleteOrModified); - m_NodesDeleteObserverTags.push_back(_NonConstDataNode->AddObserver(itk::DeleteEvent(), modifiedCommand)); + 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); + m_Nodes.push_back(nonConstDataNode); else if (insertNewNode) - m_Nodes.insert(m_Nodes.begin() + index, _NonConstDataNode); - - // ... and to the combobox - std::string _NonConstDataNodeName = "unnamed node"; - // _NonConstDataNodeName is "unnamed node" so far, change it if there is a name property in the node - if (nameProperty) - _NonConstDataNodeName = nameProperty->GetValueAsString(); + m_Nodes.insert(m_Nodes.begin() + index, nonConstDataNode); if (addNewNode) { - this->addItem(QString::fromStdString(_NonConstDataNodeName)); + 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(_NonConstDataNodeName)); + 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 - // explicietely calling RemoveNode of QmitkDataStorageComboBox since derived classes may prevent the removal of all + // 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 + ++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; }