diff --git a/Modules/QtWidgets/include/QmitkAbstractDataStorageModel.h b/Modules/QtWidgets/include/QmitkAbstractDataStorageModel.h index 5d4f0f9123..d267484d6b 100644 --- a/Modules/QtWidgets/include/QmitkAbstractDataStorageModel.h +++ b/Modules/QtWidgets/include/QmitkAbstractDataStorageModel.h @@ -1,88 +1,88 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef QMITKABSTRACTDATASTORAGEMODEL_H #define QMITKABSTRACTDATASTORAGEMODEL_H #include // mitk core #include #include #include // qt #include /* * @brief This abstract class extends the 'QAbstractItemModel' to accept an 'mitk::DataStorage' and a 'mitk::NodePredicateBase'. * It registers itself as a node event listener of the data storage. * The 'QmitkAbstractDataStorageModel' provides three empty functions, 'NodeAdded', 'NodeChanged' and 'NodeRemoved', that * may be implemented by subclasses. These functions allow to react to the 'AddNodeEvent', 'ChangedNodeEvent' and * 'RemoveNodeEvent' of the data storage. This might be useful to force an update on a custom view to correctly * represent the content of the data storage. * * A concrete implementation of this class is used to store the temporarily shown data nodes of the data storage. * These nodes may be a subset of all the nodes inside the data storage, if a specific node predicate is set. * * A model that implements this class has to return mitk::DataNode::Pointer objects for model indexes when the * role is QmitkDataNodeRole. */ class MITKQTWIDGETS_EXPORT QmitkAbstractDataStorageModel : public QAbstractItemModel { Q_OBJECT public: ~QmitkAbstractDataStorageModel() override; /* * @brief Sets the data storage and adds listener for node events. * * @param dataStorage A pointer to the data storage to set. */ void SetDataStorage(mitk::DataStorage* dataStorage); - mitk::DataStorage* GetDataStorage() const; + mitk::DataStorage::Pointer GetDataStorage() const; /* * @brief Sets the node predicate and updates the model data, according to the node predicate. * * @param nodePredicate A pointer to node predicate. */ void SetNodePredicate(const mitk::NodePredicateBase* nodePredicate); const mitk::NodePredicateBase* GetNodePredicate() const { return m_NodePredicate; } protected: virtual void DataStorageChanged() = 0; virtual void NodePredicateChanged() = 0; virtual void NodeAdded(const mitk::DataNode* node) = 0; virtual void NodeChanged(const mitk::DataNode* node) = 0; virtual void NodeRemoved(const mitk::DataNode* node) = 0; QmitkAbstractDataStorageModel(QObject* parent = nullptr); QmitkAbstractDataStorageModel(mitk::DataStorage* dataStorage, QObject* parent = nullptr); mitk::WeakPointer m_DataStorage; mitk::NodePredicateBase::ConstPointer m_NodePredicate; private: /** Helper triggered on the storage delete event */ void SetDataStorageDeleted(); unsigned long m_DataStorageDeletedTag; }; #endif // QMITKABSTRACTDATASTORAGEMODEL_H diff --git a/Modules/QtWidgets/src/QmitkAbstractDataStorageModel.cpp b/Modules/QtWidgets/src/QmitkAbstractDataStorageModel.cpp index 011a9f8763..719a96cf37 100644 --- a/Modules/QtWidgets/src/QmitkAbstractDataStorageModel.cpp +++ b/Modules/QtWidgets/src/QmitkAbstractDataStorageModel.cpp @@ -1,115 +1,115 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include QmitkAbstractDataStorageModel::QmitkAbstractDataStorageModel(QObject* parent/* = nullptr*/) : QAbstractItemModel(parent) , m_DataStorage(nullptr) , m_NodePredicate(nullptr) { // nothing here } QmitkAbstractDataStorageModel::QmitkAbstractDataStorageModel(mitk::DataStorage* dataStorage, QObject* parent/* = nullptr*/) : QAbstractItemModel(parent) , m_DataStorage(nullptr) , m_NodePredicate(nullptr) { SetDataStorage(dataStorage); } QmitkAbstractDataStorageModel::~QmitkAbstractDataStorageModel() { auto dataStorage = m_DataStorage.Lock(); if (dataStorage.IsNotNull()) { // remove Listener for the data storage itself dataStorage->RemoveObserver(m_DataStorageDeletedTag); // remove listener from data storage dataStorage->AddNodeEvent.RemoveListener( mitk::MessageDelegate1(this, &QmitkAbstractDataStorageModel::NodeAdded)); dataStorage->RemoveNodeEvent.RemoveListener( mitk::MessageDelegate1(this, &QmitkAbstractDataStorageModel::NodeRemoved)); dataStorage->ChangedNodeEvent.RemoveListener( mitk::MessageDelegate1(this, &QmitkAbstractDataStorageModel::NodeChanged)); } } void QmitkAbstractDataStorageModel::SetDataStorage(mitk::DataStorage* dataStorage) { if (m_DataStorage == dataStorage) { return; } auto lockedDataStorage = m_DataStorage.Lock(); if (lockedDataStorage.IsNotNull()) { // remove Listener for the data storage itself lockedDataStorage->RemoveObserver(m_DataStorageDeletedTag); // remove listener from old data storage lockedDataStorage->AddNodeEvent.RemoveListener( mitk::MessageDelegate1(this, &QmitkAbstractDataStorageModel::NodeAdded)); lockedDataStorage->RemoveNodeEvent.RemoveListener( mitk::MessageDelegate1(this, &QmitkAbstractDataStorageModel::NodeRemoved)); lockedDataStorage->ChangedNodeEvent.RemoveListener( mitk::MessageDelegate1(this, &QmitkAbstractDataStorageModel::NodeChanged)); } m_DataStorage = dataStorage; lockedDataStorage = m_DataStorage.Lock(); if (lockedDataStorage.IsNotNull()) { // add Listener for the data storage itself auto command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &QmitkAbstractDataStorageModel::SetDataStorageDeleted); m_DataStorageDeletedTag = lockedDataStorage->AddObserver(itk::DeleteEvent(), command); // add listener for new data storage lockedDataStorage->AddNodeEvent.AddListener( mitk::MessageDelegate1(this, &QmitkAbstractDataStorageModel::NodeAdded)); lockedDataStorage->RemoveNodeEvent.AddListener( mitk::MessageDelegate1(this, &QmitkAbstractDataStorageModel::NodeRemoved)); lockedDataStorage->ChangedNodeEvent.AddListener( mitk::MessageDelegate1(this, &QmitkAbstractDataStorageModel::NodeChanged)); } // update model if the data storage has been changed DataStorageChanged(); } -mitk::DataStorage* QmitkAbstractDataStorageModel::GetDataStorage() const +mitk::DataStorage::Pointer QmitkAbstractDataStorageModel::GetDataStorage() const { return m_DataStorage.Lock(); } void QmitkAbstractDataStorageModel::SetDataStorageDeleted() { this->SetDataStorage(nullptr); } void QmitkAbstractDataStorageModel::SetNodePredicate(const mitk::NodePredicateBase* nodePredicate) { if (m_NodePredicate == nodePredicate) { return; } m_NodePredicate = nodePredicate; // update model if the node predicate has been changed NodePredicateChanged(); } diff --git a/Modules/RenderWindowManagerUI/include/QmitkRenderWindowDataStorageListModel.h b/Modules/RenderWindowManagerUI/include/QmitkRenderWindowDataStorageListModel.h index 50b705f279..3e392fdf9b 100644 --- a/Modules/RenderWindowManagerUI/include/QmitkRenderWindowDataStorageListModel.h +++ b/Modules/RenderWindowManagerUI/include/QmitkRenderWindowDataStorageListModel.h @@ -1,104 +1,104 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef QMITKDATASTORAGERENDERWINDOWLISTMODEL_H #define QMITKDATASTORAGERENDERWINDOWLISTMODEL_H // render window manager UI model #include "MitkRenderWindowManagerUIExports.h" // render window manager module #include "mitkRenderWindowLayerController.h" #include "mitkRenderWindowLayerUtilities.h" //mitk core #include // qt widgets module #include /* * @brief The 'QmitkDataStorageRenderWindowListModel' is a list model derived from the 'QmitkAbstractDataStorageModel'. */ class MITKRENDERWINDOWMANAGERUI_EXPORT QmitkRenderWindowDataStorageListModel : public QmitkAbstractDataStorageModel { Q_OBJECT public: QmitkRenderWindowDataStorageListModel(QObject* parent = nullptr); // override from 'QmitkAbstractDataStorageModel' /** * @brief See 'QmitkAbstractDataStorageModel' */ void DataStorageChanged() override; /** * @brief See 'QmitkAbstractDataStorageModel' */ void NodePredicateChanged() override; /** * @brief See 'QmitkAbstractDataStorageModel' */ void NodeAdded(const mitk::DataNode* node) override; /** * @brief See 'QmitkAbstractDataStorageModel' */ void NodeChanged(const mitk::DataNode* node) override; /** * @brief See 'QmitkAbstractDataStorageModel' */ void NodeRemoved(const mitk::DataNode* node) override; // override from 'QAbstractItemModel' QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override; QModelIndex parent(const QModelIndex& child) const override; int rowCount(const QModelIndex& parent = QModelIndex()) const override; int columnCount(const QModelIndex& parent = QModelIndex()) const override; QVariant data(const QModelIndex& index, int role) const override; bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override; Qt::ItemFlags flags(const QModelIndex& index) const override; Qt::DropActions supportedDropActions() const override; Qt::DropActions supportedDragActions() const override; QStringList mimeTypes() const override; QMimeData* mimeData(const QModelIndexList& indexes) const override; bool dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) override; void SetControlledRenderer(mitk::RenderWindowLayerUtilities::RendererVector controlledRenderer); void SetCurrentRenderer(mitk::BaseRenderer* baseRenderer); - mitk::BaseRenderer* GetCurrentRenderer() const; + mitk::BaseRenderer::Pointer GetCurrentRenderer() const; /** * @brief Use the RenderWindowLayerController to insert the given data node into all controlled render windows. * The new node is placed on top of all existing layer nodes in the render window. * * @param dataNode The data node that should be inserted. */ void AddDataNodeToAllRenderer(mitk::DataNode* dataNode); private: void UpdateModelData(); std::unique_ptr m_RenderWindowLayerController; mitk::WeakPointer m_BaseRenderer; mitk::RenderWindowLayerUtilities::LayerStack m_LayerStack; }; #endif // QMITKDATASTORAGERENDERWINDOWLISTMODEL_H diff --git a/Modules/RenderWindowManagerUI/include/QmitkRenderWindowDataStorageTreeModel.h b/Modules/RenderWindowManagerUI/include/QmitkRenderWindowDataStorageTreeModel.h index d1ce14312b..776e38304a 100644 --- a/Modules/RenderWindowManagerUI/include/QmitkRenderWindowDataStorageTreeModel.h +++ b/Modules/RenderWindowManagerUI/include/QmitkRenderWindowDataStorageTreeModel.h @@ -1,132 +1,132 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef QMITKDATASTORAGERENDERWINDOWTREEMODEL_H #define QMITKDATASTORAGERENDERWINDOWTREEMODEL_H // render window manager UI model #include "MitkRenderWindowManagerUIExports.h" // render window manager module #include "mitkRenderWindowLayerController.h" #include "mitkRenderWindowLayerUtilities.h" //mitk core #include // qt widgets module #include #include /* * @brief The 'QmitkRenderWindowDataStorageTreeModel' is a tree model derived from the 'QmitkAbstractDataStorageModel'. */ class MITKRENDERWINDOWMANAGERUI_EXPORT QmitkRenderWindowDataStorageTreeModel : public QmitkAbstractDataStorageModel { Q_OBJECT public: QmitkRenderWindowDataStorageTreeModel(QObject* parent = nullptr); // override from 'QmitkAbstractDataStorageModel' /** * @brief See 'QmitkAbstractDataStorageModel' */ void DataStorageChanged() override; /** * @brief See 'QmitkAbstractDataStorageModel' */ void NodePredicateChanged() override; /** * @brief See 'QmitkAbstractDataStorageModel' */ void NodeAdded(const mitk::DataNode* node) override; /** * @brief See 'QmitkAbstractDataStorageModel' */ void NodeChanged(const mitk::DataNode* node) override; /** * @brief See 'QmitkAbstractDataStorageModel' */ void NodeRemoved(const mitk::DataNode* node) override; // override from 'QAbstractItemModel' QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override; QModelIndex parent(const QModelIndex& parent) const override; int rowCount(const QModelIndex& parent = QModelIndex()) const override; int columnCount(const QModelIndex& parent = QModelIndex()) const override; QVariant data(const QModelIndex& index, int role) const override; bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override; Qt::ItemFlags flags(const QModelIndex& index) const override; Qt::DropActions supportedDropActions() const override; Qt::DropActions supportedDragActions() const override; QStringList mimeTypes() const override; QMimeData* mimeData(const QModelIndexList& indexes) const override; bool dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) override; void SetControlledRenderer(mitk::RenderWindowLayerUtilities::RendererVector controlledRenderer); void SetCurrentRenderer(mitk::BaseRenderer* baseRenderer); - mitk::BaseRenderer* GetCurrentRenderer() const; + mitk::BaseRenderer::Pointer GetCurrentRenderer() const; private: void ResetTree(); void UpdateModelData(); /** * @brief Adjust the layer property according to the current tree. * The function will set the "layer" property of each underlying data node so that it fits the * the actual hierarchy represented by the current tree. */ void AdjustLayerProperty(); /** * @brief Fill a vector of tree items in a depth-first order (child-first). */ void TreeToVector(QmitkDataStorageTreeModelInternalItem* parent, std::vector& treeAsVector) const; /** * @brief Add the given data node to the tree of the given renderer. * The given renderer specifies the "layer"-property that is used for adding the new tree item * to the tree. The "layer"-property may be different for each renderer resulting in a * different tree for each renderer. * * @param dataNode The data node that should be added. * @param renderer The base renderer to which the data node should be added. */ void AddNodeInternal(const mitk::DataNode* dataNode, const mitk::BaseRenderer* renderer); /** * @brief Remove the tree item that contains the given data node. Removing an item may * leave the child items of the removed item without a parent. In this case * the children have to be moved inside the tree so the tree has to be rebuild * according to the current status of the data storage. * * @param dataNode The data node that should be removed. */ void RemoveNodeInternal(const mitk::DataNode* dataNode); mitk::DataNode* GetParentNode(const mitk::DataNode* node) const; QmitkDataStorageTreeModelInternalItem* GetItemByIndex(const QModelIndex& index) const; QModelIndex GetIndexByItem(QmitkDataStorageTreeModelInternalItem* item) const; std::unique_ptr m_RenderWindowLayerController; mitk::RenderWindowLayerUtilities::RendererVector m_ControlledRenderer; QmitkDataStorageTreeModelInternalItem* m_Root; mitk::WeakPointer m_BaseRenderer; }; #endif // QMITKDATASTORAGERENDERWINDOWTREEMODEL_H diff --git a/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageListModel.cpp b/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageListModel.cpp index 1c1b65ec63..9b6face241 100644 --- a/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageListModel.cpp +++ b/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageListModel.cpp @@ -1,351 +1,351 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // render window manager UI module #include "QmitkRenderWindowDataStorageListModel.h" // qt widgets module #include "QmitkCustomVariants.h" #include "QmitkEnums.h" #include "QmitkMimeTypes.h" #include "QmitkNodeDescriptorManager.h" QmitkRenderWindowDataStorageListModel::QmitkRenderWindowDataStorageListModel(QObject* parent /*= nullptr*/) : QmitkAbstractDataStorageModel(parent) { m_RenderWindowLayerController = std::make_unique(); } void QmitkRenderWindowDataStorageListModel::DataStorageChanged() { m_RenderWindowLayerController->SetDataStorage(m_DataStorage.Lock()); UpdateModelData(); } void QmitkRenderWindowDataStorageListModel::NodePredicateChanged() { UpdateModelData(); } void QmitkRenderWindowDataStorageListModel::NodeAdded(const mitk::DataNode* node) { // add a node to each render window specific list (or to a global list initially) AddDataNodeToAllRenderer(const_cast(node)); UpdateModelData(); } void QmitkRenderWindowDataStorageListModel::NodeChanged(const mitk::DataNode* /*node*/) { // nothing here, since the "'NodeChanged'-event is currently sent far too often } void QmitkRenderWindowDataStorageListModel::NodeRemoved(const mitk::DataNode* /*node*/) { // update model data to create a new list without the removed data node UpdateModelData(); } QModelIndex QmitkRenderWindowDataStorageListModel::index(int row, int column, const QModelIndex& parent) const { bool hasIndex = this->hasIndex(row, column, parent); if (hasIndex) { return this->createIndex(row, column); } return QModelIndex(); } QModelIndex QmitkRenderWindowDataStorageListModel::parent(const QModelIndex& /*child*/) const { return QModelIndex(); } int QmitkRenderWindowDataStorageListModel::rowCount(const QModelIndex& parent /*= QModelIndex()*/) const { if (parent.isValid()) { return 0; } return static_cast(m_LayerStack.size()); } int QmitkRenderWindowDataStorageListModel::columnCount(const QModelIndex& parent /*= QModelIndex()*/) const { if (parent.isValid()) { return 0; } return 1; } QVariant QmitkRenderWindowDataStorageListModel::data(const QModelIndex& index, int role) const { auto baseRenderer = m_BaseRenderer.Lock(); if (baseRenderer.IsNull()) { return QVariant(); } if (!index.isValid() || this != index.model()) { return QVariant(); } if (index.row() < 0 || index.row() >= static_cast(m_LayerStack.size())) { return QVariant(); } mitk::RenderWindowLayerUtilities::LayerStack::const_iterator layerStackIt = m_LayerStack.begin(); std::advance(layerStackIt, index.row()); mitk::DataNode* dataNode = layerStackIt->second; if (Qt::CheckStateRole == role) { bool visibility = false; dataNode->GetVisibility(visibility, baseRenderer); if (visibility) { return Qt::Checked; } else { return Qt::Unchecked; } } else if (Qt::DisplayRole == role) { return QVariant(QString::fromStdString(dataNode->GetName())); } else if (Qt::ToolTipRole == role) { return QVariant("Name of the data node."); } else if (Qt::DecorationRole == role) { QmitkNodeDescriptor* nodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor(dataNode); return nodeDescriptor->GetIcon(dataNode); } else if (Qt::UserRole == role || QmitkDataNodeRawPointerRole == role) { // user role always returns a reference to the data node, // which can be used to modify the data node in the data storage return QVariant::fromValue(dataNode); } else if (QmitkDataNodeRole == role) { return QVariant::fromValue(mitk::DataNode::Pointer(dataNode)); } return QVariant(); } bool QmitkRenderWindowDataStorageListModel::setData(const QModelIndex& index, const QVariant& value, int role /*= Qt::EditRole*/) { auto baseRenderer = m_BaseRenderer.Lock(); if (baseRenderer.IsNull()) { return false; } if (!index.isValid() || this != index.model()) { return false; } if (index.row() < 0 || index.row() >= static_cast(m_LayerStack.size())) { return false; } mitk::RenderWindowLayerUtilities::LayerStack::const_iterator layerStackIt = m_LayerStack.begin(); std::advance(layerStackIt, index.row()); mitk::DataNode* dataNode = layerStackIt->second; if (Qt::CheckStateRole == role) { Qt::CheckState newCheckState = static_cast(value.toInt()); bool isVisible = newCheckState; dataNode->SetVisibility(isVisible, baseRenderer); emit dataChanged(index, index); mitk::RenderingManager::GetInstance()->RequestUpdate(baseRenderer->GetRenderWindow()); return true; } return false; } Qt::ItemFlags QmitkRenderWindowDataStorageListModel::flags(const QModelIndex &index) const { if (this != index.model()) { return Qt::NoItemFlags; } if (!index.isValid()) { return Qt::ItemIsDropEnabled; } return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; } Qt::DropActions QmitkRenderWindowDataStorageListModel::supportedDropActions() const { return Qt::CopyAction | Qt::MoveAction; } Qt::DropActions QmitkRenderWindowDataStorageListModel::supportedDragActions() const { return Qt::CopyAction | Qt::MoveAction; } QStringList QmitkRenderWindowDataStorageListModel::mimeTypes() const { QStringList types = QAbstractItemModel::mimeTypes(); types << QmitkMimeTypes::DataNodePtrs; return types; } QMimeData* QmitkRenderWindowDataStorageListModel::mimeData(const QModelIndexList& indexes) const { QMimeData* mimeData = new QMimeData(); QByteArray encodedData; QDataStream stream(&encodedData, QIODevice::WriteOnly); for (const auto& index : indexes) { if (index.isValid()) { auto dataNode = data(index, QmitkDataNodeRawPointerRole).value(); stream << reinterpret_cast(dataNode); } } mimeData->setData(QmitkMimeTypes::DataNodePtrs, encodedData); return mimeData; } bool QmitkRenderWindowDataStorageListModel::dropMimeData(const QMimeData* data, Qt::DropAction action, int /*row*/, int column, const QModelIndex& parent) { auto baseRenderer = m_BaseRenderer.Lock(); if (baseRenderer.IsNull()) { return false; } if (action == Qt::IgnoreAction) { return true; } if (!data->hasFormat(QmitkMimeTypes::DataNodePtrs)) { return false; } if (column > 0) { return false; } if (parent.isValid()) { int layer = -1; auto dataNode = this->data(parent, QmitkDataNodeRawPointerRole).value(); if (nullptr != dataNode) { dataNode->GetIntProperty("layer", layer, baseRenderer); } auto dataNodeList = QmitkMimeTypes::ToDataNodePtrList(data); for (const auto& dataNode : qAsConst(dataNodeList)) { m_RenderWindowLayerController->MoveNodeToPosition(dataNode, layer, baseRenderer); } UpdateModelData(); return true; } return false; } void QmitkRenderWindowDataStorageListModel::SetControlledRenderer(mitk::RenderWindowLayerUtilities::RendererVector controlledRenderer) { m_RenderWindowLayerController->SetControlledRenderer(controlledRenderer); auto dataStorage = m_DataStorage.Lock(); if (dataStorage.IsNotNull()) { mitk::DataStorage::SetOfObjects::ConstPointer allDataNodes = dataStorage->GetAll(); for (mitk::DataStorage::SetOfObjects::ConstIterator it = allDataNodes->Begin(); it != allDataNodes->End(); ++it) { mitk::DataNode::Pointer dataNode = it->Value(); if (dataNode.IsNull()) { continue; } AddDataNodeToAllRenderer(dataNode); } } } void QmitkRenderWindowDataStorageListModel::SetCurrentRenderer(mitk::BaseRenderer* baseRenderer) { if (m_BaseRenderer == baseRenderer) { return; } m_BaseRenderer = baseRenderer; if (!m_BaseRenderer.IsExpired()) { UpdateModelData(); } } -mitk::BaseRenderer* QmitkRenderWindowDataStorageListModel::GetCurrentRenderer() const +mitk::BaseRenderer::Pointer QmitkRenderWindowDataStorageListModel::GetCurrentRenderer() const { return m_BaseRenderer.Lock(); } void QmitkRenderWindowDataStorageListModel::AddDataNodeToAllRenderer(mitk::DataNode* dataNode) { m_RenderWindowLayerController->InsertLayerNode(dataNode); } void QmitkRenderWindowDataStorageListModel::UpdateModelData() { auto dataStorage = m_DataStorage.Lock(); if (dataStorage.IsNotNull()) { auto baseRenderer = m_BaseRenderer.Lock(); if (baseRenderer.IsNotNull()) { // update the model, so that it will be filled with the nodes of the new data storage beginResetModel(); // get the current layer stack of the given base renderer m_LayerStack = mitk::RenderWindowLayerUtilities::GetLayerStack(dataStorage, baseRenderer, true); endResetModel(); } } } diff --git a/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageTreeModel.cpp b/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageTreeModel.cpp index aa66c160e2..70a3d1c434 100644 --- a/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageTreeModel.cpp +++ b/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageTreeModel.cpp @@ -1,600 +1,600 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // render window manager UI module #include "QmitkRenderWindowDataStorageTreeModel.h" // mitk core #include // qt widgets module #include "QmitkCustomVariants.h" #include "QmitkEnums.h" #include "QmitkMimeTypes.h" #include "QmitkNodeDescriptorManager.h" QmitkRenderWindowDataStorageTreeModel::QmitkRenderWindowDataStorageTreeModel(QObject* parent /*= nullptr*/) : QmitkAbstractDataStorageModel(parent) , m_Root(nullptr) { m_RenderWindowLayerController = std::make_unique(); ResetTree(); } void QmitkRenderWindowDataStorageTreeModel::DataStorageChanged() { m_RenderWindowLayerController->SetDataStorage(m_DataStorage.Lock()); ResetTree(); UpdateModelData(); } void QmitkRenderWindowDataStorageTreeModel::NodePredicateChanged() { ResetTree(); UpdateModelData(); } void QmitkRenderWindowDataStorageTreeModel::NodeAdded(const mitk::DataNode* node) { for (const auto renderer : m_ControlledRenderer) { // add the node to each render window mitk::RenderWindowLayerUtilities::SetRenderWindowProperties(const_cast(node), renderer); } auto baseRenderer = m_BaseRenderer.Lock(); if (baseRenderer.IsNotNull()) { AddNodeInternal(node, baseRenderer); } } void QmitkRenderWindowDataStorageTreeModel::NodeChanged(const mitk::DataNode* node) { auto item = m_Root->Find(node); if (nullptr != item) { auto parentItem = item->GetParent(); // as the root node should not be removed one should always have a parent item if (nullptr == parentItem) { return; } auto index = createIndex(item->GetIndex(), 0, item); emit dataChanged(index, index); } } void QmitkRenderWindowDataStorageTreeModel::NodeRemoved(const mitk::DataNode* node) { RemoveNodeInternal(node); } QModelIndex QmitkRenderWindowDataStorageTreeModel::index(int row, int column, const QModelIndex& parent) const { auto item = GetItemByIndex(parent); if (nullptr != item) { item = item->GetChild(row); } if (nullptr == item) { return QModelIndex(); } return createIndex(row, column, item); } QModelIndex QmitkRenderWindowDataStorageTreeModel::parent(const QModelIndex& parent) const { auto item = GetItemByIndex(parent); if (nullptr != item) { item = item->GetParent(); } if(nullptr == item) { return QModelIndex(); } if (item == m_Root) { return QModelIndex(); } return createIndex(item->GetIndex(), 0, item); } int QmitkRenderWindowDataStorageTreeModel::rowCount(const QModelIndex& parent /*= QModelIndex()*/) const { auto item = GetItemByIndex(parent); if (nullptr == item) { return 0; } return item->GetChildCount(); } int QmitkRenderWindowDataStorageTreeModel::columnCount(const QModelIndex&/* parent = QModelIndex()*/) const { if (0 == m_Root->GetChildCount()) { // no items stored, no need to display columns return 0; } return 1; } QVariant QmitkRenderWindowDataStorageTreeModel::data(const QModelIndex& index, int role) const { auto baseRenderer = m_BaseRenderer.Lock(); if (baseRenderer.IsNull()) { return QVariant(); } if (!index.isValid() || this != index.model()) { return QVariant(); } auto item = GetItemByIndex(index); if (nullptr == item) { return QVariant(); } auto dataNode = item->GetDataNode(); if (nullptr == dataNode) { return QVariant(); } if (Qt::CheckStateRole == role) { bool visibility = false; dataNode->GetVisibility(visibility, baseRenderer); if (visibility) { return Qt::Checked; } else { return Qt::Unchecked; } } else if (Qt::DisplayRole == role) { return QVariant(QString::fromStdString(dataNode->GetName())); } else if (Qt::ToolTipRole == role) { return QVariant("Name of the data node."); } else if (Qt::DecorationRole == role) { QmitkNodeDescriptor* nodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor(dataNode); return nodeDescriptor->GetIcon(dataNode); } else if (Qt::UserRole == role || QmitkDataNodeRawPointerRole == role) { // user role always returns a reference to the data node, // which can be used to modify the data node in the data storage return QVariant::fromValue(dataNode); } else if (QmitkDataNodeRole == role) { return QVariant::fromValue(mitk::DataNode::Pointer(dataNode)); } return QVariant(); } bool QmitkRenderWindowDataStorageTreeModel::setData(const QModelIndex& index, const QVariant& value, int role /*= Qt::EditRole*/) { auto baseRenderer = m_BaseRenderer.Lock(); if (baseRenderer.IsNull()) { return false; } if (!index.isValid() || this != index.model()) { return false; } auto item = GetItemByIndex(index); if (nullptr == item) { return false; } auto dataNode = item->GetDataNode(); if (nullptr == dataNode) { return false; } if (Qt::EditRole == role && !value.toString().isEmpty()) { dataNode->SetName(value.toString().toStdString().c_str()); emit dataChanged(index, index); return true; } if (Qt::CheckStateRole == role) { Qt::CheckState newCheckState = static_cast(value.toInt()); bool isVisible = newCheckState; dataNode->SetVisibility(isVisible, baseRenderer); emit dataChanged(index, index); mitk::RenderingManager::GetInstance()->RequestUpdate(baseRenderer->GetRenderWindow()); return true; } return false; } Qt::ItemFlags QmitkRenderWindowDataStorageTreeModel::flags(const QModelIndex& index) const { if (this != index.model()) { return Qt::NoItemFlags; } if (!index.isValid()) { return Qt::ItemIsDropEnabled; } auto item = GetItemByIndex(index); if (nullptr == item) { return Qt::NoItemFlags; } const auto dataNode = item->GetDataNode(); if (m_NodePredicate.IsNull() || m_NodePredicate->CheckNode(dataNode)) { return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; } return Qt::NoItemFlags; } Qt::DropActions QmitkRenderWindowDataStorageTreeModel::supportedDropActions() const { return Qt::CopyAction | Qt::MoveAction; } Qt::DropActions QmitkRenderWindowDataStorageTreeModel::supportedDragActions() const { return Qt::CopyAction | Qt::MoveAction; } QStringList QmitkRenderWindowDataStorageTreeModel::mimeTypes() const { QStringList types = QAbstractItemModel::mimeTypes(); types << QmitkMimeTypes::DataNodePtrs; return types; } QMimeData* QmitkRenderWindowDataStorageTreeModel::mimeData(const QModelIndexList& indexes) const { QMimeData* mimeData = new QMimeData(); QByteArray encodedData; QDataStream stream(&encodedData, QIODevice::WriteOnly); for (const auto& index : indexes) { if (index.isValid()) { auto dataNode = data(index, QmitkDataNodeRawPointerRole).value(); stream << reinterpret_cast(dataNode); } } mimeData->setData(QmitkMimeTypes::DataNodePtrs, encodedData); return mimeData; } bool QmitkRenderWindowDataStorageTreeModel::dropMimeData(const QMimeData* data, Qt::DropAction action, int /*row*/, int /*column*/, const QModelIndex& parent) { auto baseRenderer = m_BaseRenderer.Lock(); if (baseRenderer.IsNull()) { return false; } if (action == Qt::IgnoreAction) { return true; } if (!data->hasFormat(QmitkMimeTypes::DataNodePtrs)) { return false; } if (!parent.isValid()) { return false; } int layer = -1; auto dataNode = this->data(parent, QmitkDataNodeRawPointerRole).value(); if (nullptr != dataNode) { dataNode->GetIntProperty("layer", layer, baseRenderer); } auto dataNodeList = QmitkMimeTypes::ToDataNodePtrList(data); for (const auto& dataNode : qAsConst(dataNodeList)) { m_RenderWindowLayerController->MoveNodeToPosition(dataNode, layer, baseRenderer); } ResetTree(); UpdateModelData(); AdjustLayerProperty(); return true; } void QmitkRenderWindowDataStorageTreeModel::SetControlledRenderer(mitk::RenderWindowLayerUtilities::RendererVector controlledRenderer) { m_RenderWindowLayerController->SetControlledRenderer(controlledRenderer); m_ControlledRenderer = controlledRenderer; ResetTree(); auto dataStorage = m_DataStorage.Lock(); if (dataStorage.IsNull()) { return; } for (const auto& renderer : controlledRenderer) { if (nullptr == renderer) { continue; } auto allDataNodes = dataStorage->GetAll(); for (const auto& dataNode : *allDataNodes) { // add the node to each render window mitk::RenderWindowLayerUtilities::SetRenderWindowProperties(dataNode, renderer); } } } void QmitkRenderWindowDataStorageTreeModel::SetCurrentRenderer(mitk::BaseRenderer* baseRenderer) { if (m_BaseRenderer == baseRenderer) { return; } // base renderer changed // reset tree to build a new renderer-specific item hierarchy m_BaseRenderer = baseRenderer; ResetTree(); UpdateModelData(); } -mitk::BaseRenderer* QmitkRenderWindowDataStorageTreeModel::GetCurrentRenderer() const +mitk::BaseRenderer::Pointer QmitkRenderWindowDataStorageTreeModel::GetCurrentRenderer() const { return m_BaseRenderer.Lock(); } void QmitkRenderWindowDataStorageTreeModel::ResetTree() { beginResetModel(); if (nullptr != m_Root) { m_Root->Delete(); } mitk::DataNode::Pointer rootDataNode = mitk::DataNode::New(); rootDataNode->SetName("Data Storage"); m_Root = new QmitkDataStorageTreeModelInternalItem(rootDataNode); endResetModel(); } void QmitkRenderWindowDataStorageTreeModel::UpdateModelData() { auto dataStorage = m_DataStorage.Lock(); if (dataStorage.IsNotNull()) { auto baseRenderer = m_BaseRenderer.Lock(); if (baseRenderer.IsNotNull()) { mitk::NodePredicateAnd::Pointer combinedNodePredicate = mitk::RenderWindowLayerUtilities::GetRenderWindowPredicate(baseRenderer); auto filteredDataNodes = dataStorage->GetSubset(combinedNodePredicate); for (const auto& dataNode : *filteredDataNodes) { AddNodeInternal(dataNode, baseRenderer); } } } } void QmitkRenderWindowDataStorageTreeModel::AdjustLayerProperty() { auto baseRenderer = m_BaseRenderer.Lock(); if (baseRenderer.IsNull()) { return; } std::vector treeAsVector; TreeToVector(m_Root, treeAsVector); int i = treeAsVector.size() - 1; for (auto it = treeAsVector.begin(); it != treeAsVector.end(); ++it) { auto dataNode = (*it)->GetDataNode(); dataNode->SetIntProperty("layer", i, baseRenderer); --i; } } void QmitkRenderWindowDataStorageTreeModel::TreeToVector(QmitkDataStorageTreeModelInternalItem* parent, std::vector& treeAsVector) const { QmitkDataStorageTreeModelInternalItem* item; for (int i = 0; i < parent->GetChildCount(); ++i) { item = parent->GetChild(i); TreeToVector(item, treeAsVector); treeAsVector.push_back(item); } } void QmitkRenderWindowDataStorageTreeModel::AddNodeInternal(const mitk::DataNode* dataNode, const mitk::BaseRenderer* renderer) { if (nullptr == dataNode || m_DataStorage.IsExpired() || nullptr != m_Root->Find(dataNode)) { return; } // find out if we have a root node auto parentItem = m_Root; QModelIndex index; auto parentDataNode = GetParentNode(dataNode); if (nullptr != parentDataNode) // no top level data node { parentItem = m_Root->Find(parentDataNode); if (nullptr == parentItem) { // parent node not contained in the tree; add it NodeAdded(parentDataNode); parentItem = m_Root->Find(parentDataNode); if (nullptr == parentItem) { // could not find and add the parent tree; abort return; } } // get the index of this parent with the help of the grand parent index = createIndex(parentItem->GetIndex(), 0, parentItem); } int firstRowWithASiblingBelow = 0; int nodeLayer = -1; dataNode->GetIntProperty("layer", nodeLayer, renderer); for (const auto& siblingItem : parentItem->GetChildren()) { int siblingLayer = -1; auto siblingNode = siblingItem->GetDataNode(); if (nullptr != siblingNode) { siblingNode->GetIntProperty("layer", siblingLayer, renderer); } if (nodeLayer > siblingLayer) { break; } ++firstRowWithASiblingBelow; } beginInsertRows(index, firstRowWithASiblingBelow, firstRowWithASiblingBelow); auto newNode = new QmitkDataStorageTreeModelInternalItem(const_cast(dataNode)); parentItem->InsertChild(newNode, firstRowWithASiblingBelow); endInsertRows(); } void QmitkRenderWindowDataStorageTreeModel::RemoveNodeInternal(const mitk::DataNode* dataNode) { if (nullptr == dataNode || nullptr == m_Root) { return; } auto item = m_Root->Find(dataNode); if (nullptr == item) { return; } auto parentItem = item->GetParent(); auto parentIndex = GetIndexByItem(parentItem); auto children = item->GetChildren(); beginRemoveRows(parentIndex, item->GetIndex(), item->GetIndex()); parentItem->RemoveChild(item); delete item; endRemoveRows(); if (!children.empty()) { // rebuild tree because children could not be at the top level ResetTree(); UpdateModelData(); } } mitk::DataNode* QmitkRenderWindowDataStorageTreeModel::GetParentNode(const mitk::DataNode* node) const { mitk::DataNode* dataNode = nullptr; auto dataStorage = m_DataStorage.Lock(); if (dataStorage.IsNull()) { return dataNode; } auto sources = dataStorage->GetSources(node); if (sources->empty()) { return dataNode; } return sources->front(); } QmitkDataStorageTreeModelInternalItem* QmitkRenderWindowDataStorageTreeModel::GetItemByIndex(const QModelIndex& index) const { if (index.isValid()) { return static_cast(index.internalPointer()); } return m_Root; } QModelIndex QmitkRenderWindowDataStorageTreeModel::GetIndexByItem(QmitkDataStorageTreeModelInternalItem* item) const { if (item == m_Root) { return QModelIndex(); } return createIndex(item->GetIndex(), 0, item); } diff --git a/Modules/Segmentation/Controllers/mitkToolManager.cpp b/Modules/Segmentation/Controllers/mitkToolManager.cpp index e7458c294b..bf4b30c3bf 100644 --- a/Modules/Segmentation/Controllers/mitkToolManager.cpp +++ b/Modules/Segmentation/Controllers/mitkToolManager.cpp @@ -1,596 +1,596 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkToolManager.h" #include "mitkToolManagerProvider.h" #include "mitkCoreObjectFactory.h" #include #include #include #include "mitkInteractionEventObserver.h" #include "mitkSegTool2D.h" #include "mitkRenderingManager.h" #include "mitkSliceNavigationController.h" #include "usGetModuleContext.h" #include "usModuleContext.h" mitk::ToolManager::ToolManager(DataStorage *storage) : m_ActiveTool(nullptr), m_ActiveToolID(-1), m_RegisteredClients(0), m_DataStorage(storage) { CoreObjectFactory::GetInstance(); // to make sure a CoreObjectFactory was instantiated (and in turn, possible tools // are registered) - bug 1029 this->InitializeTools(); } void mitk::ToolManager::EnsureTimeObservation() { if (nullptr != mitk::RenderingManager::GetInstance() && nullptr != mitk::RenderingManager::GetInstance()->GetTimeNavigationController()) { auto timeController = mitk::RenderingManager::GetInstance()->GetTimeNavigationController(); m_LastTimePoint = mitk::RenderingManager::GetInstance()->GetTimeNavigationController()->GetSelectedTimePoint(); auto currentTimeController = m_CurrentTimeNavigationController.Lock(); if (timeController != currentTimeController) { if (currentTimeController.IsNotNull()) { currentTimeController->RemoveObserver(m_TimePointObserverTag); } itk::MemberCommand::Pointer command = itk::MemberCommand::New(); command->SetCallbackFunction(this, &ToolManager::OnTimeChanged); command->SetCallbackFunction(this, &ToolManager::OnTimeChangedConst); m_CurrentTimeNavigationController = timeController; m_TimePointObserverTag = timeController->AddObserver(SliceNavigationController::GeometryTimeEvent(nullptr,0), command); } } } void mitk::ToolManager::StopTimeObservation() { auto currentTimeController = m_CurrentTimeNavigationController.Lock(); if (currentTimeController.IsNotNull()) { currentTimeController->RemoveObserver(m_TimePointObserverTag); m_CurrentTimeNavigationController = nullptr; m_TimePointObserverTag = 0; } } mitk::ToolManager::~ToolManager() { for (auto dataIter = m_WorkingData.begin(); dataIter != m_WorkingData.end(); ++dataIter) (*dataIter)->RemoveObserver(m_WorkingDataObserverTags[(*dataIter)]); if (this->GetDataStorage() != nullptr) this->GetDataStorage()->RemoveNodeEvent.RemoveListener( mitk::MessageDelegate1(this, &ToolManager::OnNodeRemoved)); if (m_ActiveTool) { m_ActiveTool->Deactivated(); m_ActiveToolRegistration.Unregister(); m_ActiveTool = nullptr; m_ActiveToolID = -1; // no tool active ActiveToolChanged.Send(); } for (auto observerTagMapIter = m_ReferenceDataObserverTags.begin(); observerTagMapIter != m_ReferenceDataObserverTags.end(); ++observerTagMapIter) { observerTagMapIter->first->RemoveObserver(observerTagMapIter->second); } this->StopTimeObservation(); } void mitk::ToolManager::InitializeTools() { // clear all previous tool pointers (tools may be still activated from another recently used plugin) if (m_ActiveTool) { m_ActiveTool->Deactivated(); m_ActiveToolRegistration.Unregister(); m_ActiveTool = nullptr; m_ActiveToolID = -1; // no tool active ActiveToolChanged.Send(); } m_Tools.clear(); // get a list of all known mitk::Tools std::list thingsThatClaimToBeATool = itk::ObjectFactoryBase::CreateAllInstance("mitkTool"); // remember these tools for (auto iter = thingsThatClaimToBeATool.begin(); iter != thingsThatClaimToBeATool.end(); ++iter) { if (auto *tool = dynamic_cast(iter->GetPointer())) { tool->InitializeStateMachine(); tool->SetToolManager(this); // important to call right after instantiation tool->ErrorMessage += MessageDelegate1(this, &ToolManager::OnToolErrorMessage); tool->GeneralMessage += MessageDelegate1(this, &ToolManager::OnGeneralToolMessage); m_Tools.push_back(tool); } } } void mitk::ToolManager::OnToolErrorMessage(std::string s) { this->ToolErrorMessage(s); } void mitk::ToolManager::OnGeneralToolMessage(std::string s) { this->GeneralToolMessage(s); } const mitk::ToolManager::ToolVectorTypeConst mitk::ToolManager::GetTools() { ToolVectorTypeConst resultList; for (auto iter = m_Tools.begin(); iter != m_Tools.end(); ++iter) { resultList.push_back(iter->GetPointer()); } return resultList; } mitk::Tool *mitk::ToolManager::GetToolById(int id) { try { return m_Tools.at(id); } catch (const std::exception &) { return nullptr; } } bool mitk::ToolManager::ActivateTool(int id) { const auto workingDataNode = this->GetWorkingData(0); const mitk::BaseData* workingData = nullptr; if (nullptr != workingDataNode) { workingData = workingDataNode->GetData(); } const auto referenceDataNode = this->GetReferenceData(0); const mitk::BaseData* referenceData = nullptr; if (nullptr != referenceDataNode) { referenceData = referenceDataNode->GetData(); } if (id != -1 && !this->GetToolById(id)->CanHandle(referenceData, workingData)) return false; if (this->GetDataStorage()) { this->GetDataStorage()->RemoveNodeEvent.AddListener( mitk::MessageDelegate1(this, &ToolManager::OnNodeRemoved)); } if (GetToolById(id) == m_ActiveTool) return true; // no change needed static int nextTool = -1; nextTool = id; static bool inActivateTool = false; if (inActivateTool) { return true; } inActivateTool = true; while (nextTool != m_ActiveToolID) { // Deactivate all other active tools to ensure a globally single active tool for (const auto& toolManager : ToolManagerProvider::GetInstance()->GetToolManagers()) { if (nullptr != toolManager.second->m_ActiveTool) { toolManager.second->m_ActiveTool->Deactivated(); toolManager.second->m_ActiveToolRegistration.Unregister(); // The active tool of *this* ToolManager is handled below this loop if (this != toolManager.second) { toolManager.second->m_ActiveTool = nullptr; toolManager.second->m_ActiveToolID = -1; toolManager.second->ActiveToolChanged.Send(); } } } m_ActiveTool = GetToolById(nextTool); m_ActiveToolID = m_ActiveTool ? nextTool : -1; // current ID if tool is valid, otherwise -1 ActiveToolChanged.Send(); if (m_ActiveTool) { this->EnsureTimeObservation(); if (m_RegisteredClients > 0) { m_ActiveTool->Activated(); m_ActiveToolRegistration = us::GetModuleContext()->RegisterService(m_ActiveTool, us::ServiceProperties()); } } } inActivateTool = false; return (m_ActiveTool != nullptr); } void mitk::ToolManager::SetReferenceData(DataVectorType data) { if (data != m_ReferenceData) { // remove observers from old nodes for (auto dataIter = m_ReferenceData.begin(); dataIter != m_ReferenceData.end(); ++dataIter) { auto searchIter = m_ReferenceDataObserverTags.find(*dataIter); if (searchIter != m_ReferenceDataObserverTags.end()) { (*dataIter)->RemoveObserver(searchIter->second); } } m_ReferenceData = data; // TODO tell active tool? // attach new observers m_ReferenceDataObserverTags.clear(); for (auto dataIter = m_ReferenceData.begin(); dataIter != m_ReferenceData.end(); ++dataIter) { itk::MemberCommand::Pointer command = itk::MemberCommand::New(); command->SetCallbackFunction(this, &ToolManager::OnOneOfTheReferenceDataDeleted); command->SetCallbackFunction(this, &ToolManager::OnOneOfTheReferenceDataDeletedConst); m_ReferenceDataObserverTags.insert( std::pair((*dataIter), (*dataIter)->AddObserver(itk::DeleteEvent(), command))); } ReferenceDataChanged.Send(); } } void mitk::ToolManager::OnOneOfTheReferenceDataDeletedConst(const itk::Object *caller, const itk::EventObject &e) { OnOneOfTheReferenceDataDeleted(const_cast(caller), e); } void mitk::ToolManager::OnOneOfTheReferenceDataDeleted(itk::Object *caller, const itk::EventObject &itkNotUsed(e)) { DataVectorType v; for (auto dataIter = m_ReferenceData.begin(); dataIter != m_ReferenceData.end(); ++dataIter) { if ((void *)(*dataIter) != (void *)caller) { v.push_back(*dataIter); } else { m_ReferenceDataObserverTags.erase(*dataIter); // no tag to remove anymore } } this->SetReferenceData(v); } void mitk::ToolManager::SetReferenceData(DataNode *data) { DataVectorType v; if (data) { v.push_back(data); } SetReferenceData(v); } void mitk::ToolManager::SetWorkingData(DataVectorType data) { if (data != m_WorkingData) { // remove observers from old nodes for (auto dataIter = m_WorkingData.begin(); dataIter != m_WorkingData.end(); ++dataIter) { auto searchIter = m_WorkingDataObserverTags.find(*dataIter); if (searchIter != m_WorkingDataObserverTags.end()) { (*dataIter)->RemoveObserver(searchIter->second); } } m_WorkingData = data; // TODO tell active tool? // Quick workaround for bug #16598 if (m_WorkingData.empty()) this->ActivateTool(-1); // workaround end // attach new observers m_WorkingDataObserverTags.clear(); for (auto dataIter = m_WorkingData.begin(); dataIter != m_WorkingData.end(); ++dataIter) { itk::MemberCommand::Pointer command = itk::MemberCommand::New(); command->SetCallbackFunction(this, &ToolManager::OnOneOfTheWorkingDataDeleted); command->SetCallbackFunction(this, &ToolManager::OnOneOfTheWorkingDataDeletedConst); m_WorkingDataObserverTags.insert( std::pair((*dataIter), (*dataIter)->AddObserver(itk::DeleteEvent(), command))); } WorkingDataChanged.Send(); } } void mitk::ToolManager::OnOneOfTheWorkingDataDeletedConst(const itk::Object *caller, const itk::EventObject &e) { OnOneOfTheWorkingDataDeleted(const_cast(caller), e); } void mitk::ToolManager::OnOneOfTheWorkingDataDeleted(itk::Object *caller, const itk::EventObject &itkNotUsed(e)) { DataVectorType v; for (auto dataIter = m_WorkingData.begin(); dataIter != m_WorkingData.end(); ++dataIter) { if ((void *)(*dataIter) != (void *)caller) { v.push_back(*dataIter); } else { m_WorkingDataObserverTags.erase(*dataIter); // no tag to remove anymore } } this->SetWorkingData(v); } void mitk::ToolManager::SetWorkingData(DataNode *data) { DataVectorType v; if (data) // don't allow for nullptr nodes { v.push_back(data); } SetWorkingData(v); } void mitk::ToolManager::SetRoiData(DataVectorType data) { if (data != m_RoiData) { // remove observers from old nodes for (auto dataIter = m_RoiData.begin(); dataIter != m_RoiData.end(); ++dataIter) { auto searchIter = m_RoiDataObserverTags.find(*dataIter); if (searchIter != m_RoiDataObserverTags.end()) { (*dataIter)->RemoveObserver(searchIter->second); } } m_RoiData = data; // TODO tell active tool? // attach new observers m_RoiDataObserverTags.clear(); for (auto dataIter = m_RoiData.begin(); dataIter != m_RoiData.end(); ++dataIter) { itk::MemberCommand::Pointer command = itk::MemberCommand::New(); command->SetCallbackFunction(this, &ToolManager::OnOneOfTheRoiDataDeleted); command->SetCallbackFunction(this, &ToolManager::OnOneOfTheRoiDataDeletedConst); m_RoiDataObserverTags.insert( std::pair((*dataIter), (*dataIter)->AddObserver(itk::DeleteEvent(), command))); } RoiDataChanged.Send(); } } void mitk::ToolManager::SetRoiData(DataNode *data) { DataVectorType v; if (data) { v.push_back(data); } this->SetRoiData(v); } void mitk::ToolManager::OnOneOfTheRoiDataDeletedConst(const itk::Object *caller, const itk::EventObject &e) { OnOneOfTheRoiDataDeleted(const_cast(caller), e); } void mitk::ToolManager::OnOneOfTheRoiDataDeleted(itk::Object *caller, const itk::EventObject &itkNotUsed(e)) { DataVectorType v; for (auto dataIter = m_RoiData.begin(); dataIter != m_RoiData.end(); ++dataIter) { if ((void *)(*dataIter) != (void *)caller) { v.push_back(*dataIter); } else { m_RoiDataObserverTags.erase(*dataIter); // no tag to remove anymore } } this->SetRoiData(v); } mitk::ToolManager::DataVectorType mitk::ToolManager::GetReferenceData() { return m_ReferenceData; } mitk::DataNode *mitk::ToolManager::GetReferenceData(int idx) { try { return m_ReferenceData.at(idx); } catch (const std::exception &) { return nullptr; } } mitk::ToolManager::DataVectorType mitk::ToolManager::GetWorkingData() { return m_WorkingData; } mitk::ToolManager::DataVectorType mitk::ToolManager::GetRoiData() { return m_RoiData; } mitk::DataNode *mitk::ToolManager::GetRoiData(int idx) { try { return m_RoiData.at(idx); } catch (const std::exception &) { return nullptr; } } -mitk::DataStorage *mitk::ToolManager::GetDataStorage() +mitk::DataStorage::Pointer mitk::ToolManager::GetDataStorage() const { return m_DataStorage.Lock(); } void mitk::ToolManager::SetDataStorage(DataStorage &storage) { m_DataStorage = &storage; } mitk::DataNode *mitk::ToolManager::GetWorkingData(unsigned int idx) { if (m_WorkingData.empty()) return nullptr; if (m_WorkingData.size() > idx) return m_WorkingData[idx]; return nullptr; } int mitk::ToolManager::GetActiveToolID() { return m_ActiveToolID; } mitk::Tool *mitk::ToolManager::GetActiveTool() { return m_ActiveTool; } void mitk::ToolManager::RegisterClient() { if (m_RegisteredClients < 1) { if (m_ActiveTool) { m_ActiveTool->Activated(); m_ActiveToolRegistration = us::GetModuleContext()->RegisterService(m_ActiveTool, us::ServiceProperties()); } } ++m_RegisteredClients; } void mitk::ToolManager::UnregisterClient() { if (m_RegisteredClients < 1) return; --m_RegisteredClients; if (m_RegisteredClients < 1) { if (m_ActiveTool) { m_ActiveTool->Deactivated(); m_ActiveToolRegistration.Unregister(); } } } int mitk::ToolManager::GetToolID(const Tool *tool) { int id(0); for (auto iter = m_Tools.begin(); iter != m_Tools.end(); ++iter, ++id) { if (tool == iter->GetPointer()) { return id; } } return -1; } void mitk::ToolManager::OnNodeRemoved(const mitk::DataNode *node) { // check all storage vectors OnOneOfTheReferenceDataDeleted(const_cast(node), itk::DeleteEvent()); OnOneOfTheRoiDataDeleted(const_cast(node), itk::DeleteEvent()); OnOneOfTheWorkingDataDeleted(const_cast(node), itk::DeleteEvent()); } void mitk::ToolManager::OnTimeChanged(itk::Object* caller, const itk::EventObject& e) { this->OnTimeChangedConst(caller, e); } void mitk::ToolManager::OnTimeChangedConst(const itk::Object* caller, const itk::EventObject& /*e*/) { auto currentController = m_CurrentTimeNavigationController.Lock(); if (caller == currentController) { const auto currentTimePoint = currentController->GetSelectedTimePoint(); if (currentTimePoint != m_LastTimePoint) { m_LastTimePoint = currentTimePoint; SelectedTimePointChanged.Send(); } } } mitk::TimePointType mitk::ToolManager::GetCurrentTimePoint() const { return m_LastTimePoint; } diff --git a/Modules/Segmentation/Controllers/mitkToolManager.h b/Modules/Segmentation/Controllers/mitkToolManager.h index 4cdfbf263a..9079e2579d 100644 --- a/Modules/Segmentation/Controllers/mitkToolManager.h +++ b/Modules/Segmentation/Controllers/mitkToolManager.h @@ -1,302 +1,302 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkToolManager_h_Included #define mitkToolManager_h_Included #include "mitkDataNode.h" #include "mitkDataStorage.h" #include "mitkTool.h" #include "mitkWeakPointer.h" #include #pragma GCC visibility push(default) #include #pragma GCC visibility pop #include namespace mitk { class Image; class PlaneGeometry; /** \brief Manages and coordinates instances of mitk::Tool. \sa QmitkToolSelectionBox \sa Tool \sa QmitkSegmentationView \ingroup Interaction \ingroup ToolManagerEtAl There is a separate page describing the general design of QmitkSegmentationView: \ref QmitkSegmentationTechnicalPage This class creates and manages several instances of mitk::Tool. \li ToolManager creates instances of mitk::Tool by asking the itk::ObjectFactory to list all known implementations of mitk::Tool. As a result, one has to implement both a subclass of mitk::Tool and a matching subclass of itk::ObjectFactoryBase that is registered to the top-level itk::ObjectFactory. For an example, see mitkContourToolFactory.h. (this limitiation of one-class-one-factory is due to the implementation of itk::ObjectFactory). In MITK, the right place to register the factories to itk::ObjectFactory is the mitk::QMCoreObjectFactory or mitk::SBCoreObjectFactory. \li ToolManager knows a set of "reference" DataNodes and a set of "working" DataNodes. The first application are segmentation tools, where the reference is the original image and the working data the (kind of) binary segmentation. However, ToolManager is implemented more generally, so that there could be other tools that work, e.g., with surfaces. \li There is a set of events that are sent by ToolManager. At the moment these are TODO update documentation: - mitk::ToolReferenceDataChangedEvent whenever somebody calls SetReferenceData. Most of the time this actually means that the data has changed, but there might be cases where the same data is passed to SetReferenceData a second time, so don't rely on the assumption that something actually changed. - mitk::ToolSelectedEvent is sent when a (truly) different tool was activated. In reaction to this event you can ask for the active Tool using GetActiveTool or GetActiveToolID (where nullptr or -1 indicate that NO tool is active at the moment). Design descisions: \li Not a singleton, because there could be two functionalities using tools, each one with different reference/working data. $Author$ */ class MITKSEGMENTATION_EXPORT ToolManager : public itk::Object { public: typedef std::vector ToolVectorType; typedef std::vector ToolVectorTypeConst; typedef std::vector DataVectorType; // has to be observed for delete events! typedef std::map NodeTagMapType; Message<> NodePropertiesChanged; Message<> NewNodesGenerated; Message1 NewNodeObjectsGenerated; Message<> ActiveToolChanged; Message<> ReferenceDataChanged; Message<> WorkingDataChanged; Message<> RoiDataChanged; Message<> SelectedTimePointChanged; Message1 ToolErrorMessage; Message1 GeneralToolMessage; mitkClassMacroItkParent(ToolManager, itk::Object); mitkNewMacro1Param(ToolManager, DataStorage *); /** \brief Gives you a list of all tools. This is const on purpose. */ const ToolVectorTypeConst GetTools(); int GetToolID(const Tool *tool); /** \param id The tool of interest. Counting starts with 0. */ Tool *GetToolById(int id); /** \param id The tool to activate. Provide -1 for disabling any tools. Counting starts with 0. Registeres a listner for NodeRemoved event at DataStorage (see mitk::ToolManager::OnNodeRemoved). */ bool ActivateTool(int id); template int GetToolIdByToolType() { int id = 0; for (auto iter = m_Tools.begin(); iter != m_Tools.end(); ++iter, ++id) { if (dynamic_cast(iter->GetPointer())) { return id; } } return -1; } /** \return -1 for "No tool is active" */ int GetActiveToolID(); /** \return nullptr for "No tool is active" */ Tool *GetActiveTool(); /** \brief Set a list of data/images as reference objects. */ void SetReferenceData(DataVectorType); /** \brief Set single data item/image as reference object. */ void SetReferenceData(DataNode *); /** \brief Set a list of data/images as working objects. */ void SetWorkingData(DataVectorType); /** \brief Set single data item/image as working object. */ void SetWorkingData(DataNode *); /** \brief Set a list of data/images as roi objects. */ void SetRoiData(DataVectorType); /** \brief Set a single data item/image as roi object. */ void SetRoiData(DataNode *); /** \brief Get the list of reference data. */ DataVectorType GetReferenceData(); /** \brief Get the current reference data. \warning If there is a list of items, this method will only return the first list item. */ DataNode *GetReferenceData(int); /** \brief Get the list of working data. */ DataVectorType GetWorkingData(); /** \brief Get the current working data. \warning If there is a list of items, this method will only return the first list item. */ DataNode *GetWorkingData(unsigned int); /** \brief Get the current roi data */ DataVectorType GetRoiData(); /** \brief Get the roi data at position idx */ DataNode *GetRoiData(int idx); - DataStorage *GetDataStorage(); + DataStorage::Pointer GetDataStorage() const; void SetDataStorage(DataStorage &storage); /** Get the current selected time point of the RenderManager */ TimePointType GetCurrentTimePoint() const; /** \brief Tell that someone is using tools. GUI elements should call this when they become active. This method increases an internal "client count". */ void RegisterClient(); /** \brief Tell that someone is NOT using tools. GUI elements should call this when they become active. This method increases an internal "client count". */ void UnregisterClient(); /** \brief Initialize all classes derived from mitk::Tool by itkObjectFactoy */ void InitializeTools(); void OnOneOfTheReferenceDataDeletedConst(const itk::Object *caller, const itk::EventObject &e); void OnOneOfTheReferenceDataDeleted(itk::Object *caller, const itk::EventObject &e); void OnOneOfTheWorkingDataDeletedConst(const itk::Object *caller, const itk::EventObject &e); void OnOneOfTheWorkingDataDeleted(itk::Object *caller, const itk::EventObject &e); void OnOneOfTheRoiDataDeletedConst(const itk::Object *caller, const itk::EventObject &e); void OnOneOfTheRoiDataDeleted(itk::Object *caller, const itk::EventObject &e); /** \brief Connected to tool's messages This method just resends error messages coming from any of the tools. This way clients (GUIs) only have to observe one message. */ void OnToolErrorMessage(std::string s); void OnGeneralToolMessage(std::string s); protected: /** You may specify a list of tool "groups" that should be available for this ToolManager. Every Tool can report its group as a string. This constructor will try to find the tool's group inside the supplied string. If there is a match, the tool is accepted. Effectively, you can provide a human readable list like "default, lymphnodevolumetry, oldERISstuff". */ ToolManager(DataStorage *storage); // purposely hidden ~ToolManager() override; ToolVectorType m_Tools; Tool *m_ActiveTool; int m_ActiveToolID; us::ServiceRegistration m_ActiveToolRegistration; DataVectorType m_ReferenceData; NodeTagMapType m_ReferenceDataObserverTags; DataVectorType m_WorkingData; NodeTagMapType m_WorkingDataObserverTags; DataVectorType m_RoiData; NodeTagMapType m_RoiDataObserverTags; int m_RegisteredClients; WeakPointer m_DataStorage; /// \brief Callback for NodeRemove events void OnNodeRemoved(const mitk::DataNode *node); /** Callback for time changed events*/ void OnTimeChangedConst(const itk::Object* caller, const itk::EventObject& e); void OnTimeChanged(itk::Object* caller, const itk::EventObject& e); void EnsureTimeObservation(); void StopTimeObservation(); private: /** Time point of last detected change*/ TimePointType m_LastTimePoint = 0; /** Tag of the observer that listens to time changes*/ unsigned long m_TimePointObserverTag = 0; /** Pointer to the observed time stepper*/ WeakPointer m_CurrentTimeNavigationController; }; } // namespace #endif