diff --git a/Modules/SemanticRelationsUI/src/QmitkPatientTableModel.cpp b/Modules/SemanticRelationsUI/src/QmitkPatientTableModel.cpp index 9a61e2ff39..4e6068805c 100644 --- a/Modules/SemanticRelationsUI/src/QmitkPatientTableModel.cpp +++ b/Modules/SemanticRelationsUI/src/QmitkPatientTableModel.cpp @@ -1,341 +1,346 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // semantic relations UI module #include "QmitkPatientTableModel.h" #include "QmitkSemanticRelationsUIHelper.h" // semantic relations module #include #include #include "QmitkCustomVariants.h" #include "QmitkEnums.h" QmitkPatientTableModel::QmitkPatientTableModel(QObject* parent /*= nullptr*/) : QmitkAbstractSemanticRelationsStorageModel(parent) , m_SelectedNodeType("Image") { // nothing here } QmitkPatientTableModel::~QmitkPatientTableModel() { // nothing here } QModelIndex QmitkPatientTableModel::index(int row, int column, const QModelIndex &parent/* = QModelIndex()*/) const { bool hasIndex = this->hasIndex(row, column, parent); if (hasIndex) { return this->createIndex(row, column); } return QModelIndex(); } QModelIndex QmitkPatientTableModel::parent(const QModelIndex &child) const { return QModelIndex(); } int QmitkPatientTableModel::rowCount(const QModelIndex &parent/* = QModelIndex()*/) const { if (parent.isValid()) { return 0; } return m_InformationTypes.size(); } int QmitkPatientTableModel::columnCount(const QModelIndex &parent/* = QModelIndex()*/) const { if (parent.isValid()) { return 0; } return m_ControlPoints.size(); } QVariant QmitkPatientTableModel::data(const QModelIndex &index, int role/* = Qt::DisplayRole*/) const { if (!index.isValid()) { return QVariant(); } if (index.row() < 0 || index.row() >= static_cast(m_InformationTypes.size()) || index.column() < 0 || index.column() >= static_cast(m_ControlPoints.size())) { return QVariant(); } mitk::DataNode* dataNode = GetCurrentDataNode(index); if (nullptr == dataNode) { return QVariant(); } if (Qt::DecorationRole == role) { auto it = m_PixmapMap.find(dataNode); if (it != m_PixmapMap.end()) { return QVariant(it->second); } } else if (role == QmitkDataNodeRole) { return QVariant::fromValue(mitk::DataNode::Pointer(dataNode)); } else if (role == QmitkDataNodeRawPointerRole) { return QVariant::fromValue(dataNode); } return QVariant(); } QVariant QmitkPatientTableModel::headerData(int section, Qt::Orientation orientation, int role) const { if (Qt::Horizontal == orientation && Qt::DisplayRole == role) { if (m_ControlPoints.size() > section) { mitk::SemanticTypes::ControlPoint currentControlPoint = m_ControlPoints.at(section); // generate a string from the control point std::string currentControlPointAsString = mitk::GetControlPointAsString(currentControlPoint); return QVariant(QString::fromStdString(currentControlPointAsString)); } } if (Qt::Vertical == orientation && Qt::DisplayRole == role) { if (m_InformationTypes.size() > section) { mitk::SemanticTypes::InformationType currentInformationType = m_InformationTypes.at(section); return QVariant(QString::fromStdString(currentInformationType)); } } return QVariant(); } Qt::ItemFlags QmitkPatientTableModel::flags(const QModelIndex &index) const { Qt::ItemFlags flags; mitk::DataNode* dataNode = GetCurrentDataNode(index); if (nullptr == dataNode) { return flags; } flags = Qt::ItemIsSelectable; auto it = m_LesionPresence.find(dataNode); if (it != m_LesionPresence.end()) { return it->second ? flags |= Qt::ItemIsEnabled : flags; } return flags; } void QmitkPatientTableModel::SetNodeType(const std::string& nodeType) { m_SelectedNodeType = nodeType; UpdateModelData(); } void QmitkPatientTableModel::NodePredicateChanged() { UpdateModelData(); } void QmitkPatientTableModel::NodeAdded(const mitk::DataNode* node) { // does not react to data storage changes } void QmitkPatientTableModel::NodeChanged(const mitk::DataNode* node) { // nothing here, since the "'NodeChanged'-event is currently sent far too often //UpdateModelData(); } void QmitkPatientTableModel::NodeRemoved(const mitk::DataNode* node) { // does not react to data storage changes } void QmitkPatientTableModel::SetPixmapOfNode(const mitk::DataNode* dataNode, QPixmap* pixmapFromImage) { if (nullptr == dataNode) { return; } std::map::iterator iter = m_PixmapMap.find(dataNode); if (iter != m_PixmapMap.end()) { // key already existing if (nullptr != pixmapFromImage) { // overwrite already stored pixmap iter->second = pixmapFromImage->scaled(120, 120, Qt::IgnoreAspectRatio); } else { // remove key if no pixmap is given m_PixmapMap.erase(iter); } } else { m_PixmapMap.insert(std::make_pair(dataNode, pixmapFromImage->scaled(120, 120, Qt::IgnoreAspectRatio))); } } void QmitkPatientTableModel::SetLesionPresence(const mitk::DataNode* dataNode, bool lesionPresence) { if (nullptr == dataNode) { return; } std::map::iterator iter = m_LesionPresence.find(dataNode); if (iter != m_LesionPresence.end()) { // key already existing, overwrite already stored bool value iter->second = lesionPresence; } else { m_LesionPresence.insert(std::make_pair(dataNode, lesionPresence)); } } void QmitkPatientTableModel::SetData() { // get all control points of current case m_ControlPoints = m_SemanticRelations->GetAllControlPointsOfCase(m_CaseID); // sort the vector of control points for the timeline std::sort(m_ControlPoints.begin(), m_ControlPoints.end()); // get all information types points of current case m_InformationTypes = m_SemanticRelations->GetAllInformationTypesOfCase(m_CaseID); m_PixmapMap.clear(); m_LesionPresence.clear(); SetDataNodes(); } void QmitkPatientTableModel::SetDataNodes() { std::vector allDataNodes; if("Image" == m_SelectedNodeType) { allDataNodes = m_SemanticRelations->GetAllImagesOfCase(m_CaseID); } else if("Segmentation" == m_SelectedNodeType) { allDataNodes = m_SemanticRelations->GetAllSegmentationsOfCase(m_CaseID); } for (const auto& dataNode : allDataNodes) { // set the pixmap for the current node QPixmap pixmapFromImage = QmitkSemanticRelationsUIHelper::GetPixmapFromImageNode(dataNode); SetPixmapOfNode(dataNode, &pixmapFromImage); // set the lesion presence for the current node - bool lesionPresence = IsLesionPresentOnDataNode(dataNode); + bool lesionPresence = true; + if (m_SemanticRelations->InstanceExists(m_CaseID, m_Lesion)) + { + lesionPresence = IsLesionPresentOnDataNode(dataNode); + } + SetLesionPresence(dataNode, lesionPresence); } } bool QmitkPatientTableModel::IsLesionPresentOnDataNode(const mitk::DataNode* dataNode) const { if (m_DataStorage.IsExpired()) { return false; } auto dataStorage = m_DataStorage.Lock(); try { mitk::SemanticRelations::DataNodeVector allSegmentationsOfLesion = m_SemanticRelations->GetAllSegmentationsOfLesion(m_CaseID, m_Lesion); for (const auto& segmentation : allSegmentationsOfLesion) { if ("Segmentation" == m_SelectedNodeType) { if (dataNode == segmentation) { // found a segmentation of the node that is represented by the selected lesion return true; } } else if ("Image" == m_SelectedNodeType) { // get parent node of the current segmentation node with the node predicate mitk::DataStorage::SetOfObjects::ConstPointer parentNodes = dataStorage->GetSources(segmentation, mitk::NodePredicates::GetImagePredicate(), false); for (auto it = parentNodes->Begin(); it != parentNodes->End(); ++it) { if (dataNode == it.Value()) { // found a segmentation of the node that is represented by the selected lesion return true; } } } } } catch (const mitk::SemanticRelationException&) { return false; } return false; } mitk::DataNode* QmitkPatientTableModel::GetCurrentDataNode(const QModelIndex& index) const { mitk::SemanticTypes::ControlPoint currentControlPoint = m_ControlPoints.at(index.column()); mitk::SemanticTypes::InformationType currentInformationType = m_InformationTypes.at(index.row()); try { std::vector filteredDataNodes; if ("Image" == m_SelectedNodeType) { filteredDataNodes = m_SemanticRelations->GetAllSpecificImages(m_CaseID, currentControlPoint, currentInformationType); } else if ("Segmentation" == m_SelectedNodeType) { filteredDataNodes = m_SemanticRelations->GetAllSpecificSegmentations(m_CaseID, currentControlPoint, currentInformationType); } if (filteredDataNodes.empty()) { return nullptr; } return filteredDataNodes.front(); } catch (const mitk::SemanticRelationException&) { return nullptr; } } 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 e85c535367..c503f7fdbb 100644 --- a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkLesionInfoWidget.h +++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkLesionInfoWidget.h @@ -1,121 +1,119 @@ /*=================================================================== 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 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; } /* * @brief Resets all items from the lesion list widget. */ void ResetLesionListWidget(); /* * @brief Resets the background color of all items in each list widget. */ void ResetBackgroundColors(); void DarkenBackgroundColors(); Q_SIGNALS: 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(); // slots for the mouse click events of the list widgets void OnCurrentLesionItemChanged(QListWidgetItem*, QListWidgetItem*); void OnLesionItemDoubleClicked(QListWidgetItem*); void OnLesionListContextMenuRequested(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&); 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