diff --git a/Modules/QtWidgets/files.cmake b/Modules/QtWidgets/files.cmake index 4822eb025f..814f2211e4 100644 --- a/Modules/QtWidgets/files.cmake +++ b/Modules/QtWidgets/files.cmake @@ -1,107 +1,109 @@ file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*") set(CPP_FILES QmitkAbstractDataStorageModel.cpp QmitkApplicationCursor.cpp QmitkDataStorageComboBox.cpp QmitkDataStorageDefaultListModel.cpp QmitkDataStorageListModel.cpp QmitkDataStorageTableModel.cpp QmitkDataStorageSimpleTreeModel.cpp QmitkDataStorageTreeModel.cpp QmitkDataStorageTreeModelInternalItem.cpp + QmitkDnDDataNodeWidget.cpp QmitkFileReaderOptionsDialog.cpp QmitkFileReaderWriterOptionsWidget.cpp QmitkFileWriterOptionsDialog.cpp QmitkIOUtil.cpp QmitkLevelWindowPresetDefinitionDialog.cpp QmitkLevelWindowRangeChangeDialog.cpp QmitkLevelWindowWidgetContextMenu.cpp QmitkLevelWindowWidget.cpp QmitkLineEditLevelWindowWidget.cpp QmitkMemoryUsageIndicatorView.cpp QmitkMimeTypes.cpp QmitkNodeDescriptor.cpp QmitkColoredNodeDescriptor.cpp QmitkNodeDescriptorManager.cpp QmitkRenderWindowMenu.cpp QmitkProgressBar.cpp QmitkPropertiesTableEditor.cpp QmitkPropertiesTableModel.cpp QmitkPropertyDelegate.cpp QmitkRegisterClasses.cpp QmitkRenderingManager.cpp QmitkRenderingManagerFactory.cpp QmitkRenderWindow.cpp QmitkServiceListWidget.cpp QmitkSliderLevelWindowWidget.cpp QmitkStdMultiWidget.cpp QmitkMouseModeSwitcher.cpp QmitkDataStorageFilterProxyModel.cpp QmitkDataStorageComboBoxWithSelectNone.cpp QmitkPropertyItem.cpp QmitkPropertyItemDelegate.cpp QmitkPropertyItemModel.cpp QmitkStyleManager.cpp QmitkAbstractDataStorageInspector.cpp QmitkDataStorageListInspector.cpp QmitkDataStorageTreeInspector.cpp QmitkModelViewSelectionConnector.cpp mitkIDataStorageInspectorProvider.cpp mitkQtWidgetsActivator.cpp mitkDataStorageInspectorGenerator.cpp ) set(MOC_H_FILES include/QmitkAbstractDataStorageModel.h include/QmitkDataStorageComboBox.h include/QmitkDataStorageTableModel.h include/QmitkDataStorageTreeModel.h include/QmitkDataStorageSimpleTreeModel.h include/QmitkDataStorageDefaultListModel.h + include/QmitkDnDDataNodeWidget.h include/QmitkFileReaderOptionsDialog.h include/QmitkFileReaderWriterOptionsWidget.h include/QmitkFileWriterOptionsDialog.h include/QmitkLevelWindowPresetDefinitionDialog.h include/QmitkLevelWindowRangeChangeDialog.h include/QmitkLevelWindowWidgetContextMenu.h include/QmitkLevelWindowWidget.h include/QmitkLineEditLevelWindowWidget.h include/QmitkMemoryUsageIndicatorView.h include/QmitkNodeDescriptor.h include/QmitkColoredNodeDescriptor.h include/QmitkNodeDescriptorManager.h include/QmitkRenderWindowMenu.h include/QmitkProgressBar.h include/QmitkPropertiesTableEditor.h include/QmitkPropertyDelegate.h include/QmitkRenderingManager.h include/QmitkRenderWindow.h include/QmitkServiceListWidget.h include/QmitkSliderLevelWindowWidget.h include/QmitkStdMultiWidget.h include/QmitkMouseModeSwitcher.h include/QmitkDataStorageComboBoxWithSelectNone.h include/QmitkPropertyItemDelegate.h include/QmitkPropertyItemModel.h include/QmitkDataStorageListInspector.h include/QmitkAbstractDataStorageInspector.h include/QmitkDataStorageTreeInspector.h include/QmitkModelViewSelectionConnector.h ) set(UI_FILES src/QmitkFileReaderOptionsDialog.ui src/QmitkFileWriterOptionsDialog.ui src/QmitkLevelWindowPresetDefinition.ui src/QmitkLevelWindowWidget.ui src/QmitkLevelWindowRangeChange.ui src/QmitkMemoryUsageIndicator.ui src/QmitkServiceListWidgetControls.ui src/QmitkDataStorageListInspector.ui src/QmitkDataStorageTreeInspector.ui ) set(QRC_FILES resource/Qmitk.qrc ) diff --git a/Modules/QtWidgets/include/QmitkDnDDataNodeWidget.h b/Modules/QtWidgets/include/QmitkDnDDataNodeWidget.h new file mode 100644 index 0000000000..7a927a3314 --- /dev/null +++ b/Modules/QtWidgets/include/QmitkDnDDataNodeWidget.h @@ -0,0 +1,66 @@ +/*=================================================================== + +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 QMITKDNDDATANODEWIDGET_H +#define QMITKDNDDATANODEWIDGET_H + +#include "MitkQtWidgetsExports.h" + +// mitk core module +#include + +// qt +#include + +class QDragEnterEvent; +class QDropEvent; + +/** +* @brief A drag 'n' drop widget (QFrame) that checks the mime data of the incoming +* event. If the drag event is coming from another widget and the mime data +* is of type 'application/x-qmitk-datanode-ptrs' the node(s) will be dropped +* and a signal is emitted. +* A class including this dnd-widget can than handle the vector of dropped nodes +* appropriately. +* +*/ +class MITKQTWIDGETS_EXPORT QmitkDnDDataNodeWidget : public QFrame +{ + Q_OBJECT + +public: + + QmitkDnDDataNodeWidget(QWidget* parent = nullptr); + ~QmitkDnDDataNodeWidget() override; + +Q_SIGNALS: + + /** + * @brief The signal will be emitted if the drag events are accepted. + * It contains the sending dnd-widget and the vector of nodes that have been dropped. + * + */ + void NodesDropped(QmitkDnDDataNodeWidget* dnDDataNodeWidget, std::vector nodes); + +private: + + void dragEnterEvent(QDragEnterEvent* event) override; + void dragMoveEvent(QDragMoveEvent* event) override; + void dropEvent(QDropEvent* event) override; + +}; + +#endif // QMITKDNDDATANODEWIDGET_H diff --git a/Modules/QtWidgets/src/QmitkDnDDataNodeWidget.cpp b/Modules/QtWidgets/src/QmitkDnDDataNodeWidget.cpp new file mode 100644 index 0000000000..010e2504a0 --- /dev/null +++ b/Modules/QtWidgets/src/QmitkDnDDataNodeWidget.cpp @@ -0,0 +1,70 @@ +/*=================================================================== + +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. + +===================================================================*/ + +#include + +// mitk qt widgets module +#include "QmitkMimeTypes.h" + +// qt +#include + +QmitkDnDDataNodeWidget::QmitkDnDDataNodeWidget(QWidget* parent /*= nullptr*/) + : QFrame(parent) +{ + setAcceptDrops(true); +} + +QmitkDnDDataNodeWidget::~QmitkDnDDataNodeWidget() +{ + // nothing here +} + +void QmitkDnDDataNodeWidget::dragEnterEvent(QDragEnterEvent* event) +{ + if (this != event->source()) + { + event->acceptProposedAction(); + } + else + { + event->ignore(); + } +} + +void QmitkDnDDataNodeWidget::dragMoveEvent(QDragMoveEvent* event) +{ + if (event->mimeData()->hasFormat(QmitkMimeTypes::DataNodePtrs)) + { + event->acceptProposedAction(); + } + else + { + event->ignore(); + } +} + +void QmitkDnDDataNodeWidget::dropEvent(QDropEvent* event) +{ + QList dataNodeList = QmitkMimeTypes::ToDataNodePtrList(event->mimeData()); + if (!dataNodeList.empty()) + { + emit NodesDropped(this, dataNodeList.toVector().toStdVector()); + } + + event->acceptProposedAction(); +} + diff --git a/Modules/SemanticRelationsUI/files.cmake b/Modules/SemanticRelationsUI/files.cmake index ceda26fe10..9d2e0591b6 100644 --- a/Modules/SemanticRelationsUI/files.cmake +++ b/Modules/SemanticRelationsUI/files.cmake @@ -1,26 +1,24 @@ file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*") set(CPP_FILES mitkModuleActivator.cpp QmitkAbstractSemanticRelationsStorageModel.cpp QmitkControlPointDialog.cpp QmitkLesionTextDialog.cpp QmitkPatientTableInspector.cpp QmitkPatientTableModel.cpp - QmitkSemanticRelationsModel.cpp QmitkSemanticRelationsUIHelper.cpp ) set(MOC_H_FILES include/QmitkAbstractSemanticRelationsStorageInspector.h include/QmitkAbstractSemanticRelationsStorageModel.h include/QmitkControlPointDialog.h include/QmitkLesionTextDialog.h include/QmitkPatientTableInspector.h include/QmitkPatientTableModel.h - include/QmitkSemanticRelationsModel.h ) set(UI_FILES src/QmitkPatientTableInspector.ui ) 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 97765ef20b..80fe8e3a5b 100644 --- a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsView.cpp +++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsView.cpp @@ -1,163 +1,273 @@ /*=================================================================== 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" // semantic relations module #include #include #include +// mitk qt widgets module +#include + // blueberry #include #include // qt #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); + SetUpConnections(); } void QmitkSemanticRelationsView::SetUpConnections() { connect(m_Controls.caseIDComboBox, static_cast(&QComboBox::currentIndexChanged), this, &QmitkSemanticRelationsView::OnCaseIDSelectionChanged); - connect(m_LesionInfoWidget, &QmitkLesionInfoWidget::LesionChanged, this, &QmitkSemanticRelationsView::OnLesionChanged); + connect(m_DnDDataNodeWidget, &QmitkDnDDataNodeWidget::NodesDropped, this, &QmitkSemanticRelationsView::NodesAdded); } 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::NodesAdded(QmitkDnDDataNodeWidget* dnDDataNodeWidget, std::vector nodes) +{ + 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); + } } } void QmitkSemanticRelationsView::OnCaseIDSelectionChanged(const QString& caseID) { m_LesionInfoWidget->SetCurrentCaseID(caseID.toStdString()); m_PatientTableInspector->SetCaseID(caseID.toStdString()); } void QmitkSemanticRelationsView::OnJumpToPosition(const mitk::Point3D& position) { mitk::IRenderWindowPart* renderWindowPart = GetRenderWindowPart(); if (nullptr != renderWindowPart) { renderWindowPart->SetSelectedPosition(position); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkSemanticRelationsView::OnLesionChanged(const mitk::SemanticTypes::Lesion& lesion) { m_PatientTableInspector->SetLesion(lesion); } 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::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; QMessageBox msgBox; msgBox.setWindowTitle("Could not remove the selected image."); msgBox.setText("The program wasn't able to correctly remove the selected image from the semantic relations model.\n" "Reason:\n" + QString::fromStdString(exceptionMessage.str())); msgBox.setIcon(QMessageBox::Warning); msgBox.exec(); } } void QmitkSemanticRelationsView::RemoveSegmentation(const mitk::DataNode* segmentation) { try { m_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 from the semantic relations model.\n" "Reason:\n" + QString::fromStdString(exceptionMessage.str())); msgBox.setIcon(QMessageBox::Warning); msgBox.exec(); } } 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 4e54595d9d..fee49e432a 100644 --- a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsView.h +++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsView.h @@ -1,87 +1,94 @@ /*=================================================================== 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" // semantic relations module #include #include // semantic relations UI module #include // blueberry #include // mitk qt #include +class QmitkDnDDataNodeWidget; + /* * @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. * * SIDE NOTE: Modifying the control points and information types of data in the semantic relations model is currently done * by using the right-click context-menu of the "PatientTableWidget" in the "Select Patient Node"-Dialog. * This is a leftover from when the widget was not used as a selection widget. Those functionality will be moved * to this main GUI soon. */ class QmitkSemanticRelationsView : public QmitkAbstractView { Q_OBJECT public: static const std::string VIEW_ID; protected: virtual void SetFocus() override; virtual void CreateQtPartControl(QWidget* parent) override; private Q_SLOTS: void OnCaseIDSelectionChanged(const QString&); void AddToComboBox(const mitk::SemanticTypes::CaseID&); void OnJumpToPosition(const mitk::Point3D&); void OnLesionChanged(const mitk::SemanticTypes::Lesion&); private: void SetUpConnections(); virtual void NodeRemoved(const mitk::DataNode* dataNode) override; + void NodesAdded(QmitkDnDDataNodeWidget* dnDDataNodeWidget, std::vector nodes); void RemoveFromComboBox(const mitk::SemanticTypes::CaseID& caseID); + 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; std::unique_ptr m_SemanticRelations; }; #endif // QMITKSEMANTICRELATIONSVIEW_H