diff --git a/Modules/QtWidgets/src/QmitkMultiWidgetConfigurationToolBar.cpp b/Modules/QtWidgets/src/QmitkMultiWidgetConfigurationToolBar.cpp
index a078239b81..e5a695957e 100644
--- a/Modules/QtWidgets/src/QmitkMultiWidgetConfigurationToolBar.cpp
+++ b/Modules/QtWidgets/src/QmitkMultiWidgetConfigurationToolBar.cpp
@@ -1,82 +1,82 @@
/*===================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center,
Division of Medical Image Computing.
All rights reserved.
This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.
See LICENSE.txt or http://www.mitk.org for details.
===================================================================*/
#include "QmitkMultiWidgetConfigurationToolBar.h"
QmitkMultiWidgetConfigurationToolBar::QmitkMultiWidgetConfigurationToolBar()
: QToolBar()
{
QToolBar::setOrientation(Qt::Vertical);
QToolBar::setIconSize(QSize(17, 17));
InitializeToolBar();
}
QmitkMultiWidgetConfigurationToolBar::~QmitkMultiWidgetConfigurationToolBar()
{
// nothing here
}
void QmitkMultiWidgetConfigurationToolBar::InitializeToolBar()
{
// create popup to show a widget to modify the multi widget layout
m_LayoutSelectionPopup = new QmitkMultiWidgetLayoutSelectionWidget(this);
m_LayoutSelectionPopup->hide();
AddButtons();
connect(m_LayoutSelectionPopup, &QmitkMultiWidgetLayoutSelectionWidget::LayoutSet, this, &QmitkMultiWidgetConfigurationToolBar::LayoutSet);
}
void QmitkMultiWidgetConfigurationToolBar::AddButtons()
{
QAction* setLayoutAction = new QAction(QIcon(":/Qmitk/mwLayout.png"), tr("Set multi widget layout"), this);
connect(setLayoutAction, &QAction::triggered, this, &QmitkMultiWidgetConfigurationToolBar::OnSetLayout);
QToolBar::addAction(setLayoutAction);
m_SynchronizeAction = new QAction(QIcon(":/Qmitk/mwSynchronized.png"), tr("Desynchronize render windows"), this);
m_SynchronizeAction->setCheckable(true);
m_SynchronizeAction->setChecked(true);
connect(m_SynchronizeAction, &QAction::triggered, this, &QmitkMultiWidgetConfigurationToolBar::OnSynchronize);
QToolBar::addAction(m_SynchronizeAction);
}
void QmitkMultiWidgetConfigurationToolBar::OnSetLayout()
{
m_LayoutSelectionPopup->setWindowFlags(Qt::Popup);
- m_LayoutSelectionPopup->move(this->cursor().pos());
+ m_LayoutSelectionPopup->move(this->cursor().pos().x() - m_LayoutSelectionPopup->width(), this->cursor().pos().y());
m_LayoutSelectionPopup->show();
}
void QmitkMultiWidgetConfigurationToolBar::OnSynchronize()
{
bool synchronized = m_SynchronizeAction->isChecked();
if (synchronized)
{
m_SynchronizeAction->setIcon(QIcon(":/Qmitk/mwSynchronized.png"));
m_SynchronizeAction->setText(tr("Desynchronize render windows"));
}
else
{
m_SynchronizeAction->setIcon(QIcon(":/Qmitk/mwDesynchronized.png"));
m_SynchronizeAction->setText(tr("Synchronize render windows"));
}
m_SynchronizeAction->setChecked(synchronized);
emit Synchronized(synchronized);
}
diff --git a/Modules/QtWidgets/src/QmitkMultiWidgetLayoutSelectionWidget.cpp b/Modules/QtWidgets/src/QmitkMultiWidgetLayoutSelectionWidget.cpp
index 687ad5a934..17081206c4 100644
--- a/Modules/QtWidgets/src/QmitkMultiWidgetLayoutSelectionWidget.cpp
+++ b/Modules/QtWidgets/src/QmitkMultiWidgetLayoutSelectionWidget.cpp
@@ -1,76 +1,80 @@
/*===================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center,
Division of Medical Image Computing.
All rights reserved.
This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.
See LICENSE.txt or http://www.mitk.org for details.
===================================================================*/
#include "QmitkMultiWidgetLayoutSelectionWidget.h"
QmitkMultiWidgetLayoutSelectionWidget::QmitkMultiWidgetLayoutSelectionWidget(QWidget* parent/* = 0*/)
: QWidget(parent)
{
Init();
}
void QmitkMultiWidgetLayoutSelectionWidget::Init()
{
ui.setupUi(this);
+
+ auto stylesheet = "QTableWidget::item{background-color: white;}\nQTableWidget::item:selected{background-color: #1C97EA;}";
+ ui.tableWidget->setStyleSheet(stylesheet);
+
connect(ui.tableWidget, &QTableWidget::itemSelectionChanged, this, &QmitkMultiWidgetLayoutSelectionWidget::OnTableItemSelectionChanged);
connect(ui.setLayoutPushButton, &QPushButton::clicked, this, &QmitkMultiWidgetLayoutSelectionWidget::OnSetLayoutButtonClicked);
}
void QmitkMultiWidgetLayoutSelectionWidget::OnTableItemSelectionChanged()
{
QItemSelectionModel* selectionModel = ui.tableWidget->selectionModel();
int row = 0;
int column = 0;
QModelIndexList indices = selectionModel->selectedIndexes();
if (indices.size() > 0)
{
row = indices[0].row();
column = indices[0].column();
QModelIndex topLeft = ui.tableWidget->model()->index(0, 0, QModelIndex());
QModelIndex bottomRight = ui.tableWidget->model()->index(row, column, QModelIndex());
QItemSelection cellSelection;
cellSelection.select(topLeft, bottomRight);
selectionModel->select(cellSelection, QItemSelectionModel::Select);
}
}
void QmitkMultiWidgetLayoutSelectionWidget::OnSetLayoutButtonClicked()
{
int row = 0;
int column = 0;
QModelIndexList indices = ui.tableWidget->selectionModel()->selectedIndexes();
if (indices.size() > 0)
{
// find largest row and column
for (const QModelIndex modelIndex : indices)
{
if (modelIndex.row() > row)
{
row = modelIndex.row();
}
if (modelIndex.column() > column)
{
column = modelIndex.column();
}
}
close();
emit LayoutSet(row+1, column+1);
}
}
diff --git a/Modules/QtWidgets/src/QmitkMultiWidgetLayoutSelectionWidget.ui b/Modules/QtWidgets/src/QmitkMultiWidgetLayoutSelectionWidget.ui
index 34d3e62dfd..5c2d9e4af1 100644
--- a/Modules/QtWidgets/src/QmitkMultiWidgetLayoutSelectionWidget.ui
+++ b/Modules/QtWidgets/src/QmitkMultiWidgetLayoutSelectionWidget.ui
@@ -1,72 +1,70 @@
QmitkMultiWidgetLayoutSelectionWidget
0
0
230
230
-
QAbstractItemView::NoEditTriggers
false
false
3
4
false
50
50
false
50
50
-
-
-
Set multi widget layout
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);
+}
diff --git a/Modules/SemanticRelationsUI/src/QmitkLesionTreeModel.cpp b/Modules/SemanticRelationsUI/src/QmitkLesionTreeModel.cpp
index 261e378da1..44adbf74ab 100644
--- a/Modules/SemanticRelationsUI/src/QmitkLesionTreeModel.cpp
+++ b/Modules/SemanticRelationsUI/src/QmitkLesionTreeModel.cpp
@@ -1,297 +1,302 @@
/*===================================================================
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.
===================================================================*/
// semantic relations UI module
#include "QmitkLesionTreeModel.h"
// semantic relations module
#include
#include
#include
#include
#include
#include
// qt
#include
QmitkLesionTreeModel::QmitkLesionTreeModel(QObject* parent/* = nullptr*/)
: QmitkAbstractSemanticRelationsStorageModel(parent)
, m_LastSegmentation(nullptr)
, m_RootItem(std::make_shared(mitk::LesionData()))
{
// nothing here
}
//////////////////////////////////////////////////////////////////////////
// overridden virtual functions from QAbstractItemModel
//////////////////////////////////////////////////////////////////////////
QModelIndex QmitkLesionTreeModel::index(int row, int column, const QModelIndex& itemIndex) const
{
if (!hasIndex(row, column, itemIndex))
{
return QModelIndex();
}
auto childItem = GetItemByIndex(itemIndex)->GetChildInRow(row);
if (nullptr == childItem)
{
return QModelIndex();
}
return createIndex(row, column, childItem.get());
}
QModelIndex QmitkLesionTreeModel::parent(const QModelIndex& itemIndex) const
{
if (!itemIndex.isValid())
{
return QModelIndex();
}
auto parentItem = GetItemByIndex(itemIndex)->GetParent();
if (parentItem.expired())
{
return QModelIndex();
}
auto sharedParent = parentItem.lock();
if (sharedParent == m_RootItem)
{
return QModelIndex();
}
return createIndex(sharedParent->GetRow(), 0, sharedParent.get());
}
int QmitkLesionTreeModel::rowCount(const QModelIndex& itemIndex/* = QModelIndex()*/) const
{
return GetItemByIndex(itemIndex)->ChildCount();
}
int QmitkLesionTreeModel::columnCount(const QModelIndex&/* itemIndex = QModelIndex() */) const
{
if (0 == m_RootItem->ChildCount())
{
// no lesion items stored, no need to display columns
return 0;
}
return m_ControlPoints.size() + 1;
}
QVariant QmitkLesionTreeModel::data(const QModelIndex& index, int role) const
{
if (!index.isValid())
{
return QVariant();
}
if (index.column() < 0 || index.column() > static_cast(m_ControlPoints.size()))
{
return QVariant();
}
QmitkLesionTreeItem* currentItem = GetItemByIndex(index);
if (Qt::DisplayRole == role)
{
if (currentItem->GetParent().expired())
{
return QVariant();
}
auto parentItem = currentItem->GetParent().lock();
// parent exists and is the root item -> 1. item of a lesion entry
if (m_RootItem == parentItem)
{
// display role fills the first columns with the lesion UID / name
if (0 == index.column())
{
std::string itemString = currentItem->GetData().GetLesionName();
if (itemString.empty())
{
itemString = currentItem->GetData().GetLesionUID();
}
return QString::fromStdString(itemString);
}
else
{
// display role fills other columns with the lesion presence info
const auto lesionPresence = currentItem->GetData().GetLesionPresence();
if (index.column() - 1 > static_cast(lesionPresence.size()))
{
return "N/A";
}
- return QVariant(lesionPresence.at(index.column() - 1));
+ if (lesionPresence.at(index.column() - 1))
+ {
+ return QString::fromStdString("present");
+ }
+
+ return QString::fromStdString("not present");
}
}
}
if (Qt::BackgroundColorRole == role)
{
auto it = m_DataNodePresence.find(currentItem->GetData().GetLesion().UID);
if (it != m_DataNodePresence.end())
{
return it->second ? QVariant(QColor(Qt::darkGreen)) : QVariant(QColor(Qt::transparent));
}
return QVariant(QColor(Qt::transparent));
}
if (Qt::UserRole == role)
{
return QVariant::fromValue(currentItem);
}
return QVariant();
}
QVariant QmitkLesionTreeModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (0 == m_RootItem->ChildCount())
{
// no lesion items stored, no need to display the header
return QVariant();
}
if (Qt::Horizontal == orientation && Qt::DisplayRole == role)
{
if (0 == section)
{
return QVariant("Lesion");
}
if (static_cast(m_ControlPoints.size()) >= section)
{
mitk::SemanticTypes::ControlPoint currentControlPoint = m_ControlPoints.at(section-1);
return QVariant(QString::fromStdString(currentControlPoint.ToString()));
}
}
return QVariant();
}
const mitk::DataNode* QmitkLesionTreeModel::GetLastSegmentation() const
{
return m_LastSegmentation;
}
void QmitkLesionTreeModel::NodeAdded(const mitk::DataNode* dataNode)
{
if (mitk::NodePredicates::GetSegmentationPredicate()->CheckNode(dataNode))
{
m_LastSegmentation = dataNode;
}
}
void QmitkLesionTreeModel::SetData()
{
m_RootItem = std::make_shared(mitk::LesionData());
// get all control points of current case
m_ControlPoints = mitk::RelationStorage::GetAllControlPointsOfCase(m_CaseID);
// sort the vector of control points for the timeline
std::sort(m_ControlPoints.begin(), m_ControlPoints.end());
SetLesionData();
SetSelectedDataNodesPresence();
}
void QmitkLesionTreeModel::SetLesionData()
{
m_CurrentLesions = mitk::RelationStorage::GetAllLesionsOfCase(m_CaseID);
for (auto& lesion : m_CurrentLesions)
{
AddLesion(lesion);
}
}
void QmitkLesionTreeModel::AddLesion(const mitk::SemanticTypes::Lesion& lesion)
{
if (m_DataStorage.IsExpired())
{
return;
}
auto dataStorage = m_DataStorage.Lock();
// create new lesion tree item data and modify it according to the control point data
mitk::LesionData lesionData(lesion);
mitk::ComputeLesionPresence(lesionData, m_CaseID);
// add the top-level lesion item to the root item
std::shared_ptr newLesionTreeItem = std::make_shared(lesionData);
m_RootItem->AddChild(newLesionTreeItem);
}
void QmitkLesionTreeModel::SetSelectedDataNodesPresence()
{
m_DataNodePresence.clear();
for (const auto& dataNode : m_SelectedDataNodes)
{
if (!mitk::SemanticRelationsInference::InstanceExists(dataNode))
{
continue;
}
for (const auto& lesion : m_CurrentLesions)
{
if (!mitk::SemanticRelationsInference::InstanceExists(m_CaseID, lesion))
{
continue;
}
try
{
// set the lesion presence for the current node
bool dataNodePresence = mitk::SemanticRelationsInference::IsLesionPresent(lesion, dataNode);
SetDataNodePresenceOfLesion(&lesion, dataNodePresence);
}
catch (const mitk::SemanticRelationException&)
{
continue;
}
}
}
}
void QmitkLesionTreeModel::SetDataNodePresenceOfLesion(const mitk::SemanticTypes::Lesion* lesion, bool dataNodePresence)
{
std::map::iterator iter = m_DataNodePresence.find(lesion->UID);
if (iter != m_DataNodePresence.end())
{
// key already existing, overwrite already stored bool value
iter->second = dataNodePresence;
}
else
{
m_DataNodePresence.insert(std::make_pair(lesion->UID, dataNodePresence));
}
}
QmitkLesionTreeItem* QmitkLesionTreeModel::GetItemByIndex(const QModelIndex& index) const
{
if (index.isValid())
{
auto item = static_cast(index.internalPointer());
if (nullptr != item)
{
return item;
}
}
return m_RootItem.get();
}
diff --git a/Modules/SemanticRelationsUI/src/QmitkPatientTableModel.cpp b/Modules/SemanticRelationsUI/src/QmitkPatientTableModel.cpp
index 93a04931e8..04d9e0fc44 100644
--- a/Modules/SemanticRelationsUI/src/QmitkPatientTableModel.cpp
+++ b/Modules/SemanticRelationsUI/src/QmitkPatientTableModel.cpp
@@ -1,350 +1,350 @@
/*===================================================================
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.
===================================================================*/
// semantic relations UI module
#include "QmitkPatientTableModel.h"
#include "QmitkPatientTableHeaderView.h"
#include "QmitkSemanticRelationsUIHelper.h"
// semantic relations module
#include
#include
#include
#include
#include
#include
#include
// qt
#include
// c++
#include
#include
QmitkPatientTableModel::QmitkPatientTableModel(QObject* parent /*= nullptr*/)
: QmitkAbstractSemanticRelationsStorageModel(parent)
, m_SelectedNodeType("Image")
{
m_HeaderModel = new QStandardItemModel(this);
}
QmitkPatientTableModel::~QmitkPatientTableModel()
{
// nothing here
}
QModelIndex QmitkPatientTableModel::index(int row, int column, const QModelIndex& parent/* = QModelIndex()*/) const
{
if (hasIndex(row, column, parent))
{
return createIndex(row, column);
}
return QModelIndex();
}
QModelIndex QmitkPatientTableModel::parent(const QModelIndex& /*child*/) const
{
return QModelIndex();
}
int QmitkPatientTableModel::rowCount(const QModelIndex& parent/* = QModelIndex()*/) const
{
if (parent.isValid())
{
return 0;
}
return m_InformationTypes.size();
}
int QmitkPatientTableModel::columnCount(const QModelIndex& parent/* = QModelIndex()*/) const
{
if (parent.isValid())
{
return 0;
}
return m_ExaminationPeriods.size();
}
QVariant QmitkPatientTableModel::data(const QModelIndex& index, int role/* = Qt::DisplayRole*/) const
{
// special role for returning the horizontal header
if (QmitkPatientTableHeaderView::HorizontalHeaderDataRole == role)
{
return QVariant::fromValue(m_HeaderModel);
}
if (!index.isValid())
{
return QVariant();
}
if (index.row() < 0 || index.row() >= static_cast(m_InformationTypes.size())
|| index.column() < 0 || index.column() >= static_cast(m_ExaminationPeriods.size()))
{
return QVariant();
}
mitk::DataNode* dataNode = GetCurrentDataNode(index);
- if (nullptr == dataNode)
- {
- return QVariant();
- }
if (Qt::DecorationRole == role)
{
auto it = m_PixmapMap.find(dataNode);
if (it != m_PixmapMap.end())
{
return QVariant(it->second);
}
- }
- if (QmitkDataNodeRole == role)
- {
- return QVariant::fromValue(mitk::DataNode::Pointer(dataNode));
- }
-
- if (QmitkDataNodeRawPointerRole == role)
- {
- return QVariant::fromValue(dataNode);
+ auto emptyPixmap = QPixmap(120, 120);
+ emptyPixmap.fill(Qt::transparent);
+ return emptyPixmap;
}
if (Qt::BackgroundColorRole == role)
{
auto it = m_LesionPresence.find(dataNode);
if (it != m_LesionPresence.end())
{
return it->second ? QVariant(QColor(Qt::darkGreen)) : QVariant(QColor(Qt::transparent));
}
return QVariant(QColor(Qt::transparent));
}
+ if (QmitkDataNodeRole == role)
+ {
+ return QVariant::fromValue(mitk::DataNode::Pointer(dataNode));
+ }
+
+ if (QmitkDataNodeRawPointerRole == role)
+ {
+ return QVariant::fromValue(dataNode);
+ }
+
return QVariant();
}
QVariant QmitkPatientTableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (Qt::Vertical == orientation && Qt::DisplayRole == role)
{
if (static_cast(m_InformationTypes.size()) > section)
{
mitk::SemanticTypes::InformationType currentInformationType = m_InformationTypes.at(section);
return QVariant(QString::fromStdString(currentInformationType));
}
}
return QVariant();
}
Qt::ItemFlags QmitkPatientTableModel::flags(const QModelIndex& index) const
{
Qt::ItemFlags flags;
mitk::DataNode* dataNode = GetCurrentDataNode(index);
if (nullptr != dataNode)
{
flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}
return flags;
}
void QmitkPatientTableModel::SetNodeType(const std::string& nodeType)
{
m_SelectedNodeType = nodeType;
UpdateModelData();
}
void QmitkPatientTableModel::NodePredicateChanged()
{
UpdateModelData();
}
void QmitkPatientTableModel::SetData()
{
// get all examination periods of current case
m_ExaminationPeriods = mitk::RelationStorage::GetAllExaminationPeriodsOfCase(m_CaseID);
// sort all examination periods for the timeline
mitk::SortAllExaminationPeriods(m_CaseID, m_ExaminationPeriods);
// rename examination periods according to their new order
std::string examinationPeriodName = "Baseline";
for (int i = 0; i < m_ExaminationPeriods.size(); ++i)
{
auto& examinationPeriod = m_ExaminationPeriods.at(i);
examinationPeriod.name = examinationPeriodName;
mitk::RelationStorage::RenameExaminationPeriod(m_CaseID, examinationPeriod);
examinationPeriodName = "Follow-up " + std::to_string(i);
}
// get all information types points of current case
m_InformationTypes = mitk::RelationStorage::GetAllInformationTypesOfCase(m_CaseID);
if ("Image" == m_SelectedNodeType)
{
m_CurrentDataNodes = m_SemanticRelationsDataStorageAccess->GetAllImagesOfCase(m_CaseID);
}
else if ("Segmentation" == m_SelectedNodeType)
{
m_CurrentDataNodes = m_SemanticRelationsDataStorageAccess->GetAllSegmentationsOfCase(m_CaseID);
}
SetHeaderModel();
SetPixmaps();
SetLesionPresences();
}
void QmitkPatientTableModel::SetHeaderModel()
{
m_HeaderModel->clear();
QStandardItem* rootItem = new QStandardItem("Timeline");
QList standardItems;
for (const auto& examinationPeriod : m_ExaminationPeriods)
{
QStandardItem* examinationPeriodItem = new QStandardItem(QString::fromStdString(examinationPeriod.name));
standardItems.push_back(examinationPeriodItem);
rootItem->appendColumn(standardItems);
standardItems.clear();
}
m_HeaderModel->setItem(0, 0, rootItem);
}
void QmitkPatientTableModel::SetPixmaps()
{
m_PixmapMap.clear();
for (const auto& dataNode : m_CurrentDataNodes)
{
// set the pixmap for the current node
QPixmap pixmapFromImage = QmitkSemanticRelationsUIHelper::GetPixmapFromImageNode(dataNode);
SetPixmapOfNode(dataNode, &pixmapFromImage);
}
}
void QmitkPatientTableModel::SetPixmapOfNode(const mitk::DataNode* dataNode, QPixmap* pixmapFromImage)
{
if (nullptr == dataNode)
{
return;
}
std::map::iterator iter = m_PixmapMap.find(dataNode);
if (iter != m_PixmapMap.end())
{
// key already existing
if (nullptr != pixmapFromImage)
{
// overwrite already stored pixmap
iter->second = pixmapFromImage->scaled(120, 120, Qt::IgnoreAspectRatio);
}
else
{
// remove key if no pixmap is given
m_PixmapMap.erase(iter);
}
}
else
{
m_PixmapMap.insert(std::make_pair(dataNode, pixmapFromImage->scaled(120, 120, Qt::IgnoreAspectRatio)));
}
}
void QmitkPatientTableModel::SetLesionPresences()
{
m_LesionPresence.clear();
if (!mitk::SemanticRelationsInference::InstanceExists(m_CaseID, m_Lesion))
{
return;
}
for (const auto& dataNode : m_CurrentDataNodes)
{
if (!mitk::SemanticRelationsInference::InstanceExists(dataNode))
{
continue;
}
// set the lesion presence for the current node
bool lesionPresence = mitk::SemanticRelationsInference::IsLesionPresent(m_Lesion, dataNode);
SetLesionPresenceOfNode(dataNode, lesionPresence);
}
}
void QmitkPatientTableModel::SetLesionPresenceOfNode(const mitk::DataNode* dataNode, bool lesionPresence)
{
std::map::iterator iter = m_LesionPresence.find(dataNode);
if (iter != m_LesionPresence.end())
{
// key already existing, overwrite already stored bool value
iter->second = lesionPresence;
}
else
{
m_LesionPresence.insert(std::make_pair(dataNode, lesionPresence));
}
}
mitk::DataNode* QmitkPatientTableModel::GetCurrentDataNode(const QModelIndex& index) const
{
if (!index.isValid())
{
return nullptr;
}
auto examinationPeriod = m_ExaminationPeriods.at(index.column());
auto currentInformationType = m_InformationTypes.at(index.row());
auto controlPointsOfExaminationPeriod = examinationPeriod.controlPointUIDs;
for (const auto& controlPointUID : controlPointsOfExaminationPeriod)
{
auto currentControlPoint = mitk::GetControlPointByUID(m_CaseID, controlPointUID);
try
{
std::vector filteredDataNodes;
if ("Image" == m_SelectedNodeType)
{
filteredDataNodes = m_SemanticRelationsDataStorageAccess->GetAllSpecificImages(m_CaseID, currentControlPoint, currentInformationType);
}
else if ("Segmentation" == m_SelectedNodeType)
{
filteredDataNodes = m_SemanticRelationsDataStorageAccess->GetAllSpecificSegmentations(m_CaseID, currentControlPoint, currentInformationType);
}
if (filteredDataNodes.empty())
{
// try next control point
continue;
}
else
{
// found a specific image
return filteredDataNodes.front();
}
}
catch (const mitk::SemanticRelationException&)
{
return nullptr;
}
}
// could not find a specif image
return nullptr;
}
diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/CMakeLists.txt b/Plugins/org.mitk.gui.qt.semanticrelations/CMakeLists.txt
index 2ffd63c2e3..970cb000dd 100644
--- a/Plugins/org.mitk.gui.qt.semanticrelations/CMakeLists.txt
+++ b/Plugins/org.mitk.gui.qt.semanticrelations/CMakeLists.txt
@@ -1,7 +1,7 @@
project(org_mitk_gui_qt_semanticrelations)
mitk_create_plugin(
EXPORT_DIRECTIVE MITK_GUI_SEMANTICRELATIONS_EXPORT
EXPORTED_INCLUDE_SUFFIXES src
- MODULE_DEPENDS MitkPersistence MitkSemanticRelationsUI MitkRenderWindowManager
+ MODULE_DEPENDS MitkPersistence MitkSemanticRelationsUI MitkRenderWindowManager MitkMultilabel MitkSegmentationUI
)
diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkLesionInfoWidget.cpp b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkLesionInfoWidget.cpp
index 910b6cefaa..4a6872c152 100644
--- a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkLesionInfoWidget.cpp
+++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkLesionInfoWidget.cpp
@@ -1,461 +1,496 @@
/*===================================================================
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.
===================================================================*/
// semantic relations plugin
#include "QmitkLesionInfoWidget.h"
#include "QmitkDataNodeAddToSemanticRelationsAction.h"
#include "QmitkFocusOnLesionAction.h"
#include "QmitkSemanticRelationsNodeSelectionDialog.h"
// semantic relations UI module
#include
// semantic relations module
#include
#include
#include
#include
#include
-// registration ontology module
-//#include
+// segmentation
+#include
+#include
// qt
#include
#include
#include
#include
#include
QmitkLesionInfoWidget::QmitkLesionInfoWidget(mitk::DataStorage* dataStorage,
berry::IWorkbenchPartSite::Pointer workbenchPartSite,
QWidget* parent /*= nullptr*/)
: QWidget(parent)
, m_DataStorage(dataStorage)
, m_WorkbenchPartSite(workbenchPartSite)
, m_SemanticRelationsDataStorageAccess(std::make_unique(dataStorage))
, m_SemanticRelationsIntegration(std::make_unique())
{
Initialize();
}
void QmitkLesionInfoWidget::Initialize()
{
m_Controls.setupUi(this);
m_Controls.lesionTreeView->setAlternatingRowColors(true);
m_Controls.lesionTreeView->setSelectionMode(QAbstractItemView::SingleSelection);
m_Controls.lesionTreeView->setSelectionBehavior(QAbstractItemView::SelectRows);
m_Controls.lesionTreeView->setContextMenuPolicy(Qt::CustomContextMenu);
m_StorageModel = new QmitkLesionTreeModel(m_Controls.lesionTreeView);
if (m_DataStorage.IsExpired())
{
return;
}
auto dataStorage = m_DataStorage.Lock();
m_StorageModel->SetDataStorage(dataStorage);
m_Controls.lesionTreeView->setModel(m_StorageModel);
SetUpConnections();
}
void QmitkLesionInfoWidget::SetUpConnections()
{
connect(m_StorageModel, &QmitkLesionTreeModel::ModelUpdated, this, &QmitkLesionInfoWidget::OnModelUpdated);
connect(m_Controls.addLesionPushButton, &QPushButton::clicked, this, &QmitkLesionInfoWidget::OnAddLesionButtonClicked);
connect(m_Controls.lesionTreeView->selectionModel(), &QItemSelectionModel::currentChanged, this, &QmitkLesionInfoWidget::OnSelectionChanged);
connect(m_Controls.lesionTreeView, &QTreeView::customContextMenuRequested, this, &QmitkLesionInfoWidget::OnLesionListContextMenuRequested);
}
void QmitkLesionInfoWidget::SetCaseID(const mitk::SemanticTypes::CaseID& caseID)
{
m_CaseID = caseID;
m_StorageModel->SetCaseID(caseID);
}
void QmitkLesionInfoWidget::SetDataNodeSelection(const QList& dataNodeSelection)
{
m_StorageModel->SetDataNodeSelection(dataNodeSelection);
}
//////////////////////////////////////////////////////////////////////////
// Implementation of the QT_SLOTS
//////////////////////////////////////////////////////////////////////////
void QmitkLesionInfoWidget::OnModelUpdated()
{
m_Controls.lesionTreeView->expandAll();
int columns = m_Controls.lesionTreeView->model()->columnCount();
for (int i = 0; i < columns; ++i)
{
m_Controls.lesionTreeView->resizeColumnToContents(i);
}
}
void QmitkLesionInfoWidget::OnAddLesionButtonClicked()
{
if (m_CaseID.empty())
{
QMessageBox msgBox(QMessageBox::Warning,
"No case ID set.",
"In order to add a lesion, please specify the current case / patient.");
msgBox.exec();
return;
}
mitk::SemanticTypes::Lesion newLesion = mitk::GenerateNewLesion();
try
{
m_SemanticRelationsIntegration->AddLesion(m_CaseID, newLesion);
}
catch (mitk::SemanticRelationException& e)
{
MITK_INFO << "Could not add a new lesion. " << e;
}
}
void QmitkLesionInfoWidget::OnSelectionChanged(const QModelIndex& current, const QModelIndex& /*previous*/)
{
// only the UID is needed to identify a representing lesion
QVariant data = m_StorageModel->data(current, Qt::UserRole);
if (!data.canConvert())
{
return;
}
auto lesion = data.value()->GetData().GetLesion();
if (false == mitk::SemanticRelationsInference::InstanceExists(m_CaseID, lesion))
{
// no UID of a existing lesion found; cannot create a lesion
return;
}
// if selected data nodes are set, reset to empty list to
// hide "selected data nodes presence background highlighting" in the model
if (!m_StorageModel->GetSelectedDataNodes().isEmpty())
{
m_StorageModel->SetDataNodeSelection(QList());
}
emit LesionSelectionChanged(lesion);
}
void QmitkLesionInfoWidget::OnLesionListContextMenuRequested(const QPoint& pos)
{
if (nullptr == m_SemanticRelationsIntegration)
{
return;
}
if (m_CaseID.empty())
{
QMessageBox msgBox(QMessageBox::Warning,
"No case ID set.",
"In order to access the context menu entries a case ID has to be set.");
msgBox.exec();
return;
}
QModelIndex index = m_Controls.lesionTreeView->indexAt(pos);
if (!index.isValid())
{
// no item clicked; cannot retrieve the current lesion
return;
}
QVariant data = m_StorageModel->data(index, Qt::UserRole);
mitk::SemanticTypes::Lesion selectedLesion;
if (data.canConvert())
{
selectedLesion = data.value()->GetData().GetLesion();
}
else
{
return;
}
QMenu* menu = new QMenu(m_Controls.lesionTreeView);
QAction* linkToSegmentation = new QAction("Link to segmentation", this);
linkToSegmentation->setEnabled(true);
connect(linkToSegmentation, &QAction::triggered, [this, selectedLesion] { OnLinkToSegmentation(selectedLesion); });
menu->addAction(linkToSegmentation);
QAction* setLesionName = new QAction("Set lesion name", this);
setLesionName->setEnabled(true);
connect(setLesionName, &QAction::triggered, [this, selectedLesion] { OnSetLesionName(selectedLesion); });
menu->addAction(setLesionName);
QAction* setLesionClass = new QAction("Set lesion class", this);
setLesionClass->setEnabled(true);
connect(setLesionClass, &QAction::triggered, [this, selectedLesion] { OnSetLesionClass(selectedLesion); });
menu->addAction(setLesionClass);
- QAction* propageLesionToImage = new QAction("Propagate lesion to image", this);
- propageLesionToImage->setEnabled(true);
- connect(propageLesionToImage, &QAction::triggered, [this, selectedLesion] { OnPropagateLesion(selectedLesion); });
- menu->addAction(propageLesionToImage);
+ QAction* createNewSegmentation = new QAction("Create new lesion", this);
+ createNewSegmentation->setEnabled(true);
+ connect(createNewSegmentation, &QAction::triggered, [this, selectedLesion] { OnCreateNewSegmentation(selectedLesion); });
+ menu->addAction(createNewSegmentation);
QAction* removeLesion = new QAction("Remove lesion", this);
removeLesion->setEnabled(true);
connect(removeLesion, &QAction::triggered, [this, selectedLesion] { OnRemoveLesion(selectedLesion); });
menu->addAction(removeLesion);
if (!m_WorkbenchPartSite.Expired())
{
QmitkFocusOnLesionAction* focusOnLesion = new QmitkFocusOnLesionAction(this, m_WorkbenchPartSite.Lock());
focusOnLesion->SetDataStorage(m_DataStorage.Lock());
focusOnLesion->SetSelectedLesion(selectedLesion);
menu->addAction(focusOnLesion);
}
menu->popup(QCursor::pos());
}
void QmitkLesionInfoWidget::OnLinkToSegmentation(mitk::SemanticTypes::Lesion selectedLesion)
{
if (m_DataStorage.IsExpired())
{
return;
}
auto dataStorage = m_DataStorage.Lock();
QmitkSemanticRelationsNodeSelectionDialog* dialog = new QmitkSemanticRelationsNodeSelectionDialog(this, "Select segmentation to link to the selected lesion.", "");
dialog->setWindowTitle("Select segmentation node");
dialog->SetDataStorage(dataStorage);
dialog->SetNodePredicate(mitk::NodePredicates::GetSegmentationPredicate());
dialog->SetSelectOnlyVisibleNodes(true);
dialog->SetCaseID(m_CaseID);
// set the last added segmentation node as pre-selected data node
const mitk::DataNode* lastSegmentation = m_StorageModel->GetLastSegmentation();
QList selectedDataNodes;
if (nullptr != lastSegmentation)
{
selectedDataNodes.push_back(const_cast(lastSegmentation));
dialog->SetCurrentSelection(selectedDataNodes);
}
int dialogReturnValue = dialog->exec();
if (QDialog::Rejected == dialogReturnValue)
{
return;
}
mitk::DataNode::Pointer selectedDataNode = nullptr;
selectedDataNodes = dialog->GetSelectedNodes();
if (!selectedDataNodes.isEmpty())
{
// only single selection allowed
selectedDataNode = selectedDataNodes.front();
}
if (nullptr == selectedDataNode
|| false == mitk::NodePredicates::GetSegmentationPredicate()->CheckNode(selectedDataNode))
{
QMessageBox msgBox(QMessageBox::Warning,
"No valid segmentation node selected.",
"In order to link the selected lesion to a segmentation, please specify a valid segmentation node.");
msgBox.exec();
return;
}
mitk::BaseData* baseData = selectedDataNode->GetData();
if (nullptr == baseData)
{
QMessageBox msgBox(QMessageBox::Warning,
"No valid base data.",
"In order to link the selected lesion to a segmentation, please specify a valid segmentation node.");
msgBox.exec();
return;
}
- // if the segmentation is not contained in the semantic relations, add it
- if (!mitk::SemanticRelationsInference::InstanceExists(selectedDataNode))
- {
- try
- {
- AddToSemanticRelationsAction::Run(dataStorage, selectedDataNode);
- }
- catch (const mitk::SemanticRelationException& e)
- {
- std::stringstream exceptionMessage; exceptionMessage << e;
- QMessageBox msgBox(QMessageBox::Warning,
- "Could not link the selected lesion.",
- "The program wasn't able to correctly link the selected lesion with the selected segmentation.\n"
- "Reason:\n" + QString::fromStdString(exceptionMessage.str() + "\n"));
- msgBox.exec();
- }
- }
-
- // link the segmentation
- try
- {
- m_SemanticRelationsIntegration->LinkSegmentationToLesion(selectedDataNode, selectedLesion);
- }
- catch (const mitk::SemanticRelationException& e)
- {
- std::stringstream exceptionMessage; exceptionMessage << e;
- QMessageBox msgBox(QMessageBox::Warning,
- "Could not link the selected lesion.",
- "The program wasn't able to correctly link the selected lesion with the selected segmentation.\n"
- "Reason:\n" + QString::fromStdString(exceptionMessage.str()));
- msgBox.exec();
- }
+ LinkSegmentationToLesion(selectedDataNode, selectedLesion);
}
void QmitkLesionInfoWidget::OnSetLesionName(mitk::SemanticTypes::Lesion selectedLesion)
{
// use the lesion information to set the input text for the dialog
QmitkLesionTextDialog* inputDialog = new QmitkLesionTextDialog(this);
inputDialog->setWindowTitle("Set lesion name");
inputDialog->SetLineEditText(selectedLesion.name);
int dialogReturnValue = inputDialog->exec();
if (QDialog::Rejected == dialogReturnValue)
{
return;
}
selectedLesion.name = inputDialog->GetLineEditText().toStdString();
m_SemanticRelationsIntegration->OverwriteLesion(m_CaseID, selectedLesion);
}
void QmitkLesionInfoWidget::OnSetLesionClass(mitk::SemanticTypes::Lesion selectedLesion)
{
// use the lesion information to set the input text for the dialog
QmitkLesionTextDialog* inputDialog = new QmitkLesionTextDialog(this);
inputDialog->setWindowTitle("Set lesion class");
inputDialog->SetLineEditText(selectedLesion.lesionClass.classType);
// prepare the completer for the dialogs input text field
mitk::LesionClassVector allLesionClasses = mitk::SemanticRelationsInference::GetAllLesionClassesOfCase(m_CaseID);
QStringList wordList;
for (const auto& lesionClass : allLesionClasses)
{
wordList << QString::fromStdString(lesionClass.classType);
}
QCompleter* completer = new QCompleter(wordList, this);
completer->setCaseSensitivity(Qt::CaseInsensitive);
inputDialog->GetLineEdit()->setCompleter(completer);
int dialogReturnValue = inputDialog->exec();
if (QDialog::Rejected == dialogReturnValue)
{
return;
}
// retrieve the new input lesion class type and check for an already existing lesion class types
std::string newLesionClassType = inputDialog->GetLineEditText().toStdString();
mitk::SemanticTypes::LesionClass existingLesionClass = mitk::FindExistingLesionClass(newLesionClassType, allLesionClasses);
if (existingLesionClass.UID.empty())
{
// could not find lesion class information for the new lesion class type
// create a new lesion class for the selected lesion
existingLesionClass = mitk::GenerateNewLesionClass(newLesionClassType);
}
selectedLesion.lesionClass = existingLesionClass;
m_SemanticRelationsIntegration->OverwriteLesion(m_CaseID, selectedLesion);
}
-void QmitkLesionInfoWidget::OnPropagateLesion(mitk::SemanticTypes::Lesion selectedLesion)
+void QmitkLesionInfoWidget::OnCreateNewSegmentation(mitk::SemanticTypes::Lesion selectedLesion)
{
if (m_DataStorage.IsExpired())
{
return;
}
auto dataStorage = m_DataStorage.Lock();
- QmitkSemanticRelationsNodeSelectionDialog* dialog = new QmitkSemanticRelationsNodeSelectionDialog(this, "Select data node to propagate the selected lesion.", "");
+ QmitkSemanticRelationsNodeSelectionDialog* dialog = new QmitkSemanticRelationsNodeSelectionDialog(this, "Select image to segment lesion on.", "");
dialog->setWindowTitle("Select image node");
dialog->SetDataStorage(dataStorage);
dialog->SetNodePredicate(mitk::NodePredicates::GetImagePredicate());
dialog->SetSelectOnlyVisibleNodes(true);
dialog->SetCaseID(m_CaseID);
dialog->SetLesion(selectedLesion);
int dialogReturnValue = dialog->exec();
if (QDialog::Rejected == dialogReturnValue)
{
return;
}
auto nodes = dialog->GetSelectedNodes();
mitk::DataNode::Pointer selectedDataNode = nullptr;
if (!nodes.isEmpty())
{
// only single selection allowed
selectedDataNode = nodes.front();
}
if (nullptr == selectedDataNode
|| false == mitk::NodePredicates::GetImagePredicate()->CheckNode(selectedDataNode))
{
QMessageBox msgBox(QMessageBox::Warning,
"No valid image node selected.",
- "In order to propagate the selected lesion to an image, please specify a valid image node.");
+ "In order to create a new segmentation, please specify a valid image node.");
msgBox.exec();
return;
}
- mitk::BaseData* baseData = selectedDataNode->GetData();
- if (nullptr == baseData)
+ mitk::Image* selectedImage = dynamic_cast(selectedDataNode->GetData());
+ if (nullptr == selectedImage)
{
QMessageBox msgBox(QMessageBox::Warning,
- "No valid base data.",
- "In order to propagate the selected lesion to an image, please specify a valid image node.");
+ "No valid image.",
+ "In order to create a new segmentation, please specify a valid image node.");
msgBox.exec();
return;
}
+ mitk::LabelSetImage::Pointer segmentation = mitk::LabelSetImage::New();
try
{
- /*
- auto allSegmentationsOfLesion = m_SemanticRelationsDataStorageAccess->GetAllSegmentationsOfLesion(m_CaseID, selectedLesion);
- mitk::FindClosestSegmentationMask();
- */
+ segmentation->Initialize(selectedImage);
}
- catch (const mitk::SemanticRelationException& e)
+ catch (mitk::Exception& e)
{
std::stringstream exceptionMessage; exceptionMessage << e;
QMessageBox msgBox(QMessageBox::Warning,
- "Could not propagate the selected lesion.",
- "The program wasn't able to correctly propagate the selected lesion to the selected image.\n"
+ "Could not initialize segmentation.",
+ "The segmentation could not be correctly initialized with the selected image geometry.\n"
"Reason:\n" + QString::fromStdString(exceptionMessage.str()));
msgBox.exec();
+ return;
+ }
+
+ auto segmentationDialog = new QmitkNewSegmentationDialog(this);
+ segmentationDialog->setWindowTitle("New lesion segmentation");
+
+ dialogReturnValue = segmentationDialog->exec();
+ if (dialogReturnValue == QDialog::Rejected)
+ {
+ return;
+ }
+
+ QString segmentatioName = segmentationDialog->GetSegmentationName();
+ if (segmentatioName.isEmpty())
+ {
+ segmentatioName = "Unnamed";
}
+ segmentation->GetActiveLabelSet()->AddLabel(segmentatioName.toStdString(), segmentationDialog->GetColor());
+
+ mitk::DataNode::Pointer segmentationNode = mitk::DataNode::New();
+ segmentationNode->SetData(segmentation);
+ segmentationNode->SetName(segmentatioName.toStdString());
+ dataStorage->Add(segmentationNode, selectedDataNode);
+
+ LinkSegmentationToLesion(segmentationNode, selectedLesion);
}
void QmitkLesionInfoWidget::OnRemoveLesion(mitk::SemanticTypes::Lesion selectedLesion)
{
try
{
m_SemanticRelationsIntegration->RemoveLesion(m_CaseID, selectedLesion);
}
catch (const mitk::SemanticRelationException& e)
{
std::stringstream exceptionMessage; exceptionMessage << e;
QMessageBox msgBox(QMessageBox::Warning,
"Could not remove the selected lesion.",
"The program wasn't able to correctly remove the selected lesion from the semantic relations model.\n"
"Reason:\n" + QString::fromStdString(exceptionMessage.str()));
msgBox.exec();
}
}
+
+void QmitkLesionInfoWidget::LinkSegmentationToLesion(const mitk::DataNode* selectedDataNode, mitk::SemanticTypes::Lesion selectedLesion)
+{
+ if (m_DataStorage.IsExpired())
+ {
+ return;
+ }
+
+ auto dataStorage = m_DataStorage.Lock();
+
+ // if the segmentation is not contained in the semantic relations, add it
+ if (!mitk::SemanticRelationsInference::InstanceExists(selectedDataNode))
+ {
+ try
+ {
+ AddToSemanticRelationsAction::Run(dataStorage, selectedDataNode);
+ }
+ catch (const mitk::SemanticRelationException& e)
+ {
+ std::stringstream exceptionMessage; exceptionMessage << e;
+ QMessageBox msgBox(QMessageBox::Warning,
+ "Could not link the selected lesion.",
+ "The program wasn't able to correctly link the selected lesion with the selected segmentation.\n"
+ "Reason:\n" + QString::fromStdString(exceptionMessage.str() + "\n"));
+ msgBox.exec();
+ }
+ }
+
+ // link the segmentation
+ try
+ {
+ m_SemanticRelationsIntegration->LinkSegmentationToLesion(selectedDataNode, selectedLesion);
+ }
+ catch (const mitk::SemanticRelationException& e)
+ {
+ std::stringstream exceptionMessage; exceptionMessage << e;
+ QMessageBox msgBox(QMessageBox::Warning,
+ "Could not link the selected lesion.",
+ "The program wasn't able to correctly link the selected lesion with the selected segmentation.\n"
+ "Reason:\n" + QString::fromStdString(exceptionMessage.str()));
+ msgBox.exec();
+ }
+}
diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkLesionInfoWidget.h b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkLesionInfoWidget.h
index 6864f1ca0f..f675f664fa 100644
--- a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkLesionInfoWidget.h
+++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkLesionInfoWidget.h
@@ -1,105 +1,107 @@
/*===================================================================
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 QMITKLESIONINFOWIDGET_H
#define QMITKLESIONINFOWIDGET_H
// semantic relations plugin
#include
// semantic relations UI module
#include
// semantic relations module
#include
#include
// mitk
#include
// berry
#include
// qt
#include
/*
* @brief The QmitkLesionInfoWidget is a widget that shows and modifies the currently available lesion data of the semantic relations model.
*
* The widget provides a dialogs to add nodes from the data storage to the semantic relations model.
* It provides functionality to create new lesions and link them with segmentation nodes.
*
* The QmitkLesionInfoWidget provides three QListWidgets, that show the lesion data and the referenced segmentation data, as
* well as the connected image data, depending on the selected lesion.
*/
class QmitkLesionInfoWidget : public QWidget
{
Q_OBJECT
public:
static const QBrush DEFAULT_BACKGROUND_COLOR;
static const QBrush SELECTED_BACKGROUND_COLOR;
static const QBrush CONNECTED_BACKGROUND_COLOR;
QmitkLesionInfoWidget(mitk::DataStorage* dataStorage, berry::IWorkbenchPartSite::Pointer workbenchPartSite, QWidget* parent = nullptr);
void SetCaseID(const mitk::SemanticTypes::CaseID& caseID);
void SetDataNodeSelection(const QList& dataNodeSelection);
Q_SIGNALS:
void LesionSelectionChanged(const mitk::SemanticTypes::Lesion&);
private Q_SLOTS:
void OnModelUpdated();
/*
* @brief Generates a new, empty lesion to add to the semantic relations model for the current case ID.
*/
void OnAddLesionButtonClicked();
// slots for the mouse click events of tree view's selection model
void OnSelectionChanged(const QModelIndex& current, const QModelIndex& previous);
void OnLesionListContextMenuRequested(const QPoint&);
// slots for the context menu actions of the lesion list widget
void OnLinkToSegmentation(mitk::SemanticTypes::Lesion);
void OnSetLesionName(mitk::SemanticTypes::Lesion);
void OnSetLesionClass(mitk::SemanticTypes::Lesion);
- void OnPropagateLesion(mitk::SemanticTypes::Lesion);
+ void OnCreateNewSegmentation(mitk::SemanticTypes::Lesion);
void OnRemoveLesion(mitk::SemanticTypes::Lesion);
private:
void Initialize();
void SetUpConnections();
+ void LinkSegmentationToLesion(const mitk::DataNode* selectedDataNode, mitk::SemanticTypes::Lesion selectedLesion);
+
Ui::QmitkLesionInfoWidgetControls m_Controls;
QmitkLesionTreeModel* m_StorageModel;
mitk::SemanticTypes::CaseID m_CaseID;
mitk::WeakPointer m_DataStorage;
berry::IWorkbenchPartSite::WeakPtr m_WorkbenchPartSite;
std::unique_ptr m_SemanticRelationsDataStorageAccess;
std::unique_ptr m_SemanticRelationsIntegration;
};
#endif // QMITKLESIONINFOWIDGET_H