diff --git a/Modules/SegmentationUI/Qmitk/QmitkLabelColorItemDelegate.h b/Modules/SegmentationUI/Qmitk/QmitkLabelColorItemDelegate.h index 865251e0fd..01f6e4b143 100644 --- a/Modules/SegmentationUI/Qmitk/QmitkLabelColorItemDelegate.h +++ b/Modules/SegmentationUI/Qmitk/QmitkLabelColorItemDelegate.h @@ -1,40 +1,40 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef QmitkLabelColorItemDelegate_h #define QmitkLabelColorItemDelegate_h #include #include "MitkSegmentationUIExports.h" /** \class QmitkLabelColorItemDelegate -\brief An item delegate for rendering and editing label color in a QMultiLabelSegmentationTreeView.*/ +\brief An item delegate for rendering and editing label color in a QMultiLabelTreeView.*/ class MITKSEGMENTATIONUI_EXPORT QmitkLabelColorItemDelegate : public QStyledItemDelegate { Q_OBJECT public: /// /// Creates a new PropertyDelegate. /// explicit QmitkLabelColorItemDelegate(QObject *parent = nullptr); bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) override; void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; }; #endif diff --git a/Modules/SegmentationUI/Qmitk/QmitkMultiLabelSegmentationInspector.cpp b/Modules/SegmentationUI/Qmitk/QmitkMultiLabelInspector.cpp similarity index 71% rename from Modules/SegmentationUI/Qmitk/QmitkMultiLabelSegmentationInspector.cpp rename to Modules/SegmentationUI/Qmitk/QmitkMultiLabelInspector.cpp index d5fff800f7..8654c9b354 100644 --- a/Modules/SegmentationUI/Qmitk/QmitkMultiLabelSegmentationInspector.cpp +++ b/Modules/SegmentationUI/Qmitk/QmitkMultiLabelInspector.cpp @@ -1,163 +1,163 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ -#include +#include -#include +#include #include #include #include -QmitkMultiLabelSegmentationInspector::QmitkMultiLabelSegmentationInspector(QWidget* parent/* = nullptr*/) +QmitkMultiLabelInspector::QmitkMultiLabelInspector(QWidget* parent/* = nullptr*/) : QWidget(parent) { m_Controls.setupUi(this); - m_Model = new QmitkMultiLabelSegmentationTreeModel(this); + m_Model = new QmitkMultiLabelTreeModel(this); m_Controls.view->setModel(m_Model); m_ColorItemDelegate = new QmitkLabelColorItemDelegate(this); auto visibleIcon = QmitkStyleManager::ThemeIcon(QLatin1String(":/Qmitk/visible.svg")); auto invisibleIcon = QmitkStyleManager::ThemeIcon(QLatin1String(":/Qmitk/invisible.svg")); m_VisibilityItemDelegate = new QmitkLabelToggleItemDelegate(visibleIcon, invisibleIcon, this); auto lockIcon = QmitkStyleManager::ThemeIcon(QLatin1String(":/Qmitk/lock.svg")); auto unlockIcon = QmitkStyleManager::ThemeIcon(QLatin1String(":/Qmitk/unlock.svg")); m_LockItemDelegate = new QmitkLabelToggleItemDelegate(lockIcon, unlockIcon, this); this->m_Controls.view->setItemDelegateForColumn(1, m_LockItemDelegate); this->m_Controls.view->setItemDelegateForColumn(2, m_ColorItemDelegate); this->m_Controls.view->setItemDelegateForColumn(3, m_VisibilityItemDelegate); this->m_Controls.view->header()->setSectionResizeMode(0,QHeaderView::Stretch); this->m_Controls.view->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents); this->m_Controls.view->header()->setSectionResizeMode(2, QHeaderView::ResizeToContents); this->m_Controls.view->header()->setSectionResizeMode(3, QHeaderView::ResizeToContents); - connect(m_Model, &QAbstractItemModel::modelReset, this, &QmitkMultiLabelSegmentationInspector::OnModelReset); + connect(m_Model, &QAbstractItemModel::modelReset, this, &QmitkMultiLabelInspector::OnModelReset); connect(m_Controls.view->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), SLOT(ChangeModelSelection(const QItemSelection&, const QItemSelection&))); } -void QmitkMultiLabelSegmentationInspector::Initialize() +void QmitkMultiLabelInspector::Initialize() { m_LastValidSelectedLabels = {}; m_Model->SetSegmentation(m_Segmentation.Lock()); m_Controls.view->expandAll(); } -void QmitkMultiLabelSegmentationInspector::SetSelectionMode(SelectionMode mode) +void QmitkMultiLabelInspector::SetSelectionMode(SelectionMode mode) { m_Controls.view->setSelectionMode(mode); } -QmitkMultiLabelSegmentationInspector::SelectionMode QmitkMultiLabelSegmentationInspector::GetSelectionMode() const +QmitkMultiLabelInspector::SelectionMode QmitkMultiLabelInspector::GetSelectionMode() const { return m_Controls.view->selectionMode(); } -void QmitkMultiLabelSegmentationInspector::SetMultiLabelSegmentation(mitk::LabelSetImage* segmentation) +void QmitkMultiLabelInspector::SetMultiLabelSegmentation(mitk::LabelSetImage* segmentation) { if (segmentation != m_Segmentation.Lock()) { m_Segmentation = segmentation; this->Initialize(); } } -void QmitkMultiLabelSegmentationInspector::OnModelReset() +void QmitkMultiLabelInspector::OnModelReset() { m_LastValidSelectedLabels = {}; } -bool EqualLabelSelections(const QmitkMultiLabelSegmentationInspector::LabelValueVectorType& selection1, const QmitkMultiLabelSegmentationInspector::LabelValueVectorType& selection2) +bool EqualLabelSelections(const QmitkMultiLabelInspector::LabelValueVectorType& selection1, const QmitkMultiLabelInspector::LabelValueVectorType& selection2) { if (selection1.size() == selection2.size()) { // lambda to compare node pointer inside both lists auto lambda = [](mitk::LabelSetImage::LabelValueType lhs, mitk::LabelSetImage::LabelValueType rhs) { return lhs == rhs; }; return std::is_permutation(selection1.begin(), selection1.end(), selection2.begin(), selection2.end(), lambda); } return false; } -void QmitkMultiLabelSegmentationInspector::SetSelectedLabels(const LabelValueVectorType& selectedLabels) +void QmitkMultiLabelInspector::SetSelectedLabels(const LabelValueVectorType& selectedLabels) { bool equal = EqualLabelSelections(this->GetSelectedLabels(), selectedLabels); if (equal) { return; } this->UpdateSelectionModel(selectedLabels); m_LastValidSelectedLabels = selectedLabels; } -void QmitkMultiLabelSegmentationInspector::UpdateSelectionModel(const LabelValueVectorType& selectedLabels) +void QmitkMultiLabelInspector::UpdateSelectionModel(const LabelValueVectorType& selectedLabels) { // create new selection by retrieving the corresponding indices of the labels QItemSelection newCurrentSelection; for (const auto& labelID : selectedLabels) { - QModelIndexList matched = m_Model->match(m_Model->index(0, 0), QmitkMultiLabelSegmentationTreeModel::ItemModelRole::LabelValueRole, QVariant(labelID), 1, Qt::MatchRecursive); + QModelIndexList matched = m_Model->match(m_Model->index(0, 0), QmitkMultiLabelTreeModel::ItemModelRole::LabelValueRole, QVariant(labelID), 1, Qt::MatchRecursive); if (!matched.empty()) { newCurrentSelection.select(matched.front(), matched.front()); } } m_Controls.view->selectionModel()->select(newCurrentSelection, QItemSelectionModel::ClearAndSelect); } -void QmitkMultiLabelSegmentationInspector::SetSelectedLabel(mitk::LabelSetImage::LabelValueType selectedLabel) +void QmitkMultiLabelInspector::SetSelectedLabel(mitk::LabelSetImage::LabelValueType selectedLabel) { this->SetSelectedLabels({ selectedLabel }); } -QmitkMultiLabelSegmentationInspector::LabelValueVectorType QmitkMultiLabelSegmentationInspector::GetSelectedLabelsFromSelectionModel() const +QmitkMultiLabelInspector::LabelValueVectorType QmitkMultiLabelInspector::GetSelectedLabelsFromSelectionModel() const { LabelValueVectorType result; QModelIndexList selectedIndexes = m_Controls.view->selectionModel()->selectedIndexes(); for (const auto& index : qAsConst(selectedIndexes)) { - QVariant qvariantDataNode = m_Model->data(index, QmitkMultiLabelSegmentationTreeModel::ItemModelRole::LabelValueRole); + QVariant qvariantDataNode = m_Model->data(index, QmitkMultiLabelTreeModel::ItemModelRole::LabelValueRole); if (qvariantDataNode.canConvert()) { result.push_back(qvariantDataNode.value()); } } return result; } -QmitkMultiLabelSegmentationInspector::LabelValueVectorType QmitkMultiLabelSegmentationInspector::GetSelectedLabels() const +QmitkMultiLabelInspector::LabelValueVectorType QmitkMultiLabelInspector::GetSelectedLabels() const { return m_LastValidSelectedLabels; } -void QmitkMultiLabelSegmentationInspector::ChangeModelSelection(const QItemSelection& selected, const QItemSelection& deselected) +void QmitkMultiLabelInspector::ChangeModelSelection(const QItemSelection& selected, const QItemSelection& deselected) { auto internalSelection = GetSelectedLabelsFromSelectionModel(); if (internalSelection.empty()) { //empty selections are not allowed by UI interactions, there should always be at least on label selected. //but selections are e.g. also cleared if the model is updated (e.g. due to addition of labels) UpdateSelectionModel(m_LastValidSelectedLabels); } else { m_LastValidSelectedLabels = internalSelection; emit CurrentSelectionChanged(GetSelectedLabels()); } } diff --git a/Modules/SegmentationUI/Qmitk/QmitkMultiLabelSegmentationInspector.h b/Modules/SegmentationUI/Qmitk/QmitkMultiLabelInspector.h similarity index 88% rename from Modules/SegmentationUI/Qmitk/QmitkMultiLabelSegmentationInspector.h rename to Modules/SegmentationUI/Qmitk/QmitkMultiLabelInspector.h index 5c662eb4b7..36ef69ebee 100644 --- a/Modules/SegmentationUI/Qmitk/QmitkMultiLabelSegmentationInspector.h +++ b/Modules/SegmentationUI/Qmitk/QmitkMultiLabelInspector.h @@ -1,103 +1,103 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef QMITKMULTILABELSEGMENTATIONINSPECTOR_H #define QMITKMULTILABELSEGMENTATIONINSPECTOR_H #include #include #include -#include -#include "ui_QmitkMultiLabelSegmentationInspector.h" +#include +#include "ui_QmitkMultiLabelInspectorControls.h" -class QmitkMultiLabelSegmentationTreeModel; +class QmitkMultiLabelTreeModel; class QStyledItemDelegate; /* * @brief This is an inspector that offers a simple list view on a data storage. */ -class MITKSEGMENTATIONUI_EXPORT QmitkMultiLabelSegmentationInspector : public QWidget +class MITKSEGMENTATIONUI_EXPORT QmitkMultiLabelInspector : public QWidget { Q_OBJECT public: - QmitkMultiLabelSegmentationInspector(QWidget* parent = nullptr); + QmitkMultiLabelInspector(QWidget* parent = nullptr); using SelectionMode = QAbstractItemView::SelectionMode; void SetSelectionMode(SelectionMode mode); SelectionMode GetSelectionMode() const; /** * @brief Sets the segmentation that will be used /monitored by the widget. * * @param segmentation A pointer to the segmentation to set. */ void SetMultiLabelSegmentation(mitk::LabelSetImage* segmentation); using LabelValueVectorType = mitk::LabelSetImage::LabelValueVectorType; /** * @brief Retrieve the currently selected labels (equals the last CurrentSelectionChanged values). */ LabelValueVectorType GetSelectedLabels() const; Q_SIGNALS: /** * @brief A signal that will be emitted if the selected labels change. * * @param labels A list of label values that are now selected. */ void CurrentSelectionChanged(LabelValueVectorType labels); public Q_SLOTS: /** * @brief Transform a list label values into a model selection and set this as a new selection of the view * * @param selectedNodes A list of data nodes that should be newly selected. */ void SetSelectedLabels(const LabelValueVectorType& selectedLabels); void SetSelectedLabel(mitk::LabelSetImage::LabelValueType selectedLabel); protected: void Initialize(); void OnModelReset(); - QmitkMultiLabelSegmentationTreeModel* m_Model; + QmitkMultiLabelTreeModel* m_Model; mitk::WeakPointer m_Segmentation; LabelValueVectorType m_LastValidSelectedLabels; QStyledItemDelegate* m_LockItemDelegate; QStyledItemDelegate* m_ColorItemDelegate; QStyledItemDelegate* m_VisibilityItemDelegate; - Ui_QmitkMultiLabelSegmentationInspector m_Controls; + Ui_QmitkMultiLabelInspector m_Controls; LabelValueVectorType GetSelectedLabelsFromSelectionModel() const; void UpdateSelectionModel(const LabelValueVectorType& selectedLabels); private Q_SLOTS: /** * @brief Transform a labels selection into a data node list and emit the 'CurrentSelectionChanged'-signal. * * The function adds the selected nodes from the original selection that could not be modified, if * 'm_SelectOnlyVisibleNodes' is false. * This slot is internally connected to the 'selectionChanged'-signal of the selection model of the private member item view. * * @param selected The newly selected items. * @param deselected The newly deselected items. */ void ChangeModelSelection(const QItemSelection& selected, const QItemSelection& deselected); }; #endif // QMITKDATASTORAGELISTINSPECTOR_H diff --git a/Modules/SegmentationUI/Qmitk/QmitkMultiLabelSegmentationInspector.ui b/Modules/SegmentationUI/Qmitk/QmitkMultiLabelInspectorControls.ui similarity index 85% rename from Modules/SegmentationUI/Qmitk/QmitkMultiLabelSegmentationInspector.ui rename to Modules/SegmentationUI/Qmitk/QmitkMultiLabelInspectorControls.ui index 8ba8f2588a..24c9521ccf 100644 --- a/Modules/SegmentationUI/Qmitk/QmitkMultiLabelSegmentationInspector.ui +++ b/Modules/SegmentationUI/Qmitk/QmitkMultiLabelInspectorControls.ui @@ -1,74 +1,74 @@ - QmitkMultiLabelSegmentationInspector - + QmitkMultiLabelInspector + 0 0 400 300 Form 0 0 0 0 0 - + QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed|QAbstractItemView::SelectedClicked false false QAbstractItemView::SingleSelection QAbstractItemView::SelectRows false 10 50 false - QmitkMultiLabelSegmentationTreeView + QmitkMultiLabelTreeView QTreeView -
QmitkMultiLabelSegmentationTreeView.h
+
QmitkMultiLabelTreeView.h
diff --git a/Modules/SegmentationUI/Qmitk/QmitkMultiLabelSegmentationTreeModel.cpp b/Modules/SegmentationUI/Qmitk/QmitkMultiLabelTreeModel.cpp similarity index 77% rename from Modules/SegmentationUI/Qmitk/QmitkMultiLabelSegmentationTreeModel.cpp rename to Modules/SegmentationUI/Qmitk/QmitkMultiLabelTreeModel.cpp index 77f8c23264..f8bd883899 100644 --- a/Modules/SegmentationUI/Qmitk/QmitkMultiLabelSegmentationTreeModel.cpp +++ b/Modules/SegmentationUI/Qmitk/QmitkMultiLabelTreeModel.cpp @@ -1,742 +1,739 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ -#include "QmitkMultiLabelSegmentationTreeModel.h" +#include "QmitkMultiLabelTreeModel.h" #include "mitkImageStatisticsContainerManager.h" #include "mitkProportionalTimeGeometry.h" #include "mitkStatisticsToImageRelationRule.h" #include "mitkStatisticsToMaskRelationRule.h" #include "QmitkStyleManager.h" class QmitkMultiLabelSegTreeItem { public: enum class ItemType { Group, Label, Instance }; QmitkMultiLabelSegTreeItem() { }; explicit QmitkMultiLabelSegTreeItem(ItemType type, QmitkMultiLabelSegTreeItem* parentItem, mitk::Label* label = nullptr, std::string className = ""): m_ItemType(type), m_Label(label), m_parentItem(parentItem), m_ClassName(className) { }; ~QmitkMultiLabelSegTreeItem() { for (auto item : m_childItems) { delete item; } }; void AppendChild(QmitkMultiLabelSegTreeItem* child) { m_childItems.push_back(child); }; void RemoveChild(std::size_t row) { if (row < m_childItems.size()) { delete m_childItems[row]; m_childItems.erase(m_childItems.begin() + row); } }; int Row() const { if (m_parentItem) { auto finding = std::find(m_parentItem->m_childItems.begin(), m_parentItem->m_childItems.end(), this); if (finding != m_parentItem->m_childItems.end()) { return std::distance(m_parentItem->m_childItems.begin(), finding); } } return 0; }; QmitkMultiLabelSegTreeItem* ParentItem() { return m_parentItem; }; const QmitkMultiLabelSegTreeItem* RootItem() const { auto item = this; while (item->m_parentItem != nullptr) { item = item->m_parentItem; } return item; }; std::size_t GetGroupID() const { auto root = this->RootItem(); auto item = this; if (root == this) return 0; while (root != item->m_parentItem) { item = item->m_parentItem; } auto iter = std::find(root->m_childItems.begin(), root->m_childItems.end(), item); - if (root->m_childItems.end() == iter) mitkThrow() << "Invalid internal state of QmitkMultiLabelSegmentationTreeModel. Root does not have an item as child that has root as parent."; + if (root->m_childItems.end() == iter) mitkThrow() << "Invalid internal state of QmitkMultiLabelTreeModel. Root does not have an item as child that has root as parent."; return std::distance(root->m_childItems.begin(), iter); } bool HandleAsInstance() const { return (ItemType::Instance == m_ItemType) || ((ItemType::Label == m_ItemType) && (m_childItems.size() == 1)); } mitk::Label* GetLabel() const { if (ItemType::Instance == m_ItemType) { return m_Label; } if (ItemType::Label == m_ItemType) { - if (m_childItems.empty()) mitkThrow() << "Invalid internal state of QmitkMultiLabelSegmentationTreeModel. Internal label item has no instance item."; + if (m_childItems.empty()) mitkThrow() << "Invalid internal state of QmitkMultiLabelTreeModel. Internal label item has no instance item."; return m_childItems[0]->GetLabel(); } return nullptr; }; mitk::LabelSetImage::LabelValueType GetLabelValue() const { auto label = this->GetLabel(); if (nullptr == label) { - mitkThrow() << "Invalid internal state of QmitkMultiLabelSegmentationTreeModel. Called GetLabelValue on an group item."; + mitkThrow() << "Invalid internal state of QmitkMultiLabelTreeModel. Called GetLabelValue on an group item."; } return label->GetValue(); }; QmitkMultiLabelSegTreeItem* m_parentItem = nullptr; std::vector m_childItems; ItemType m_ItemType = ItemType::Group; mitk::Label::Pointer m_Label; std::string m_ClassName; }; -QmitkMultiLabelSegmentationTreeModel::QmitkMultiLabelSegmentationTreeModel(QObject *parent) : QAbstractItemModel(parent) +QmitkMultiLabelTreeModel::QmitkMultiLabelTreeModel(QObject *parent) : QAbstractItemModel(parent) , m_Observed(false) { m_RootItem = std::make_unique(); } -QmitkMultiLabelSegmentationTreeModel ::~QmitkMultiLabelSegmentationTreeModel() +QmitkMultiLabelTreeModel ::~QmitkMultiLabelTreeModel() { this->SetSegmentation(nullptr); }; -int QmitkMultiLabelSegmentationTreeModel::columnCount(const QModelIndex& /*parent*/) const +int QmitkMultiLabelTreeModel::columnCount(const QModelIndex& /*parent*/) const { return 4; } -int QmitkMultiLabelSegmentationTreeModel::rowCount(const QModelIndex &parent) const +int QmitkMultiLabelTreeModel::rowCount(const QModelIndex &parent) const { if (parent.column() > 0) return 0; if (m_Segmentation.IsNull()) return 0; QmitkMultiLabelSegTreeItem* parentItem = m_RootItem.get(); if (parent.isValid()) parentItem = static_cast(parent.internalPointer()); if (parentItem->HandleAsInstance()) { return 0; } return parentItem->m_childItems.size(); } -QVariant QmitkMultiLabelSegmentationTreeModel::data(const QModelIndex &index, int role) const +QVariant QmitkMultiLabelTreeModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); auto item = static_cast(index.internalPointer()); if (!item) return QVariant(); if (role == Qt::DisplayRole||role == Qt::EditRole) { if (TableColumns::NAME_COL == index.column()) { switch (item->m_ItemType) { case QmitkMultiLabelSegTreeItem::ItemType::Group: return QVariant(QString("Group ")+QString::number(item->GetGroupID())); case QmitkMultiLabelSegTreeItem::ItemType::Label: { auto label = item->GetLabel(); - if (nullptr == label) mitkThrow() << "Invalid internal state. QmitkMultiLabelSegmentationTreeModel item is refering to a label that does not exist."; + if (nullptr == label) mitkThrow() << "Invalid internal state. QmitkMultiLabelTreeModel item is refering to a label that does not exist."; return QVariant(QString::fromStdString(label->GetName())); } case QmitkMultiLabelSegTreeItem::ItemType::Instance: return QVariant(QString("Instance #") + QString::number(item->GetLabelValue())); } } else { if (item->HandleAsInstance()) { auto label = item->GetLabel(); if (TableColumns::LOCKED_COL == index.column()) { return QVariant(label->GetLocked()); } else if (TableColumns::COLOR_COL == index.column()) { return QVariant(QColor(label->GetColor().GetRed() * 255, label->GetColor().GetGreen() * 255, label->GetColor().GetBlue() * 255)); } else if (TableColumns::VISIBLE_COL == index.column()) { return QVariant(label->GetVisible()); } } else { } } } else if (role == ItemModelRole::LabelDataRole) { if (TableColumns::NAME_COL == index.column()) { if (item->HandleAsInstance()) { auto label = item->GetLabel(); return QVariant::fromValue(label); } } } else if (role == ItemModelRole::LabelValueRole) { if (TableColumns::NAME_COL == index.column()) { if (item->HandleAsInstance()) { auto label = item->GetLabel(); return QVariant(label->GetValue()); } } } return QVariant(); } mitk::Color QtToMitk(const QColor& color) { mitk::Color mitkColor; mitkColor.SetRed(color.red() / 255.0f); mitkColor.SetGreen(color.green() / 255.0f); mitkColor.SetBlue(color.blue() / 255.0f); return mitkColor; } -bool QmitkMultiLabelSegmentationTreeModel::setData(const QModelIndex& index, const QVariant& value, int role) +bool QmitkMultiLabelTreeModel::setData(const QModelIndex& index, const QVariant& value, int role) { if (!index.isValid()) return false; auto item = static_cast(index.internalPointer()); if (!item) return false; if (role == Qt::EditRole) { if (TableColumns::NAME_COL != index.column()) { if (item->HandleAsInstance()) { auto label = item->GetLabel(); if (TableColumns::LOCKED_COL == index.column()) { label->SetLocked(value.toBool()); } else if (TableColumns::COLOR_COL == index.column()) { label->SetColor(QtToMitk(value.value())); } else if (TableColumns::VISIBLE_COL == index.column()) { label->SetVisible(value.toBool()); } auto groupID = m_Segmentation->GetGroupIndexOfLabel(label->GetValue()); m_Segmentation->GetLabelSet(groupID)->UpdateLookupTable(label->GetValue()); } else { } return true; } } return false; } -QModelIndex QmitkMultiLabelSegmentationTreeModel::index(int row, int column, const QModelIndex &parent) const +QModelIndex QmitkMultiLabelTreeModel::index(int row, int column, const QModelIndex &parent) const { if (!hasIndex(row, column, parent)) return QModelIndex(); auto parentItem = m_RootItem.get(); if (parent.isValid()) parentItem = static_cast(parent.internalPointer()); QmitkMultiLabelSegTreeItem *childItem = parentItem->m_childItems[row]; if (childItem) return createIndex(row, column, childItem); else return QModelIndex(); } -QModelIndex QmitkMultiLabelSegmentationTreeModel::parent(const QModelIndex &child) const +QModelIndex QmitkMultiLabelTreeModel::parent(const QModelIndex &child) const { if (!child.isValid()) return QModelIndex(); QmitkMultiLabelSegTreeItem *childItem = static_cast(child.internalPointer()); QmitkMultiLabelSegTreeItem *parentItem = childItem->ParentItem(); if (parentItem == m_RootItem.get()) return QModelIndex(); return createIndex(parentItem->Row(), 0, parentItem); } -QModelIndex GetIndexByItem(QmitkMultiLabelSegTreeItem* start, QmitkMultiLabelSegmentationTreeModel* model) +QModelIndex GetIndexByItem(QmitkMultiLabelSegTreeItem* start, QmitkMultiLabelTreeModel* model) { QModelIndex parentIndex = QModelIndex(); if (nullptr != start->m_parentItem) { parentIndex = GetIndexByItem(start->m_parentItem, model); } else { return parentIndex; } return model->index(start->Row(), 0, parentIndex); } -QmitkMultiLabelSegTreeItem* GetGroupItem(QmitkMultiLabelSegmentationTreeModel::SpatialGroupIndexType groupIndex, QmitkMultiLabelSegTreeItem* root) +QmitkMultiLabelSegTreeItem* GetGroupItem(QmitkMultiLabelTreeModel::SpatialGroupIndexType groupIndex, QmitkMultiLabelSegTreeItem* root) { if (nullptr != root && groupIndex < root->m_childItems.size()) { return root->m_childItems[groupIndex]; } return nullptr; } -QmitkMultiLabelSegTreeItem* GetInstanceItem(QmitkMultiLabelSegmentationTreeModel::LabelValueType labelValue, QmitkMultiLabelSegTreeItem* root) +QmitkMultiLabelSegTreeItem* GetInstanceItem(QmitkMultiLabelTreeModel::LabelValueType labelValue, QmitkMultiLabelSegTreeItem* root) { QmitkMultiLabelSegTreeItem* result = nullptr; for (auto item : root->m_childItems) { result = GetInstanceItem(labelValue, item); if (nullptr != result) return result; } if (root->m_ItemType == QmitkMultiLabelSegTreeItem::ItemType::Instance && root->GetLabelValue() == labelValue) { return root; } return nullptr; } QmitkMultiLabelSegTreeItem* GetLabelItemInGroup(const std::string& labelName, QmitkMultiLabelSegTreeItem * group) { if (nullptr != group) { auto predicate = [labelName](const QmitkMultiLabelSegTreeItem* item) { return labelName == item->m_ClassName; }; auto finding = std::find_if(group->m_childItems.begin(), group->m_childItems.end(), predicate); if (group->m_childItems.end() != finding) { return *finding; } } return nullptr; } -Qt::ItemFlags QmitkMultiLabelSegmentationTreeModel::flags(const QModelIndex &index) const +Qt::ItemFlags QmitkMultiLabelTreeModel::flags(const QModelIndex &index) const { if (!index.isValid()) return Qt::NoItemFlags; if (!index.isValid()) return Qt::NoItemFlags; auto item = static_cast(index.internalPointer()); if (!item) return Qt::NoItemFlags; if (TableColumns::NAME_COL != index.column()) { if (item->HandleAsInstance()) { return Qt::ItemIsEnabled | Qt::ItemIsEditable; } else { return Qt::ItemIsEnabled; } return true; } else { if (item->HandleAsInstance()) { return Qt::ItemIsEnabled | Qt::ItemIsSelectable; } else { return Qt::ItemIsEnabled; } return true; } return Qt::NoItemFlags; } -QVariant QmitkMultiLabelSegmentationTreeModel::headerData(int section, Qt::Orientation orientation, int role) const +QVariant QmitkMultiLabelTreeModel::headerData(int section, Qt::Orientation orientation, int role) const { if ((Qt::DisplayRole == role) && (Qt::Horizontal == orientation)) { if (TableColumns::NAME_COL == section) { return "Name"; } else if (TableColumns::LOCKED_COL == section) { return "Locked"; } else if (TableColumns::COLOR_COL == section) { return "Color"; } else if (TableColumns::VISIBLE_COL == section) { return "Visibility"; } } return QVariant(); } -const mitk::LabelSetImage* QmitkMultiLabelSegmentationTreeModel::GetSegmentation() const +const mitk::LabelSetImage* QmitkMultiLabelTreeModel::GetSegmentation() const { return m_Segmentation; } -void QmitkMultiLabelSegmentationTreeModel::SetSegmentation(mitk::LabelSetImage* segmentation) +void QmitkMultiLabelTreeModel::SetSegmentation(mitk::LabelSetImage* segmentation) { if (m_Segmentation != segmentation) { this->RemoveObserver(); this->m_Segmentation = segmentation; this->AddObserver(); this->UpdateInternalTree(); } } /**Helper function that adds a labek into the item tree. Passes back the new created instance iten*/ QmitkMultiLabelSegTreeItem* AddLabelToGroupTree(mitk::Label* label, QmitkMultiLabelSegTreeItem* groupItem, bool& newLabelItemCreated) { if (nullptr == groupItem) return nullptr; if (nullptr == label) return nullptr; newLabelItemCreated = false; std::set labelNames; for (auto labelItem : groupItem->m_childItems) { labelNames.emplace(labelItem->GetLabel()->GetName()); } QmitkMultiLabelSegTreeItem* labelItem = nullptr; auto finding = labelNames.find(label->GetName()); if (finding != labelNames.end()) { //other label with same name exists labelItem = groupItem->m_childItems[std::distance(labelNames.begin(), finding)]; } else { newLabelItemCreated = true; labelItem = new QmitkMultiLabelSegTreeItem(QmitkMultiLabelSegTreeItem::ItemType::Label, groupItem, nullptr, label->GetName()); auto predicate = [label](const std::string& name) { return name > label->GetName(); }; auto insertFinding = std::find_if(labelNames.begin(), labelNames.end(), predicate); groupItem->m_childItems.insert(groupItem->m_childItems.begin() + std::distance(labelNames.begin(), insertFinding), labelItem); } auto instanceItem = new QmitkMultiLabelSegTreeItem(QmitkMultiLabelSegTreeItem::ItemType::Instance, labelItem, label); auto predicate = [label](const QmitkMultiLabelSegTreeItem* item) { return item->GetLabelValue() > label->GetValue(); }; auto insertFinding = std::find_if(labelItem->m_childItems.begin(), labelItem->m_childItems.end(), predicate); labelItem->m_childItems.insert(labelItem->m_childItems.begin() + std::distance(labelItem->m_childItems.begin(), insertFinding), instanceItem); return instanceItem; } -void QmitkMultiLabelSegmentationTreeModel::GenerateInternalGroupTree(unsigned int groupID, QmitkMultiLabelSegTreeItem* groupItem) +void QmitkMultiLabelTreeModel::GenerateInternalGroupTree(unsigned int groupID, QmitkMultiLabelSegTreeItem* groupItem) { auto labelSet = m_Segmentation->GetLabelSet(groupID); for (auto lIter = labelSet->IteratorConstBegin(); lIter != labelSet->IteratorConstEnd(); lIter++) { if (lIter->second == m_Segmentation->GetExteriorLabel()) continue; bool newItemCreated = false; AddLabelToGroupTree(lIter->second, groupItem, newItemCreated); } } -QmitkMultiLabelSegTreeItem* QmitkMultiLabelSegmentationTreeModel::GenerateInternalTree() +QmitkMultiLabelSegTreeItem* QmitkMultiLabelTreeModel::GenerateInternalTree() { auto rootItem = new QmitkMultiLabelSegTreeItem(); if (m_Segmentation.IsNotNull()) { for (unsigned int groupID = 0; groupID < m_Segmentation->GetNumberOfLayers(); ++groupID) { auto groupItem = new QmitkMultiLabelSegTreeItem(QmitkMultiLabelSegTreeItem::ItemType::Group, rootItem); rootItem->AppendChild(groupItem); GenerateInternalGroupTree(groupID, groupItem); } } return rootItem; } -void QmitkMultiLabelSegmentationTreeModel::UpdateInternalTree() +void QmitkMultiLabelTreeModel::UpdateInternalTree() { emit beginResetModel(); auto newTree = this->GenerateInternalTree(); this->m_RootItem.reset(newTree); emit endResetModel(); emit modelChanged(); } -void QmitkMultiLabelSegmentationTreeModel::AddObserver() +void QmitkMultiLabelTreeModel::AddObserver() { if (this->m_Segmentation.IsNotNull()) { if (m_Observed) { - MITK_DEBUG << "Invalid observer state in QmitkMultiLabelSegmentationTreeModel. There is already a registered observer. Internal logic is not correct. May be an old observer was not removed."; + MITK_DEBUG << "Invalid observer state in QmitkMultiLabelTreeModel. There is already a registered observer. Internal logic is not correct. May be an old observer was not removed."; } - this->m_Segmentation->AddLabelAddedListener(mitk::MessageDelegate1( - this, &QmitkMultiLabelSegmentationTreeModel::OnLabelAdded)); - this->m_Segmentation->AddLabelModifiedListener(mitk::MessageDelegate1( - this, &QmitkMultiLabelSegmentationTreeModel::OnLabelModified)); - this->m_Segmentation->AddLabelRemovedListener(mitk::MessageDelegate1( - this, &QmitkMultiLabelSegmentationTreeModel::OnLabelRemoved)); - this->m_Segmentation->AddGroupAddedListener(mitk::MessageDelegate1( - this, &QmitkMultiLabelSegmentationTreeModel::OnGroupAdded)); - this->m_Segmentation->AddGroupModifiedListener(mitk::MessageDelegate1( - this, &QmitkMultiLabelSegmentationTreeModel::OnGroupModified)); - this->m_Segmentation->AddGroupRemovedListener(mitk::MessageDelegate1( - this, &QmitkMultiLabelSegmentationTreeModel::OnGroupRemoved)); + this->m_Segmentation->AddLabelAddedListener(mitk::MessageDelegate1( + this, &QmitkMultiLabelTreeModel::OnLabelAdded)); + this->m_Segmentation->AddLabelModifiedListener(mitk::MessageDelegate1( + this, &QmitkMultiLabelTreeModel::OnLabelModified)); + this->m_Segmentation->AddLabelRemovedListener(mitk::MessageDelegate1( + this, &QmitkMultiLabelTreeModel::OnLabelRemoved)); + this->m_Segmentation->AddGroupAddedListener(mitk::MessageDelegate1( + this, &QmitkMultiLabelTreeModel::OnGroupAdded)); + this->m_Segmentation->AddGroupModifiedListener(mitk::MessageDelegate1( + this, &QmitkMultiLabelTreeModel::OnGroupModified)); + this->m_Segmentation->AddGroupRemovedListener(mitk::MessageDelegate1( + this, &QmitkMultiLabelTreeModel::OnGroupRemoved)); m_Observed = true; } } -void QmitkMultiLabelSegmentationTreeModel::RemoveObserver() +void QmitkMultiLabelTreeModel::RemoveObserver() { if (this->m_Segmentation.IsNotNull()) { - this->m_Segmentation->RemoveLabelAddedListener(mitk::MessageDelegate1( - this, &QmitkMultiLabelSegmentationTreeModel::OnLabelAdded)); - this->m_Segmentation->RemoveLabelModifiedListener(mitk::MessageDelegate1( - this, &QmitkMultiLabelSegmentationTreeModel::OnLabelModified)); - this->m_Segmentation->RemoveLabelRemovedListener(mitk::MessageDelegate1( - this, &QmitkMultiLabelSegmentationTreeModel::OnLabelRemoved)); - this->m_Segmentation->RemoveGroupAddedListener(mitk::MessageDelegate1( - this, &QmitkMultiLabelSegmentationTreeModel::OnGroupAdded)); - this->m_Segmentation->RemoveGroupModifiedListener(mitk::MessageDelegate1( - this, &QmitkMultiLabelSegmentationTreeModel::OnGroupModified)); - this->m_Segmentation->RemoveGroupRemovedListener(mitk::MessageDelegate1( - this, &QmitkMultiLabelSegmentationTreeModel::OnGroupRemoved)); + this->m_Segmentation->RemoveLabelAddedListener(mitk::MessageDelegate1( + this, &QmitkMultiLabelTreeModel::OnLabelAdded)); + this->m_Segmentation->RemoveLabelModifiedListener(mitk::MessageDelegate1( + this, &QmitkMultiLabelTreeModel::OnLabelModified)); + this->m_Segmentation->RemoveLabelRemovedListener(mitk::MessageDelegate1( + this, &QmitkMultiLabelTreeModel::OnLabelRemoved)); + this->m_Segmentation->RemoveGroupAddedListener(mitk::MessageDelegate1( + this, &QmitkMultiLabelTreeModel::OnGroupAdded)); + this->m_Segmentation->RemoveGroupModifiedListener(mitk::MessageDelegate1( + this, &QmitkMultiLabelTreeModel::OnGroupModified)); + this->m_Segmentation->RemoveGroupRemovedListener(mitk::MessageDelegate1( + this, &QmitkMultiLabelTreeModel::OnGroupRemoved)); } m_Observed = false; } -void QmitkMultiLabelSegmentationTreeModel::OnLabelAdded(LabelValueType labelValue) +void QmitkMultiLabelTreeModel::OnLabelAdded(LabelValueType labelValue) { SpatialGroupIndexType groupIndex = 0; if (m_Segmentation->IsLabeInGroup(labelValue, groupIndex)) { auto label = m_Segmentation->GetLabel(labelValue); if (nullptr == label) mitkThrow() << "Invalid internal state. Segmentation signaled the addition of an label that does not exist in the segmentation. Invalid label value:" << labelValue; if (label == m_Segmentation->GetExteriorLabel()) return; auto groupItem = GetGroupItem(groupIndex, this->m_RootItem.get()); bool newLabelCreated = false; auto instanceItem = AddLabelToGroupTree(label, groupItem, newLabelCreated); if (newLabelCreated) { if (groupItem->m_childItems.size() == 1) { //first label added auto groupIndex = GetIndexByItem(groupItem, this); emit dataChanged(groupIndex, groupIndex); } else { //whole new label level added to group item auto groupIndex = GetIndexByItem(groupItem, this); this->beginInsertRows(groupIndex, instanceItem->ParentItem()->Row(), instanceItem->ParentItem()->Row()); this->endInsertRows(); } } else { // instance item was added to existing label item auto labelIndex = GetIndexByItem(instanceItem->ParentItem(), this); this->beginInsertRows(labelIndex, instanceItem->Row(), instanceItem->Row()); this->endInsertRows(); } } else { mitkThrow() << "Group less labels are not supported in the current implementation."; } } -void QmitkMultiLabelSegmentationTreeModel::OnLabelModified(LabelValueType labelValue) +void QmitkMultiLabelTreeModel::OnLabelModified(LabelValueType labelValue) { if (labelValue == m_Segmentation->GetExteriorLabel()->GetValue()) return; auto instanceItem = GetInstanceItem(labelValue, this->m_RootItem.get()); if (nullptr == instanceItem) { - mitkThrow() << "Internal invalid state. QmitkMultiLabelSegmentationTreeModel recieved a LabelModified signal for a label that is not represented in the model. Invalid label: " << labelValue; + mitkThrow() << "Internal invalid state. QmitkMultiLabelTreeModel recieved a LabelModified signal for a label that is not represented in the model. Invalid label: " << labelValue; } auto labelItem = instanceItem->ParentItem(); if (labelItem->m_ClassName == instanceItem->GetLabel()->GetName()) { //only the state of the label changed, but not its position in the model tree. auto index = GetIndexByItem(labelItem, this); emit dataChanged(index, index); } else { //the name of the label changed and thus its place in the model tree, delete the current item and add a new one this->OnLabelRemoved(labelValue); this->OnLabelAdded(labelValue); } } -void QmitkMultiLabelSegmentationTreeModel::OnLabelRemoved(LabelValueType labelValue) +void QmitkMultiLabelTreeModel::OnLabelRemoved(LabelValueType labelValue) { if (labelValue == m_Segmentation->GetExteriorLabel()->GetValue()) return; auto instanceItem = GetInstanceItem(labelValue, this->m_RootItem.get()); - if (nullptr == instanceItem) mitkThrow() << "Internal invalid state. QmitkMultiLabelSegmentationTreeModel recieved a LabelRemoved signal for a label that is not represented in the model. Invalid label: " << labelValue; + if (nullptr == instanceItem) mitkThrow() << "Internal invalid state. QmitkMultiLabelTreeModel recieved a LabelRemoved signal for a label that is not represented in the model. Invalid label: " << labelValue; auto labelItem = instanceItem->ParentItem(); if (labelItem->m_childItems.size() > 1) { auto labelIndex = GetIndexByItem(labelItem, this); this->beginRemoveRows(labelIndex, instanceItem->Row(), instanceItem->Row()); labelItem->RemoveChild(instanceItem->Row()); this->endRemoveRows(); } else { //was the only instance of the label, therefor also remove the label node from the tree. auto groupItem = labelItem->ParentItem(); auto groupIndex = GetIndexByItem(groupItem, this); this->beginRemoveRows(groupIndex, labelItem->Row(), labelItem->Row()); groupItem->RemoveChild(labelItem->Row()); this->endRemoveRows(); } } -void QmitkMultiLabelSegmentationTreeModel::OnGroupAdded(SpatialGroupIndexType groupIndex) +void QmitkMultiLabelTreeModel::OnGroupAdded(SpatialGroupIndexType groupIndex) { if (m_ShowGroups) { this->beginInsertRows(QModelIndex(), groupIndex, groupIndex); auto rootItem = m_RootItem.get(); auto groupItem = new QmitkMultiLabelSegTreeItem(QmitkMultiLabelSegTreeItem::ItemType::Group, rootItem); rootItem->AppendChild(groupItem); this->GenerateInternalGroupTree(groupIndex, groupItem); this->endInsertRows(); } } -void QmitkMultiLabelSegmentationTreeModel::OnGroupModified(SpatialGroupIndexType groupIndex) +void QmitkMultiLabelTreeModel::OnGroupModified(SpatialGroupIndexType groupIndex) { //currently not needed } -void QmitkMultiLabelSegmentationTreeModel::OnGroupRemoved(SpatialGroupIndexType groupIndex) +void QmitkMultiLabelTreeModel::OnGroupRemoved(SpatialGroupIndexType groupIndex) { if (m_ShowGroups) { this->beginRemoveRows(QModelIndex(), groupIndex, groupIndex); auto root = m_RootItem.get(); root->RemoveChild(groupIndex); this->endRemoveRows(); } } -//TODO -//treeview ableiten und selection command überschreiben. soll nur reagieren by labels bzw instancen, wenn es welche gibt -//und nur in column 0 diff --git a/Modules/SegmentationUI/Qmitk/QmitkMultiLabelSegmentationTreeModel.h b/Modules/SegmentationUI/Qmitk/QmitkMultiLabelTreeModel.h similarity index 88% rename from Modules/SegmentationUI/Qmitk/QmitkMultiLabelSegmentationTreeModel.h rename to Modules/SegmentationUI/Qmitk/QmitkMultiLabelTreeModel.h index 73def6eb8f..1cef2abe4d 100644 --- a/Modules/SegmentationUI/Qmitk/QmitkMultiLabelSegmentationTreeModel.h +++ b/Modules/SegmentationUI/Qmitk/QmitkMultiLabelTreeModel.h @@ -1,108 +1,108 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ -#ifndef QmitkMultiLabelSegmentationTreeModel_h -#define QmitkMultiLabelSegmentationTreeModel_h +#ifndef QmitkMultiLabelTreeModel_h +#define QmitkMultiLabelTreeModel_h #include "mitkLabelSetImage.h" // qt #include #include "MitkSegmentationUIExports.h" class QmitkMultiLabelSegTreeItem; /*! -\class QmitkMultiLabelSegmentationTreeModel +\class QmitkMultiLabelTreeModel The class is used to represent the information of an MITK MultiLabel segmentation instance (labels, spacial groups...). */ -class MITKSEGMENTATIONUI_EXPORT QmitkMultiLabelSegmentationTreeModel : public QAbstractItemModel +class MITKSEGMENTATIONUI_EXPORT QmitkMultiLabelTreeModel : public QAbstractItemModel { Q_OBJECT public: using LabelValueType = mitk::LabelSetImage::LabelValueType; using SpatialGroupIndexType = mitk::LabelSetImage::SpatialGroupIndexType; - QmitkMultiLabelSegmentationTreeModel(QObject *parent = nullptr); - ~QmitkMultiLabelSegmentationTreeModel() override; + QmitkMultiLabelTreeModel(QObject *parent = nullptr); + ~QmitkMultiLabelTreeModel() override; void SetSegmentation(mitk::LabelSetImage* segmentation); const mitk::LabelSetImage* GetSegmentation() const; Qt::ItemFlags flags(const QModelIndex &index) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override; QVariant headerData(int section, Qt::Orientation orientation, int role) const override; int rowCount(const QModelIndex &parent = QModelIndex()) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override; QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; QModelIndex parent(const QModelIndex &child) const override; enum TableColumns { NAME_COL = 0, LOCKED_COL, COLOR_COL, VISIBLE_COL }; enum ItemModelRole { LabelDataRole = 64, LabelValueRole = 65, //this role returns the value of the label instance. //If index is in a row that does not represent a a Label instance //an invalid QVarient will be returned. }; signals: void dataAvailable(); /** Is emitted whenever the model changes are finished (usually a bit later than dataAvailable()).*/ void modelChanged(); protected: void OnLabelAdded(LabelValueType labelValue); void OnLabelModified(LabelValueType labelValue); void OnLabelRemoved(LabelValueType labelValue); void OnGroupAdded(SpatialGroupIndexType groupIndex); void OnGroupModified(SpatialGroupIndexType groupIndex); void OnGroupRemoved(SpatialGroupIndexType groupIndex); private: void AddObserver(); void RemoveObserver(); void UpdateInternalTree(); void GenerateInternalGroupTree(unsigned int layerID, QmitkMultiLabelSegTreeItem* layerItem); QmitkMultiLabelSegTreeItem* GenerateInternalTree(); /* builds a hierarchical tree model for the image statistics 1. Level: Image --> 2. Level: Mask [if exist] --> 3. Level: Timestep [if >1 exist] */ void BuildHierarchicalModel(); mitk::LabelSetImage::Pointer m_Segmentation; std::mutex m_Mutex; std::unique_ptr m_RootItem; bool m_Observed; bool m_ShowGroups = true; }; -#endif // mitkQmitkMultiLabelSegmentationTreeModel_h +#endif // mitkQmitkMultiLabelTreeModel_h diff --git a/Modules/SegmentationUI/Qmitk/QmitkMultiLabelSegmentationTreeView.cpp b/Modules/SegmentationUI/Qmitk/QmitkMultiLabelTreeView.cpp similarity index 55% rename from Modules/SegmentationUI/Qmitk/QmitkMultiLabelSegmentationTreeView.cpp rename to Modules/SegmentationUI/Qmitk/QmitkMultiLabelTreeView.cpp index ac3c50c7e2..b6cba705c8 100644 --- a/Modules/SegmentationUI/Qmitk/QmitkMultiLabelSegmentationTreeView.cpp +++ b/Modules/SegmentationUI/Qmitk/QmitkMultiLabelTreeView.cpp @@ -1,31 +1,31 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ -#include +#include -#include +#include -QmitkMultiLabelSegmentationTreeView::QmitkMultiLabelSegmentationTreeView(QWidget* parent) : QTreeView(parent) +QmitkMultiLabelTreeView::QmitkMultiLabelTreeView(QWidget* parent) : QTreeView(parent) { } -QItemSelectionModel::SelectionFlags QmitkMultiLabelSegmentationTreeView::selectionCommand(const QModelIndex& index, const QEvent* event) const +QItemSelectionModel::SelectionFlags QmitkMultiLabelTreeView::selectionCommand(const QModelIndex& index, const QEvent* event) const { - auto value = index.data(QmitkMultiLabelSegmentationTreeModel::ItemModelRole::LabelValueRole); + auto value = index.data(QmitkMultiLabelTreeModel::ItemModelRole::LabelValueRole); if (index.column()!=0 || !value.isValid()) { return QItemSelectionModel::NoUpdate; } return QAbstractItemView::selectionCommand(index, event); } diff --git a/Modules/SegmentationUI/Qmitk/QmitkMultiLabelSegmentationTreeView.h b/Modules/SegmentationUI/Qmitk/QmitkMultiLabelTreeView.h similarity index 84% rename from Modules/SegmentationUI/Qmitk/QmitkMultiLabelSegmentationTreeView.h rename to Modules/SegmentationUI/Qmitk/QmitkMultiLabelTreeView.h index 9f4e426494..ba9ef13678 100644 --- a/Modules/SegmentationUI/Qmitk/QmitkMultiLabelSegmentationTreeView.h +++ b/Modules/SegmentationUI/Qmitk/QmitkMultiLabelTreeView.h @@ -1,34 +1,34 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef QMITKMULTILABELSEGMENTATIONTREEVIEW_H #define QMITKMULTILABELSEGMENTATIONTREEVIEW_H #include #include /* * @brief This is an inspector that offers a simple list view on a data storage. */ -class MITKSEGMENTATIONUI_EXPORT QmitkMultiLabelSegmentationTreeView : public QTreeView +class MITKSEGMENTATIONUI_EXPORT QmitkMultiLabelTreeView : public QTreeView { Q_OBJECT public: - QmitkMultiLabelSegmentationTreeView(QWidget* parent = nullptr); + QmitkMultiLabelTreeView(QWidget* parent = nullptr); protected: QItemSelectionModel::SelectionFlags selectionCommand(const QModelIndex& index, const QEvent* event = nullptr) const override; }; #endif // QMITKDATASTORAGELISTINSPECTOR_H diff --git a/Modules/SegmentationUI/files.cmake b/Modules/SegmentationUI/files.cmake index 15b7ba8b5b..37a210ef5d 100644 --- a/Modules/SegmentationUI/files.cmake +++ b/Modules/SegmentationUI/files.cmake @@ -1,110 +1,110 @@ set(CPP_FILES Qmitk/QmitkSegWithPreviewToolGUIBase.cpp Qmitk/QmitkMultiLabelSegWithPreviewToolGUIBase.cpp Qmitk/QmitkBinaryThresholdToolGUIBase.cpp Qmitk/QmitkBinaryThresholdToolGUI.cpp Qmitk/QmitkBinaryThresholdULToolGUI.cpp Qmitk/QmitkConfirmSegmentationDialog.cpp Qmitk/QmitkCopyToClipBoardDialog.cpp Qmitk/QmitkDrawPaintbrushToolGUI.cpp Qmitk/QmitkErasePaintbrushToolGUI.cpp Qmitk/QmitkEditableContourToolGUIBase.cpp Qmitk/QmitkGrowCutToolGUI.cpp Qmitk/QmitkLiveWireTool2DGUI.cpp Qmitk/QmitkLassoToolGUI.cpp Qmitk/QmitkOtsuTool3DGUI.cpp Qmitk/QmitkPaintbrushToolGUI.cpp Qmitk/QmitkPickingToolGUI.cpp Qmitk/QmitkSlicesInterpolator.cpp Qmitk/QmitkToolGUI.cpp Qmitk/QmitkToolGUIArea.cpp Qmitk/QmitkToolSelectionBox.cpp Qmitk/QmitknnUNetFolderParser.cpp Qmitk/QmitknnUNetToolGUI.cpp Qmitk/QmitknnUNetWorker.cpp Qmitk/QmitknnUNetGPU.cpp Qmitk/QmitkSurfaceStampWidget.cpp Qmitk/QmitkMaskStampWidget.cpp Qmitk/QmitkStaticDynamicSegmentationDialog.cpp Qmitk/QmitkSimpleLabelSetListWidget.cpp Qmitk/QmitkSegmentationTaskListWidget.cpp - Qmitk/QmitkMultiLabelSegmentationInspector.cpp - Qmitk/QmitkMultiLabelSegmentationTreeModel.cpp - Qmitk/QmitkMultiLabelSegmentationTreeView.cpp + Qmitk/QmitkMultiLabelInspector.cpp + Qmitk/QmitkMultiLabelTreeModel.cpp + Qmitk/QmitkMultiLabelTreeView.cpp Qmitk/QmitkLabelColorItemDelegate.cpp Qmitk/QmitkLabelToggleItemDelegate.cpp SegmentationUtilities/QmitkBooleanOperationsWidget.cpp SegmentationUtilities/QmitkContourModelToImageWidget.cpp SegmentationUtilities/QmitkImageMaskingWidget.cpp SegmentationUtilities/QmitkMorphologicalOperationsWidget.cpp SegmentationUtilities/QmitkSurfaceToImageWidget.cpp SegmentationUtilities/QmitkSegmentationUtilityWidget.cpp SegmentationUtilities/QmitkDataSelectionWidget.cpp ) set(MOC_H_FILES Qmitk/QmitkSegWithPreviewToolGUIBase.h Qmitk/QmitkMultiLabelSegWithPreviewToolGUIBase.h Qmitk/QmitkBinaryThresholdToolGUIBase.h Qmitk/QmitkBinaryThresholdToolGUI.h Qmitk/QmitkBinaryThresholdULToolGUI.h Qmitk/QmitkConfirmSegmentationDialog.h Qmitk/QmitkCopyToClipBoardDialog.h Qmitk/QmitkDrawPaintbrushToolGUI.h Qmitk/QmitkErasePaintbrushToolGUI.h Qmitk/QmitkEditableContourToolGUIBase.h Qmitk/QmitkGrowCutToolGUI.h Qmitk/QmitkLiveWireTool2DGUI.h Qmitk/QmitkLassoToolGUI.h Qmitk/QmitkOtsuTool3DGUI.h Qmitk/QmitkPaintbrushToolGUI.h Qmitk/QmitkPickingToolGUI.h Qmitk/QmitkSlicesInterpolator.h Qmitk/QmitkToolGUI.h Qmitk/QmitkToolGUIArea.h Qmitk/QmitkToolSelectionBox.h Qmitk/QmitknnUNetFolderParser.h Qmitk/QmitknnUNetToolGUI.h Qmitk/QmitknnUNetGPU.h Qmitk/QmitknnUNetWorker.h Qmitk/QmitknnUNetEnsembleLayout.h Qmitk/QmitkSurfaceStampWidget.h Qmitk/QmitkMaskStampWidget.h Qmitk/QmitkStaticDynamicSegmentationDialog.h Qmitk/QmitkSimpleLabelSetListWidget.h Qmitk/QmitkSegmentationTaskListWidget.h - Qmitk/QmitkMultiLabelSegmentationInspector.h - Qmitk/QmitkMultiLabelSegmentationTreeModel.h - Qmitk/QmitkMultiLabelSegmentationTreeView.h + Qmitk/QmitkMultiLabelInspector.h + Qmitk/QmitkMultiLabelTreeModel.h + Qmitk/QmitkMultiLabelTreeView.h Qmitk/QmitkLabelColorItemDelegate.h Qmitk/QmitkLabelToggleItemDelegate.h SegmentationUtilities/QmitkBooleanOperationsWidget.h SegmentationUtilities/QmitkContourModelToImageWidget.h SegmentationUtilities/QmitkImageMaskingWidget.h SegmentationUtilities/QmitkMorphologicalOperationsWidget.h SegmentationUtilities/QmitkSurfaceToImageWidget.h SegmentationUtilities/QmitkSegmentationUtilityWidget.h SegmentationUtilities/QmitkDataSelectionWidget.h ) set(UI_FILES Qmitk/QmitkConfirmSegmentationDialog.ui Qmitk/QmitkGrowCutToolWidgetControls.ui Qmitk/QmitkOtsuToolWidgetControls.ui Qmitk/QmitkSurfaceStampWidgetGUIControls.ui Qmitk/QmitkMaskStampWidgetGUIControls.ui Qmitk/QmitknnUNetToolGUIControls.ui Qmitk/QmitkEditableContourToolGUIControls.ui Qmitk/QmitkSegmentationTaskListWidget.ui - Qmitk/QmitkMultiLabelSegmentationInspector.ui + Qmitk/QmitkMultiLabelInspectorControls.ui SegmentationUtilities/QmitkBooleanOperationsWidgetControls.ui SegmentationUtilities/QmitkContourModelToImageWidgetControls.ui SegmentationUtilities/QmitkImageMaskingWidgetControls.ui SegmentationUtilities/QmitkMorphologicalOperationsWidgetControls.ui SegmentationUtilities/QmitkSurfaceToImageWidgetControls.ui SegmentationUtilities/QmitkDataSelectionWidgetControls.ui ) set(QRC_FILES resources/SegmentationUI.qrc ) diff --git a/Modules/SegmentationUI/test/QmitkMultiLabelSegmentationTreeModelTest.cpp b/Modules/SegmentationUI/test/QmitkMultiLabelTreeModelTest.cpp similarity index 94% rename from Modules/SegmentationUI/test/QmitkMultiLabelSegmentationTreeModelTest.cpp rename to Modules/SegmentationUI/test/QmitkMultiLabelTreeModelTest.cpp index 2d68821e47..4cb8931a2d 100644 --- a/Modules/SegmentationUI/test/QmitkMultiLabelSegmentationTreeModelTest.cpp +++ b/Modules/SegmentationUI/test/QmitkMultiLabelTreeModelTest.cpp @@ -1,543 +1,543 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include -#include "QmitkMultiLabelSegmentationTreeModel.h" +#include "QmitkMultiLabelTreeModel.h" #include #include -class QmitkMultiLabelSegmentationTreeModelTestSuite : public mitk::TestFixture +class QmitkMultiLabelTreeModelTestSuite : public mitk::TestFixture { - CPPUNIT_TEST_SUITE(QmitkMultiLabelSegmentationTreeModelTestSuite); + CPPUNIT_TEST_SUITE(QmitkMultiLabelTreeModelTestSuite); MITK_TEST(NullTest); MITK_TEST(GetterSetterTest); MITK_TEST(AddingLabelTest); MITK_TEST(AddingLayerTest); MITK_TEST(RemovingLabelTest); MITK_TEST(RemovingLayerTest); MITK_TEST(ModifyLabelNameTest); MITK_TEST(ModifyLabelTest); CPPUNIT_TEST_SUITE_END(); mitk::LabelSetImage::Pointer m_Segmentation; QCoreApplication* m_TestApp; public: mitk::LabelSetImage::Pointer GenerateSegmentation() { // Create a new labelset image auto seg = mitk::LabelSetImage::New(); mitk::Image::Pointer regularImage = mitk::Image::New(); unsigned int dimensions[3] = { 5, 5, 5 }; regularImage->Initialize(mitk::MakeScalarPixelType(), 3, dimensions); seg->Initialize(regularImage); return seg; } QColor GetQColor(const mitk::Label* label) { return QColor(label->GetColor().GetRed() * 255, label->GetColor().GetGreen() * 255, label->GetColor().GetBlue() * 255); } mitk::Label::Pointer CreateLabel(const std::string& name, mitk::Label::PixelType value) { auto label = mitk::Label::New(); label->SetName(name); label->SetValue(value); label->SetColor(mitk::Color(value / 255.)); return label; } /** Populate a seg with a following setup (in brackets the order of addition). * - Group 1 (1) * - Label A * - Instance 1 (1) * - Instance 5 (2) * - Instance 10 (8) * - Label B * - Instance 4 (3) * - Label D * - Instance 2 (7) * - Group 2 (4) * - Group 3 (5) * - Label B * - Instance 9 (6) */ void PopulateSegmentation(mitk::LabelSetImage* seg) { seg->SetActiveLayer(0); seg->GetActiveLabelSet()->AddLabel(CreateLabel("A", 1)); seg->GetActiveLabelSet()->AddLabel(CreateLabel("A", 5)); seg->GetActiveLabelSet()->AddLabel(CreateLabel("B", 4)); seg->AddLayer(); seg->AddLayer(); seg->SetActiveLayer(2); seg->GetActiveLabelSet()->AddLabel(CreateLabel("B", 9)); seg->SetActiveLayer(0); seg->GetActiveLabelSet()->AddLabel(CreateLabel("D", 2)); seg->GetActiveLabelSet()->AddLabel(CreateLabel("A", 10)); } void setUp() override { m_Segmentation = GenerateSegmentation(); PopulateSegmentation(m_Segmentation); int argc = 0; char** argv = nullptr; m_TestApp = new QCoreApplication(argc, argv); } void tearDown() override { delete m_TestApp; } - QModelIndex GetIndex(const QmitkMultiLabelSegmentationTreeModel& model, const std::vector& rows, int column = 0) const + QModelIndex GetIndex(const QmitkMultiLabelTreeModel& model, const std::vector& rows, int column = 0) const { QModelIndex testIndex; int i = 0; for (auto row : rows) { if (i + 1 < rows.size()) { testIndex = model.index(row, 0, testIndex); } else { testIndex = model.index(row, column, testIndex); } i++; } return testIndex; } - bool CheckModelItem(const QmitkMultiLabelSegmentationTreeModel& model, const std::vector& rows, const QVariant& reference, int column = 0, const mitk::Label* label = nullptr) const + bool CheckModelItem(const QmitkMultiLabelTreeModel& model, const std::vector& rows, const QVariant& reference, int column = 0, const mitk::Label* label = nullptr) const { QModelIndex testIndex = GetIndex(model, rows, column); auto value = model.data(testIndex); bool test = value == reference; if (!test) std::cerr << std::endl <<" Model item error. Expected: '" << reference.toString().toStdString() << "'; actual: '" << value.toString().toStdString() <<"'"; return test; } - bool CheckModelRow(const QmitkMultiLabelSegmentationTreeModel& model, const std::vector& rows, const std::vector references) const + bool CheckModelRow(const QmitkMultiLabelTreeModel& model, const std::vector& rows, const std::vector references) const { int column = 0; bool test = true; for (const auto& ref : references) { test = test & CheckModelItem(model, rows, ref, column, nullptr); column++; } return test; } - void CheckModelGroup0Default(const QmitkMultiLabelSegmentationTreeModel& model) + void CheckModelGroup0Default(const QmitkMultiLabelTreeModel& model) { CPPUNIT_ASSERT(CheckModelRow(model, { 0 }, { QString("Group 0"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(3, model.rowCount(GetIndex(model, { 0 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,0 }, { QString("A"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(3, model.rowCount(GetIndex(model, { 0,0 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,0 }, { QString("Instance #1"), QVariant(true), QVariant(QColor(1,1,1)), QVariant(true) })); CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,1 }, { QString("Instance #5"), QVariant(true), QVariant(QColor(5,5,5)), QVariant(true) })); CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,2 }, { QString("Instance #10"), QVariant(true), QVariant(QColor(10,10,10)), QVariant(true) })); CPPUNIT_ASSERT(CheckModelRow(model, { 0,1 }, { QString("B"), QVariant(true), QVariant(QColor(4,4,4)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,1 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,2 }, { QString("D"), QVariant(true), QVariant(QColor(2,2,2)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,2 }))); } - void CheckModelGroup1Default(const QmitkMultiLabelSegmentationTreeModel& model) + void CheckModelGroup1Default(const QmitkMultiLabelTreeModel& model) { CPPUNIT_ASSERT(CheckModelRow(model, { 1 }, { QString("Group 1"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 1 }))); } - void CheckModelGroup2Default(const QmitkMultiLabelSegmentationTreeModel& model) + void CheckModelGroup2Default(const QmitkMultiLabelTreeModel& model) { CPPUNIT_ASSERT(CheckModelRow(model, { 2 }, { QString("Group 2"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(1, model.rowCount(GetIndex(model, { 2 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 2,0 }, { QString("B"), QVariant(true), QVariant(QColor(9,9,9)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 2,0 }))); } - void CheckModelDefault(const QmitkMultiLabelSegmentationTreeModel& model) + void CheckModelDefault(const QmitkMultiLabelTreeModel& model) { CPPUNIT_ASSERT_EQUAL(3, model.rowCount(QModelIndex())); CheckModelGroup0Default(model); CheckModelGroup1Default(model); CheckModelGroup2Default(model); } void NullTest() { - QmitkMultiLabelSegmentationTreeModel model(nullptr); + QmitkMultiLabelTreeModel model(nullptr); CPPUNIT_ASSERT(nullptr == model.GetSegmentation()); } void GetterSetterTest() { - QmitkMultiLabelSegmentationTreeModel model(nullptr); + QmitkMultiLabelTreeModel model(nullptr); model.SetSegmentation(m_Segmentation); CheckModelDefault(model); model.SetSegmentation(nullptr); CPPUNIT_ASSERT(nullptr == model.GetSegmentation()); CPPUNIT_ASSERT(false == model.hasChildren(QModelIndex())); } void AddingLabelTest() { - QmitkMultiLabelSegmentationTreeModel model(nullptr); + QmitkMultiLabelTreeModel model(nullptr); model.SetSegmentation(m_Segmentation); //Add label instance (not visible) to labelwith multiple instances (at the end) m_Segmentation->SetActiveLayer(0); auto newLabel = CreateLabel("A", 100); newLabel->SetVisible(false); m_Segmentation->GetActiveLabelSet()->AddLabel(newLabel); CPPUNIT_ASSERT_EQUAL(3, model.rowCount(QModelIndex())); CPPUNIT_ASSERT(CheckModelRow(model, { 0 }, { QString("Group 0"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(3, model.rowCount(GetIndex(model, { 0 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,0 }, { QString("A"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(4, model.rowCount(GetIndex(model, { 0,0 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,0 }, { QString("Instance #1"), QVariant(true), QVariant(QColor(1,1,1)), QVariant(true) })); CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,1 }, { QString("Instance #5"), QVariant(true), QVariant(QColor(5,5,5)), QVariant(true) })); CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,2 }, { QString("Instance #10"), QVariant(true), QVariant(QColor(10,10,10)), QVariant(true) })); CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,3 }, { QString("Instance #100"), QVariant(true), QVariant(QColor(100,100,100)), QVariant(false) })); CPPUNIT_ASSERT(CheckModelRow(model, { 0,1 }, { QString("B"), QVariant(true), QVariant(QColor(4,4,4)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,1 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,2 }, { QString("D"), QVariant(true), QVariant(QColor(2,2,2)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,2 }))); CheckModelGroup1Default(model); CheckModelGroup2Default(model); //Add label instance (not locked) to label with multiple instances (in between) m_Segmentation->SetActiveLayer(0); newLabel = CreateLabel("A", 7); newLabel->SetLocked(false); m_Segmentation->GetActiveLabelSet()->AddLabel(newLabel); CPPUNIT_ASSERT_EQUAL(3, model.rowCount(QModelIndex())); CPPUNIT_ASSERT(CheckModelRow(model, { 0 }, { QString("Group 0"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(3, model.rowCount(GetIndex(model, { 0 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,0 }, { QString("A"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(5, model.rowCount(GetIndex(model, { 0,0 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,0 }, { QString("Instance #1"), QVariant(true), QVariant(QColor(1,1,1)), QVariant(true) })); CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,1 }, { QString("Instance #5"), QVariant(true), QVariant(QColor(5,5,5)), QVariant(true) })); CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,2 }, { QString("Instance #7"), QVariant(false), QVariant(QColor(7,7,7)), QVariant(true) })); CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,3 }, { QString("Instance #10"), QVariant(true), QVariant(QColor(10,10,10)), QVariant(true) })); CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,4 }, { QString("Instance #100"), QVariant(true), QVariant(QColor(100,100,100)), QVariant(false) })); CPPUNIT_ASSERT(CheckModelRow(model, { 0,1 }, { QString("B"), QVariant(true), QVariant(QColor(4,4,4)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,1 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,2 }, { QString("D"), QVariant(true), QVariant(QColor(2,2,2)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,2 }))); CheckModelGroup1Default(model); CheckModelGroup2Default(model); //reset everything m_Segmentation = GenerateSegmentation(); PopulateSegmentation(m_Segmentation); model.SetSegmentation(m_Segmentation); //Add label instance to an empty group m_Segmentation->SetActiveLayer(1); newLabel = CreateLabel("A", 3); m_Segmentation->GetActiveLabelSet()->AddLabel(newLabel); CPPUNIT_ASSERT_EQUAL(3, model.rowCount(QModelIndex())); CheckModelGroup0Default(model); CPPUNIT_ASSERT(CheckModelRow(model, { 1 }, { QString("Group 1"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(1, model.rowCount(GetIndex(model, { 1 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 1,0 }, { QString("A"), QVariant(true), QVariant(QColor(3,3,3)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 1,0 }))); CheckModelGroup2Default(model); } void AddingLayerTest() { - QmitkMultiLabelSegmentationTreeModel model(nullptr); + QmitkMultiLabelTreeModel model(nullptr); model.SetSegmentation(m_Segmentation); m_Segmentation->AddLayer(); CPPUNIT_ASSERT_EQUAL(4, model.rowCount(QModelIndex())); CheckModelGroup0Default(model); CheckModelGroup1Default(model); CheckModelGroup2Default(model); CPPUNIT_ASSERT(CheckModelRow(model, { 3 }, { QString("Group 3"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 3 }))); } void RemovingLabelTest() { - QmitkMultiLabelSegmentationTreeModel model(nullptr); + QmitkMultiLabelTreeModel model(nullptr); model.SetSegmentation(m_Segmentation); //remove label instance from label with multiple instances (middel) m_Segmentation->RemoveLabel(5, 0); CPPUNIT_ASSERT_EQUAL(3, model.rowCount(QModelIndex())); CPPUNIT_ASSERT(CheckModelRow(model, { 0 }, { QString("Group 0"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(3, model.rowCount(GetIndex(model, { 0 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,0 }, { QString("A"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(2, model.rowCount(GetIndex(model, { 0,0 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,0 }, { QString("Instance #1"), QVariant(true), QVariant(QColor(1,1,1)), QVariant(true) })); CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,1 }, { QString("Instance #10"), QVariant(true), QVariant(QColor(10,10,10)), QVariant(true) })); CPPUNIT_ASSERT(CheckModelRow(model, { 0,1 }, { QString("B"), QVariant(true), QVariant(QColor(4,4,4)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,1 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,2 }, { QString("D"), QVariant(true), QVariant(QColor(2,2,2)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,2 }))); CheckModelGroup1Default(model); CheckModelGroup2Default(model); //remove label instance from label with multiple instances (first) m_Segmentation->RemoveLabel(1, 0); CPPUNIT_ASSERT_EQUAL(3, model.rowCount(QModelIndex())); CPPUNIT_ASSERT(CheckModelRow(model, { 0 }, { QString("Group 0"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(3, model.rowCount(GetIndex(model, { 0 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,0 }, { QString("A"), QVariant(true), QVariant(QColor(10,10,10)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,0 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,1 }, { QString("B"), QVariant(true), QVariant(QColor(4,4,4)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,1 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,2 }, { QString("D"), QVariant(true), QVariant(QColor(2,2,2)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,2 }))); CheckModelGroup1Default(model); CheckModelGroup2Default(model); //reset everything m_Segmentation = GenerateSegmentation(); PopulateSegmentation(m_Segmentation); model.SetSegmentation(m_Segmentation); //remove label instance from label with multiple instances (at the end) m_Segmentation->RemoveLabel(10, 0); CPPUNIT_ASSERT_EQUAL(3, model.rowCount(QModelIndex())); CPPUNIT_ASSERT(CheckModelRow(model, { 0 }, { QString("Group 0"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(3, model.rowCount(GetIndex(model, { 0 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,0 }, { QString("A"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(2, model.rowCount(GetIndex(model, { 0,0 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,0 }, { QString("Instance #1"), QVariant(true), QVariant(QColor(1,1,1)), QVariant(true) })); CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,1 }, { QString("Instance #5"), QVariant(true), QVariant(QColor(5,5,5)), QVariant(true) })); CPPUNIT_ASSERT(CheckModelRow(model, { 0,1 }, { QString("B"), QVariant(true), QVariant(QColor(4,4,4)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,1 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,2 }, { QString("D"), QVariant(true), QVariant(QColor(2,2,2)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,2 }))); CheckModelGroup1Default(model); CheckModelGroup2Default(model); //reset everything m_Segmentation = GenerateSegmentation(); PopulateSegmentation(m_Segmentation); model.SetSegmentation(m_Segmentation); //remove label instance from label with only one instance m_Segmentation->RemoveLabel(9, 2); CPPUNIT_ASSERT_EQUAL(3, model.rowCount(QModelIndex())); CheckModelGroup0Default(model); CheckModelGroup1Default(model); CPPUNIT_ASSERT(CheckModelRow(model, { 2 }, { QString("Group 2"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 2 }))); } void RemovingLayerTest() { - QmitkMultiLabelSegmentationTreeModel model(nullptr); + QmitkMultiLabelTreeModel model(nullptr); model.SetSegmentation(m_Segmentation); //remove group in the middle m_Segmentation->SetActiveLayer(1); m_Segmentation->RemoveLayer(); CPPUNIT_ASSERT_EQUAL(2, model.rowCount(QModelIndex())); CheckModelGroup0Default(model); CPPUNIT_ASSERT(CheckModelRow(model, { 1 }, { QString("Group 1"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(1, model.rowCount(GetIndex(model, { 1 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 1,0 }, { QString("B"), QVariant(true), QVariant(QColor(9,9,9)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 1,0 }))); //remove groups in the end m_Segmentation->SetActiveLayer(1); m_Segmentation->RemoveLayer(); CPPUNIT_ASSERT_EQUAL(1, model.rowCount(QModelIndex())); CheckModelGroup0Default(model); //remove all groups m_Segmentation->SetActiveLayer(0); m_Segmentation->RemoveLayer(); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(QModelIndex())); //reset everything m_Segmentation = GenerateSegmentation(); PopulateSegmentation(m_Segmentation); model.SetSegmentation(m_Segmentation); //remove first group m_Segmentation->SetActiveLayer(0); m_Segmentation->RemoveLayer(); CPPUNIT_ASSERT_EQUAL(2, model.rowCount(QModelIndex())); CPPUNIT_ASSERT(CheckModelRow(model, { 0 }, { QString("Group 0"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 1 }, { QString("Group 1"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(1, model.rowCount(GetIndex(model, { 1 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 1,0 }, { QString("B"), QVariant(true), QVariant(QColor(9,9,9)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 1,0 }))); } void ModifyLabelNameTest() { - QmitkMultiLabelSegmentationTreeModel model(nullptr); + QmitkMultiLabelTreeModel model(nullptr); model.SetSegmentation(m_Segmentation); //move from multiple instance to new label in the middle auto label = m_Segmentation->GetLabel(5,0); label->SetName("C"); CPPUNIT_ASSERT_EQUAL(3, model.rowCount(QModelIndex())); CPPUNIT_ASSERT(CheckModelRow(model, { 0 }, { QString("Group 0"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(4, model.rowCount(GetIndex(model, { 0 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,0 }, { QString("A"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(2, model.rowCount(GetIndex(model, { 0,0 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,0 }, { QString("Instance #1"), QVariant(true), QVariant(QColor(1,1,1)), QVariant(true) })); CPPUNIT_ASSERT(CheckModelRow(model, { 0,0,1 }, { QString("Instance #10"), QVariant(true), QVariant(QColor(10,10,10)), QVariant(true) })); CPPUNIT_ASSERT(CheckModelRow(model, { 0,1 }, { QString("B"), QVariant(true), QVariant(QColor(4,4,4)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,1 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,2 }, { QString("C"), QVariant(true), QVariant(QColor(5,5,5)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,2 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,3 }, { QString("D"), QVariant(true), QVariant(QColor(2,2,2)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,3 }))); CheckModelGroup1Default(model); CheckModelGroup2Default(model); //move from multiple instance to new label at the end label = m_Segmentation->GetLabel(10, 0); label->SetName("E"); CPPUNIT_ASSERT_EQUAL(3, model.rowCount(QModelIndex())); CPPUNIT_ASSERT(CheckModelRow(model, { 0 }, { QString("Group 0"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(5, model.rowCount(GetIndex(model, { 0 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,0 }, { QString("A"), QVariant(true), QVariant(QColor(1,1,1)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,0 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,1 }, { QString("B"), QVariant(true), QVariant(QColor(4,4,4)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,1 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,2 }, { QString("C"), QVariant(true), QVariant(QColor(5,5,5)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,2 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,3 }, { QString("D"), QVariant(true), QVariant(QColor(2,2,2)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,3 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,4 }, { QString("E"), QVariant(true), QVariant(QColor(10,10,10)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,4 }))); CheckModelGroup1Default(model); CheckModelGroup2Default(model); //move last instance to new label label = m_Segmentation->GetLabel(10, 0); label->SetName("F"); CPPUNIT_ASSERT_EQUAL(3, model.rowCount(QModelIndex())); CPPUNIT_ASSERT(CheckModelRow(model, { 0 }, { QString("Group 0"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(5, model.rowCount(GetIndex(model, { 0 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,0 }, { QString("A"), QVariant(true), QVariant(QColor(1,1,1)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,0 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,1 }, { QString("B"), QVariant(true), QVariant(QColor(4,4,4)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,1 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,2 }, { QString("C"), QVariant(true), QVariant(QColor(5,5,5)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,2 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,3 }, { QString("D"), QVariant(true), QVariant(QColor(2,2,2)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,3 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,4 }, { QString("F"), QVariant(true), QVariant(QColor(10,10,10)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,4 }))); CheckModelGroup1Default(model); CheckModelGroup2Default(model); //move last instance to an existing label label->SetName("B"); CPPUNIT_ASSERT_EQUAL(3, model.rowCount(QModelIndex())); CPPUNIT_ASSERT(CheckModelRow(model, { 0 }, { QString("Group 0"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(4, model.rowCount(GetIndex(model, { 0 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,0 }, { QString("A"), QVariant(true), QVariant(QColor(1,1,1)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,0 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,1 }, { QString("B"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(2, model.rowCount(GetIndex(model, { 0,1 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,1,0 }, { QString("Instance #4"), QVariant(true), QVariant(QColor(4,4,4)), QVariant(true) })); CPPUNIT_ASSERT(CheckModelRow(model, { 0,1,1 }, { QString("Instance #10"), QVariant(true), QVariant(QColor(10,10,10)), QVariant(true) })); CPPUNIT_ASSERT(CheckModelRow(model, { 0,2 }, { QString("C"), QVariant(true), QVariant(QColor(5,5,5)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,2 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 0,3 }, { QString("D"), QVariant(true), QVariant(QColor(2,2,2)), QVariant(true) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 0,3 }))); CheckModelGroup1Default(model); CheckModelGroup2Default(model); } void ModifyLabelTest() { - QmitkMultiLabelSegmentationTreeModel model(nullptr); + QmitkMultiLabelTreeModel model(nullptr); model.SetSegmentation(m_Segmentation); auto label = m_Segmentation->GetLabel(9, 2); //check single instance modifications label->SetVisible(false); CPPUNIT_ASSERT_EQUAL(3, model.rowCount(QModelIndex())); CheckModelGroup0Default(model); CheckModelGroup1Default(model); CPPUNIT_ASSERT(CheckModelRow(model, { 2 }, { QString("Group 2"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(1, model.rowCount(GetIndex(model, { 2 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 2,0 }, { QString("B"), QVariant(true), QVariant(QColor(9,9,9)), QVariant(false) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 2,0 }))); label->SetLocked(false); label->SetColor(mitk::Color(22 / 255.)); CPPUNIT_ASSERT_EQUAL(3, model.rowCount(QModelIndex())); CheckModelGroup0Default(model); CheckModelGroup1Default(model); CPPUNIT_ASSERT(CheckModelRow(model, { 2 }, { QString("Group 2"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(1, model.rowCount(GetIndex(model, { 2 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 2,0 }, { QString("B"), QVariant(false), QVariant(QColor(22,22,22)), QVariant(false) })); CPPUNIT_ASSERT_EQUAL(0, model.rowCount(GetIndex(model, { 2,0 }))); //check instance modifications with multi instance label m_Segmentation->SetActiveLayer(2); m_Segmentation->GetActiveLabelSet()->AddLabel(CreateLabel("B", 33)); label->SetVisible(true); CPPUNIT_ASSERT_EQUAL(3, model.rowCount(QModelIndex())); CheckModelGroup0Default(model); CheckModelGroup1Default(model); CPPUNIT_ASSERT(CheckModelRow(model, { 2 }, { QString("Group 2"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(1, model.rowCount(GetIndex(model, { 2 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 2,0 }, { QString("B"), QVariant(), QVariant(), QVariant() })); CPPUNIT_ASSERT_EQUAL(2, model.rowCount(GetIndex(model, { 2,0 }))); CPPUNIT_ASSERT(CheckModelRow(model, { 2,0,0 }, { QString("Instance #9"), QVariant(false), QVariant(QColor(22,22,22)), QVariant(true) })); CPPUNIT_ASSERT(CheckModelRow(model, { 2,0,1 }, { QString("Instance #33"), QVariant(true), QVariant(QColor(33,33,33)), QVariant(true) })); } }; -MITK_TEST_SUITE_REGISTRATION(QmitkMultiLabelSegmentationTreeModel) +MITK_TEST_SUITE_REGISTRATION(QmitkMultiLabelTreeModel) diff --git a/Modules/SegmentationUI/test/files.cmake b/Modules/SegmentationUI/test/files.cmake index bb7ac62024..f7a7e63e96 100644 --- a/Modules/SegmentationUI/test/files.cmake +++ b/Modules/SegmentationUI/test/files.cmake @@ -1,3 +1,3 @@ set(MODULE_TESTS - QmitkMultiLabelSegmentationTreeModelTest.cpp + QmitkMultiLabelTreeModelTest.cpp ) diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.cpp b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.cpp index 387088ee60..e65f4eb0d9 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.cpp +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.cpp @@ -1,1090 +1,1090 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "QmitkSegmentationView.h" #include "mitkPluginActivator.h" // blueberry #include // mitk #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Qmitk #include #include #include -#include +#include // us #include #include // Qt #include #include #include // vtk #include #include namespace { QList Get2DWindows(const QList allWindows) { QList all2DWindows; for (auto* window : allWindows) { if (window->GetRenderer()->GetMapperID() == mitk::BaseRenderer::Standard2D) { all2DWindows.append(window); } } return all2DWindows; } } const std::string QmitkSegmentationView::VIEW_ID = "org.mitk.views.segmentation"; QmitkSegmentationView::QmitkSegmentationView() : m_Parent(nullptr) , m_Controls(nullptr) , m_RenderWindowPart(nullptr) , m_ToolManager(nullptr) , m_ReferenceNode(nullptr) , m_WorkingNode(nullptr) , m_DrawOutline(true) , m_SelectionMode(false) , m_MouseCursorSet(false) , m_DefaultLabelNaming(true) , m_SelectionChangeIsAlreadyBeingHandled(false) { auto isImage = mitk::TNodePredicateDataType::New(); auto isDwi = mitk::NodePredicateDataType::New("DiffusionImage"); auto isDti = mitk::NodePredicateDataType::New("TensorImage"); auto isOdf = mitk::NodePredicateDataType::New("OdfImage"); auto isSegment = mitk::NodePredicateDataType::New("Segment"); auto validImages = mitk::NodePredicateOr::New(); validImages->AddPredicate(mitk::NodePredicateAnd::New(isImage, mitk::NodePredicateNot::New(isSegment))); validImages->AddPredicate(isDwi); validImages->AddPredicate(isDti); validImages->AddPredicate(isOdf); m_SegmentationPredicate = mitk::NodePredicateAnd::New(); m_SegmentationPredicate->AddPredicate(mitk::TNodePredicateDataType::New()); m_SegmentationPredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))); m_SegmentationPredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("hidden object"))); m_ReferencePredicate = mitk::NodePredicateAnd::New(); m_ReferencePredicate->AddPredicate(validImages); m_ReferencePredicate->AddPredicate(mitk::NodePredicateNot::New(m_SegmentationPredicate)); m_ReferencePredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))); m_ReferencePredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("hidden object"))); } QmitkSegmentationView::~QmitkSegmentationView() { if (nullptr != m_Controls) { this->LooseLabelSetConnection(); // deactivate all tools m_ToolManager->ActivateTool(-1); // removing all observers from working data for (NodeTagMapType::iterator dataIter = m_WorkingDataObserverTags.begin(); dataIter != m_WorkingDataObserverTags.end(); ++dataIter) { (*dataIter).first->GetProperty("visible")->RemoveObserver((*dataIter).second); } m_WorkingDataObserverTags.clear(); // removing all observers from reference data for (NodeTagMapType::iterator dataIter = m_ReferenceDataObserverTags.begin(); dataIter != m_ReferenceDataObserverTags.end(); ++dataIter) { (*dataIter).first->GetProperty("visible")->RemoveObserver((*dataIter).second); } m_ReferenceDataObserverTags.clear(); mitk::RenderingManager::GetInstance()->RemoveObserver(m_RenderingManagerObserverTag); ctkPluginContext* context = mitk::PluginActivator::getContext(); ctkServiceReference ppmRef = context->getServiceReference(); mitk::PlanePositionManagerService* service = context->getService(ppmRef); service->RemoveAllPlanePositions(); context->ungetService(ppmRef); m_ToolManager->SetReferenceData(nullptr); m_ToolManager->SetWorkingData(nullptr); } m_ToolManager->ActiveToolChanged -= mitk::MessageDelegate(this, &QmitkSegmentationView::ActiveToolChanged); delete m_Controls; } /**********************************************************************/ /* private Q_SLOTS */ /**********************************************************************/ void QmitkSegmentationView::OnReferenceSelectionChanged(QList) { this->OnAnySelectionChanged(); } void QmitkSegmentationView::OnSegmentationSelectionChanged(QList) { this->OnAnySelectionChanged(); } void QmitkSegmentationView::OnAnySelectionChanged() { // When only a segmentation has been selected and the method is then called by a reference image selection, // the already selected segmentation may not match the geometry predicate of the new reference image anymore. // This will trigger a recursive call of this method further below. While it would be resolved gracefully, we // can spare the extra call with an early-out. The original call of this method will handle the segmentation // selection change afterwards anyway. if (m_SelectionChangeIsAlreadyBeingHandled) return; auto selectedReferenceNode = m_Controls->referenceNodeSelector->GetSelectedNode(); bool referenceNodeChanged = false; m_ToolManager->ActivateTool(-1); if (m_ReferenceNode != selectedReferenceNode) { referenceNodeChanged = true; // Remove visibility observer for the current reference node if (m_ReferenceDataObserverTags.find(m_ReferenceNode) != m_ReferenceDataObserverTags.end()) { m_ReferenceNode->GetProperty("visible")->RemoveObserver(m_ReferenceDataObserverTags[m_ReferenceNode]); m_ReferenceDataObserverTags.erase(m_ReferenceNode); } // Set new reference node m_ReferenceNode = selectedReferenceNode; m_ToolManager->SetReferenceData(m_ReferenceNode); // Prepare for a potential recursive call when changing node predicates of the working node selector m_SelectionChangeIsAlreadyBeingHandled = true; if (m_ReferenceNode.IsNull()) { // Without a reference image, allow all segmentations to be selected m_Controls->workingNodeSelector->SetNodePredicate(m_SegmentationPredicate); m_SelectionChangeIsAlreadyBeingHandled = false; } else { // With a reference image, only allow segmentations that fit the geometry of the reference image to be selected. m_Controls->workingNodeSelector->SetNodePredicate(mitk::NodePredicateAnd::New( mitk::NodePredicateSubGeometry::New(m_ReferenceNode->GetData()->GetGeometry()), m_SegmentationPredicate.GetPointer())); m_SelectionChangeIsAlreadyBeingHandled = false; this->ApplySelectionModeOnReferenceNode(); // Add visibility observer for the new reference node auto command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &QmitkSegmentationView::ValidateSelectionInput); m_ReferenceDataObserverTags[m_ReferenceNode] = m_ReferenceNode->GetProperty("visible")->AddObserver(itk::ModifiedEvent(), command); } } auto selectedWorkingNode = m_Controls->workingNodeSelector->GetSelectedNode(); bool workingNodeChanged = false; if (m_WorkingNode != selectedWorkingNode) { workingNodeChanged = true; // Remove visibility observer for the current working node if (m_WorkingDataObserverTags.find(m_WorkingNode) != m_WorkingDataObserverTags.end()) { m_WorkingNode->GetProperty("visible")->RemoveObserver(m_WorkingDataObserverTags[m_WorkingNode]); m_WorkingDataObserverTags.erase(m_WorkingNode); } // Disconnect from current label set image this->LooseLabelSetConnection(); // Set new working node m_WorkingNode = selectedWorkingNode; m_ToolManager->SetWorkingData(m_WorkingNode); if (m_WorkingNode.IsNotNull()) { this->ApplySelectionModeOnWorkingNode(); // Connect to new label set image this->EstablishLabelSetConnection(); m_Controls->labelSetWidget->ResetAllTableWidgetItems(); // Add visibility observer for the new segmentation node auto command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &QmitkSegmentationView::ValidateSelectionInput); m_WorkingDataObserverTags[m_WorkingNode] = m_WorkingNode->GetProperty("visible")->AddObserver(itk::ModifiedEvent(), command); } } // Reset camera if any selection changed but only if both reference node and working node are set if ((referenceNodeChanged || workingNodeChanged) && (m_ReferenceNode.IsNotNull() && m_WorkingNode.IsNotNull())) { if (nullptr != m_RenderWindowPart) { m_RenderWindowPart->InitializeViews(m_ReferenceNode->GetData()->GetTimeGeometry(), false); } } this->UpdateGUI(); } void QmitkSegmentationView::OnVisibilityShortcutActivated() { if (m_WorkingNode.IsNull()) { return; } bool isVisible = false; m_WorkingNode->GetBoolProperty("visible", isVisible); m_WorkingNode->SetVisibility(!isVisible); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkSegmentationView::OnLabelToggleShortcutActivated() { if (m_WorkingNode.IsNull()) { return; } auto workingImage = dynamic_cast(m_WorkingNode->GetData()); if (nullptr == workingImage) { return; } this->WaitCursorOn(); workingImage->GetActiveLabelSet()->SetNextActiveLabel(); workingImage->Modified(); this->WaitCursorOff(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkSegmentationView::OnNewSegmentation() { m_ToolManager->ActivateTool(-1); if (m_ReferenceNode.IsNull()) { MITK_ERROR << "'Create new segmentation' button should never be clickable unless a reference image is selected."; return; } mitk::Image::ConstPointer referenceImage = dynamic_cast(m_ReferenceNode->GetData()); if (referenceImage.IsNull()) { QMessageBox::information( m_Parent, "New segmentation", "Please load and select an image before starting some action."); return; } if (referenceImage->GetDimension() <= 1) { QMessageBox::information( m_Parent, "New segmentation", "Segmentation is currently not supported for 2D images"); return; } auto segTemplateImage = referenceImage; if (referenceImage->GetDimension() > 3) { QmitkStaticDynamicSegmentationDialog dialog(m_Parent); dialog.SetReferenceImage(referenceImage.GetPointer()); dialog.exec(); segTemplateImage = dialog.GetSegmentationTemplate(); } mitk::DataNode::Pointer newSegmentationNode; try { this->WaitCursorOn(); newSegmentationNode = mitk::LabelSetImageHelper::CreateNewSegmentationNode(m_ReferenceNode, segTemplateImage); this->WaitCursorOff(); } catch (mitk::Exception& e) { this->WaitCursorOff(); MITK_ERROR << "Exception caught: " << e.GetDescription(); QMessageBox::warning(m_Parent, "New segmentation", "Could not create a new segmentation."); return; } auto newLabelSetImage = dynamic_cast(newSegmentationNode->GetData()); if (nullptr == newLabelSetImage) { // something went wrong return; } const auto labelSetPreset = this->GetDefaultLabelSetPreset(); if (labelSetPreset.empty() || !mitk::LabelSetIOHelper::LoadLabelSetImagePreset(labelSetPreset, newLabelSetImage)) { auto newLabel = mitk::LabelSetImageHelper::CreateNewLabel(newLabelSetImage); if (!m_DefaultLabelNaming) { QmitkNewSegmentationDialog dialog(m_Parent); dialog.SetName(QString::fromStdString(newLabel->GetName())); dialog.SetColor(newLabel->GetColor()); if (QDialog::Rejected == dialog.exec()) return; auto name = dialog.GetName(); if (!name.isEmpty()) newLabel->SetName(name.toStdString()); newLabel->SetColor(dialog.GetColor()); } newLabelSetImage->GetActiveLabelSet()->AddLabel(newLabel); } if (!this->GetDataStorage()->Exists(newSegmentationNode)) { this->GetDataStorage()->Add(newSegmentationNode, m_ReferenceNode); } if (m_ToolManager->GetWorkingData(0)) { m_ToolManager->GetWorkingData(0)->SetSelected(false); } newSegmentationNode->SetSelected(true); m_Controls->workingNodeSelector->SetCurrentSelectedNode(newSegmentationNode); } std::string QmitkSegmentationView::GetDefaultLabelSetPreset() const { auto labelSetPreset = mitk::BaseApplication::instance().config().getString(mitk::BaseApplication::ARG_SEGMENTATION_LABELSET_PRESET.toStdString(), ""); if (labelSetPreset.empty()) labelSetPreset = m_LabelSetPresetPreference.toStdString(); return labelSetPreset; } void QmitkSegmentationView::OnManualTool2DSelected(int id) { this->ResetMouseCursor(); mitk::StatusBar::GetInstance()->DisplayText(""); if (id >= 0) { std::string text = "Active Tool: \""; text += m_ToolManager->GetToolById(id)->GetName(); text += "\""; mitk::StatusBar::GetInstance()->DisplayText(text.c_str()); us::ModuleResource resource = m_ToolManager->GetToolById(id)->GetCursorIconResource(); this->SetMouseCursor(resource, 0, 0); } } void QmitkSegmentationView::OnShowMarkerNodes(bool state) { mitk::SegTool2D::Pointer manualSegmentationTool; unsigned int numberOfExistingTools = m_ToolManager->GetTools().size(); for (unsigned int i = 0; i < numberOfExistingTools; i++) { manualSegmentationTool = dynamic_cast(m_ToolManager->GetToolById(i)); if (nullptr == manualSegmentationTool) { continue; } manualSegmentationTool->SetShowMarkerNodes(state); } } void QmitkSegmentationView::OnLayersChanged() { this->EstablishLabelSetConnection(); m_Controls->labelSetWidget->ResetAllTableWidgetItems(); } void QmitkSegmentationView::OnShowLabelTable(bool value) { m_Controls->labelSetWidget->setVisible(value); } void QmitkSegmentationView::OnGoToLabel(const mitk::Point3D& pos) { if (m_RenderWindowPart) { m_RenderWindowPart->SetSelectedPosition(pos); } } void QmitkSegmentationView::OnLabelSetWidgetReset() { this->ValidateSelectionInput(); } /**********************************************************************/ /* private */ /**********************************************************************/ void QmitkSegmentationView::CreateQtPartControl(QWidget* parent) { m_Parent = parent; m_Controls = new Ui::QmitkSegmentationViewControls; m_Controls->setupUi(parent); // *------------------------ // * SHORTCUTS // *------------------------ QShortcut* visibilityShortcut = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key::Key_H), parent); connect(visibilityShortcut, &QShortcut::activated, this, &QmitkSegmentationView::OnVisibilityShortcutActivated); QShortcut* labelToggleShortcut = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key::Key_L, Qt::CTRL | Qt::Key::Key_I), parent); connect(labelToggleShortcut, &QShortcut::activated, this, &QmitkSegmentationView::OnLabelToggleShortcutActivated); // *------------------------ // * DATA SELECTION WIDGETS // *------------------------ m_Controls->referenceNodeSelector->SetDataStorage(GetDataStorage()); m_Controls->referenceNodeSelector->SetNodePredicate(m_ReferencePredicate); m_Controls->referenceNodeSelector->SetInvalidInfo("Select an image"); m_Controls->referenceNodeSelector->SetPopUpTitel("Select an image"); m_Controls->referenceNodeSelector->SetPopUpHint("Select an image that should be used to define the geometry and bounds of the segmentation."); m_Controls->workingNodeSelector->SetDataStorage(GetDataStorage()); m_Controls->workingNodeSelector->SetNodePredicate(m_SegmentationPredicate); m_Controls->workingNodeSelector->SetInvalidInfo("Select a segmentation"); m_Controls->workingNodeSelector->SetPopUpTitel("Select a segmentation"); m_Controls->workingNodeSelector->SetPopUpHint("Select a segmentation that should be modified. Only segmentation with the same geometry and within the bounds of the reference image are selected."); connect(m_Controls->referenceNodeSelector, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, this, &QmitkSegmentationView::OnReferenceSelectionChanged); connect(m_Controls->workingNodeSelector, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, this, &QmitkSegmentationView::OnSegmentationSelectionChanged); // *------------------------ // * TOOLMANAGER // *------------------------ m_ToolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); m_ToolManager->SetDataStorage(*(this->GetDataStorage())); m_ToolManager->InitializeTools(); QString segTools2D = tr("Add Subtract Lasso Fill Erase Close Paint Wipe 'Region Growing' 'Live Wire'"); QString segTools3D = tr("Threshold 'UL Threshold' Otsu 'Region Growing 3D' Picking GrowCut"); #ifdef __linux__ segTools3D.append(" nnUNet"); // plugin not enabled for MacOS / Windows #endif std::regex extSegTool2DRegEx("SegTool2D$"); std::regex extSegTool3DRegEx("SegTool3D$"); auto tools = m_ToolManager->GetTools(); for (const auto &tool : tools) { if (std::regex_search(tool->GetNameOfClass(), extSegTool2DRegEx)) { segTools2D.append(QString(" '%1'").arg(tool->GetName())); } else if (std::regex_search(tool->GetNameOfClass(), extSegTool3DRegEx)) { segTools3D.append(QString(" '%1'").arg(tool->GetName())); } } // setup 2D tools m_Controls->toolSelectionBox2D->SetToolManager(*m_ToolManager); m_Controls->toolSelectionBox2D->SetGenerateAccelerators(true); m_Controls->toolSelectionBox2D->SetToolGUIArea(m_Controls->toolGUIArea2D); m_Controls->toolSelectionBox2D->SetDisplayedToolGroups(segTools2D.toStdString()); m_Controls->toolSelectionBox2D->SetLayoutColumns(3); connect(m_Controls->toolSelectionBox2D, &QmitkToolSelectionBox::ToolSelected, this, &QmitkSegmentationView::OnManualTool2DSelected); // setup 3D Tools m_Controls->toolSelectionBox3D->SetToolManager(*m_ToolManager); m_Controls->toolSelectionBox3D->SetGenerateAccelerators(true); m_Controls->toolSelectionBox3D->SetToolGUIArea(m_Controls->toolGUIArea3D); m_Controls->toolSelectionBox3D->SetDisplayedToolGroups(segTools3D.toStdString()); m_Controls->toolSelectionBox3D->SetLayoutColumns(3); m_Controls->slicesInterpolator->SetDataStorage(this->GetDataStorage()); // create general signal / slot connections connect(m_Controls->newSegmentationButton, &QToolButton::clicked, this, &QmitkSegmentationView::OnNewSegmentation); connect(m_Controls->slicesInterpolator, &QmitkSlicesInterpolator::SignalShowMarkerNodes, this, &QmitkSegmentationView::OnShowMarkerNodes); connect(m_Controls->layersWidget, &QmitkLayersWidget::LayersChanged, this, &QmitkSegmentationView::OnLayersChanged); connect(m_Controls->labelsWidget, &QmitkLabelsWidget::ShowLabelTable, this, &QmitkSegmentationView::OnShowLabelTable); // *------------------------ // * LABELSETWIDGET // *------------------------ connect(m_Controls->labelSetWidget, &QmitkLabelSetWidget::goToLabel, this, &QmitkSegmentationView::OnGoToLabel); connect(m_Controls->labelSetWidget, &QmitkLabelSetWidget::LabelSetWidgetReset, this, &QmitkSegmentationView::OnLabelSetWidgetReset); m_Controls->labelSetWidget->SetDataStorage(this->GetDataStorage()); m_Controls->labelSetWidget->hide(); auto command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &QmitkSegmentationView::ValidateSelectionInput); m_RenderingManagerObserverTag = mitk::RenderingManager::GetInstance()->AddObserver(mitk::RenderingManagerViewsInitializedEvent(), command); m_RenderWindowPart = this->GetRenderWindowPart(); if (nullptr != m_RenderWindowPart) { this->RenderWindowPartActivated(m_RenderWindowPart); } // Make sure the GUI notices if appropriate data is already present on creation. // Should be done last, if everything else is configured because it triggers the autoselection of data. m_Controls->referenceNodeSelector->SetAutoSelectNewNodes(true); m_Controls->workingNodeSelector->SetAutoSelectNewNodes(true); - m_Inspector = new QmitkMultiLabelSegmentationInspector(parent); + m_Inspector = new QmitkMultiLabelInspector(parent); m_Controls->verticalLayout->addWidget(m_Inspector); this->UpdateGUI(); } void QmitkSegmentationView::ActiveToolChanged() { if (nullptr == m_RenderWindowPart) { return; } mitk::TimeGeometry* interactionReferenceGeometry = nullptr; auto activeTool = m_ToolManager->GetActiveTool(); if (nullptr != activeTool && m_ReferenceNode.IsNotNull()) { mitk::Image::ConstPointer referenceImage = dynamic_cast(m_ReferenceNode->GetData()); if (referenceImage.IsNotNull()) { // tool activated, reference image available: set reference geometry interactionReferenceGeometry = m_ReferenceNode->GetData()->GetTimeGeometry(); } } // set the interaction reference geometry for the render window part (might be nullptr) m_RenderWindowPart->SetInteractionReferenceGeometry(interactionReferenceGeometry); } void QmitkSegmentationView::RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) { if (m_RenderWindowPart != renderWindowPart) { m_RenderWindowPart = renderWindowPart; } if (nullptr != m_Parent) { m_Parent->setEnabled(true); } if (nullptr == m_Controls) { return; } if (nullptr != m_RenderWindowPart) { auto all2DWindows = Get2DWindows(m_RenderWindowPart->GetQmitkRenderWindows().values()); m_Controls->slicesInterpolator->Initialize(m_ToolManager, all2DWindows); if (!m_RenderWindowPart->HasCoupledRenderWindows()) { // react if the active tool changed, only if a render window part with decoupled render windows is used m_ToolManager->ActiveToolChanged += mitk::MessageDelegate(this, &QmitkSegmentationView::ActiveToolChanged); } } } void QmitkSegmentationView::RenderWindowPartDeactivated(mitk::IRenderWindowPart* /*renderWindowPart*/) { m_RenderWindowPart = nullptr; if (nullptr != m_Parent) { m_Parent->setEnabled(false); } // remove message-connection to make sure no message is processed if no render window part is available m_ToolManager->ActiveToolChanged -= mitk::MessageDelegate(this, &QmitkSegmentationView::ActiveToolChanged); m_Controls->slicesInterpolator->Uninitialize(); } void QmitkSegmentationView::RenderWindowPartInputChanged(mitk::IRenderWindowPart* /*renderWindowPart*/) { if (nullptr == m_RenderWindowPart) { return; } m_Controls->slicesInterpolator->Uninitialize(); auto all2DWindows = Get2DWindows(m_RenderWindowPart->GetQmitkRenderWindows().values()); m_Controls->slicesInterpolator->Initialize(m_ToolManager, all2DWindows); } void QmitkSegmentationView::OnPreferencesChanged(const mitk::IPreferences* prefs) { auto labelSuggestions = mitk::BaseApplication::instance().config().getString(mitk::BaseApplication::ARG_SEGMENTATION_LABEL_SUGGESTIONS.toStdString(), ""); m_DefaultLabelNaming = labelSuggestions.empty() ? prefs->GetBool("default label naming", true) : false; // No default label naming when label suggestions are enforced via command-line argument if (nullptr != m_Controls) { m_Controls->labelsWidget->SetDefaultLabelNaming(m_DefaultLabelNaming); bool slimView = prefs->GetBool("slim view", false); m_Controls->toolSelectionBox2D->SetShowNames(!slimView); m_Controls->toolSelectionBox3D->SetShowNames(!slimView); } m_DrawOutline = prefs->GetBool("draw outline", true); m_SelectionMode = prefs->GetBool("selection mode", false); m_LabelSetPresetPreference = QString::fromStdString(prefs->Get("label set preset", "")); this->ApplyDisplayOptions(); this->ApplySelectionMode(); } void QmitkSegmentationView::NodeAdded(const mitk::DataNode* node) { if (m_SegmentationPredicate->CheckNode(node)) this->ApplyDisplayOptions(const_cast(node)); this->ApplySelectionMode(); } void QmitkSegmentationView::NodeRemoved(const mitk::DataNode* node) { if (!m_SegmentationPredicate->CheckNode(node)) { return; } // remove all possible contour markers of the segmentation mitk::DataStorage::SetOfObjects::ConstPointer allContourMarkers = this->GetDataStorage()->GetDerivations( node, mitk::NodePredicateProperty::New("isContourMarker", mitk::BoolProperty::New(true))); ctkPluginContext* context = mitk::PluginActivator::getContext(); ctkServiceReference ppmRef = context->getServiceReference(); mitk::PlanePositionManagerService* service = context->getService(ppmRef); for (mitk::DataStorage::SetOfObjects::ConstIterator it = allContourMarkers->Begin(); it != allContourMarkers->End(); ++it) { std::string nodeName = node->GetName(); unsigned int t = nodeName.find_last_of(" "); unsigned int id = atof(nodeName.substr(t + 1).c_str()) - 1; service->RemovePlanePosition(id); this->GetDataStorage()->Remove(it->Value()); } context->ungetService(ppmRef); service = nullptr; mitk::Image* image = dynamic_cast(node->GetData()); mitk::SurfaceInterpolationController::GetInstance()->RemoveInterpolationSession(image); } void QmitkSegmentationView::EstablishLabelSetConnection() { if (m_WorkingNode.IsNull()) return; auto workingImage = dynamic_cast(m_WorkingNode->GetData()); if (nullptr == workingImage) return; workingImage->GetActiveLabelSet()->AddLabelEvent += mitk::MessageDelegate1( m_Controls->labelSetWidget, &QmitkLabelSetWidget::ResetAllTableWidgetItems); workingImage->GetActiveLabelSet()->RemoveLabelEvent += mitk::MessageDelegate1( m_Controls->labelSetWidget, &QmitkLabelSetWidget::ResetAllTableWidgetItems); workingImage->GetActiveLabelSet()->ModifyLabelEvent += mitk::MessageDelegate1( m_Controls->labelSetWidget, &QmitkLabelSetWidget::UpdateAllTableWidgetItems); workingImage->GetActiveLabelSet()->AllLabelsModifiedEvent += mitk::MessageDelegate( m_Controls->labelSetWidget, &QmitkLabelSetWidget::UpdateAllTableWidgetItems); workingImage->GetActiveLabelSet()->ActiveLabelEvent += mitk::MessageDelegate1(m_Controls->labelSetWidget, &QmitkLabelSetWidget::SelectLabelByPixelValue); workingImage->AfterChangeLayerEvent += mitk::MessageDelegate( this, &QmitkSegmentationView::UpdateGUI); - workingImage->GetActiveLabelSet()->ActiveLabelEvent += mitk::MessageDelegate1(m_Inspector, &QmitkMultiLabelSegmentationInspector::SetSelectedLabel); + workingImage->GetActiveLabelSet()->ActiveLabelEvent += mitk::MessageDelegate1(m_Inspector, &QmitkMultiLabelInspector::SetSelectedLabel); } void QmitkSegmentationView::LooseLabelSetConnection() { if (m_WorkingNode.IsNull()) return; auto workingImage = dynamic_cast(m_WorkingNode->GetData()); if (nullptr == workingImage) return; workingImage->GetActiveLabelSet()->AddLabelEvent -= mitk::MessageDelegate1( m_Controls->labelSetWidget, &QmitkLabelSetWidget::ResetAllTableWidgetItems); workingImage->GetActiveLabelSet()->RemoveLabelEvent -= mitk::MessageDelegate1( m_Controls->labelSetWidget, &QmitkLabelSetWidget::ResetAllTableWidgetItems); workingImage->GetActiveLabelSet()->ModifyLabelEvent -= mitk::MessageDelegate1( m_Controls->labelSetWidget, &QmitkLabelSetWidget::UpdateAllTableWidgetItems); workingImage->GetActiveLabelSet()->AllLabelsModifiedEvent -= mitk::MessageDelegate( m_Controls->labelSetWidget, &QmitkLabelSetWidget::UpdateAllTableWidgetItems); workingImage->GetActiveLabelSet()->ActiveLabelEvent -= mitk::MessageDelegate1(m_Controls->labelSetWidget, &QmitkLabelSetWidget::SelectLabelByPixelValue); workingImage->AfterChangeLayerEvent -= mitk::MessageDelegate( this, &QmitkSegmentationView::UpdateGUI); } void QmitkSegmentationView::ApplyDisplayOptions() { if (nullptr == m_Parent) { return; } if (nullptr == m_Controls) { return; // might happen on initialization (preferences loaded) } mitk::DataStorage::SetOfObjects::ConstPointer allImages = this->GetDataStorage()->GetSubset(m_SegmentationPredicate); for (mitk::DataStorage::SetOfObjects::const_iterator iter = allImages->begin(); iter != allImages->end(); ++iter) { this->ApplyDisplayOptions(*iter); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkSegmentationView::ApplyDisplayOptions(mitk::DataNode* node) { if (nullptr == node) { return; } auto labelSetImage = dynamic_cast(node->GetData()); if (nullptr == labelSetImage) { return; } // the outline property can be set in the segmentation preference page node->SetProperty("labelset.contour.active", mitk::BoolProperty::New(m_DrawOutline)); // force render window update to show outline mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkSegmentationView::ApplySelectionMode() { if (!m_SelectionMode) return; this->ApplySelectionModeOnReferenceNode(); this->ApplySelectionModeOnWorkingNode(); } void QmitkSegmentationView::ApplySelectionModeOnReferenceNode() { this->ApplySelectionMode(m_ReferenceNode, m_ReferencePredicate); } void QmitkSegmentationView::ApplySelectionModeOnWorkingNode() { this->ApplySelectionMode(m_WorkingNode, m_SegmentationPredicate); } void QmitkSegmentationView::ApplySelectionMode(mitk::DataNode* node, mitk::NodePredicateBase* predicate) { if (!m_SelectionMode || node == nullptr || predicate == nullptr) return; auto nodes = this->GetDataStorage()->GetSubset(predicate); for (auto iter = nodes->begin(); iter != nodes->end(); ++iter) (*iter)->SetVisibility(*iter == node); } void QmitkSegmentationView::OnContourMarkerSelected(const mitk::DataNode* node) { QmitkRenderWindow* selectedRenderWindow = nullptr; auto* renderWindowPart = this->GetRenderWindowPart(mitk::WorkbenchUtil::OPEN); auto* axialRenderWindow = renderWindowPart->GetQmitkRenderWindow("axial"); auto* sagittalRenderWindow = renderWindowPart->GetQmitkRenderWindow("sagittal"); auto* coronalRenderWindow = renderWindowPart->GetQmitkRenderWindow("coronal"); auto* threeDRenderWindow = renderWindowPart->GetQmitkRenderWindow("3d"); bool PlanarFigureInitializedWindow = false; // find initialized renderwindow if (node->GetBoolProperty("PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, axialRenderWindow->GetRenderer())) { selectedRenderWindow = axialRenderWindow; } if (!selectedRenderWindow && node->GetBoolProperty( "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, sagittalRenderWindow->GetRenderer())) { selectedRenderWindow = sagittalRenderWindow; } if (!selectedRenderWindow && node->GetBoolProperty( "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, coronalRenderWindow->GetRenderer())) { selectedRenderWindow = coronalRenderWindow; } if (!selectedRenderWindow && node->GetBoolProperty( "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, threeDRenderWindow->GetRenderer())) { selectedRenderWindow = threeDRenderWindow; } // make node visible if (nullptr != selectedRenderWindow) { std::string nodeName = node->GetName(); unsigned int t = nodeName.find_last_of(" "); unsigned int id = atof(nodeName.substr(t + 1).c_str()) - 1; ctkPluginContext* context = mitk::PluginActivator::getContext(); ctkServiceReference ppmRef = context->getServiceReference(); mitk::PlanePositionManagerService* service = context->getService(ppmRef); selectedRenderWindow->GetSliceNavigationController()->ExecuteOperation(service->GetPlanePosition(id)); context->ungetService(ppmRef); selectedRenderWindow->GetRenderer()->GetCameraController()->Fit(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkSegmentationView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, const QList& nodes) { if (0 == nodes.size()) { return; } std::string markerName = "Position"; unsigned int numberOfNodes = nodes.size(); std::string nodeName = nodes.at(0)->GetName(); if ((numberOfNodes == 1) && (nodeName.find(markerName) == 0)) { this->OnContourMarkerSelected(nodes.at(0)); return; } } void QmitkSegmentationView::ResetMouseCursor() { if (m_MouseCursorSet) { mitk::ApplicationCursor::GetInstance()->PopCursor(); m_MouseCursorSet = false; } } void QmitkSegmentationView::SetMouseCursor(const us::ModuleResource& resource, int hotspotX, int hotspotY) { // Remove previously set mouse cursor if (m_MouseCursorSet) { this->ResetMouseCursor(); } if (resource) { us::ModuleResourceStream cursor(resource, std::ios::binary); mitk::ApplicationCursor::GetInstance()->PushCursor(cursor, hotspotX, hotspotY); m_MouseCursorSet = true; } } void QmitkSegmentationView::UpdateGUI() { mitk::DataNode* referenceNode = m_ToolManager->GetReferenceData(0); bool hasReferenceNode = referenceNode != nullptr; mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); bool hasWorkingNode = workingNode != nullptr; m_Controls->newSegmentationButton->setEnabled(false); if (hasReferenceNode) { m_Controls->newSegmentationButton->setEnabled(true); } if (hasWorkingNode && hasReferenceNode) { int layer = -1; referenceNode->GetIntProperty("layer", layer); workingNode->SetIntProperty("layer", layer + 1); } m_Controls->layersWidget->UpdateGUI(); m_Controls->labelsWidget->UpdateGUI(); this->ValidateSelectionInput(); } void QmitkSegmentationView::ValidateSelectionInput() { auto referenceNode = m_Controls->referenceNodeSelector->GetSelectedNode(); auto workingNode = m_Controls->workingNodeSelector->GetSelectedNode(); bool hasReferenceNode = referenceNode.IsNotNull(); bool hasWorkingNode = workingNode.IsNotNull(); bool hasBothNodes = hasReferenceNode && hasWorkingNode; QString warning; bool toolSelectionBoxesEnabled = hasReferenceNode && hasWorkingNode; unsigned int numberOfLabels = 0; m_Controls->layersWidget->setEnabled(hasWorkingNode); m_Controls->labelsWidget->setEnabled(hasWorkingNode); m_Controls->labelSetWidget->setEnabled(hasWorkingNode); m_Controls->toolSelectionBox2D->setEnabled(hasBothNodes); m_Controls->toolSelectionBox3D->setEnabled(hasBothNodes); m_Controls->slicesInterpolator->setEnabled(false); m_Controls->interpolatorWarningLabel->hide(); if (hasReferenceNode) { if (nullptr != m_RenderWindowPart && m_RenderWindowPart->HasCoupledRenderWindows() && !referenceNode->IsVisible(nullptr)) { warning += tr("The selected reference image is currently not visible!"); toolSelectionBoxesEnabled = false; } } if (hasWorkingNode) { if (nullptr != m_RenderWindowPart && m_RenderWindowPart->HasCoupledRenderWindows() && !workingNode->IsVisible(nullptr)) { warning += (!warning.isEmpty() ? "
" : "") + tr("The selected segmentation is currently not visible!"); toolSelectionBoxesEnabled = false; } m_ToolManager->SetReferenceData(referenceNode); m_ToolManager->SetWorkingData(workingNode); m_Controls->layersWidget->setEnabled(true); m_Controls->labelsWidget->setEnabled(true); m_Controls->labelSetWidget->setEnabled(true); m_Controls->toolSelectionBox2D->setEnabled(true); m_Controls->toolSelectionBox3D->setEnabled(true); auto labelSetImage = dynamic_cast(workingNode->GetData()); auto activeLayer = labelSetImage->GetActiveLayer(); numberOfLabels = labelSetImage->GetNumberOfLabels(activeLayer); if (numberOfLabels > 1) m_Controls->slicesInterpolator->setEnabled(true); } m_Inspector->SetMultiLabelSegmentation(dynamic_cast(workingNode->GetData())); toolSelectionBoxesEnabled &= numberOfLabels > 1; // Here we need to check whether the geometry of the selected segmentation image (working image geometry) // is aligned with the geometry of the 3D render window. // It is not allowed to use a geometry different from the working image geometry for segmenting. // We only need to this if the tool selection box would be enabled without this check. // Additionally this check only has to be performed for render window parts with coupled render windows. // For different render window parts the user is given the option to reinitialize each render window individually // (see QmitkRenderWindow::ShowOverlayMessage). if (toolSelectionBoxesEnabled && nullptr != m_RenderWindowPart && m_RenderWindowPart->HasCoupledRenderWindows()) { const mitk::BaseGeometry* workingNodeGeometry = workingNode->GetData()->GetGeometry(); const mitk::BaseGeometry* renderWindowGeometry = m_RenderWindowPart->GetQmitkRenderWindow("3d")->GetSliceNavigationController()->GetCurrentGeometry3D(); if (nullptr != workingNodeGeometry && nullptr != renderWindowGeometry) { if (!mitk::Equal(*workingNodeGeometry->GetBoundingBox(), *renderWindowGeometry->GetBoundingBox(), mitk::eps, true)) { warning += (!warning.isEmpty() ? "
" : "") + tr("Please reinitialize the selected segmentation image!"); toolSelectionBoxesEnabled = false; } } } m_Controls->toolSelectionBox2D->setEnabled(toolSelectionBoxesEnabled); m_Controls->toolSelectionBox3D->setEnabled(toolSelectionBoxesEnabled); this->UpdateWarningLabel(warning); m_ToolManager->SetReferenceData(referenceNode); m_ToolManager->SetWorkingData(workingNode); } void QmitkSegmentationView::UpdateWarningLabel(QString text) { if (text.isEmpty()) { m_Controls->selectionWarningLabel->hide(); } else { m_Controls->selectionWarningLabel->setText("" + text + ""); m_Controls->selectionWarningLabel->show(); } } diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.h b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.h index 74de6f9ac0..c2abbc71b9 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.h +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.h @@ -1,192 +1,192 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef QmitkSegmentationView_h #define QmitkSegmentationView_h #include "ui_QmitkSegmentationViewControls.h" #include #include -class QmitkMultiLabelSegmentationInspector; +class QmitkMultiLabelInspector; /** * @brief The segmentation view provides a set of tool to use different segmentation algorithms. * It provides two selection widgets to load an image node and a segmentation node * on which to perform the segmentation. Creating new segmentation nodes is also possible. * The available segmentation tools are grouped into "2D"- and "3D"-tools. * * Most segmentation tools / algorithms need some kind of user interaction, where the * user is asked to draw something in the image display or set some seed points / start values. * The tools also often provide additional propeties so that a user can modify the * algorithm's behavior. * * This class additionally provides options to work with different layers (create new layers, * switch between layers). * Moreover, a multilabel widget displays all the existing labels of a multilabel segmentation * for the currently active layer. * The multilabel widget allows to control the labels by creatin new one, removing existing ones, * showing / hiding single labels, merging labels, (re-)naming them etc. * * Additionally the view provides an option to create "2D"- and "3D"-interpolations between * neighboring segmentation masks on unsegmented slices. * Interpolation for multilabel segmentations is currently not implemented. */ class QmitkSegmentationView : public QmitkAbstractView, public mitk::IRenderWindowPartListener { Q_OBJECT public: static const std::string VIEW_ID; QmitkSegmentationView(); ~QmitkSegmentationView() override; private Q_SLOTS: // reaction to the selection of a new reference image in the selection widget void OnReferenceSelectionChanged(QList nodes); // reaction to the selection of a new segmentation image in the selection widget void OnSegmentationSelectionChanged(QList nodes); // reaction to the shortcut ("CTRL+H") for toggling the visibility of the working node void OnVisibilityShortcutActivated(); // reaction to the shortcut ("CTRL+L") for iterating over all labels void OnLabelToggleShortcutActivated(); // reaction to the button "New segmentation" void OnNewSegmentation(); void OnManualTool2DSelected(int id); void OnShowMarkerNodes(bool); void OnLayersChanged(); void OnShowLabelTable(bool); void OnGoToLabel(const mitk::Point3D &pos); void OnLabelSetWidgetReset(); private: void CreateQtPartControl(QWidget* parent) override; void SetFocus() override {} /** * @brief Enable or disable the SegmentationInteractor. * * The active tool is retrieved from the tool manager. * If the active tool is valid, the SegmentationInteractor is enabled * to listen to 'SegmentationInteractionEvent's. */ void ActiveToolChanged(); /** * @brief Test whether the geometry of the reference image * fits the world geometry of the respective renderer. * * The respective renderer is retrieved from the given event, which * needs to be a 'SegmentationInteractionEvent'. * This event provides not only the sending base renderer but also a * bool that indicates whether the mouse cursor entered or left the * base renderer. * This information is used to compare the renderer's world geometry * with the oriented time geometry of the current reference image. * If the geometries align, the renderer is not blocked anymore and the * view's warning message is removed. * If the geometries do not align, 'ShowRenderWindowWarning' is called * and a warning message is added to the top of this plugin view. * * @param event The observed mitk::SegmentationInteractionEvent. */ void ValidateRendererGeometry(const itk::EventObject& event); void RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) override; void RenderWindowPartDeactivated(mitk::IRenderWindowPart* renderWindowPart) override; void RenderWindowPartInputChanged(mitk::IRenderWindowPart* renderWindowPart) override; void OnPreferencesChanged(const mitk::IPreferences* prefs) override; void NodeAdded(const mitk::DataNode* node) override; void NodeRemoved(const mitk::DataNode* node) override; void EstablishLabelSetConnection(); void LooseLabelSetConnection(); void OnAnySelectionChanged(); // make sure all images / segmentations look according to the user preference settings void ApplyDisplayOptions(); // decorates a DataNode according to the user preference settings void ApplyDisplayOptions(mitk::DataNode* node); void ApplySelectionMode(); void ApplySelectionModeOnReferenceNode(); void ApplySelectionModeOnWorkingNode(); void ApplySelectionMode(mitk::DataNode* node, mitk::NodePredicateBase* predicate); // If a contourmarker is selected, the plane in the related widget will be reoriented according to the marker`s geometry void OnContourMarkerSelected(const mitk::DataNode* node); void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList &nodes) override; void ResetMouseCursor(); void SetMouseCursor(const us::ModuleResource&, int hotspotX, int hotspotY); void UpdateGUI(); void ValidateSelectionInput(); void UpdateWarningLabel(QString text); std::string GetDefaultLabelSetPreset() const; QWidget* m_Parent; Ui::QmitkSegmentationViewControls* m_Controls; mitk::IRenderWindowPart* m_RenderWindowPart; mitk::ToolManager* m_ToolManager; mitk::DataNode::Pointer m_ReferenceNode; mitk::DataNode::Pointer m_WorkingNode; typedef std::map NodeTagMapType; NodeTagMapType m_WorkingDataObserverTags; NodeTagMapType m_ReferenceDataObserverTags; unsigned int m_RenderingManagerObserverTag; mitk::NodePredicateAnd::Pointer m_ReferencePredicate; mitk::NodePredicateAnd::Pointer m_SegmentationPredicate; bool m_DrawOutline; bool m_SelectionMode; bool m_MouseCursorSet; QString m_LabelSetPresetPreference; bool m_DefaultLabelNaming; bool m_SelectionChangeIsAlreadyBeingHandled; - QmitkMultiLabelSegmentationInspector* m_Inspector; + QmitkMultiLabelInspector* m_Inspector; }; #endif