diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/files.cmake b/Plugins/org.mitk.gui.qt.semanticrelations/files.cmake index 193d7eaef8..61da5e0556 100644 --- a/Plugins/org.mitk.gui.qt.semanticrelations/files.cmake +++ b/Plugins/org.mitk.gui.qt.semanticrelations/files.cmake @@ -1,38 +1,42 @@ set(INTERNAL_CPP_FILES mitkPluginActivator.cpp + QmitkDataNodeAddToSemanticRelationsAction.cpp QmitkDataNodeControlPointAction.cpp QmitkDataNodeInformationTypeAction.cpp + QmitkDataNodeRemoveFromSemanticRelationsAction.cpp QmitkDataNodeOpenInAction.cpp QmitkLesionInfoWidget.cpp QmitkSemanticRelationsContextMenu.cpp QmitkSemanticRelationsNodeSelectionDialog.cpp QmitkSemanticRelationsView.cpp ) set(UI_FILES src/internal/QmitkLesionInfoWidgetControls.ui src/internal/QmitkSemanticRelationsControls.ui ) set(MOC_H_FILES src/internal/mitkPluginActivator.h + src/internal/QmitkDataNodeAddToSemanticRelationsAction.h src/internal/QmitkDataNodeControlPointAction.h src/internal/QmitkDataNodeInformationTypeAction.h + src/internal/QmitkDataNodeRemoveFromSemanticRelationsAction.h src/internal/QmitkDataNodeOpenInAction.h src/internal/QmitkLesionInfoWidget.h src/internal/QmitkSemanticRelationsContextMenu.h src/internal/QmitkSemanticRelationsNodeSelectionDialog.h src/internal/QmitkSemanticRelationsView.h ) set(CACHED_RESOURCE_FILES resources/SemanticRelations_48.png plugin.xml ) set(QRC_FILES ) foreach(file ${INTERNAL_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/internal/${file}) endforeach(file ${INTERNAL_CPP_FILES}) diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeAddToSemanticRelationsAction.cpp b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeAddToSemanticRelationsAction.cpp new file mode 100644 index 0000000000..d5dd92e18f --- /dev/null +++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeAddToSemanticRelationsAction.cpp @@ -0,0 +1,221 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +// semantic relations plugin +#include "QmitkDataNodeAddToSemanticRelationsAction.h" + +// semantic relations module +#include +#include +#include + +// mitk gui common plugin +#include + +// berry +#include +#include + +// qt +#include + +// namespace that contains the concrete action +namespace AdddToSemanticRelationsAction +{ + void Run(mitk::SemanticRelations* semanticRelations, const mitk::DataStorage* dataStorage, const mitk::DataNode* dataNode) + { + if (nullptr == dataNode) + { + return; + } + + if (mitk::NodePredicates::GetImagePredicate()->CheckNode(dataNode)) + { + AddImage(semanticRelations, dataNode); + } + else if (mitk::NodePredicates::GetSegmentationPredicate()->CheckNode(dataNode)) + { + AddSegmentation(semanticRelations, dataStorage, dataNode); + } + } + + void AddImage(mitk::SemanticRelations* semanticRelations, const mitk::DataNode* image) + { + if (nullptr == image) + { + return; + } + + try + { + // add the image to the semantic relations storage + semanticRelations->AddImage(image); + } + catch (const mitk::SemanticRelationException& e) + { + std::stringstream exceptionMessage; exceptionMessage << e; + QMessageBox msgBox; + msgBox.setWindowTitle("Could not add the selected image."); + msgBox.setText("The program wasn't able to correctly add the selected images.\n" + "Reason:\n" + QString::fromStdString(exceptionMessage.str())); + msgBox.setIcon(QMessageBox::Warning); + msgBox.exec(); + return; + } + } + + void AddSegmentation(mitk::SemanticRelations* semanticRelations, const mitk::DataStorage* dataStorage, const mitk::DataNode* segmentation) + { + if (nullptr == segmentation) + { + return; + } + + mitk::BaseData* baseData = segmentation->GetData(); + if (nullptr == baseData) + { + return; + } + + // continue with valid segmentation data + // get parent node of the current segmentation node with the node predicate + mitk::DataStorage::SetOfObjects::ConstPointer parentNodes = dataStorage->GetSources(segmentation, mitk::NodePredicates::GetImagePredicate(), false); + + // check for already existing, identifying base properties + mitk::BaseProperty* caseIDProperty = baseData->GetProperty("DICOM.0010.0010"); + mitk::BaseProperty* nodeIDProperty = baseData->GetProperty("DICOM.0020.000E"); + if (nullptr == caseIDProperty || nullptr == nodeIDProperty) + { + MITK_INFO << "No DICOM tags for case and node identification found. Transferring DICOM tags from the parent node to the selected segmentation node."; + + mitk::SemanticTypes::CaseID caseID = mitk::GetCaseIDFromDataNode(parentNodes->front()); + mitk::SemanticTypes::ID nodeID = mitk::GetIDFromDataNode(parentNodes->front()); + // transfer DICOM tags to the segmentation node + mitk::StringProperty::Pointer caseIDTag = mitk::StringProperty::New(caseID); + baseData->SetProperty("DICOM.0010.0010", caseIDTag); // DICOM tag is "PatientName" + + // add UID to distinguish between different segmentations of the same parent node + mitk::StringProperty::Pointer nodeIDTag = mitk::StringProperty::New(nodeID + mitk::UIDGeneratorBoost::GenerateUID()); + baseData->SetProperty("DICOM.0020.000E", nodeIDTag); // DICOM tag is "SeriesInstanceUID" + } + + try + { + semanticRelations->AddSegmentation(segmentation, parentNodes->front()); + } + catch (const mitk::SemanticRelationException& e) + { + std::stringstream exceptionMessage; exceptionMessage << e; + QMessageBox msgBox; + msgBox.setWindowTitle("Could not add the selected segmentation."); + msgBox.setText("The program wasn't able to correctly add the selected segmentation.\n" + "Reason:\n" + QString::fromStdString(exceptionMessage.str())); + msgBox.setIcon(QMessageBox::Warning); + msgBox.exec(); + return; + } + } +} + +QmitkDataNodeAddToSemanticRelationsAction::QmitkDataNodeAddToSemanticRelationsAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchPartSite) + : QAction(parent) + , m_WorkbenchPartSite(workbenchPartSite) +{ + setText(tr("Add to semantic relations")); + InitializeAction(); +} + +QmitkDataNodeAddToSemanticRelationsAction::QmitkDataNodeAddToSemanticRelationsAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchPartSite) + : QAction(parent) + , m_WorkbenchPartSite(berry::IWorkbenchPartSite::Pointer(workbenchPartSite)) +{ + setText(tr("Add to semantic relations")); + InitializeAction(); +} + +QmitkDataNodeAddToSemanticRelationsAction::~QmitkDataNodeAddToSemanticRelationsAction() +{ + // nothing here +} + +void QmitkDataNodeAddToSemanticRelationsAction::SetDataStorage(mitk::DataStorage* dataStorage) +{ + if (m_DataStorage != dataStorage) + { + // set the new data storage + m_DataStorage = dataStorage; + m_SemanticRelations = std::make_unique(m_DataStorage.Lock()); + } +} + +void QmitkDataNodeAddToSemanticRelationsAction::InitializeAction() +{ + connect(this, &QAction::triggered, this, &QmitkDataNodeAddToSemanticRelationsAction::OnActionTriggered); +} + +void QmitkDataNodeAddToSemanticRelationsAction::OnActionTriggered(bool checked) +{ + if (nullptr == m_SemanticRelations) + { + return; + } + + if (m_DataStorage.IsExpired()) + { + return; + } + + auto dataNode = GetSelectedNode(); + AdddToSemanticRelationsAction::Run(m_SemanticRelations.get(), m_DataStorage.Lock(), dataNode); +} + +QList QmitkDataNodeAddToSemanticRelationsAction::GetSelectedNodes() +{ + QList selectedNodes; + if (m_WorkbenchPartSite.Expired()) + { + return selectedNodes; + } + + berry::ISelection::ConstPointer selection = m_WorkbenchPartSite.Lock()->GetWorkbenchWindow()->GetSelectionService()->GetSelection(); + mitk::DataNodeSelection::ConstPointer currentSelection = selection.Cast(); + + if (currentSelection.IsNull() || currentSelection->IsEmpty()) + { + return selectedNodes; + } + + selectedNodes = QList::fromStdList(currentSelection->GetSelectedDataNodes()); + return selectedNodes; +} + +mitk::DataNode::Pointer QmitkDataNodeAddToSemanticRelationsAction::GetSelectedNode() +{ + QList selectedNodes = GetSelectedNodes(); + if (selectedNodes.empty()) + { + return nullptr; + } + + // no batch action; should only be called with a single node + mitk::DataNode::Pointer dataNode = selectedNodes.front(); + if (nullptr == dataNode) + { + return nullptr; + } + + return dataNode; +} \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeAddToSemanticRelationsAction.h b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeAddToSemanticRelationsAction.h new file mode 100644 index 0000000000..b3ce3d5598 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeAddToSemanticRelationsAction.h @@ -0,0 +1,73 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef QMITKDATANODEADDTOSEMANTICRELATIONSACTION_H +#define QMITKDATANODEADDTOSEMANTICRELATIONSACTION_H + +#include + +// mitk core +#include +#include +#include + +// semantic relations module +#include + +// berry +#include + +// qt +#include + +namespace AdddToSemanticRelationsAction +{ + MITK_GUI_SEMANTICRELATIONS_EXPORT void Run(mitk::SemanticRelations* semanticRelations, const mitk::DataStorage* dataStorage, const mitk::DataNode* image); + + void AddImage(mitk::SemanticRelations* semanticRelations, const mitk::DataNode* image); + void AddSegmentation(mitk::SemanticRelations* semanticRelations, const mitk::DataStorage* dataStorage, const mitk::DataNode* segmentation); +} + +class MITK_GUI_SEMANTICRELATIONS_EXPORT QmitkDataNodeAddToSemanticRelationsAction : public QAction +{ + Q_OBJECT + +public: + + QmitkDataNodeAddToSemanticRelationsAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchPartSite); + QmitkDataNodeAddToSemanticRelationsAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchPartSite); + + virtual ~QmitkDataNodeAddToSemanticRelationsAction() override; + + void SetDataStorage(mitk::DataStorage* dataStorage); + +private Q_SLOTS: + + void OnActionTriggered(bool); + +protected: + + void InitializeAction(); + + QList GetSelectedNodes(); + mitk::DataNode::Pointer GetSelectedNode(); + + berry::IWorkbenchPartSite::WeakPtr m_WorkbenchPartSite; + mitk::WeakPointer m_DataStorage; + std::unique_ptr m_SemanticRelations; +}; + +#endif // QMITKDATANODEADDTOSEMANTICRELATIONSACTION_H diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeRemoveFromSemanticRelationsAction.cpp b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeRemoveFromSemanticRelationsAction.cpp new file mode 100644 index 0000000000..3e86b3169e --- /dev/null +++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeRemoveFromSemanticRelationsAction.cpp @@ -0,0 +1,193 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +// semantic relations plugin +#include "QmitkDataNodeRemoveFromSemanticRelationsAction.h" + +// semantic relations module +#include +#include +#include + +// mitk gui common plugin +#include + +// berry +#include +#include + +// qt +#include + +// namespace that contains the concrete action +namespace RemoveFromSemanticRelationsAction +{ + void Run(mitk::SemanticRelations* semanticRelations, const mitk::DataStorage* dataStorage, const mitk::DataNode* dataNode) + { + if (nullptr == dataNode) + { + return; + } + + if (mitk::NodePredicates::GetImagePredicate()->CheckNode(dataNode)) + { + RemoveImage(semanticRelations, dataNode); + } + else if (mitk::NodePredicates::GetSegmentationPredicate()->CheckNode(dataNode)) + { + RemoveSegmentation(semanticRelations, dataStorage, dataNode); + } + } + + void RemoveImage(mitk::SemanticRelations* semanticRelations, const mitk::DataNode* image) + { + if (nullptr == image) + { + return; + } + + try + { + // remove the image from the semantic relations storage + semanticRelations->RemoveImage(image); + } + catch (const mitk::SemanticRelationException& e) + { + std::stringstream exceptionMessage; exceptionMessage << e; + QMessageBox msgBox; + msgBox.setWindowTitle("Could not remove the selected image."); + msgBox.setText("The program wasn't able to correctly remove the selected image.\n" + "Reason:\n" + QString::fromStdString(exceptionMessage.str())); + msgBox.setIcon(QMessageBox::Warning); + msgBox.exec(); + return; + } + } + + void RemoveSegmentation(mitk::SemanticRelations* semanticRelations, const mitk::DataStorage* dataStorage, const mitk::DataNode* segmentation) + { + if (nullptr == segmentation) + { + return; + } + + try + { + semanticRelations->RemoveSegmentation(segmentation); + } + catch (const mitk::SemanticRelationException& e) + { + std::stringstream exceptionMessage; exceptionMessage << e; + QMessageBox msgBox; + msgBox.setWindowTitle("Could not remove the selected segmentation."); + msgBox.setText("The program wasn't able to correctly remove the selected segmentation.\n" + "Reason:\n" + QString::fromStdString(exceptionMessage.str())); + msgBox.setIcon(QMessageBox::Warning); + msgBox.exec(); + return; + } + } +} + +QmitkDataNodeRemoveFromSemanticRelationsAction::QmitkDataNodeRemoveFromSemanticRelationsAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchPartSite) + : QAction(parent) + , m_WorkbenchPartSite(workbenchPartSite) +{ + setText(tr("Remove from semantic relations")); + InitializeAction(); +} + +QmitkDataNodeRemoveFromSemanticRelationsAction::QmitkDataNodeRemoveFromSemanticRelationsAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchPartSite) + : QAction(parent) + , m_WorkbenchPartSite(berry::IWorkbenchPartSite::Pointer(workbenchPartSite)) +{ + setText(tr("Remove from semantic relations")); + InitializeAction(); +} + +QmitkDataNodeRemoveFromSemanticRelationsAction::~QmitkDataNodeRemoveFromSemanticRelationsAction() +{ + // nothing here +} + +void QmitkDataNodeRemoveFromSemanticRelationsAction::SetDataStorage(mitk::DataStorage* dataStorage) +{ + if (m_DataStorage != dataStorage) + { + // set the new data storage + m_DataStorage = dataStorage; + m_SemanticRelations = std::make_unique(m_DataStorage.Lock()); + } +} + +void QmitkDataNodeRemoveFromSemanticRelationsAction::InitializeAction() +{ + connect(this, &QAction::triggered, this, &QmitkDataNodeRemoveFromSemanticRelationsAction::OnActionTriggered); +} + +void QmitkDataNodeRemoveFromSemanticRelationsAction::OnActionTriggered(bool checked) +{ + if (nullptr == m_SemanticRelations) + { + return; + } + + if (m_DataStorage.IsExpired()) + { + return; + } + + auto dataNode = GetSelectedNode(); + RemoveFromSemanticRelationsAction::Run(m_SemanticRelations.get(), m_DataStorage.Lock(), dataNode); +} + +QList QmitkDataNodeRemoveFromSemanticRelationsAction::GetSelectedNodes() +{ + QList selectedNodes; + if (m_WorkbenchPartSite.Expired()) + { + return selectedNodes; + } + + berry::ISelection::ConstPointer selection = m_WorkbenchPartSite.Lock()->GetWorkbenchWindow()->GetSelectionService()->GetSelection(); + mitk::DataNodeSelection::ConstPointer currentSelection = selection.Cast(); + + if (currentSelection.IsNull() || currentSelection->IsEmpty()) + { + return selectedNodes; + } + + selectedNodes = QList::fromStdList(currentSelection->GetSelectedDataNodes()); + return selectedNodes; +} + +mitk::DataNode::Pointer QmitkDataNodeRemoveFromSemanticRelationsAction::GetSelectedNode() +{ + QList selectedNodes = GetSelectedNodes(); + if (selectedNodes.empty()) + { + return nullptr; + } + + // no batch action; should only be called with a single node + mitk::DataNode::Pointer dataNode = selectedNodes.front(); + if (nullptr == dataNode) + { + return nullptr; + } + + return dataNode; +} \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeRemoveFromSemanticRelationsAction.h b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeRemoveFromSemanticRelationsAction.h new file mode 100644 index 0000000000..cf48d0ef33 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeRemoveFromSemanticRelationsAction.h @@ -0,0 +1,73 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef QMITKDATANODEREMOVEFROMSEMANTICRELATIONSACTION_H +#define QMITKDATANODEREMOVEFROMSEMANTICRELATIONSACTION_H + +#include + +// mitk core +#include +#include +#include + +// semantic relations module +#include + +// berry +#include + +// qt +#include + +namespace RemoveFromSemanticRelationsAction +{ + MITK_GUI_SEMANTICRELATIONS_EXPORT void Run(mitk::SemanticRelations* semanticRelations, const mitk::DataStorage* dataStorage, const mitk::DataNode* image); + + void RemoveImage(mitk::SemanticRelations* semanticRelations, const mitk::DataNode* image); + void RemoveSegmentation(mitk::SemanticRelations* semanticRelations, const mitk::DataStorage* dataStorage, const mitk::DataNode* segmentation); +} + +class MITK_GUI_SEMANTICRELATIONS_EXPORT QmitkDataNodeRemoveFromSemanticRelationsAction : public QAction +{ + Q_OBJECT + +public: + + QmitkDataNodeRemoveFromSemanticRelationsAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchPartSite); + QmitkDataNodeRemoveFromSemanticRelationsAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchPartSite); + + virtual ~QmitkDataNodeRemoveFromSemanticRelationsAction() override; + + void SetDataStorage(mitk::DataStorage* dataStorage); + +private Q_SLOTS: + + void OnActionTriggered(bool); + +protected: + + void InitializeAction(); + + QList GetSelectedNodes(); + mitk::DataNode::Pointer GetSelectedNode(); + + berry::IWorkbenchPartSite::WeakPtr m_WorkbenchPartSite; + mitk::WeakPointer m_DataStorage; + std::unique_ptr m_SemanticRelations; +}; + +#endif // QMITKDATANODEREMOVEFROMSEMANTICRELATIONSACTION_H diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsContextMenu.cpp b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsContextMenu.cpp index c769f88f65..4fdf19c9c8 100644 --- a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsContextMenu.cpp +++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsContextMenu.cpp @@ -1,70 +1,74 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // semantic relations plugin #include "QmitkSemanticRelationsContextMenu.h" QmitkSemanticRelationsContextMenu::QmitkSemanticRelationsContextMenu(berry::IWorkbenchPartSite::Pointer workbenchPartSite, QWidget* parent) : QMenu(parent) { m_WorkbenchPartSite = workbenchPartSite; m_Parent = parent; InitDefaultActions(); } QmitkSemanticRelationsContextMenu::~QmitkSemanticRelationsContextMenu() { // nothing here } void QmitkSemanticRelationsContextMenu::SetDataStorage(mitk::DataStorage* dataStorage) { if (m_DataStorage != dataStorage) { // set the new data storage - also for all actions m_DataStorage = dataStorage; m_ControlPointAction->SetDataStorage(m_DataStorage.Lock()); m_InformationTypeAction->SetDataStorage(m_DataStorage.Lock()); + m_RemoveFromSemanticRelationsAction->SetDataStorage(m_DataStorage.Lock()); } } void QmitkSemanticRelationsContextMenu::SetControlledRenderer(RenderWindowLayerUtilities::RendererVector controlledRenderer) { if (m_ControlledRenderer != controlledRenderer) { // set the new set of controlled renderer m_ControlledRenderer = controlledRenderer; m_OpenInAction->SetControlledRenderer(m_ControlledRenderer); } } void QmitkSemanticRelationsContextMenu::OnContextMenuRequested(const QPoint& /*pos*/) { popup(QCursor::pos()); } void QmitkSemanticRelationsContextMenu::InitDefaultActions() { m_ControlPointAction = new QmitkDataNodeControlPointAction(m_Parent, m_WorkbenchPartSite.Lock()); addAction(m_ControlPointAction); m_InformationTypeAction = new QmitkDataNodeInformationTypeAction(m_Parent, m_WorkbenchPartSite.Lock()); addAction(m_InformationTypeAction); + m_RemoveFromSemanticRelationsAction = new QmitkDataNodeRemoveFromSemanticRelationsAction(m_Parent, m_WorkbenchPartSite.Lock()); + addAction(m_RemoveFromSemanticRelationsAction); + m_OpenInAction = new QmitkDataNodeOpenInAction(m_Parent, m_WorkbenchPartSite.Lock()); addAction(m_OpenInAction); } diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsContextMenu.h b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsContextMenu.h index d41945ad30..54dfacb155 100644 --- a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsContextMenu.h +++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsContextMenu.h @@ -1,69 +1,71 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QMITKSEMANTICRELATIONSCONTEXTMENU_H #define QMITKSEMANTICRELATIONSCONTEXTMENU_H // semantic relations plugin #include "QmitkDataNodeControlPointAction.h" #include "QmitkDataNodeInformationTypeAction.h" +#include "QmitkDataNodeRemoveFromSemanticRelationsAction.h" #include "QmitkDataNodeOpenInAction.h" // mitk core #include #include // mitk render window manager module #include // blueberry ui qt plugin #include //qt #include class QmitkSemanticRelationsContextMenu : public QMenu { Q_OBJECT public: QmitkSemanticRelationsContextMenu(berry::IWorkbenchPartSite::Pointer workbenchPartSite, QWidget* parent = nullptr); virtual ~QmitkSemanticRelationsContextMenu() override; void SetDataStorage(mitk::DataStorage* dataStorage); void SetControlledRenderer(RenderWindowLayerUtilities::RendererVector controlledRenderer); public Q_SLOTS: void OnContextMenuRequested(const QPoint&); private: void InitDefaultActions(); QWidget* m_Parent; berry::IWorkbenchPartSite::WeakPtr m_WorkbenchPartSite; mitk::WeakPointer m_DataStorage; RenderWindowLayerUtilities::RendererVector m_ControlledRenderer; QmitkDataNodeControlPointAction* m_ControlPointAction; QmitkDataNodeInformationTypeAction* m_InformationTypeAction; + QmitkDataNodeRemoveFromSemanticRelationsAction* m_RemoveFromSemanticRelationsAction; QmitkDataNodeOpenInAction* m_OpenInAction; }; #endif // QMITKSEMANTICRELATIONSCONTEXTMENU_H diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsView.cpp b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsView.cpp index e5a903cda0..f1d314d19f 100644 --- a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsView.cpp +++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsView.cpp @@ -1,384 +1,264 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // semantic relations plugin #include "QmitkSemanticRelationsView.h" #include "QmitkSemanticRelationsNodeSelectionDialog.h" +#include "QmitkDataNodeAddToSemanticRelationsAction.h" +#include "QmitkDataNodeRemoveFromSemanticRelationsAction.h" // semantic relations module #include #include -#include // mitk qt widgets module #include #include // mitk multi label module #include // berry #include #include // qt #include -#include const std::string QmitkSemanticRelationsView::VIEW_ID = "org.mitk.views.semanticrelations"; void QmitkSemanticRelationsView::SetFocus() { // nothing here } void QmitkSemanticRelationsView::CreateQtPartControl(QWidget* parent) { // create GUI widgets m_Controls.setupUi(parent); // initialize the semantic relations m_SemanticRelations = std::make_unique(GetDataStorage()); m_LesionInfoWidget = new QmitkLesionInfoWidget(GetDataStorage(), parent); m_Controls.gridLayout->addWidget(m_LesionInfoWidget); m_PatientTableInspector = new QmitkPatientTableInspector(parent); m_PatientTableInspector->SetDataStorage(GetDataStorage()); m_Controls.gridLayout->addWidget(m_PatientTableInspector); QGridLayout* dndDataNodeWidgetLayout = new QGridLayout; dndDataNodeWidgetLayout->addWidget(m_PatientTableInspector, 0, 0); dndDataNodeWidgetLayout->setContentsMargins(0, 0, 0, 0); m_DnDDataNodeWidget = new QmitkDnDDataNodeWidget(parent); m_DnDDataNodeWidget->setLayout(dndDataNodeWidgetLayout); m_Controls.gridLayout->addWidget(m_DnDDataNodeWidget); m_ContextMenu = new QmitkSemanticRelationsContextMenu(GetSite(), m_PatientTableInspector); m_ContextMenu->SetDataStorage(GetDataStorage()); mitk::IRenderWindowPart* renderWindowPart = GetRenderWindowPart(); if (nullptr != renderWindowPart) { RenderWindowPartActivated(renderWindowPart); } SetUpConnections(); } void QmitkSemanticRelationsView::RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) { // connect QmitkRenderWindows - underlying vtkRenderWindow is the same as "mitk::RenderingManager::GetInstance()->GetAllRegisteredRenderWindows()" QHash windowMap = renderWindowPart->GetQmitkRenderWindows(); QHash::Iterator it; mitk::BaseRenderer* baseRenderer = nullptr; RenderWindowLayerUtilities::RendererVector controlledRenderer; for (it = windowMap.begin(); it != windowMap.end(); ++it) { baseRenderer = mitk::BaseRenderer::GetInstance(it.value()->GetVtkRenderWindow()); if (nullptr != baseRenderer) { controlledRenderer.push_back(baseRenderer); } } m_ContextMenu->SetControlledRenderer(controlledRenderer); } void QmitkSemanticRelationsView::RenderWindowPartDeactivated(mitk::IRenderWindowPart* renderWindowPart) { // nothing here } void QmitkSemanticRelationsView::SetUpConnections() { connect(m_Controls.caseIDComboBox, static_cast(&QComboBox::currentIndexChanged), this, &QmitkSemanticRelationsView::OnCaseIDSelectionChanged); connect(m_LesionInfoWidget, &QmitkLesionInfoWidget::LesionChanged, this, &QmitkSemanticRelationsView::OnLesionChanged); connect(m_PatientTableInspector, &QmitkPatientTableInspector::DataNodeDoubleClicked, this, &QmitkSemanticRelationsView::OnDataNodeDoubleClicked); connect(m_DnDDataNodeWidget, &QmitkDnDDataNodeWidget::NodesDropped, this, &QmitkSemanticRelationsView::OnNodesAdded); connect(m_PatientTableInspector, &QmitkPatientTableInspector::OnContextMenuRequested, m_ContextMenu, &QmitkSemanticRelationsContextMenu::OnContextMenuRequested); - connect(m_PatientTableInspector, &QmitkPatientTableInspector::OnNodeRemoved, this, &QmitkSemanticRelationsView::OnNodeRemoved); + connect(m_PatientTableInspector, &QmitkPatientTableInspector::OnNodeRemoved, this, &QmitkSemanticRelationsView::NodeRemoved); } QItemSelectionModel* QmitkSemanticRelationsView::GetDataNodeSelectionModel() const { return m_PatientTableInspector->GetSelectionModel(); } void QmitkSemanticRelationsView::NodeRemoved(const mitk::DataNode* dataNode) { if (nullptr == dataNode) { return; } - if (mitk::NodePredicates::GetImagePredicate()->CheckNode(dataNode)) - { - RemoveImage(dataNode); - } - else if (mitk::NodePredicates::GetSegmentationPredicate()->CheckNode(dataNode)) - { - RemoveSegmentation(dataNode); - } -} - -void QmitkSemanticRelationsView::OnCaseIDSelectionChanged(const QString& caseID) -{ - m_LesionInfoWidget->SetCurrentCaseID(caseID.toStdString()); - m_PatientTableInspector->SetCaseID(caseID.toStdString()); -} - -void QmitkSemanticRelationsView::AddToComboBox(const mitk::SemanticTypes::CaseID& caseID) -{ - int foundIndex = m_Controls.caseIDComboBox->findText(QString::fromStdString(caseID)); - if (-1 == foundIndex) + if (m_SemanticRelations->InstanceExists(dataNode)) { - // add the caseID to the combo box, as it is not already contained - m_Controls.caseIDComboBox->addItem(QString::fromStdString(caseID)); + RemoveFromSemanticRelationsAction::Run(m_SemanticRelations.get(), GetDataStorage(), dataNode); + mitk::SemanticTypes::CaseID caseID = mitk::GetCaseIDFromDataNode(dataNode); + RemoveFromComboBox(caseID); } } void QmitkSemanticRelationsView::OnLesionChanged(const mitk::SemanticTypes::Lesion& lesion) { m_PatientTableInspector->SetLesion(lesion); } void QmitkSemanticRelationsView::OnDataNodeDoubleClicked(const mitk::DataNode* dataNode) { if (nullptr == dataNode) { return; } if (mitk::NodePredicates::GetImagePredicate()->CheckNode(dataNode)) { OpenInEditor(dataNode); } else if (mitk::NodePredicates::GetSegmentationPredicate()->CheckNode(dataNode)) { JumpToPosition(dataNode); } } +void QmitkSemanticRelationsView::OnCaseIDSelectionChanged(const QString& caseID) +{ + m_LesionInfoWidget->SetCurrentCaseID(caseID.toStdString()); + m_PatientTableInspector->SetCaseID(caseID.toStdString()); +} + void QmitkSemanticRelationsView::OnNodesAdded(QmitkDnDDataNodeWidget* dnDDataNodeWidget, std::vector nodes) { + mitk::SemanticTypes::CaseID caseID = ""; for (mitk::DataNode* dataNode : nodes) { - if (nullptr == dataNode) - { - continue; - } - - if (mitk::NodePredicates::GetImagePredicate()->CheckNode(dataNode)) - { - AddImage(dataNode); - } - else if (mitk::NodePredicates::GetSegmentationPredicate()->CheckNode(dataNode)) - { - AddSegmentation(dataNode); - } + AdddToSemanticRelationsAction::Run(m_SemanticRelations.get(), GetDataStorage(), dataNode); + caseID = mitk::GetCaseIDFromDataNode(dataNode); + AddToComboBox(caseID); } } void QmitkSemanticRelationsView::OnNodeRemoved(const mitk::DataNode* dataNode) { NodeRemoved(dataNode); } +void QmitkSemanticRelationsView::AddToComboBox(const mitk::SemanticTypes::CaseID& caseID) +{ + int foundIndex = m_Controls.caseIDComboBox->findText(QString::fromStdString(caseID)); + if (-1 == foundIndex) + { + // add the caseID to the combo box, as it is not already contained + m_Controls.caseIDComboBox->addItem(QString::fromStdString(caseID)); + } +} + void QmitkSemanticRelationsView::RemoveFromComboBox(const mitk::SemanticTypes::CaseID& caseID) { std::vector allControlPoints = m_SemanticRelations->GetAllControlPointsOfCase(caseID); int foundIndex = m_Controls.caseIDComboBox->findText(QString::fromStdString(caseID)); if (allControlPoints.empty() && -1 != foundIndex) { // TODO: find new way to check for empty case id // caseID does not contain any control points and therefore no data // remove the caseID, if it is still contained m_Controls.caseIDComboBox->removeItem(foundIndex); } } void QmitkSemanticRelationsView::OpenInEditor(const mitk::DataNode* dataNode) { auto renderWindowPart = GetRenderWindowPart(); if (nullptr == renderWindowPart) { renderWindowPart = GetRenderWindowPart(QmitkAbstractView::BRING_TO_FRONT | QmitkAbstractView::OPEN); if (nullptr == renderWindowPart) { // no render window available return; } } auto image = dynamic_cast(dataNode->GetData()); if (nullptr != image) { mitk::RenderingManager::GetInstance()->InitializeViews(image->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); } } void QmitkSemanticRelationsView::JumpToPosition(const mitk::DataNode* dataNode) { if (nullptr == dataNode) { return; } mitk::LabelSetImage* labelSetImage = dynamic_cast(dataNode->GetData()); if (nullptr == labelSetImage) { return; } int activeLayer = labelSetImage->GetActiveLayer(); mitk::Label* activeLabel = labelSetImage->GetActiveLabel(activeLayer); labelSetImage->UpdateCenterOfMass(activeLabel->GetValue(), activeLayer); const mitk::Point3D& centerPosition = activeLabel->GetCenterOfMassCoordinates(); if (centerPosition.GetVnlVector().max_value() > 0.0) { auto renderWindowPart = GetRenderWindowPart(); if (nullptr == renderWindowPart) { renderWindowPart = GetRenderWindowPart(QmitkAbstractView::BRING_TO_FRONT | QmitkAbstractView::OPEN); if (nullptr == renderWindowPart) { // no render window available return; } } auto segmentation = dynamic_cast(dataNode->GetData()); if (nullptr != segmentation) { renderWindowPart->SetSelectedPosition(centerPosition); mitk::RenderingManager::GetInstance()->InitializeViews(segmentation->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); } } } - -void QmitkSemanticRelationsView::AddImage(const mitk::DataNode* image) -{ - if (nullptr == image) - { - return; - } - - try - { - // add the image to the semantic relations storage - m_SemanticRelations->AddImage(image); - mitk::SemanticTypes::CaseID caseID = mitk::GetCaseIDFromDataNode(image); - AddToComboBox(caseID); - } - catch (const mitk::SemanticRelationException& e) - { - std::stringstream exceptionMessage; exceptionMessage << e; - QMessageBox msgBox; - msgBox.setWindowTitle("Could not add the selected image."); - msgBox.setText("The program wasn't able to correctly add the selected images.\n" - "Reason:\n" + QString::fromStdString(exceptionMessage.str())); - msgBox.setIcon(QMessageBox::Warning); - msgBox.exec(); - return; - } -} - -void QmitkSemanticRelationsView::AddSegmentation(const mitk::DataNode* segmentation) -{ - if (nullptr == segmentation) - { - return; - } - - mitk::BaseData* baseData = segmentation->GetData(); - if (nullptr == baseData) - { - return; - } - - // continue with valid segmentation data - // get parent node of the current segmentation node with the node predicate - mitk::DataStorage::SetOfObjects::ConstPointer parentNodes = GetDataStorage()->GetSources(segmentation, mitk::NodePredicates::GetImagePredicate(), false); - - // check for already existing, identifying base properties - mitk::BaseProperty* caseIDProperty = baseData->GetProperty("DICOM.0010.0010"); - mitk::BaseProperty* nodeIDProperty = baseData->GetProperty("DICOM.0020.000E"); - if (nullptr == caseIDProperty || nullptr == nodeIDProperty) - { - MITK_INFO << "No DICOM tags for case and node identification found. Transferring DICOM tags from the parent node to the selected segmentation node."; - - mitk::SemanticTypes::CaseID caseID = mitk::GetCaseIDFromDataNode(parentNodes->front()); - mitk::SemanticTypes::ID nodeID = mitk::GetIDFromDataNode(parentNodes->front()); - // transfer DICOM tags to the segmentation node - mitk::StringProperty::Pointer caseIDTag = mitk::StringProperty::New(caseID); - baseData->SetProperty("DICOM.0010.0010", caseIDTag); // DICOM tag is "PatientName" - - // add UID to distinguish between different segmentations of the same parent node - mitk::StringProperty::Pointer nodeIDTag = mitk::StringProperty::New(nodeID + mitk::UIDGeneratorBoost::GenerateUID()); - baseData->SetProperty("DICOM.0020.000E", nodeIDTag); // DICOM tag is "SeriesInstanceUID" - } - - try - { - m_SemanticRelations->AddSegmentation(segmentation, parentNodes->front()); - } - catch (const mitk::SemanticRelationException& e) - { - std::stringstream exceptionMessage; exceptionMessage << e; - QMessageBox msgBox; - msgBox.setWindowTitle("Could not add the selected segmentation."); - msgBox.setText("The program wasn't able to correctly add the selected segmentation.\n" - "Reason:\n" + QString::fromStdString(exceptionMessage.str())); - msgBox.setIcon(QMessageBox::Warning); - msgBox.exec(); - return; - } -} - -void QmitkSemanticRelationsView::RemoveImage(const mitk::DataNode* image) -{ - try - { - m_SemanticRelations->RemoveImage(image); - mitk::SemanticTypes::CaseID caseID = mitk::GetCaseIDFromDataNode(image); - RemoveFromComboBox(caseID); - } - catch (const mitk::SemanticRelationException& e) - { - std::stringstream exceptionMessage; exceptionMessage << e; - MITK_WARN << "Could not correctly remove the selected image from the semantic relations model.\n" - << "Reason: " + exceptionMessage.str(); - } -} - -void QmitkSemanticRelationsView::RemoveSegmentation(const mitk::DataNode* segmentation) -{ - try - { - m_SemanticRelations->RemoveSegmentation(segmentation); - } - catch (const mitk::SemanticRelationException& e) - { - std::stringstream exceptionMessage; exceptionMessage << e; - MITK_WARN << "Could not correctly remove the selected segmentation from the semantic relations model.\n" - << "Reason: " + exceptionMessage.str(); - } -} diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsView.h b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsView.h index 418725afe1..15bc8dd129 100644 --- a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsView.h +++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsView.h @@ -1,114 +1,107 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QMITKSEMANTICRELATIONSVIEW_H #define QMITKSEMANTICRELATIONSVIEW_H // semantic relations plugin #include "ui_QmitkSemanticRelationsControls.h" #include "QmitkLesionInfoWidget.h" #include "QmitkSemanticRelationsContextMenu.h" // semantic relations module #include #include // semantic relations UI module #include // mitk gui common plugin #include // berry #include // mitk qt #include class QmitkDnDDataNodeWidget; class QMenu; /* * @brief The QmitkSemanticRelationsView is an MITK view to combine and show the widgets of the 'SemanticRelationsUI'-module and this semantic relations plugin. * * It allows the MITK user to see and modify the content of the SemanticRelations-session. * A combo box is used to select and show the current patient. */ class QmitkSemanticRelationsView : public QmitkAbstractView, public mitk::IRenderWindowPartListener { Q_OBJECT public: static const std::string VIEW_ID; protected: virtual void SetFocus() override; virtual void CreateQtPartControl(QWidget* parent) override; virtual void RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) override; virtual void RenderWindowPartDeactivated(mitk::IRenderWindowPart* renderWindowPart) override; private Q_SLOTS: - void OnCaseIDSelectionChanged(const QString&); - - void AddToComboBox(const mitk::SemanticTypes::CaseID&); void OnLesionChanged(const mitk::SemanticTypes::Lesion&); void OnDataNodeDoubleClicked(const mitk::DataNode*); - void OnNodesAdded(QmitkDnDDataNodeWidget*, std::vector); + void OnCaseIDSelectionChanged(const QString&); - void OnNodeRemoved(const mitk::DataNode* dataNode); + void OnNodesAdded(QmitkDnDDataNodeWidget*, std::vector); + void OnNodeRemoved(const mitk::DataNode*); private: void SetUpConnections(); /** * @brief Provide a QItemSelectionModel, which supports the data role 'QmitkDataNodeRole' (\see QmitkRenderWindowDataModel). * * The provided QItemSelectionModel is used in the QmitkAbstractView-base class as the selection model of * the selection provider (\see QmitkAbstractView::SetSelectionProvider()). * The default selection provider is a QmitkDataNodeSelectionProvider. Each time a selection in the provided * QItemSeletionModel is changed, a selection changed event is fired. All plugins (views), that subclass the * QmitkAbstractView will be informed about the selection changed via the OnSelectionChanged-function. */ virtual QItemSelectionModel* GetDataNodeSelectionModel() const override; virtual void NodeRemoved(const mitk::DataNode* dataNode) override; + void AddToComboBox(const mitk::SemanticTypes::CaseID& caseID); void RemoveFromComboBox(const mitk::SemanticTypes::CaseID& caseID); void OpenInEditor(const mitk::DataNode* dataNode); void JumpToPosition(const mitk::DataNode* dataNode); - void AddImage(const mitk::DataNode* image); - void AddSegmentation(const mitk::DataNode* segmentation); - - void RemoveImage(const mitk::DataNode* image); - void RemoveSegmentation(const mitk::DataNode* segmentation); - Ui::QmitkSemanticRelationsControls m_Controls; QmitkLesionInfoWidget* m_LesionInfoWidget; QmitkPatientTableInspector* m_PatientTableInspector; QmitkDnDDataNodeWidget* m_DnDDataNodeWidget; QmitkSemanticRelationsContextMenu* m_ContextMenu; std::unique_ptr m_SemanticRelations; }; #endif // QMITKSEMANTICRELATIONSVIEW_H