diff --git a/Modules/SemanticRelationsUI/include/QmitkAbstractSemanticRelationsStorageModel.h b/Modules/SemanticRelationsUI/include/QmitkAbstractSemanticRelationsStorageModel.h index 207274636b..abf0253036 100644 --- a/Modules/SemanticRelationsUI/include/QmitkAbstractSemanticRelationsStorageModel.h +++ b/Modules/SemanticRelationsUI/include/QmitkAbstractSemanticRelationsStorageModel.h @@ -1,92 +1,104 @@ /*=================================================================== 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 QMITKABSTRACTSEMANTICRELATIONSSTORAGEMODEL_H #define QMITKABSTRACTSEMANTICRELATIONSSTORAGEMODEL_H // semantic relations module +#include #include #include // qt widgets module #include "QmitkAbstractDataStorageModel.h" /* * @brief The QmitkAbstractSemanticRelationsStorageModel is a subclass of 'QmitkAbstractDataStorageModel' and provides additional * functionality to set and store a semantic relations instance, the current case ID and the current lesion. */ -class QmitkAbstractSemanticRelationsStorageModel : public QmitkAbstractDataStorageModel +class QmitkAbstractSemanticRelationsStorageModel : public QmitkAbstractDataStorageModel, public mitk::ISemanticRelationsObserver { Q_OBJECT public: QmitkAbstractSemanticRelationsStorageModel(QObject* parent = nullptr); virtual ~QmitkAbstractSemanticRelationsStorageModel(); + /* + * @brief Updates this model with the data from the semantic relations. + * + * Overridden from 'ISemanticRelationsObserver'. + * In order for the Update-function to be called, this model has to be added as a observer of SemanticRelation + * (e.g. m_SemanticRelations->AddObserver(m_SemanticRelationsStorageModel);) + * + * @par caseID The current case ID to identify the currently active patient / case. + */ + virtual void Update(const mitk::SemanticTypes::CaseID& caseID) override; + std::shared_ptr GetSemanticRelations() const { return m_SemanticRelations; } /** * @brief Sets the current case ID which is needed to access the semantic relations storage. * * @param caseID A case ID as string */ void SetCaseID(const mitk::SemanticTypes::CaseID& caseID); const mitk::SemanticTypes::CaseID& GetCaseID() const { return m_CaseID; } /** * @brief Sets the current lesion which can be used to show on which images the lesion is visible. * * @param lesion The selected lesion */ void SetLesion(const mitk::SemanticTypes::Lesion& lesion); const mitk::SemanticTypes::Lesion& GetLesion() const { return m_Lesion; } /* * @brief Updates the semantic relations storage model with the current data from the semantic relations model, * if the case ID is equal to the currently selected case ID of the table model. */ void UpdateModelData(const mitk::SemanticTypes::CaseID& caseID); /* * @brief Updates the semantic relations storage model with the current data from the semantic relations model * and the current case ID. */ void UpdateModelData(); Q_SIGNALS: void ModelUpdated(); protected: /** * @brief Creates a new 'SemanticRelations' instance with the new data storage and updates the model data. * This functions is called inside the 'SetDataStorage'-function from the parent class. */ virtual void DataStorageChanged() override; /** * @brief This function is called if the model data is updated. It can be used by subclasses to define * the way the data of a specific model is generated. It typically consists of access to the * semantic relations storage to retrieve certain information. */ virtual void SetData() = 0; std::shared_ptr m_SemanticRelations; mitk::SemanticTypes::CaseID m_CaseID; mitk::SemanticTypes::Lesion m_Lesion; }; #endif // QMITKABSTRACTSEMANTICRELATIONSSTORAGEMODEL_H diff --git a/Modules/SemanticRelationsUI/src/QmitkAbstractSemanticRelationsStorageModel.cpp b/Modules/SemanticRelationsUI/src/QmitkAbstractSemanticRelationsStorageModel.cpp index 4bd95abb96..5656522e18 100644 --- a/Modules/SemanticRelationsUI/src/QmitkAbstractSemanticRelationsStorageModel.cpp +++ b/Modules/SemanticRelationsUI/src/QmitkAbstractSemanticRelationsStorageModel.cpp @@ -1,75 +1,89 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // semantic relations UI module #include "QmitkAbstractSemanticRelationsStorageModel.h" #include "QmitkCustomVariants.h" QmitkAbstractSemanticRelationsStorageModel::QmitkAbstractSemanticRelationsStorageModel(QObject* parent /*= nullptr*/) : QmitkAbstractDataStorageModel(parent) , m_SemanticRelations(nullptr) { // nothing here } QmitkAbstractSemanticRelationsStorageModel::~QmitkAbstractSemanticRelationsStorageModel() { - // nothing here + if (nullptr != m_SemanticRelations) + { + m_SemanticRelations->RemoveObserver(this); + } +} + +void QmitkAbstractSemanticRelationsStorageModel::Update(const mitk::SemanticTypes::CaseID& caseID) +{ + UpdateModelData(caseID); } void QmitkAbstractSemanticRelationsStorageModel::SetCaseID(const mitk::SemanticTypes::CaseID& caseID) { m_CaseID = caseID; UpdateModelData(); } void QmitkAbstractSemanticRelationsStorageModel::SetLesion(const mitk::SemanticTypes::Lesion& lesion) { m_Lesion = lesion; UpdateModelData(); } void QmitkAbstractSemanticRelationsStorageModel::UpdateModelData(const mitk::SemanticTypes::CaseID& caseID) { // if the case ID of updated instance is equal to the currently active caseID if (caseID == m_CaseID) { UpdateModelData(); } } void QmitkAbstractSemanticRelationsStorageModel::UpdateModelData() { if (nullptr == m_SemanticRelations) { return; } // update the model, so that the table will be filled with the new patient information beginResetModel(); SetData(); endResetModel(); emit ModelUpdated(); } void QmitkAbstractSemanticRelationsStorageModel::DataStorageChanged() { + if (nullptr != m_SemanticRelations) + { + m_SemanticRelations->RemoveObserver(this); + } + m_SemanticRelations = std::make_shared(m_DataStorage.Lock()); + m_SemanticRelations->AddObserver(this); UpdateModelData(); } diff --git a/Modules/SemanticRelationsUI/src/QmitkPatientTableInspector.ui b/Modules/SemanticRelationsUI/src/QmitkPatientTableInspector.ui index 0f0d2e4e1a..c953d1b58a 100644 --- a/Modules/SemanticRelationsUI/src/QmitkPatientTableInspector.ui +++ b/Modules/SemanticRelationsUI/src/QmitkPatientTableInspector.ui @@ -1,59 +1,63 @@ QmitkPatientTableInspector 0 0 350 300 - - - 0 - + 0 0 0 0 - - + + - Show image nodes + Semantic Relations content: + + + + + + + Show segmentation nodes nodeButtonGroup - - + + - Show segmentation nodes + Show image nodes nodeButtonGroup - + diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkLesionInfoWidget.cpp b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkLesionInfoWidget.cpp index 4a4c4c59b9..22e2450673 100644 --- a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkLesionInfoWidget.cpp +++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkLesionInfoWidget.cpp @@ -1,1032 +1,475 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // semantic relations plugin #include "QmitkLesionInfoWidget.h" #include "QmitkSemanticRelationsNodeSelectionDialog.h" // semantic relations UI module #include // semantic relations module #include #include #include #include #include "QmitkCustomVariants.h" // multi label module #include // mitk core #include // qt #include #include #include #include #include const QBrush QmitkLesionInfoWidget::DEFAULT_BACKGROUND_COLOR = QBrush(Qt::transparent); const QBrush QmitkLesionInfoWidget::SELECTED_BACKGROUND_COLOR = QBrush(Qt::green); const QBrush QmitkLesionInfoWidget::CONNECTED_BACKGROUND_COLOR = QBrush(Qt::darkGreen); QmitkLesionInfoWidget::QmitkLesionInfoWidget(mitk::DataStorage* dataStorage, QWidget* parent /*= nullptr*/) : QWidget(parent) , m_DataStorage(dataStorage) , m_SemanticRelations(std::make_unique(dataStorage)) { Init(); } QmitkLesionInfoWidget::~QmitkLesionInfoWidget() { - m_SemanticRelations->RemoveObserver(this); + if (nullptr != m_SemanticRelations) + { + m_SemanticRelations->RemoveObserver(this); + } } void QmitkLesionInfoWidget::Init() { // create GUI from the Qt Designer's .ui file m_Controls.setupUi(this); m_Controls.lesionListWidget->setContextMenuPolicy(Qt::CustomContextMenu); - m_Controls.segmentationListWidget->setContextMenuPolicy(Qt::CustomContextMenu); - m_Controls.imageListWidget->setContextMenuPolicy(Qt::CustomContextMenu); SetUpConnections(); m_SemanticRelations->AddObserver(this); } void QmitkLesionInfoWidget::SetUpConnections() { // connect buttons to modify semantic relations connect(m_Controls.addLesionPushButton, &QPushButton::clicked, this, &QmitkLesionInfoWidget::OnAddLesionButtonClicked); - connect(m_Controls.addSegmentationPushButton, &QPushButton::clicked, this, &QmitkLesionInfoWidget::OnAddSegmentationButtonClicked); - connect(m_Controls.addImagePushButton, &QPushButton::clicked, this, &QmitkLesionInfoWidget::OnAddImageButtonClicked); // connect each list widget with a custom slots connect(m_Controls.lesionListWidget, &QListWidget::currentItemChanged, this, &QmitkLesionInfoWidget::OnCurrentLesionItemChanged); connect(m_Controls.lesionListWidget, &QListWidget::itemDoubleClicked, this, &QmitkLesionInfoWidget::OnLesionItemDoubleClicked); - connect(m_Controls.segmentationListWidget, &QListWidget::currentItemChanged, this, &QmitkLesionInfoWidget::OnCurrentSegmentationItemChanged); - connect(m_Controls.segmentationListWidget, &QListWidget::itemDoubleClicked, this, &QmitkLesionInfoWidget::OnSegmentationItemDoubleClicked); - connect(m_Controls.imageListWidget, &QListWidget::currentItemChanged, this, &QmitkLesionInfoWidget::OnCurrentImageItemChanged); - connect(m_Controls.imageListWidget, &QListWidget::itemDoubleClicked, this, &QmitkLesionInfoWidget::OnImageItemDoubleClicked); // connect context menu entries connect(m_Controls.lesionListWidget, &QListWidget::customContextMenuRequested, this, &QmitkLesionInfoWidget::OnLesionListContextMenuRequested); - connect(m_Controls.segmentationListWidget, &QListWidget::customContextMenuRequested, this, &QmitkLesionInfoWidget::OnSegmentationListContextMenuRequested); - connect(m_Controls.imageListWidget, &QListWidget::customContextMenuRequested, this, &QmitkLesionInfoWidget::OnImageListContextMenuRequested); } void QmitkLesionInfoWidget::SetCurrentCaseID(const mitk::SemanticTypes::CaseID& caseID) { m_CaseID = caseID; Update(m_CaseID); } void QmitkLesionInfoWidget::Update(const mitk::SemanticTypes::CaseID& caseID) { if (nullptr == m_SemanticRelations) { return; } // if the case ID of updated instance is equal to the currently active caseID if (caseID == m_CaseID) { ResetLesionListWidget(); - ResetSegmentationListWidget(); - ResetImageListWidget(); } } ////////////////////////////////////////////////////////////////////////// // Implementation of the QT_SLOTS ////////////////////////////////////////////////////////////////////////// void QmitkLesionInfoWidget::OnAddLesionButtonClicked() { if (m_CaseID.empty()) { QMessageBox msgBox; msgBox.setWindowTitle("No case ID set."); msgBox.setText("In order to add a lesion, please specify the current case / patient."); msgBox.setIcon(QMessageBox::Warning); msgBox.exec(); return; } mitk::SemanticTypes::Lesion newLesion = mitk::GenerateNewLesion(); try { m_SemanticRelations->AddLesion(m_CaseID, newLesion); } catch (mitk::SemanticRelationException& e) { MITK_INFO << "Could not add a new lesion. " << e; } } -void QmitkLesionInfoWidget::OnAddSegmentationButtonClicked() -{ - if (m_CaseID.empty()) - { - QMessageBox msgBox; - msgBox.setWindowTitle("No case ID set."); - msgBox.setText("In order to add a segmentation, please specify the current case / patient."); - msgBox.setIcon(QMessageBox::Warning); - msgBox.exec(); - return; - } - - QmitkSemanticRelationsNodeSelectionDialog* dialog = new QmitkSemanticRelationsNodeSelectionDialog(this, "Select segmentations to add to the semantic relations storage", ""); - dialog->SetDataStorage(m_DataStorage); - dialog->setWindowTitle("Select segmentation node"); - dialog->SetNodePredicate(mitk::NodePredicates::GetSegmentationPredicate()); - dialog->SetSelectOnlyVisibleNodes(true); - dialog->SetSelectionMode(QAbstractItemView::MultiSelection); - dialog->SetCaseID(m_CaseID); - - int dialogReturnValue = dialog->exec(); - if (QDialog::Rejected == dialogReturnValue) - { - return; - } - - auto nodes = dialog->GetSelectedNodes(); - for (mitk::DataNode* dataNode : nodes) - { - if (nullptr == dataNode) - { - continue; - } - - mitk::BaseData* baseData = dataNode->GetData(); - if (nullptr == baseData) - { - continue; - } - - // continue with valid segmentation data - // get parent node of the current segmentation node with the node predicate - mitk::DataStorage::SetOfObjects::ConstPointer parentNodes = m_DataStorage->GetSources(dataNode, 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(dataNode, 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 QmitkLesionInfoWidget::OnAddImageButtonClicked() -{ - QmitkSemanticRelationsNodeSelectionDialog* dialog = new QmitkSemanticRelationsNodeSelectionDialog(this, "Select images to add to the semantic relations storage", ""); - dialog->SetDataStorage(m_DataStorage); - dialog->setWindowTitle("Select image node"); - dialog->SetNodePredicate(mitk::NodePredicates::GetImagePredicate()); - dialog->SetSelectOnlyVisibleNodes(true); - dialog->SetSelectionMode(QAbstractItemView::MultiSelection); - dialog->SetCaseID(m_CaseID); - - int dialogReturnValue = dialog->exec(); - if (QDialog::Rejected == dialogReturnValue) - { - return; - } - - auto nodes = dialog->GetSelectedNodes(); - for (mitk::DataNode* dataNode : nodes) - { - if (nullptr != dataNode) - { - try - { - // add the image to the semantic relations storage - m_SemanticRelations->AddImage(dataNode); - mitk::SemanticTypes::CaseID caseID = mitk::GetCaseIDFromDataNode(dataNode); - emit ImageAdded(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 QmitkLesionInfoWidget::OnCurrentLesionItemChanged(QListWidgetItem* current, QListWidgetItem* /*previous*/) { - if (nullptr == m_SemanticRelations - || nullptr == current + if (nullptr == current + || nullptr == m_SemanticRelations || nullptr == m_DataStorage) { return; } // only the UID is needed to identify a representing lesion m_CurrentLesion.UID = current->data(Qt::UserRole).toString().toStdString(); if (false == m_SemanticRelations->InstanceExists(m_CaseID, m_CurrentLesion)) { // no UID found; cannot create a lesion return; } if (SELECTED_BACKGROUND_COLOR == current->background() || CONNECTED_BACKGROUND_COLOR == current->background()) { DarkenBackgroundColors(); } else { ResetBackgroundColors(); } current->setBackground(SELECTED_BACKGROUND_COLOR); - try - { - // get all corresponding segmentations of the currently selected lesion and set the background color - mitk::SemanticRelations::DataNodeVector allSegmentationsOfLesion = m_SemanticRelations->GetAllSegmentationsOfLesion(m_CaseID, m_CurrentLesion); - for (const auto& segmentation : allSegmentationsOfLesion) - { - QList items = m_Controls.segmentationListWidget->findItems(QString::fromStdString(segmentation->GetName()), Qt::MatchExactly); - for (auto& item : items) - { - item->setBackground(SELECTED_BACKGROUND_COLOR); - } - - // get parent nodes of the current segmentation node and set the background color - mitk::DataStorage::SetOfObjects::ConstPointer parentNodes = m_DataStorage->GetSources(segmentation, mitk::NodePredicates::GetImagePredicate(), false); - for (auto it = parentNodes->Begin(); it != parentNodes->End(); ++it) - { - QList items = m_Controls.imageListWidget->findItems(QString::fromStdString(it->Value()->GetName()), Qt::MatchExactly); - for (auto& item : items) - { - item->setBackground(SELECTED_BACKGROUND_COLOR); - } - } - } - } - catch (const mitk::SemanticRelationException& e) - { - std::stringstream exceptionMessage; exceptionMessage << e; - QMessageBox msgBox; - msgBox.setWindowTitle("No segmentations retrieved"); - msgBox.setText("Could not automatically retrieve all segmentations of the selected lesion.\n" - "Reason:\n" + QString::fromStdString(exceptionMessage.str())); - msgBox.setIcon(QMessageBox::Warning); - msgBox.exec(); - return; - } + + emit LesionChanged(m_CurrentLesion); } void QmitkLesionInfoWidget::OnLesionItemDoubleClicked(QListWidgetItem* clickedItem) { if (nullptr == clickedItem || nullptr == m_SemanticRelations) { return; } // only the UID is needed to identify a representing lesion m_CurrentLesion.UID = clickedItem->data(Qt::UserRole).toString().toStdString(); m_CurrentLesion.name = clickedItem->text().toStdString(); } -void QmitkLesionInfoWidget::OnCurrentSegmentationItemChanged(QListWidgetItem* current, QListWidgetItem* /*previous*/) -{ - if (nullptr == m_SemanticRelations - || nullptr == current - || nullptr == m_DataStorage) - { - return; - } - - QString segmentationName = current->text(); - m_CurrentSegmentation = m_DataStorage->GetNamedNode(segmentationName.toStdString()); - if (nullptr == m_CurrentSegmentation) - { - return; - } - - if (SELECTED_BACKGROUND_COLOR == current->background() - || CONNECTED_BACKGROUND_COLOR == current->background()) - { - DarkenBackgroundColors(); - } - else - { - ResetBackgroundColors(); - } - - current->setBackground(SELECTED_BACKGROUND_COLOR); - - // get parent nodes of the current segmentation node and set the background color - mitk::DataStorage::SetOfObjects::ConstPointer parentNodes = m_DataStorage->GetSources(m_CurrentSegmentation, mitk::NodePredicates::GetImagePredicate(), false); - for (auto it = parentNodes->Begin(); it != parentNodes->End(); ++it) - { - QList items = m_Controls.imageListWidget->findItems(QString::fromStdString(it->Value()->GetName()), Qt::MatchExactly); - for (auto& item : items) - { - item->setBackground(SELECTED_BACKGROUND_COLOR); - } - } - - // get represented lesion of the current segmentation node and set the background color - if (m_SemanticRelations->IsRepresentingALesion(m_CurrentSegmentation)) - { - try - { - mitk::SemanticTypes::Lesion representedLesion = m_SemanticRelations->GetRepresentedLesion(m_CurrentSegmentation); - for (int i = 0; i < m_Controls.lesionListWidget->count(); ++i) - { - QListWidgetItem* item = m_Controls.lesionListWidget->item(i); - std::string currentLesionUID = item->data(Qt::UserRole).toString().toStdString(); - if (currentLesionUID == representedLesion.UID) - { - item->setBackground(SELECTED_BACKGROUND_COLOR); - } - } - } - catch (const mitk::SemanticRelationException& e) - { - std::stringstream exceptionMessage; exceptionMessage << e; - QMessageBox msgBox; - msgBox.setWindowTitle("No lesion retrieved"); - msgBox.setText("Could not automatically retrieve the represented lesion of the selected segmentation.\n" - "Reason:\n" + QString::fromStdString(exceptionMessage.str())); - msgBox.setIcon(QMessageBox::Warning); - msgBox.exec(); - return; - } - } -} - -void QmitkLesionInfoWidget::OnSegmentationItemDoubleClicked(QListWidgetItem* clickedItem) -{ - if (nullptr == clickedItem - || nullptr == m_DataStorage) - { - return; - } - - QString segmentationName = clickedItem->text(); - m_CurrentSegmentation = m_DataStorage->GetNamedNode(segmentationName.toStdString()); - if (nullptr == m_CurrentSegmentation) - { - return; - } - - mitk::LabelSetImage* labelSetImage = dynamic_cast(m_CurrentSegmentation->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) - { - emit JumpToPosition(centerPosition); - } -} - -void QmitkLesionInfoWidget::OnCurrentImageItemChanged(QListWidgetItem* current, QListWidgetItem* /*previous*/) -{ - if (nullptr == m_SemanticRelations - || nullptr == current - || nullptr == m_DataStorage) - { - return; - } - - QString imageName = current->text(); - m_CurrentImage = m_DataStorage->GetNamedNode(imageName.toStdString()); - if (nullptr == m_CurrentImage) - { - return; - } - - if (SELECTED_BACKGROUND_COLOR == current->background() - || CONNECTED_BACKGROUND_COLOR == current->background()) - { - DarkenBackgroundColors(); - } - else - { - ResetBackgroundColors(); - } - - current->setBackground(SELECTED_BACKGROUND_COLOR); - - // get child nodes of the current image node and set the background color - mitk::DataStorage::SetOfObjects::ConstPointer segmentationNodes = m_DataStorage->GetDerivations(m_CurrentImage, mitk::NodePredicates::GetSegmentationPredicate(), false); - for (auto it = segmentationNodes->Begin(); it != segmentationNodes->End(); ++it) - { - QList items = m_Controls.segmentationListWidget->findItems(QString::fromStdString(it->Value()->GetName()), Qt::MatchExactly); - for (auto& item : items) - { - item->setBackground(SELECTED_BACKGROUND_COLOR); - } - - try - { - // get represented lesion of the current segmentation node and set the background color - if (m_SemanticRelations->IsRepresentingALesion(it->Value())) - { - mitk::SemanticTypes::Lesion representedLesion = m_SemanticRelations->GetRepresentedLesion(it->Value()); - for (int i = 0; i < m_Controls.lesionListWidget->count(); ++i) - { - QListWidgetItem* item = m_Controls.lesionListWidget->item(i); - std::string currentLesionUID = item->data(Qt::UserRole).toString().toStdString(); - if (currentLesionUID == representedLesion.UID) - { - item->setBackground(SELECTED_BACKGROUND_COLOR); - } - } - } - } - catch (const mitk::SemanticRelationException& e) - { - std::stringstream exceptionMessage; exceptionMessage << e; - QMessageBox msgBox; - msgBox.setWindowTitle("No lesion retrieved"); - msgBox.setText("Could not automatically retrieve the represented lesion of the selected segmentation.\n" - "Reason:\n" + QString::fromStdString(exceptionMessage.str())); - msgBox.setIcon(QMessageBox::Warning); - msgBox.exec(); - return; - } - } -} - -void QmitkLesionInfoWidget::OnImageItemDoubleClicked(QListWidgetItem* clickedItem) -{ - if (nullptr == clickedItem - || nullptr == m_SemanticRelations) - { - return; - } -} - void QmitkLesionInfoWidget::OnLesionListContextMenuRequested(const QPoint& pos) { QListWidgetItem* currentItem = m_Controls.lesionListWidget->itemAt(pos); if (nullptr == currentItem) { // no item clicked; cannot retrieve the current lesion return; } mitk::SemanticTypes::ID selectedLesionUID; selectedLesionUID = currentItem->data(Qt::UserRole).toString().toStdString(); if (selectedLesionUID.empty()) { // no UID found; cannot create a lesion return; } QMenu* menu = new QMenu(m_Controls.lesionListWidget); QAction* linkToSegmentation = new QAction("Link to segmentation", this); linkToSegmentation->setEnabled(true); connect(linkToSegmentation, &QAction::triggered, [this, selectedLesionUID] { OnLinkToSegmentation(selectedLesionUID); }); menu->addAction(linkToSegmentation); QAction* setLesionName = new QAction("Set lesion name", this); setLesionName->setEnabled(true); connect(setLesionName, &QAction::triggered, [this, selectedLesionUID] { OnSetLesionName(selectedLesionUID); }); menu->addAction(setLesionName); QAction* setLesionClass = new QAction("Set lesion class", this); setLesionClass->setEnabled(true); connect(setLesionClass, &QAction::triggered, [this, selectedLesionUID] { OnSetLesionClass(selectedLesionUID); }); menu->addAction(setLesionClass); QAction* removeLesion = new QAction("Remove lesion", this); removeLesion->setEnabled(true); connect(removeLesion, &QAction::triggered, [this, selectedLesionUID] { OnRemoveLesion(selectedLesionUID); }); menu->addAction(removeLesion); menu->popup(QCursor::pos()); } -void QmitkLesionInfoWidget::OnSegmentationListContextMenuRequested(const QPoint& pos) -{ - QListWidgetItem* currentItem = m_Controls.segmentationListWidget->itemAt(pos); - if (nullptr == currentItem) - { - // no item clicked; cannot retrieve the current segmentation - return; - } - - const mitk::DataNode* selectedSegmentation = m_DataStorage->GetNamedNode(currentItem->text().toStdString()); - if (nullptr == selectedSegmentation) - { - return; - } - - if (false == mitk::NodePredicates::GetSegmentationPredicate()->CheckNode(selectedSegmentation)) - { - return; - } - - QMenu* menu = new QMenu(m_Controls.segmentationListWidget); - QAction* unlinkFromLesion = new QAction("Unlink from lesion", this); - unlinkFromLesion->setEnabled(true); - connect(unlinkFromLesion, &QAction::triggered, [this, selectedSegmentation] { OnUnlinkFromLesion(selectedSegmentation); }); - menu->addAction(unlinkFromLesion); - - QAction* removeSegmentation = new QAction("Remove segmentation", this); - removeSegmentation->setEnabled(true); - connect(removeSegmentation, &QAction::triggered, [this, selectedSegmentation] { OnRemoveSegmentation(selectedSegmentation); }); - menu->addAction(removeSegmentation); - - menu->popup(QCursor::pos()); -} - -void QmitkLesionInfoWidget::OnImageListContextMenuRequested(const QPoint& pos) -{ - QListWidgetItem* currentItem = m_Controls.imageListWidget->itemAt(pos); - if (nullptr == currentItem) - { - // no item clicked; cannot retrieve the current image - return; - } - - const mitk::DataNode* selectedImage = m_DataStorage->GetNamedNode(currentItem->text().toStdString()); - if (nullptr == selectedImage) - { - return; - } - - if (false == mitk::NodePredicates::GetImagePredicate()->CheckNode(selectedImage)) - { - return; - } - - QMenu* menu = new QMenu(m_Controls.imageListWidget); - QAction* removeImage = new QAction("Remove image", this); - removeImage->setEnabled(true); - connect(removeImage, &QAction::triggered, [this, selectedImage] { OnRemoveImage(selectedImage); }); - menu->addAction(removeImage); - - menu->popup(QCursor::pos()); -} - void QmitkLesionInfoWidget::OnLinkToSegmentation(const mitk::SemanticTypes::ID& selectedLesionUID) { if (m_CaseID.empty()) { QMessageBox msgBox; msgBox.setWindowTitle("No case ID set."); msgBox.setText("In order to link a lesion to a segmentation, please specify the current case / patient."); msgBox.setIcon(QMessageBox::Warning); msgBox.exec(); return; } // retrieve the full lesion with its lesion class using the given lesion UID mitk::SemanticTypes::Lesion selectedLesion = mitk::GetLesionByUID(selectedLesionUID, m_SemanticRelations->GetAllLesionsOfCase(m_CaseID)); if (selectedLesion.UID.empty()) { // could not find lesion information for the selected lesion return; } QmitkSemanticRelationsNodeSelectionDialog* dialog = new QmitkSemanticRelationsNodeSelectionDialog(this, "Select segmentation to link to the selected lesion.", ""); dialog->SetDataStorage(m_DataStorage); dialog->setWindowTitle("Select segmentation node"); dialog->SetNodePredicate(mitk::NodePredicates::GetSegmentationPredicate()); dialog->SetSelectOnlyVisibleNodes(true); dialog->SetSelectionMode(QAbstractItemView::SingleSelection); dialog->SetCaseID(m_CaseID); int dialogReturnValue = dialog->exec(); if (QDialog::Rejected == dialogReturnValue) { return; } auto nodes = dialog->GetSelectedNodes(); mitk::DataNode::Pointer selectedDataNode = nullptr; if (!nodes.isEmpty()) { // only single selection allowed selectedDataNode = nodes.front(); } if (nullptr == selectedDataNode) { QMessageBox msgBox; msgBox.setWindowTitle("No valid segmentation node selected."); msgBox.setText("In order to link the selected lesion to a segmentation, please specify a valid segmentation node."); msgBox.setIcon(QMessageBox::Warning); msgBox.exec(); return; } if (false == mitk::NodePredicates::GetSegmentationPredicate()->CheckNode(selectedDataNode)) { QMessageBox msgBox; msgBox.setWindowTitle("No segmentation selected"); msgBox.setText("In order to link the selected lesion to a segmentation, please specify a valid segmentation node."); msgBox.setIcon(QMessageBox::Warning); msgBox.exec(); return; } mitk::BaseData* baseData = selectedDataNode->GetData(); if (nullptr == baseData) { QMessageBox msgBox; msgBox.setWindowTitle("No valid base data."); msgBox.setText("In order to link the selected lesion to a segmentation, please specify a valid segmentation node."); msgBox.setIcon(QMessageBox::Warning); msgBox.exec(); return; } try { m_SemanticRelations->LinkSegmentationToLesion(selectedDataNode, selectedLesion); } catch (const mitk::SemanticRelationException& e) { std::stringstream exceptionMessage; exceptionMessage << e; QMessageBox msgBox; msgBox.setWindowTitle("Could not link the selected lesion."); msgBox.setText("The program wasn't able to correctly link the selected lesion with the selected segmentation.\n" "Reason:\n" + QString::fromStdString(exceptionMessage.str())); msgBox.setIcon(QMessageBox::Warning); msgBox.exec(); } } void QmitkLesionInfoWidget::OnSetLesionName(const mitk::SemanticTypes::ID& selectedLesionUID) { // retrieve the full lesion with its lesion class using the given lesion UID mitk::SemanticTypes::Lesion selectedLesion = mitk::GetLesionByUID(selectedLesionUID, m_SemanticRelations->GetAllLesionsOfCase(m_CaseID)); if (selectedLesion.UID.empty()) { // could not find lesion information for the selected lesion return; } // use the lesion information to set the input text for the dialog QmitkLesionTextDialog* inputDialog = new QmitkLesionTextDialog(this); inputDialog->setWindowTitle("Set lesion name"); inputDialog->SetLineEditText(selectedLesion.name); int dialogReturnValue = inputDialog->exec(); if (QDialog::Rejected == dialogReturnValue) { return; } std::string newLesionName = inputDialog->GetLineEditText().toStdString(); selectedLesion.name = newLesionName; m_SemanticRelations->OverwriteLesion(m_CaseID, selectedLesion); } void QmitkLesionInfoWidget::OnSetLesionClass(const mitk::SemanticTypes::ID& selectedLesionUID) { // retrieve the full lesion with its lesion class using the given lesion UID mitk::SemanticTypes::Lesion selectedLesion = mitk::GetLesionByUID(selectedLesionUID, m_SemanticRelations->GetAllLesionsOfCase(m_CaseID)); if (selectedLesion.UID.empty()) { // could not find lesion information for the selected lesion return; } // use the lesion information to set the input text for the dialog QmitkLesionTextDialog* inputDialog = new QmitkLesionTextDialog(this); inputDialog->setWindowTitle("Set lesion class"); inputDialog->SetLineEditText(selectedLesion.lesionClass.classType); // prepare the completer for the dialogs input text field mitk::LesionClassVector allLesionClasses = m_SemanticRelations->GetAllLesionClassesOfCase(m_CaseID); QStringList wordList; for (const auto& lesionClass : allLesionClasses) { wordList << QString::fromStdString(lesionClass.classType); } QCompleter* completer = new QCompleter(wordList, this); completer->setCaseSensitivity(Qt::CaseInsensitive); inputDialog->GetLineEdit()->setCompleter(completer); int dialogReturnValue = inputDialog->exec(); if (QDialog::Rejected == dialogReturnValue) { return; } // retrieve the new input lesion class type and check for an already existing lesion class types std::string newLesionClassType = inputDialog->GetLineEditText().toStdString(); mitk::SemanticTypes::LesionClass existingLesionClass = mitk::FindExistingLesionClass(newLesionClassType, allLesionClasses); if (existingLesionClass.UID.empty()) { // could not find lesion class information for the new lesion class type // create a new lesion class for the selected lesion existingLesionClass = mitk::GenerateNewLesionClass(newLesionClassType); } selectedLesion.lesionClass = existingLesionClass; m_SemanticRelations->OverwriteLesion(m_CaseID, selectedLesion); } void QmitkLesionInfoWidget::OnRemoveLesion(const mitk::SemanticTypes::ID& selectedLesionUID) { if (m_CaseID.empty()) { QMessageBox msgBox; msgBox.setWindowTitle("No case ID set."); msgBox.setText("In order to remove a lesion, please specify the current case / patient."); msgBox.setIcon(QMessageBox::Warning); msgBox.exec(); return; } // retrieve the full lesion with its lesion class using the given lesion UID mitk::SemanticTypes::Lesion selectedLesion = mitk::GetLesionByUID(selectedLesionUID, m_SemanticRelations->GetAllLesionsOfCase(m_CaseID)); if (selectedLesion.UID.empty()) { // could not find lesion information for the selected lesion return; } try { m_SemanticRelations->RemoveLesion(m_CaseID, selectedLesion); } catch (const mitk::SemanticRelationException& e) { std::stringstream exceptionMessage; exceptionMessage << e; QMessageBox msgBox; msgBox.setWindowTitle("Could not remove the selected lesion."); msgBox.setText("The program wasn't able to correctly remove the selected lesion from the semantic relations model.\n" "Reason:\n" + QString::fromStdString(exceptionMessage.str())); msgBox.setIcon(QMessageBox::Warning); msgBox.exec(); } } -void QmitkLesionInfoWidget::OnUnlinkFromLesion(const mitk::DataNode* selectedSegmentation) -{ - try - { - m_SemanticRelations->UnlinkSegmentationFromLesion(selectedSegmentation); - } - catch (const mitk::SemanticRelationException& e) - { - std::stringstream exceptionMessage; exceptionMessage << e; - QMessageBox msgBox; - msgBox.setWindowTitle("Could not unlink a lesion from the selected segmentation."); - msgBox.setText("The program wasn't able to correctly unlink the lesion from the selected segmentation.\n" - "Reason:\n" + QString::fromStdString(exceptionMessage.str())); - msgBox.setIcon(QMessageBox::Warning); - msgBox.exec(); - } -} - -void QmitkLesionInfoWidget::OnRemoveSegmentation(const mitk::DataNode* selectedSegmentation) -{ - try - { - m_SemanticRelations->RemoveSegmentation(selectedSegmentation); - } - 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(); - } -} - -void QmitkLesionInfoWidget::OnRemoveImage(const mitk::DataNode* selectedImage) -{ - try - { - m_SemanticRelations->RemoveImage(selectedImage); - emit ImageRemoved(selectedImage); - } - 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 QmitkLesionInfoWidget::ResetLesionListWidget() { m_Controls.lesionListWidget->clear(); m_CurrentLesion.UID = ""; m_CurrentLesion.name = ""; // create lesion list widget entries with the current lesions mitk::SemanticRelations::LesionVector allLesionsOfCase = m_SemanticRelations->GetAllLesionsOfCase(m_CaseID); if (allLesionsOfCase.empty()) { m_Controls.lesionListWidget->addItem("No lesions found"); } for (const auto& lesion : allLesionsOfCase) { // store the UID as 'UserRole' data in the widget item QListWidgetItem* lesionItem = new QListWidgetItem; lesionItem->setData(Qt::UserRole, QString::fromStdString(lesion.UID)); // use the lesion UID for the item text, if the lesion name is non-existent if (lesion.name.empty()) { lesionItem->setText(QString::fromStdString(lesion.UID)); } else { lesionItem->setText(QString::fromStdString(lesion.name)); } m_Controls.lesionListWidget->addItem(lesionItem); } } -void QmitkLesionInfoWidget::ResetSegmentationListWidget() -{ - m_Controls.segmentationListWidget->clear(); - m_CurrentSegmentation = nullptr; - - try - { - // create segmentation list widget entries with the current segmentations - mitk::SemanticRelations::DataNodeVector allSegmentationsOfCase = m_SemanticRelations->GetAllSegmentationsOfCase(m_CaseID); - if (allSegmentationsOfCase.empty()) - { - m_Controls.segmentationListWidget->addItem("No segmentations found"); - } - for (const auto& segmentation : allSegmentationsOfCase) - { - m_Controls.segmentationListWidget->addItem(QString::fromStdString(segmentation->GetName())); - } - } - catch (const mitk::SemanticRelationException& e) - { - std::stringstream exceptionMessage; exceptionMessage << e; - QMessageBox msgBox; - msgBox.setWindowTitle("No segmentations retrieved"); - msgBox.setText("Could not automatically retrieve all segmentations of the current case.\n" - "Reason:\n" + QString::fromStdString(exceptionMessage.str())); - msgBox.setIcon(QMessageBox::Warning); - msgBox.exec(); - return; - } -} - -void QmitkLesionInfoWidget::ResetImageListWidget() -{ - m_Controls.imageListWidget->clear(); - m_CurrentImage = nullptr; - - try - { - // create image list widget entries with the current images - mitk::SemanticRelations::DataNodeVector allImagesOfCase = m_SemanticRelations->GetAllImagesOfCase(m_CaseID); - if (allImagesOfCase.empty()) - { - m_Controls.imageListWidget->addItem("No images found"); - } - for (const auto& image : allImagesOfCase) - { - m_Controls.imageListWidget->addItem(QString::fromStdString(image->GetName())); - } - } - catch (const mitk::SemanticRelationException& e) - { - std::stringstream exceptionMessage; exceptionMessage << e; - QMessageBox msgBox; - msgBox.setWindowTitle("No images retrieved"); - msgBox.setText("Could not automatically retrieve all images of the current case.\n" - "Reason:\n" + QString::fromStdString(exceptionMessage.str())); - msgBox.setIcon(QMessageBox::Warning); - msgBox.exec(); - return; - } -} - void QmitkLesionInfoWidget::ResetBackgroundColors() { // reset all lesion list widget items to original background color for (int i = 0; i < m_Controls.lesionListWidget->count(); ++i) { QListWidgetItem* item = m_Controls.lesionListWidget->item(i); item->setBackground(DEFAULT_BACKGROUND_COLOR); } - - // reset all segmentation list widget items to original background color - for (int i = 0; i < m_Controls.segmentationListWidget->count(); ++i) - { - QListWidgetItem* item = m_Controls.segmentationListWidget->item(i); - item->setBackground(DEFAULT_BACKGROUND_COLOR); - } - - // reset all image list widget items to original background color - for (int i = 0; i < m_Controls.imageListWidget->count(); ++i) - { - QListWidgetItem* item = m_Controls.imageListWidget->item(i); - item->setBackground(DEFAULT_BACKGROUND_COLOR); - } } void QmitkLesionInfoWidget::DarkenBackgroundColors() { // reset all lesion list widget items to original background color for (int i = 0; i < m_Controls.lesionListWidget->count(); ++i) { QListWidgetItem* item = m_Controls.lesionListWidget->item(i); if (DEFAULT_BACKGROUND_COLOR != item->background()) { item->setBackground(CONNECTED_BACKGROUND_COLOR); } } - - // reset all segmentation list widget items to original background color - for (int i = 0; i < m_Controls.segmentationListWidget->count(); ++i) - { - QListWidgetItem* item = m_Controls.segmentationListWidget->item(i); - if (DEFAULT_BACKGROUND_COLOR != item->background()) - { - item->setBackground(CONNECTED_BACKGROUND_COLOR); - } - } - - // reset all image list widget items to original background color - for (int i = 0; i < m_Controls.imageListWidget->count(); ++i) - { - QListWidgetItem* item = m_Controls.imageListWidget->item(i); - if (DEFAULT_BACKGROUND_COLOR != item->background()) - { - item->setBackground(CONNECTED_BACKGROUND_COLOR); - } - } } diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkLesionInfoWidget.h b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkLesionInfoWidget.h index 01c80c3ba5..e85c535367 100644 --- a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkLesionInfoWidget.h +++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkLesionInfoWidget.h @@ -1,151 +1,121 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QMITKLESIONINFOWIDGET_H #define QMITKLESIONINFOWIDGET_H // semantic relations UI module #include // semantic relations module #include #include // mitk #include // qt #include /* * @brief The QmitkLesionInfoWidget is a widget that shows and modifies the currently available lesion data of the semantic relations model. * * The widget provides a dialogs to add nodes from the data storage to the semantic relations model. * It provides functionality to create new lesions and link them with segmentation nodes. * * The QmitkLesionInfoWidget provides three QListWidgets, that show the lesion data and the referenced segmentation data, as * well as the connected image data, depending on the selected lesion. * * The QmitkLesionInfoWidget implements the 'ISemanticRelationsObserver', so that it is automatically updated, if the * semantic relations model changes. Updating means freshly getting all lesion data and filling the lesion-ListWidget with the lesion data. */ class QmitkLesionInfoWidget : public QWidget, public mitk::ISemanticRelationsObserver { Q_OBJECT public: static const QBrush DEFAULT_BACKGROUND_COLOR; static const QBrush SELECTED_BACKGROUND_COLOR; static const QBrush CONNECTED_BACKGROUND_COLOR; QmitkLesionInfoWidget::QmitkLesionInfoWidget(mitk::DataStorage* dataStorage, QWidget* parent = nullptr); ~QmitkLesionInfoWidget(); void SetCurrentCaseID(const mitk::SemanticTypes::CaseID& caseID); /* * @brief Updates the 'lesionListWidget' of the GUI with the current lesion-data from the semantic relations model. * * Overridden from 'ISemanticRelationsObserver'. - * In order for Update-function to be called, this widget has to be added as a observer of SemanticRelation + * In order for the Update-function to be called, this widget has to be added as a observer of SemanticRelation * (e.g. m_SemanticRelations->AddObserver(m_LesionInfoWidget);) * * @par caseID The current case ID to identify the currently active patient / case. */ virtual void Update(const mitk::SemanticTypes::CaseID& caseID) override; const mitk::SemanticTypes::Lesion& GetSelectedLesion() const { return m_CurrentLesion; } - const mitk::DataNode* GetSelectedSegmentation() const { return m_CurrentSegmentation; } - const mitk::DataNode* GetSelectedImage() const { return m_CurrentImage; } + /* * @brief Resets all items from the lesion list widget. */ void ResetLesionListWidget(); /* - * @brief Resets all items from the the segmentation list widget. - */ - void ResetSegmentationListWidget(); - /* - * @brief Resets all items from the the segmentation list widget. - */ - void ResetImageListWidget(); - /* * @brief Resets the background color of all items in each list widget. */ void ResetBackgroundColors(); void DarkenBackgroundColors(); Q_SIGNALS: - void JumpToPosition(const mitk::Point3D&); - void ImageAdded(const mitk::SemanticTypes::CaseID&); - void ImageRemoved(const mitk::DataNode*); + void LesionChanged(const mitk::SemanticTypes::Lesion&); private Q_SLOTS: /* * @brief Generates a new, empty lesion to add to the semantic relations model for the current case ID. */ void OnAddLesionButtonClicked(); - void OnAddSegmentationButtonClicked(); - void OnAddImageButtonClicked(); // slots for the mouse click events of the list widgets void OnCurrentLesionItemChanged(QListWidgetItem*, QListWidgetItem*); void OnLesionItemDoubleClicked(QListWidgetItem*); - void OnCurrentSegmentationItemChanged(QListWidgetItem*, QListWidgetItem*); - void OnSegmentationItemDoubleClicked(QListWidgetItem*); - void OnCurrentImageItemChanged(QListWidgetItem*, QListWidgetItem*); - void OnImageItemDoubleClicked(QListWidgetItem*); void OnLesionListContextMenuRequested(const QPoint&); - void OnSegmentationListContextMenuRequested(const QPoint&); - void OnImageListContextMenuRequested(const QPoint&); // slots for the context menu actions of the lesion list widget void OnLinkToSegmentation(const mitk::SemanticTypes::ID&); void OnSetLesionName(const mitk::SemanticTypes::ID&); void OnSetLesionClass(const mitk::SemanticTypes::ID&); void OnRemoveLesion(const mitk::SemanticTypes::ID&); - // slots for the context menu actions of the segmentation list widget - void OnUnlinkFromLesion(const mitk::DataNode*); - - -public Q_SLOTS: - - // slots for the context menu action of the image / segmentation list widget - // the slots are also used from the semantic relations view if a node in the data storage is removed - void OnRemoveSegmentation(const mitk::DataNode*); - void OnRemoveImage(const mitk::DataNode*); - private: void Init(); void SetUpConnections(); Ui::QmitkLesionInfoWidgetControls m_Controls; mitk::DataStorage* m_DataStorage; std::unique_ptr m_SemanticRelations; mitk::SemanticTypes::CaseID m_CaseID; mitk::SemanticTypes::Lesion m_CurrentLesion; mitk::DataNode::Pointer m_CurrentSegmentation; mitk::DataNode::Pointer m_CurrentImage; }; #endif // QMITKLESIONINFOWIDGET_H diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkLesionInfoWidgetControls.ui b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkLesionInfoWidgetControls.ui index 6d0d31456a..db08af5e22 100644 --- a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkLesionInfoWidgetControls.ui +++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkLesionInfoWidgetControls.ui @@ -1,72 +1,50 @@ QmitkLesionInfoWidgetControls true 0 0 350 300 - - - - Available lesions: - - - - - - - Available segmentations: - - - - - - - Available images: - - - - - - - Add lesion - - + + 0 + + + 0 + + + 0 + + + 0 + + + - + - Add segmentation + Add new lesion - - + + - Add image + Available lesions: - - - - - - - - - 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 dec945ae84..97765ef20b 100644 --- a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsView.cpp +++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsView.cpp @@ -1,112 +1,163 @@ /*=================================================================== 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 // 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); + + SetUpConnections(); +} + +void QmitkSemanticRelationsView::SetUpConnections() +{ connect(m_Controls.caseIDComboBox, static_cast(&QComboBox::currentIndexChanged), this, &QmitkSemanticRelationsView::OnCaseIDSelectionChanged); - connect(m_LesionInfoWidget, &QmitkLesionInfoWidget::ImageAdded, this, &QmitkSemanticRelationsView::AddToComboBox); - connect(m_LesionInfoWidget, &QmitkLesionInfoWidget::JumpToPosition, this, &QmitkSemanticRelationsView::OnJumpToPosition); - connect(m_LesionInfoWidget, &QmitkLesionInfoWidget::ImageRemoved, this, &QmitkSemanticRelationsView::OnImageRemoved); + connect(m_LesionInfoWidget, &QmitkLesionInfoWidget::LesionChanged, this, &QmitkSemanticRelationsView::OnLesionChanged); } -void QmitkSemanticRelationsView::NodeRemoved(const mitk::DataNode* node) +void QmitkSemanticRelationsView::NodeRemoved(const mitk::DataNode* dataNode) { - if (mitk::NodePredicates::GetImagePredicate()->CheckNode(node)) + if (nullptr == dataNode) { - m_LesionInfoWidget->OnRemoveImage(node); + return; } - else if (mitk::NodePredicates::GetSegmentationPredicate()->CheckNode(node)) + + if (mitk::NodePredicates::GetImagePredicate()->CheckNode(dataNode)) { - m_LesionInfoWidget->OnRemoveSegmentation(node); + 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::OnJumpToPosition(const mitk::Point3D& position) { mitk::IRenderWindowPart* renderWindowPart = GetRenderWindowPart(); if (nullptr != renderWindowPart) { renderWindowPart->SetSelectedPosition(position); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } -void QmitkSemanticRelationsView::OnImageRemoved(const mitk::DataNode* imageNode) +void QmitkSemanticRelationsView::OnLesionChanged(const mitk::SemanticTypes::Lesion& lesion) { - mitk::SemanticTypes::CaseID caseID = mitk::GetCaseIDFromDataNode(imageNode); - RemoveFromComboBox(caseID); + 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::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 e5a40c7602..4e54595d9d 100644 --- a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsView.h +++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsView.h @@ -1,78 +1,87 @@ /*=================================================================== 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 /* * @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 OnImageRemoved(const mitk::DataNode*); + void OnLesionChanged(const mitk::SemanticTypes::Lesion&); private: - virtual void NodeRemoved(const mitk::DataNode* node) override; + void SetUpConnections(); + + virtual void NodeRemoved(const mitk::DataNode* dataNode) override; void RemoveFromComboBox(const mitk::SemanticTypes::CaseID& caseID); + void RemoveImage(const mitk::DataNode* image); + void RemoveSegmentation(const mitk::DataNode* segmentation); + Ui::QmitkSemanticRelationsControls m_Controls; QmitkLesionInfoWidget* m_LesionInfoWidget; + QmitkPatientTableInspector* m_PatientTableInspector; std::unique_ptr m_SemanticRelations; }; #endif // QMITKSEMANTICRELATIONSVIEW_H