diff --git a/Modules/RenderWindowManager/include/mitkRenderWindowLayerUtilities.h b/Modules/RenderWindowManager/include/mitkRenderWindowLayerUtilities.h index 6e30a38584..23af38d3c3 100644 --- a/Modules/RenderWindowManager/include/mitkRenderWindowLayerUtilities.h +++ b/Modules/RenderWindowManager/include/mitkRenderWindowLayerUtilities.h @@ -1,71 +1,79 @@ /*=================================================================== 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 MITKRENDERWINDOWLAYERUTILITIES_H #define MITKRENDERWINDOWLAYERUTILITIES_H // render window manager module #include "MitkRenderWindowManagerExports.h" // mitk core #include #include #include #include /** * @brief Render window layer helper functions to retrieve the currently valid layer stack */ namespace mitk { namespace RenderWindowLayerUtilities { typedef std::vector RendererVector; typedef std::map> LayerStack; /** * The base data node of a renderer is supposed to be on layer 0 (zero), which should be the lowest layer in a render window. */ const int BASE_LAYER_INDEX = 0; /** * The top layer index, denoting that no valid (positive) layer index is given and therefore the index should be resolved into the topmost layer index. */ const int TOP_LAYER_INDEX = -1; /** * @brief Return the stack of layers of the given renderer as std::map, which guarantees ordering of the layers. * Stacked layers are only included if they have their "fixedLayer" property set to true and their "layer" property set. * * If "renderer" = nullptr: a layer stack won't be created and an empty "LayerStack" will be returned. * If "withBaseNode" = true: include the base node in the layer stack, if existing. * If "withBaseNode" = false: exclude the base node from the layer stack. * * @param dataStorage Pointer to a data storage instance whose data nodes should be checked and possibly be included. * @param renderer Pointer to the renderer instance for which the layer stack should be generated. * @param withBaseNode Boolean to decide whether the base node should be included in or excluded from the layer stack. */ MITKRENDERWINDOWMANAGER_EXPORT LayerStack GetLayerStack(const DataStorage* dataStorage, const BaseRenderer* renderer, bool withBaseNode); /** * @brief Helper function to get a node predicate that can be used to filter render window specific data nodes. * * The data nodes must not be 'helper objects'. The must have set a 'fixed layer' property for the given renderer. */ MITKRENDERWINDOWMANAGER_EXPORT NodePredicateAnd::Pointer GetRenderWindowPredicate(const BaseRenderer* renderer); - + /** + * @brief Set renderer-specific properties to mark a data node as 'managed by the specific renderer'. + * In order for a renderer to manage a data node, the 'fixedLayer' property has to be set for the given renderer. + * Additionally, the 'visible' and the 'layer' property are set and allow to individually render a set of nodes + * with a specific renderer. + * The last two mentioned properties are set so that they initially have the same value as the corresponding + * global property. + */ + MITKRENDERWINDOWMANAGER_EXPORT void SetRenderWindowProperties(mitk::DataNode* dataNode, const BaseRenderer* renderer); } // namespace RenderWindowLayerUtilities } // namespace mitk #endif // MITKRENDERWINDOWLAYERUTILITIES_H diff --git a/Modules/RenderWindowManager/src/mitkRenderWindowLayerController.cpp b/Modules/RenderWindowManager/src/mitkRenderWindowLayerController.cpp index 2ba1043c82..4ca3aa6af3 100644 --- a/Modules/RenderWindowManager/src/mitkRenderWindowLayerController.cpp +++ b/Modules/RenderWindowManager/src/mitkRenderWindowLayerController.cpp @@ -1,575 +1,567 @@ /*=================================================================== 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. ===================================================================*/ // render window manager module #include "mitkRenderWindowLayerController.h" mitk::RenderWindowLayerController::RenderWindowLayerController() : m_DataStorage(nullptr) { // nothing here } void mitk::RenderWindowLayerController::SetDataStorage(DataStorage::Pointer dataStorage) { if (m_DataStorage != dataStorage) { // set the new data storage m_DataStorage = dataStorage; } } void mitk::RenderWindowLayerController::SetControlledRenderer(RenderWindowLayerUtilities::RendererVector controlledRenderer) { if (m_ControlledRenderer != controlledRenderer) { // set the new set of controlled renderer m_ControlledRenderer = controlledRenderer; } } void mitk::RenderWindowLayerController::SetBaseDataNode(DataNode* dataNode, const BaseRenderer* renderer /*= nullptr*/) { if (nullptr == dataNode) { return; } if (nullptr == renderer) { // set the data node as base data node in all controlled renderer for (const auto& renderer : m_ControlledRenderer) { if (nullptr != renderer) { SetBaseDataNode(dataNode, renderer); } } } else { // get the layer stack with the base data node of the current renderer RenderWindowLayerUtilities::LayerStack stackedLayers = RenderWindowLayerUtilities::GetLayerStack(m_DataStorage, renderer, true); if (!stackedLayers.empty()) { // see if base layer exists RenderWindowLayerUtilities::LayerStack::iterator layerStackIterator = stackedLayers.find(RenderWindowLayerUtilities::BASE_LAYER_INDEX); if (layerStackIterator != stackedLayers.end()) { // remove the current base data node from the current renderer layerStackIterator->second->GetPropertyList(renderer)->DeleteProperty("layer"); layerStackIterator->second->SetBoolProperty("fixedLayer", false, renderer); layerStackIterator->second->SetVisibility(false, renderer); } } // "RenderWindowLayerUtilities::BASE_LAYER_INDEX" indicates the base data node --> set as new background dataNode->SetIntProperty("layer", RenderWindowLayerUtilities::BASE_LAYER_INDEX, renderer); dataNode->SetBoolProperty("fixedLayer", true, renderer); dataNode->SetVisibility(true, renderer); dataNode->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdate(renderer->GetRenderWindow()); } } void mitk::RenderWindowLayerController::InsertLayerNode(DataNode* dataNode, int layer /*= RenderWindowLayerUtilities::TOP_LAYER_INDEX*/, const BaseRenderer* renderer /*= nullptr*/) { if (nullptr == dataNode) { return; } if (nullptr == renderer) { // insert data node in all controlled renderer for (const auto& renderer : m_ControlledRenderer) { if (nullptr != renderer) { InsertLayerNode(dataNode, layer, renderer); } } } else { if (RenderWindowLayerUtilities::BASE_LAYER_INDEX == layer) { // "RenderWindowLayerUtilities::BASE_LAYER_INDEX" indicates the base data node --> set as new background (overwrite current base node if needed) SetBaseDataNode(dataNode, renderer); } else { InsertLayerNodeInternal(dataNode, layer, renderer); } } } void mitk::RenderWindowLayerController::InsertLayerNodeInternal(DataNode* dataNode, int newLayer, const BaseRenderer* renderer /*= nullptr*/) { - dataNode->SetBoolProperty("fixedLayer", true, renderer); - // use visibility of existing renderer or common renderer - bool visible = false; - bool visibilityProperty = dataNode->GetVisibility(visible, renderer); - if (true == visibilityProperty) - { - // found a visibility property - dataNode->SetVisibility(visible, renderer); - } + RenderWindowLayerUtilities::SetRenderWindowProperties(dataNode, renderer); // get the layer stack without the base node of the current renderer RenderWindowLayerUtilities::LayerStack stackedLayers = RenderWindowLayerUtilities::GetLayerStack(m_DataStorage, renderer, false); if (stackedLayers.empty()) { // no layer stack for the current renderer if (RenderWindowLayerUtilities::TOP_LAYER_INDEX == newLayer) { // set given layer as first layer above base layer (= 1) newLayer = 1; // alternatively: no layer stack for the current renderer -> insert as background node //SetBaseDataNode(dataNode, renderer); } } else { if (RenderWindowLayerUtilities::TOP_LAYER_INDEX == newLayer) { // get the first value (highest int-key -> topmost layer) // + 1 indicates inserting the node above the topmost layer newLayer = stackedLayers.begin()->first + 1; } else { MoveNodeToPosition(dataNode, newLayer, renderer); return; } } // update data storage (the "data node model") dataNode->SetIntProperty("layer", newLayer, renderer); dataNode->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdate(renderer->GetRenderWindow()); } void mitk::RenderWindowLayerController::RemoveLayerNode(DataNode* dataNode, const BaseRenderer* renderer /*= nullptr*/) { if (nullptr == dataNode) { return; } if (nullptr == renderer) { // remove data node from all controlled renderer for (const auto& renderer : m_ControlledRenderer) { if (nullptr != renderer) { RemoveLayerNode(dataNode, renderer); } } } else { // "remove" node from the renderer list dataNode->GetPropertyList(renderer)->DeleteProperty("layer"); dataNode->SetBoolProperty("fixedLayer", false, renderer); dataNode->SetVisibility(false, renderer); dataNode->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdate(renderer->GetRenderWindow()); } } bool mitk::RenderWindowLayerController::MoveNodeToPosition(DataNode* dataNode, int newLayer, const BaseRenderer* renderer /*= nullptr*/) { if (nullptr == dataNode) { return false; } if (nullptr == renderer) { // move data node to position in all controlled renderer for (const auto& renderer : m_ControlledRenderer) { if (nullptr != renderer) { MoveNodeToPosition(dataNode, newLayer, renderer); // we don't store/need the returned boolean value return false; } } } else { // get the layer stack without the base node of the current renderer RenderWindowLayerUtilities::LayerStack stackedLayers = RenderWindowLayerUtilities::GetLayerStack(m_DataStorage, renderer, false); if (!stackedLayers.empty()) { // get the current layer value of the given data node int currentLayer; bool wasFound = dataNode->GetIntProperty("layer", currentLayer, renderer); if (wasFound && currentLayer != newLayer) { // move the given data node to the specified layer dataNode->SetIntProperty("layer", newLayer, renderer); int upperBound; int lowerBound; int step; if (currentLayer < newLayer) { // move node up upperBound = newLayer + 1; lowerBound = currentLayer + 1; step = -1; // move all other nodes one step down } else { upperBound = currentLayer; lowerBound = newLayer; step = 1; // move all other nodes one step up } // move all other data nodes between the upper and the lower bound for (auto& layer : stackedLayers) { if (layer.second != dataNode && layer.first < upperBound && layer.first >= lowerBound) { layer.second->SetIntProperty("layer", layer.first + step, renderer); } // else: current data node is the selected data node or // was previously already above the selected data node or // was previously already below the new layer position } dataNode->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdate(renderer->GetRenderWindow()); return true; } // else: data node has no layer information or is already at the specified position } // else: do not work with empty layer stack } return false; } bool mitk::RenderWindowLayerController::MoveNodeToFront(DataNode* dataNode, const BaseRenderer* renderer /*= nullptr*/) { if (nullptr == dataNode) { return false; } if (nullptr == renderer) { // move data node to front in all controlled renderer for (const auto& renderer : m_ControlledRenderer) { if (nullptr != renderer) { MoveNodeToFront(dataNode, renderer); // we don't store/need the returned boolean value return false; } } } else { // get the layer stack without the base node of the current renderer RenderWindowLayerUtilities::LayerStack stackedLayers = RenderWindowLayerUtilities::GetLayerStack(m_DataStorage, renderer, false); if (!stackedLayers.empty()) { // get the first value (highest int-key -> topmost layer) int topmostLayer = stackedLayers.begin()->first; // get the current layer value of the given data node int currentLayer; bool wasFound = dataNode->GetIntProperty("layer", currentLayer, renderer); if (wasFound && currentLayer < topmostLayer) { // move the current data node above the current topmost layer dataNode->SetIntProperty("layer", topmostLayer+1, renderer); dataNode->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdate(renderer->GetRenderWindow()); return true; } // else: data node has no layer information or is already the topmost layer node } // else: do not work with empty layer stack } return false; } bool mitk::RenderWindowLayerController::MoveNodeToBack(DataNode* dataNode, const BaseRenderer* renderer /*= nullptr*/) { if (nullptr == dataNode) { return false; } if (nullptr == renderer) { // move data node to back in all controlled renderer for (const auto& renderer : m_ControlledRenderer) { if (nullptr != renderer) { MoveNodeToBack(dataNode, renderer); // we don't store/need the returned boolean value return false; } } } else { // get the layer stack without the base node of the current renderer RenderWindowLayerUtilities::LayerStack stackedLayers = RenderWindowLayerUtilities::GetLayerStack(m_DataStorage, renderer, false); if (!stackedLayers.empty()) { // get the last value (lowest int-key) // cannot be the base layer as the base node was excluded by the 'GetLayerStack'-function int lowermostLayer = stackedLayers.rbegin()->first; // get the current layer value of the given data node int currentLayer; bool wasFound = dataNode->GetIntProperty("layer", currentLayer, renderer); if (wasFound && currentLayer > lowermostLayer) { // move the current data node to the current lowermost layer dataNode->SetIntProperty("layer", lowermostLayer, renderer); // move all other data nodes one layer up for (auto& layer : stackedLayers) { if (layer.second != dataNode && layer.first < currentLayer) { layer.second->SetIntProperty("layer", layer.first + 1, renderer); } // else: current data node is the selected data node or // was previously already above the selected data node } dataNode->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdate(renderer->GetRenderWindow()); return true; } // else: data node has no layer information or is already the lowermost layer node } // else: do not work with empty layer stack } return false; } bool mitk::RenderWindowLayerController::MoveNodeUp(DataNode* dataNode, const BaseRenderer* renderer /*= nullptr*/) { if (nullptr == dataNode) { return false; } if (nullptr == renderer) { // move data node down in all controlled renderer for (const auto& renderer : m_ControlledRenderer) { if (nullptr != renderer) { MoveNodeUp(dataNode, renderer); // we don't store/need the returned boolean value return false; } } } else { // get the layer stack without the base node of the current renderer RenderWindowLayerUtilities::LayerStack stackedLayers = RenderWindowLayerUtilities::GetLayerStack(m_DataStorage, renderer, false); if (!stackedLayers.empty()) { // get the current layer value of the given data node int currentLayer; bool wasFound = dataNode->GetIntProperty("layer", currentLayer, renderer); if (wasFound) { // get the current layer in the map of stacked layers RenderWindowLayerUtilities::LayerStack::const_iterator layerStackIterator = stackedLayers.find(currentLayer); if (layerStackIterator != stackedLayers.end() && layerStackIterator != stackedLayers.begin()) { // found the element in the map, at different position than 'begin' -> // current node is not on the topmost layer and therefore can be moved one layer up // swap the layers of the dataNode and the dataNode on the next higher layer (previous map element) RenderWindowLayerUtilities::LayerStack::const_iterator prevLayerStackIterator = std::prev(layerStackIterator); dataNode->SetIntProperty("layer", prevLayerStackIterator->first, renderer); prevLayerStackIterator->second->SetIntProperty("layer", currentLayer, renderer); dataNode->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdate(renderer->GetRenderWindow()); return true; } // else: layer stack does not contain a layer with the 'currentLayer'data node or // layer is already the topmost layer node } // else: data node has no layer information } // else: do not work with empty layer stack } return false; } bool mitk::RenderWindowLayerController::MoveNodeDown(DataNode* dataNode, const BaseRenderer* renderer /*= nullptr*/) { if (nullptr == dataNode) { return false; } if (nullptr == renderer) { // move data node up in all controlled renderer for (const auto& renderer : m_ControlledRenderer) { if (nullptr != renderer) { MoveNodeDown(dataNode, renderer); // we don't store/need the returned boolean value return false; } } } else { // get the layer stack without the base node of the current renderer RenderWindowLayerUtilities::LayerStack stackedLayers = RenderWindowLayerUtilities::GetLayerStack(m_DataStorage, renderer, false); if (!stackedLayers.empty()) { // get the current layer value of the given data node int currentLayer; bool wasFound = dataNode->GetIntProperty("layer", currentLayer, renderer); if (wasFound) { // get the current layer in the map of stacked layers RenderWindowLayerUtilities::LayerStack::const_iterator layerStackIterator = stackedLayers.find(currentLayer); if (layerStackIterator != stackedLayers.end()) { // found the element in the map ... RenderWindowLayerUtilities::LayerStack::const_iterator nextLayerStackIterator = std::next(layerStackIterator); if (nextLayerStackIterator != stackedLayers.end()) { // ... and found a successor -> // current node is not on the lowermost layer and therefore can be moved one layer down // swap the layers of the dataNode and the dataNode on the next lower layer (next map element) dataNode->SetIntProperty("layer", nextLayerStackIterator->first, renderer); nextLayerStackIterator->second->SetIntProperty("layer", currentLayer, renderer); dataNode->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdate(renderer->GetRenderWindow()); return true; } // else: data node is already the lowermost layer node } // else: layer stack does not contain a layer with the 'currentLayer' } // else: data node has no layer information } // else: do not work with empty layer stack } return false; } void mitk::RenderWindowLayerController::SetVisibilityOfDataNode(bool visibility, DataNode* dataNode, const BaseRenderer* renderer /*=nullptr*/) { if (nullptr == dataNode) { return; } if (nullptr == renderer) { // set visibility of data node in all controlled renderer for (const auto& renderer : m_ControlledRenderer) { if (nullptr != renderer) { SetVisibilityOfDataNode(visibility, dataNode, renderer); } } } else { dataNode->SetVisibility(visibility, renderer); dataNode->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdate(renderer->GetRenderWindow()); } } void mitk::RenderWindowLayerController::HideDataNodeInAllRenderer(const DataNode* dataNode) { if (nullptr == dataNode) { return; } for (const auto& renderer : m_ControlledRenderer) { if (nullptr != renderer) { dataNode->GetPropertyList(renderer)->SetBoolProperty("visible", false); } } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::RenderWindowLayerController::ResetRenderer(bool onlyVisibility /*= true*/, const BaseRenderer* renderer /*= nullptr*/) { if (nullptr == renderer) { // reset all controlled renderer for (const auto& renderer : m_ControlledRenderer) { if (nullptr != renderer) { ResetRenderer(onlyVisibility, renderer); } } } else { // get the layer stack with the base node of the current renderer RenderWindowLayerUtilities::LayerStack stackedLayers = RenderWindowLayerUtilities::GetLayerStack(m_DataStorage, renderer, true); if (!stackedLayers.empty()) { for (const auto& layer : stackedLayers) { int layerLevel; layer.second->GetIntProperty("layer", layerLevel, renderer); if (RenderWindowLayerUtilities::BASE_LAYER_INDEX == layerLevel) { // set base data node visibility to true layer.second->SetVisibility(true, renderer); } else { // set visibility of all other data nodes to false layer.second->SetVisibility(false, renderer); // modify layer node if (!onlyVisibility) { // clear mode: additionally remove layer node from current renderer layer.second->GetPropertyList(renderer)->DeleteProperty("layer"); layer.second->SetBoolProperty("fixedLayer", false, renderer); } } layer.second->Modified(); } mitk::RenderingManager::GetInstance()->RequestUpdate(renderer->GetRenderWindow()); } } } diff --git a/Modules/RenderWindowManager/src/mitkRenderWindowLayerUtilities.cpp b/Modules/RenderWindowManager/src/mitkRenderWindowLayerUtilities.cpp index b3fd2e8a12..fd34b0de43 100644 --- a/Modules/RenderWindowManager/src/mitkRenderWindowLayerUtilities.cpp +++ b/Modules/RenderWindowManager/src/mitkRenderWindowLayerUtilities.cpp @@ -1,68 +1,92 @@ /*=================================================================== 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. ===================================================================*/ // render window manager module #include "mitkRenderWindowLayerUtilities.h" // mitk core #include #include mitk::RenderWindowLayerUtilities::LayerStack mitk::RenderWindowLayerUtilities::GetLayerStack(const DataStorage* dataStorage, const BaseRenderer* renderer, bool withBaseNode) { LayerStack stackedLayers; if (nullptr == dataStorage || nullptr == renderer) { // no nodes to stack or no renderer selected return stackedLayers; } int layer = -1; NodePredicateAnd::Pointer combinedNodePredicate = GetRenderWindowPredicate(renderer); DataStorage::SetOfObjects::ConstPointer filteredDataNodes = dataStorage->GetSubset(combinedNodePredicate); for (DataStorage::SetOfObjects::ConstIterator it = filteredDataNodes->Begin(); it != filteredDataNodes->End(); ++it) { DataNode::Pointer dataNode = it->Value(); if (dataNode.IsNull()) { continue; } bool layerFound = dataNode->GetIntProperty("layer", layer, renderer); if (layerFound) { if (BASE_LAYER_INDEX != layer|| withBaseNode) { // data node is not on the base layer or the base layer should be included anyway stackedLayers.insert(std::make_pair(layer, dataNode)); } } } return stackedLayers; } mitk::NodePredicateAnd::Pointer mitk::RenderWindowLayerUtilities::GetRenderWindowPredicate(const BaseRenderer* renderer) { NodePredicateAnd::Pointer renderWindowPredicate = NodePredicateAnd::New(); NodePredicateProperty::Pointer helperObject = NodePredicateProperty::New("helper object", BoolProperty::New(true)); NodePredicateProperty::Pointer fixedLayer = NodePredicateProperty::New("fixedLayer", BoolProperty::New(true), renderer); renderWindowPredicate->AddPredicate(NodePredicateNot::New(helperObject)); renderWindowPredicate->AddPredicate(fixedLayer); return renderWindowPredicate; } + +void mitk::RenderWindowLayerUtilities::SetRenderWindowProperties(mitk::DataNode* dataNode, const BaseRenderer* renderer) +{ + dataNode->SetBoolProperty("fixedLayer", true, renderer); + // use visibility of existing renderer or common renderer + // common renderer is used if renderer-specific property does not exist + bool visible = false; + bool visibilityProperty = dataNode->GetVisibility(visible, renderer); + if (true == visibilityProperty) + { + // found a visibility property + dataNode->SetVisibility(visible, renderer); + } + + // use layer of existing renderer or common renderer + // common renderer is used if renderer-specific property does not exist + int layer = -1; + bool layerProperty = dataNode->GetIntProperty("layer", layer, renderer); + if (true == layerProperty) + { + // found a layer property + dataNode->SetIntProperty("layer", layer, renderer); + } +} diff --git a/Modules/RenderWindowManagerUI/files.cmake b/Modules/RenderWindowManagerUI/files.cmake index 1637b1a861..bb0d58e96c 100644 --- a/Modules/RenderWindowManagerUI/files.cmake +++ b/Modules/RenderWindowManagerUI/files.cmake @@ -1,18 +1,21 @@ set(H_FILES include/QmitkRenderWindowDataStorageInspector.h include/QmitkRenderWindowDataStorageListModel.h + include/QmitkRenderWindowDataStorageTreeModel.h ) set(CPP_FILES QmitkRenderWindowDataStorageInspector.cpp QmitkRenderWindowDataStorageListModel.cpp + QmitkRenderWindowDataStorageTreeModel.cpp ) set(MOC_H_FILES include/QmitkRenderWindowDataStorageInspector.h include/QmitkRenderWindowDataStorageListModel.h + include/QmitkRenderWindowDataStorageTreeModel.h ) set(UI_FILES src/QmitkRenderWindowDataStorageInspector.ui ) diff --git a/Modules/RenderWindowManagerUI/include/QmitkRenderWindowDataStorageInspector.h b/Modules/RenderWindowManagerUI/include/QmitkRenderWindowDataStorageInspector.h index d0078bb2dc..03e54c8a8e 100644 --- a/Modules/RenderWindowManagerUI/include/QmitkRenderWindowDataStorageInspector.h +++ b/Modules/RenderWindowManagerUI/include/QmitkRenderWindowDataStorageInspector.h @@ -1,94 +1,96 @@ /*=================================================================== 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 QMITKRENDERWINDOWDATASTORAGEINSPECTOR_H -#define QMITKRENDERWINDOWDATASTORAGEWINSPECTOR_H +#define QMITKRENDERWINDOWDATASTORAGEINSPECTOR_H // render window manager UI module #include "MitkRenderWindowManagerUIExports.h" #include "ui_QmitkRenderWindowDataStorageInspector.h" // render window manager module #include #include -#include +#include // qt widgets module #include /** * The 'QmitkRenderWindowDataStorageInspector' offers a GUI to manipulate the base renderer / render windows of the MITK workbench. * * In order to use this widget, a (e.g.) plugin has to set the controlled renderer, which will be forwarded to * a render window view direction controller. */ class MITKRENDERWINDOWMANAGERUI_EXPORT QmitkRenderWindowDataStorageInspector : public QmitkAbstractDataStorageInspector { Q_OBJECT public: QmitkRenderWindowDataStorageInspector(QWidget* parent = nullptr); // override from 'QmitkAbstractDataStorageInspector' /** * @brief See 'QmitkAbstractDataStorageInspector' */ virtual QAbstractItemView* GetView() override; /** * @brief See 'QmitkAbstractDataStorageInspector' */ virtual const QAbstractItemView* GetView() const override; /** * @brief See 'QmitkAbstractDataStorageInspector' */ virtual void SetSelectionMode(SelectionMode mode) override; /** * @brief See 'QmitkAbstractDataStorageInspector' */ virtual SelectionMode GetSelectionMode() const override; /** * @brief Set the controlled base renderer. */ void SetControlledRenderer(mitk::RenderWindowLayerUtilities::RendererVector controlledRenderer); /** * @brief Set the currently selected render window. * * @param renderWindowId the text inside the combo box */ void SetActiveRenderWindow(const QString& renderWindowId); private Q_SLOTS: + void ModelRowsInserted(const QModelIndex& parent, int start, int end); + void SetAsBaseLayer(); void ResetRenderer(); void ChangeViewDirection(const QString& viewDirection); private: virtual void Initialize() override; void SetUpConnections(); Ui::QmitkRenderWindowDataStorageInspector m_Controls; - std::unique_ptr m_StorageModel; + std::unique_ptr m_StorageModel; std::unique_ptr m_RenderWindowLayerController; std::unique_ptr m_RenderWindowViewDirectionController; }; #endif // QMITKRENDERWINDOWDATASTORAGEINSPECTOR_H diff --git a/Modules/RenderWindowManagerUI/include/QmitkRenderWindowDataStorageTreeModel.h b/Modules/RenderWindowManagerUI/include/QmitkRenderWindowDataStorageTreeModel.h new file mode 100644 index 0000000000..44a37fbf55 --- /dev/null +++ b/Modules/RenderWindowManagerUI/include/QmitkRenderWindowDataStorageTreeModel.h @@ -0,0 +1,136 @@ +/*=================================================================== + +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 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; + +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/QmitkRenderWindowDataStorageInspector.cpp b/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageInspector.cpp index 018d3441f0..152497dc09 100644 --- a/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageInspector.cpp +++ b/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageInspector.cpp @@ -1,165 +1,173 @@ /*=================================================================== 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. ===================================================================*/ // render window manager UI module #include "QmitkRenderWindowDataStorageInspector.h" #include "QmitkCustomVariants.h" // mitk core #include // qt #include QmitkRenderWindowDataStorageInspector::QmitkRenderWindowDataStorageInspector(QWidget* parent /*=nullptr*/) : QmitkAbstractDataStorageInspector(parent) { m_Controls.setupUi(this); // initialize the render window layer controller and the render window view direction controller m_RenderWindowLayerController = std::make_unique(); m_RenderWindowViewDirectionController = std::make_unique(); - m_StorageModel = std::make_unique(this); - - m_Controls.renderWindowListView->setModel(m_StorageModel.get()); - m_Controls.renderWindowListView->setEditTriggers(QAbstractItemView::NoEditTriggers); - m_Controls.renderWindowListView->setSelectionBehavior(QAbstractItemView::SelectRows); - m_Controls.renderWindowListView->setSelectionMode(QAbstractItemView::ExtendedSelection); - m_Controls.renderWindowListView->setAlternatingRowColors(true); - m_Controls.renderWindowListView->setDragEnabled(true); - m_Controls.renderWindowListView->setDropIndicatorShown(true); - m_Controls.renderWindowListView->setAcceptDrops(true); - m_Controls.renderWindowListView->setContextMenuPolicy(Qt::CustomContextMenu); + m_StorageModel = std::make_unique(this); + + m_Controls.renderWindowTreeView->setModel(m_StorageModel.get()); + m_Controls.renderWindowTreeView->setHeaderHidden(true); + m_Controls.renderWindowTreeView->setEditTriggers(QAbstractItemView::NoEditTriggers); + m_Controls.renderWindowTreeView->setSelectionBehavior(QAbstractItemView::SelectRows); + m_Controls.renderWindowTreeView->setSelectionMode(QAbstractItemView::ExtendedSelection); + m_Controls.renderWindowTreeView->setAlternatingRowColors(true); + m_Controls.renderWindowTreeView->setDragEnabled(true); + m_Controls.renderWindowTreeView->setDropIndicatorShown(true); + m_Controls.renderWindowTreeView->setAcceptDrops(true); + m_Controls.renderWindowTreeView->setContextMenuPolicy(Qt::CustomContextMenu); SetUpConnections(); } QAbstractItemView* QmitkRenderWindowDataStorageInspector::GetView() { - return m_Controls.renderWindowListView; + return m_Controls.renderWindowTreeView; } const QAbstractItemView* QmitkRenderWindowDataStorageInspector::GetView() const { - return m_Controls.renderWindowListView; + return m_Controls.renderWindowTreeView; } void QmitkRenderWindowDataStorageInspector::SetSelectionMode(SelectionMode mode) { - m_Controls.renderWindowListView->setSelectionMode(mode); + m_Controls.renderWindowTreeView->setSelectionMode(mode); } QmitkRenderWindowDataStorageInspector::SelectionMode QmitkRenderWindowDataStorageInspector::GetSelectionMode() const { - return m_Controls.renderWindowListView->selectionMode(); + return m_Controls.renderWindowTreeView->selectionMode(); } void QmitkRenderWindowDataStorageInspector::Initialize() { if (m_DataStorage.IsExpired()) { return; } auto dataStorage = m_DataStorage.Lock(); m_StorageModel->SetDataStorage(dataStorage); m_StorageModel->SetNodePredicate(m_NodePredicate); m_RenderWindowLayerController->SetDataStorage(dataStorage); m_RenderWindowViewDirectionController->SetDataStorage(dataStorage); - m_Connector->SetView(m_Controls.renderWindowListView); + m_Connector->SetView(m_Controls.renderWindowTreeView); } void QmitkRenderWindowDataStorageInspector::SetUpConnections() { + connect(m_StorageModel.get(), &QAbstractItemModel::rowsInserted, this, &QmitkRenderWindowDataStorageInspector::ModelRowsInserted); + connect(m_Controls.pushButtonSetAsBaseLayer, &QPushButton::clicked, this, &QmitkRenderWindowDataStorageInspector::SetAsBaseLayer); connect(m_Controls.pushButtonResetRenderer, &QPushButton::clicked, this, &QmitkRenderWindowDataStorageInspector::ResetRenderer); QSignalMapper* changeViewDirectionSignalMapper = new QSignalMapper(this); changeViewDirectionSignalMapper->setMapping(m_Controls.radioButtonAxial, QString("axial")); changeViewDirectionSignalMapper->setMapping(m_Controls.radioButtonCoronal, QString("coronal")); changeViewDirectionSignalMapper->setMapping(m_Controls.radioButtonSagittal, QString("sagittal")); changeViewDirectionSignalMapper->setMapping(m_Controls.radioButton3D, QString("3D")); connect(changeViewDirectionSignalMapper, static_cast(&QSignalMapper::mapped), this, &QmitkRenderWindowDataStorageInspector::ChangeViewDirection); connect(m_Controls.radioButtonAxial, &QPushButton::clicked, changeViewDirectionSignalMapper, static_cast(&QSignalMapper::map)); connect(m_Controls.radioButtonCoronal, &QPushButton::clicked, changeViewDirectionSignalMapper, static_cast(&QSignalMapper::map)); connect(m_Controls.radioButtonSagittal, &QPushButton::clicked, changeViewDirectionSignalMapper, static_cast(&QSignalMapper::map)); connect(m_Controls.radioButton3D, &QPushButton::clicked, changeViewDirectionSignalMapper, static_cast(&QSignalMapper::map)); } void QmitkRenderWindowDataStorageInspector::SetControlledRenderer(mitk::RenderWindowLayerUtilities::RendererVector controlledRenderer) { m_StorageModel->SetControlledRenderer(controlledRenderer); m_RenderWindowLayerController->SetControlledRenderer(controlledRenderer); m_RenderWindowViewDirectionController->SetControlledRenderer(controlledRenderer); } void QmitkRenderWindowDataStorageInspector::SetActiveRenderWindow(const QString& renderWindowId) { mitk::BaseRenderer* selectedRenderer = mitk::BaseRenderer::GetByName(renderWindowId.toStdString()); if (nullptr == selectedRenderer) { return; } m_StorageModel->SetCurrentRenderer(selectedRenderer); mitk::SliceNavigationController::ViewDirection viewDirection = selectedRenderer->GetSliceNavigationController()->GetDefaultViewDirection(); switch (viewDirection) { case mitk::SliceNavigationController::Axial: m_Controls.radioButtonAxial->setChecked(true); break; case mitk::SliceNavigationController::Frontal: m_Controls.radioButtonCoronal->setChecked(true); break; case mitk::SliceNavigationController::Sagittal: m_Controls.radioButtonSagittal->setChecked(true); break; default: break; } } +void QmitkRenderWindowDataStorageInspector::ModelRowsInserted(const QModelIndex& parent, int start, int end) +{ + m_Controls.renderWindowTreeView->setExpanded(parent, true); +} + void QmitkRenderWindowDataStorageInspector::SetAsBaseLayer() { - QModelIndex selectedIndex = m_Controls.renderWindowListView->currentIndex(); + QModelIndex selectedIndex = m_Controls.renderWindowTreeView->currentIndex(); if (selectedIndex.isValid()) { QVariant qvariantDataNode = m_StorageModel->data(selectedIndex, Qt::UserRole); if (qvariantDataNode.canConvert()) { mitk::DataNode* dataNode = qvariantDataNode.value(); m_RenderWindowLayerController->SetBaseDataNode(dataNode, m_StorageModel->GetCurrentRenderer()); - m_Controls.renderWindowListView->clearSelection(); + m_Controls.renderWindowTreeView->clearSelection(); } } } void QmitkRenderWindowDataStorageInspector::ResetRenderer() { m_RenderWindowLayerController->ResetRenderer(true, m_StorageModel->GetCurrentRenderer()); - m_Controls.renderWindowListView->clearSelection(); + m_Controls.renderWindowTreeView->clearSelection(); } void QmitkRenderWindowDataStorageInspector::ChangeViewDirection(const QString& viewDirection) { m_RenderWindowViewDirectionController->SetViewDirectionOfRenderer(viewDirection.toStdString(), m_StorageModel->GetCurrentRenderer()); } diff --git a/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageInspector.ui b/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageInspector.ui index 64c507a340..785e20c50c 100644 --- a/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageInspector.ui +++ b/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageInspector.ui @@ -1,92 +1,92 @@ QmitkRenderWindowDataStorageInspector 0 0 340 246 0 0 0 0 Render window manager Render window overview - + Reset render window - + Set as base layer - + Axial true - + Coronal Sagittal 3D diff --git a/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageTreeModel.cpp b/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageTreeModel.cpp new file mode 100644 index 0000000000..87214ffa53 --- /dev/null +++ b/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageTreeModel.cpp @@ -0,0 +1,605 @@ +/*=================================================================== + +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. + +===================================================================*/ + +// 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); + } + + if (!m_BaseRenderer.IsExpired()) + { + auto baseRenderer = m_BaseRenderer.Lock(); + 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 +{ + if (m_BaseRenderer.IsExpired()) + { + return QVariant(); + } + + auto baseRenderer = m_BaseRenderer.Lock(); + + 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*/) +{ + if (m_BaseRenderer.IsExpired()) + { + return false; + } + + auto baseRenderer = m_BaseRenderer.Lock(); + + 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) +{ + if (m_BaseRenderer.IsExpired()) + { + return false; + } + + auto baseRenderer = m_BaseRenderer.Lock(); + + 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 : 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(); + if (m_DataStorage.IsExpired()) + { + return; + } + + auto dataStorage = m_DataStorage.Lock(); + + 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 +{ + if (m_BaseRenderer.IsExpired()) + { + return nullptr; + } + + return m_BaseRenderer.Lock().GetPointer(); +} + +void QmitkRenderWindowDataStorageTreeModel::ResetTree() +{ + beginResetModel(); + if (nullptr != m_Root) + { + m_Root->Delete(); + } + endResetModel(); + + mitk::DataNode::Pointer rootDataNode = mitk::DataNode::New(); + rootDataNode->SetName("Data Storage"); + m_Root = new QmitkDataStorageTreeModelInternalItem(rootDataNode); +} + +void QmitkRenderWindowDataStorageTreeModel::UpdateModelData() +{ + if (!m_DataStorage.IsExpired()) + { + auto dataStorage = m_DataStorage.Lock(); + if (!m_BaseRenderer.IsExpired()) + { + auto baseRenderer = m_BaseRenderer.Lock(); + + mitk::NodePredicateAnd::Pointer combinedNodePredicate = mitk::RenderWindowLayerUtilities::GetRenderWindowPredicate(baseRenderer); + auto filteredDataNodes = dataStorage->GetSubset(combinedNodePredicate); + for (const auto& dataNode : *filteredDataNodes) + { + AddNodeInternal(dataNode, baseRenderer); + } + } + } +} + +void QmitkRenderWindowDataStorageTreeModel::AdjustLayerProperty() +{ + if (m_BaseRenderer.IsExpired()) + { + return; + } + + auto baseRenderer = m_BaseRenderer.Lock(); + + 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; + if (m_DataStorage.IsExpired()) + { + return dataNode; + } + + auto sources = m_DataStorage.Lock()->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); +}