diff --git a/Modules/SemanticRelationsUI/files.cmake b/Modules/SemanticRelationsUI/files.cmake index 8208ef2d16..9540adc6af 100644 --- a/Modules/SemanticRelationsUI/files.cmake +++ b/Modules/SemanticRelationsUI/files.cmake @@ -1,32 +1,34 @@ file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*") set(CPP_FILES mitkModuleActivator.cpp QmitkAbstractSemanticRelationsStorageInspector.cpp QmitkAbstractSemanticRelationsStorageModel.cpp QmitkControlPointDialog.cpp QmitkLesionTextDialog.cpp QmitkLesionTreeItem.cpp QmitkLesionTreeModel.cpp QmitkPatientTableHeaderView.cpp QmitkPatientTableInspector.cpp QmitkPatientTableModel.cpp QmitkSemanticRelationsUIHelper.cpp + QmitkStatisticsTreeModel.cpp QmitkTableItemThumbnailDelegate.cpp ) set(MOC_H_FILES include/QmitkAbstractSemanticRelationsStorageInspector.h include/QmitkAbstractSemanticRelationsStorageModel.h include/QmitkControlPointDialog.h include/QmitkLesionTextDialog.h include/QmitkLesionTreeModel.h include/QmitkPatientTableHeaderView.h include/QmitkPatientTableInspector.h include/QmitkPatientTableModel.h + include/QmitkStatisticsTreeModel.h include/QmitkTableItemThumbnailDelegate.h ) set(UI_FILES src/QmitkPatientTableInspector.ui ) diff --git a/Modules/SemanticRelationsUI/include/QmitkPatientTableModel.h b/Modules/SemanticRelationsUI/include/QmitkPatientTableModel.h index 16a38ef02b..e3efbb679f 100644 --- a/Modules/SemanticRelationsUI/include/QmitkPatientTableModel.h +++ b/Modules/SemanticRelationsUI/include/QmitkPatientTableModel.h @@ -1,134 +1,134 @@ /*=================================================================== 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 QMITKPATIENTTABLEMODEL_H #define QMITKPATIENTTABLEMODEL_H // semantic relations UI module #include "QmitkAbstractSemanticRelationsStorageModel.h" // semantic relations module #include #include // mitk core #include // qt #include #include /** * @brief The QmitkPatientTableModel is a subclass of the QmitkAbstractSemanticRelationsStorageModel and holds the semantic relations data of the currently selected case. * * The QmitkPatientTableModel uses the 'data' function to return either the data node of a table cell or the thumbnail of the underlying image. * The horizontal header of the table shows the control points of the current case and the vertical header of the table shows the information types of the current case. * Using the 'GetFilteredData'-function of the SemanticRelations-class the model is able to retrieve the correct data node for each table entry. * * Additionally the model creates and holds the QPixmaps of the known data nodes in order to return a thumbnail, if needed. */ class QmitkPatientTableModel : public QmitkAbstractSemanticRelationsStorageModel { Q_OBJECT public: QmitkPatientTableModel(QObject* parent = nullptr); ~QmitkPatientTableModel(); ////////////////////////////////////////////////////////////////////////// // overridden functions from QAbstractItemModel ////////////////////////////////////////////////////////////////////////// virtual QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override; virtual QModelIndex parent(const QModelIndex& child) const override; virtual int rowCount(const QModelIndex& parent = QModelIndex()) const override; virtual int columnCount(const QModelIndex& parent = QModelIndex()) const override; virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; virtual Qt::ItemFlags flags(const QModelIndex& index) const override; ////////////////////////////////////////////////////////////////////////// /// end override ///////////////////////////////////////////////////////////////////////// void SetNodeType(const std::string& nodeType); protected: // the following functions have to be overridden... virtual void NodePredicateChanged() override; // but are not implemented in this model virtual void NodeAdded(const mitk::DataNode*) override { } virtual void NodeChanged(const mitk::DataNode*) override { } virtual void NodeRemoved(const mitk::DataNode*) override { } /** * @brief Overridden from 'QmitkAbstractSemanticRelationsStorageModel': This function retrieves all control points * and information types of the current case and stores them to define the header of the table. * Furthermore all images are retrieved and the pixmap of the images are generated and stored. */ virtual void SetData() override; private: void SetHeaderModel(); void SetPixmaps(); void SetLesionPresences(); /** * @brief The function uses the ID of the node to see if a pixmap was already set. If not, the given pixmap * is used and stored inside a member variable. If the pixmap was already set, it will be overwritten. * Using 'nullptr' as a pixmap will erase the entry for the given data node. * * @param dataNode The data node whose pixmap should be set * @param pixmapFromImage The pixmap that shows an image of the content of the data node */ void SetPixmapOfNode(const mitk::DataNode* dataNode, QPixmap* pixmapFromImage); /** * @brief The function uses the ID of the node to see if a lesion presence was already set. If not, the given * bool value is used and stored inside a member variable. If the lesion presence was already set, it * will be overwritten. * The function is used by the 'SetLesionPresences' function. * * @param dataNode The data node whose lesion presence should be set * @param lesionPresence The bool value that defines the lesion presence of the given data node */ void SetLesionPresenceOfNode(const mitk::DataNode* dataNode, bool lesionPresence); /** * @brief Returns the data node that is associated with the given table entry (index). * * The function uses the SemanticRelations-class and the current control point data and information type data to * filter the nodes of the current case. * The index is used to access the correct row in the table (information type) and the correct column in the table (control point). * * @par index The QModelIndex of the table entry */ mitk::DataNode* GetCurrentDataNode(const QModelIndex &index) const; std::map m_PixmapMap; std::map m_LesionPresence; - mitk::SemanticTypes::InformationTypeVector m_InformationTypes; mitk::SemanticTypes::ControlPointVector m_ControlPoints; mitk::SemanticTypes::ExaminationPeriodVector m_ExaminationPeriods; + mitk::SemanticTypes::InformationTypeVector m_InformationTypes; mitk::SemanticRelationsDataStorageAccess::DataNodeVector m_CurrentDataNodes; std::string m_SelectedNodeType; QStandardItemModel* m_HeaderModel; }; #endif // QMITKPATIENTTABLEMODEL_H diff --git a/Modules/SemanticRelationsUI/include/QmitkStatisticsTreeModel.h b/Modules/SemanticRelationsUI/include/QmitkStatisticsTreeModel.h new file mode 100644 index 0000000000..cf09422fe5 --- /dev/null +++ b/Modules/SemanticRelationsUI/include/QmitkStatisticsTreeModel.h @@ -0,0 +1,81 @@ +/*=================================================================== + +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 QMITKSTATISTICSTREEMODEL_H +#define QMITKSTATISTICSTREEMODEL_H + +// mitk semantic relations UI +#include "MitkSemanticRelationsUIExports.h" +#include "QmitkAbstractSemanticRelationsStorageModel.h" +#include "QmitkLesionTreeItem.h" + +/* +* @brief +*/ +class MITKSEMANTICRELATIONSUI_EXPORT QmitkStatisticsTreeModel : public QmitkAbstractSemanticRelationsStorageModel +{ + Q_OBJECT + +public: + + /** + * @brief Initialize the root item of the model. The root item does not have a parent item. + */ + QmitkStatisticsTreeModel(QObject* parent = nullptr); + + ////////////////////////////////////////////////////////////////////////// + // overridden virtual functions from QAbstractItemModel + ////////////////////////////////////////////////////////////////////////// + virtual QModelIndex index(int row, int column, const QModelIndex& itemIndex = QModelIndex()) const override; + virtual QModelIndex parent(const QModelIndex& itemIndex) const override; + + virtual int rowCount(const QModelIndex& itemIndex = QModelIndex()) const override; + virtual int columnCount(const QModelIndex& itemIndex = QModelIndex()) const override; + + virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; + virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; + ////////////////////////////////////////////////////////////////////////// + // end override + ////////////////////////////////////////////////////////////////////////// + +protected: + + // the following functions have to be overridden but are not implemented in this model + virtual void NodePredicateChanged() override { } + virtual void NodeAdded(const mitk::DataNode*) override { } + virtual void NodeChanged(const mitk::DataNode*) override { } + virtual void NodeRemoved(const mitk::DataNode*) override { } + /** + * @brief Overridden from 'QmitkAbstractSemanticRelationsStorageModel': This function retrieves all control points + * of the current case and stores them to define the header of the tree. + * Furthermore all lesions are retrieved and the lesion data is stored and show in the tree view. + */ + virtual void SetData() override; + +private: + + void SetLesionData(); + void AddLesion(const mitk::SemanticTypes::Lesion& lesion); + + QmitkLesionTreeItem* GetItemByIndex(const QModelIndex& index) const; + + std::shared_ptr m_RootItem; + mitk::SemanticTypes::ControlPointVector m_ControlPoints; + mitk::SemanticTypes::InformationTypeVector m_InformationTypes; + mitk::SemanticTypes::LesionVector m_CurrentLesions; +}; + +#endif // QMITKSTATISTICSTREEMODEL_H diff --git a/Modules/SemanticRelationsUI/src/QmitkLesionTreeModel.cpp b/Modules/SemanticRelationsUI/src/QmitkLesionTreeModel.cpp index 9e3ff1aed8..0258254257 100644 --- a/Modules/SemanticRelationsUI/src/QmitkLesionTreeModel.cpp +++ b/Modules/SemanticRelationsUI/src/QmitkLesionTreeModel.cpp @@ -1,289 +1,296 @@ /*=================================================================== 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 "QmitkLesionTreeModel.h" // semantic relations module #include #include #include #include #include #include // qt #include QmitkLesionTreeModel::QmitkLesionTreeModel(QObject* parent/* = nullptr*/) : QmitkAbstractSemanticRelationsStorageModel(parent) , m_RootItem(std::make_shared(mitk::LesionData())) { // nothing here } ////////////////////////////////////////////////////////////////////////// // overridden virtual functions from QAbstractItemModel ////////////////////////////////////////////////////////////////////////// QModelIndex QmitkLesionTreeModel::index(int row, int column, const QModelIndex& itemIndex) const { if (!hasIndex(row, column, itemIndex)) { return QModelIndex(); } auto childItem = GetItemByIndex(itemIndex)->GetChildInRow(row); if (nullptr == childItem) { return QModelIndex(); } return createIndex(row, column, childItem.get()); } QModelIndex QmitkLesionTreeModel::parent(const QModelIndex& itemIndex) const { if (!itemIndex.isValid()) { return QModelIndex(); } auto parentItem = GetItemByIndex(itemIndex)->GetParent(); if (parentItem.expired()) { return QModelIndex(); } auto sharedParent = parentItem.lock(); if (sharedParent == m_RootItem) { return QModelIndex(); } return createIndex(sharedParent->GetRow(), 0, sharedParent.get()); } int QmitkLesionTreeModel::rowCount(const QModelIndex& itemIndex/* = QModelIndex()*/) const { return GetItemByIndex(itemIndex)->ChildCount(); } int QmitkLesionTreeModel::columnCount(const QModelIndex&/* itemIndex = QModelIndex() */) const { if (0 == m_RootItem->ChildCount()) { // no lesion items stored, no need to display columns return 0; } return m_ControlPoints.size() + 1; } QVariant QmitkLesionTreeModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) { return QVariant(); } if (index.column() < 0 || index.column() > static_cast(m_ControlPoints.size())) { return QVariant(); } QmitkLesionTreeItem* currentItem = GetItemByIndex(index); if (Qt::DisplayRole == role) { if (currentItem->GetParent().expired()) { return QVariant(); } auto parentItem = currentItem->GetParent().lock(); // parent exists and is the root item -> 1. item of a lesion entry if (m_RootItem == parentItem) { // display role fills the first columns with the lesion UID / name if (0 == index.column()) { std::string itemString = currentItem->GetData().GetLesionName(); if (itemString.empty()) { itemString = currentItem->GetData().GetLesionUID(); } return QString::fromStdString(itemString); } else { // display role fills other columns with the lesion presence info const auto lesionPresence = currentItem->GetData().GetLesionPresence(); if (index.column() - 1 > static_cast(lesionPresence.size())) { return ""; } return QVariant(lesionPresence.at(index.column() - 1)); } } } if (Qt::BackgroundColorRole == role) { auto it = m_DataNodePresence.find(currentItem->GetData().GetLesion().UID); if (it != m_DataNodePresence.end()) { return it->second ? QVariant(QColor(Qt::darkGreen)) : QVariant(QColor(Qt::transparent)); } return QVariant(QColor(Qt::transparent)); } if (Qt::UserRole == role) { return QVariant::fromValue(currentItem); } return QVariant(); } QVariant QmitkLesionTreeModel::headerData(int section, Qt::Orientation orientation, int role) const { if (0 == m_RootItem->ChildCount()) { // no lesion items stored, no need to display the header return QVariant(); } if (Qt::Horizontal == orientation && Qt::DisplayRole == role) { if (0 == section) { return QVariant("Lesion"); } if (static_cast(m_ControlPoints.size()) >= section) { mitk::SemanticTypes::ControlPoint currentControlPoint = m_ControlPoints.at(section-1); return QVariant(QString::fromStdString(currentControlPoint.ToString())); } } return QVariant(); } const mitk::DataNode* QmitkLesionTreeModel::GetLastSegmentation() const { return m_LastSegmentation; } void QmitkLesionTreeModel::NodeAdded(const mitk::DataNode* dataNode) { if (mitk::NodePredicates::GetSegmentationPredicate()->CheckNode(dataNode)) { m_LastSegmentation = dataNode; } } void QmitkLesionTreeModel::SetData() { m_RootItem = std::make_shared(mitk::LesionData()); // get all control points of current case m_ControlPoints = mitk::RelationStorage::GetAllControlPointsOfCase(m_CaseID); // sort the vector of control points for the timeline std::sort(m_ControlPoints.begin(), m_ControlPoints.end()); SetLesionData(); SetSelectedDataNodesPresence(); } void QmitkLesionTreeModel::SetLesionData() { m_CurrentLesions = mitk::RelationStorage::GetAllLesionsOfCase(m_CaseID); for (auto& lesion : m_CurrentLesions) { AddLesion(lesion); } } void QmitkLesionTreeModel::AddLesion(const mitk::SemanticTypes::Lesion& lesion) { + if (m_DataStorage.IsExpired()) + { + return; + } + + auto dataStorage = m_DataStorage.Lock(); + // create new lesion tree item data and modify it according to the control point data mitk::LesionData lesionData(lesion); - mitk::GenerateAdditionalLesionData(lesionData, m_CaseID); + mitk::GenerateAdditionalLesionData(dataStorage, lesionData, m_CaseID); // add the 1. level lesion item to the root item std::shared_ptr newLesionTreeItem = std::make_shared(lesionData); m_RootItem->AddChild(newLesionTreeItem); } void QmitkLesionTreeModel::SetSelectedDataNodesPresence() { m_DataNodePresence.clear(); for (const auto& dataNode : m_SelectedDataNodes) { if (!mitk::SemanticRelationsInference::InstanceExists(dataNode)) { continue; } for (const auto& lesion : m_CurrentLesions) { if (!mitk::SemanticRelationsInference::InstanceExists(m_CaseID, lesion)) { continue; } try { // set the lesion presence for the current node bool dataNodePresence = mitk::SemanticRelationsInference::IsLesionPresent(lesion, dataNode); SetDataNodePresenceOfLesion(&lesion, dataNodePresence); } catch (const mitk::SemanticRelationException&) { continue; } } } } void QmitkLesionTreeModel::SetDataNodePresenceOfLesion(const mitk::SemanticTypes::Lesion* lesion, bool dataNodePresence) { std::map::iterator iter = m_DataNodePresence.find(lesion->UID); if (iter != m_DataNodePresence.end()) { // key already existing, overwrite already stored bool value iter->second = dataNodePresence; } else { m_DataNodePresence.insert(std::make_pair(lesion->UID, dataNodePresence)); } } QmitkLesionTreeItem* QmitkLesionTreeModel::GetItemByIndex(const QModelIndex& index) const { if (index.isValid()) { auto item = static_cast(index.internalPointer()); if (nullptr != item) { return item; } } return m_RootItem.get(); } diff --git a/Modules/SemanticRelationsUI/src/QmitkLesionTreeModel.cpp b/Modules/SemanticRelationsUI/src/QmitkStatisticsTreeModel.cpp similarity index 54% copy from Modules/SemanticRelationsUI/src/QmitkLesionTreeModel.cpp copy to Modules/SemanticRelationsUI/src/QmitkStatisticsTreeModel.cpp index 9e3ff1aed8..3f17e7031c 100644 --- a/Modules/SemanticRelationsUI/src/QmitkLesionTreeModel.cpp +++ b/Modules/SemanticRelationsUI/src/QmitkStatisticsTreeModel.cpp @@ -1,289 +1,240 @@ /*=================================================================== 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 "QmitkLesionTreeModel.h" +#include "QmitkStatisticsTreeModel.h" // semantic relations module #include #include -#include #include #include #include -// qt -#include - -QmitkLesionTreeModel::QmitkLesionTreeModel(QObject* parent/* = nullptr*/) +QmitkStatisticsTreeModel::QmitkStatisticsTreeModel(QObject* parent/* = nullptr*/) : QmitkAbstractSemanticRelationsStorageModel(parent) , m_RootItem(std::make_shared(mitk::LesionData())) { // nothing here } ////////////////////////////////////////////////////////////////////////// // overridden virtual functions from QAbstractItemModel ////////////////////////////////////////////////////////////////////////// -QModelIndex QmitkLesionTreeModel::index(int row, int column, const QModelIndex& itemIndex) const +QModelIndex QmitkStatisticsTreeModel::index(int row, int column, const QModelIndex& itemIndex) const { if (!hasIndex(row, column, itemIndex)) { return QModelIndex(); } auto childItem = GetItemByIndex(itemIndex)->GetChildInRow(row); if (nullptr == childItem) { return QModelIndex(); } return createIndex(row, column, childItem.get()); } -QModelIndex QmitkLesionTreeModel::parent(const QModelIndex& itemIndex) const +QModelIndex QmitkStatisticsTreeModel::parent(const QModelIndex& itemIndex) const { if (!itemIndex.isValid()) { return QModelIndex(); } - auto parentItem = GetItemByIndex(itemIndex)->GetParent(); - if (parentItem.expired()) + auto parentItemWeakPtr = GetItemByIndex(itemIndex)->GetParent(); + if (parentItemWeakPtr.expired()) { return QModelIndex(); } - auto sharedParent = parentItem.lock(); - if (sharedParent == m_RootItem) + auto parentItem = parentItemWeakPtr.lock(); + if (parentItem == m_RootItem) { return QModelIndex(); } - return createIndex(sharedParent->GetRow(), 0, sharedParent.get()); + return createIndex(parentItem->GetRow(), 0, parentItem.get()); } -int QmitkLesionTreeModel::rowCount(const QModelIndex& itemIndex/* = QModelIndex()*/) const +int QmitkStatisticsTreeModel::rowCount(const QModelIndex& itemIndex/* = QModelIndex()*/) const { return GetItemByIndex(itemIndex)->ChildCount(); } -int QmitkLesionTreeModel::columnCount(const QModelIndex&/* itemIndex = QModelIndex() */) const +int QmitkStatisticsTreeModel::columnCount(const QModelIndex&/* itemIndex = QModelIndex() */) const { if (0 == m_RootItem->ChildCount()) { // no lesion items stored, no need to display columns return 0; } return m_ControlPoints.size() + 1; } -QVariant QmitkLesionTreeModel::data(const QModelIndex& index, int role) const +QVariant QmitkStatisticsTreeModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) { return QVariant(); } if (index.column() < 0 || index.column() > static_cast(m_ControlPoints.size())) { return QVariant(); } QmitkLesionTreeItem* currentItem = GetItemByIndex(index); if (Qt::DisplayRole == role) { if (currentItem->GetParent().expired()) { return QVariant(); } auto parentItem = currentItem->GetParent().lock(); - // parent exists and is the root item -> 1. item of a lesion entry + // parent exists and is the root item -> top level item if (m_RootItem == parentItem) { // display role fills the first columns with the lesion UID / name if (0 == index.column()) { std::string itemString = currentItem->GetData().GetLesionName(); if (itemString.empty()) { itemString = currentItem->GetData().GetLesionUID(); } return QString::fromStdString(itemString); } + } + // parent is not the root item -> volume item + else + { + // display role fills the first columns with the information type + if (0 == index.column()) + { + if (index.row() < static_cast(m_InformationTypes.size())) + { + return QString::fromStdString(m_InformationTypes.at(index.row())); + } + return "No information type"; + } else { - // display role fills other columns with the lesion presence info - const auto lesionPresence = currentItem->GetData().GetLesionPresence(); - if (index.column() - 1 > static_cast(lesionPresence.size())) + // display role fills other columns with the lesion volume info + const auto lesionVolume = currentItem->GetData().GetLesionVolume(); + if ((index.column() - 1) * index.row() < static_cast(lesionVolume.size())) { - return ""; + return QVariant(lesionVolume.at(index.row()*m_ControlPoints.size() + (index.column() - 1))); } - - return QVariant(lesionPresence.at(index.column() - 1)); + return "No lesion volume"; } } } - if (Qt::BackgroundColorRole == role) - { - auto it = m_DataNodePresence.find(currentItem->GetData().GetLesion().UID); - if (it != m_DataNodePresence.end()) - { - return it->second ? QVariant(QColor(Qt::darkGreen)) : QVariant(QColor(Qt::transparent)); - } - - return QVariant(QColor(Qt::transparent)); - } - - if (Qt::UserRole == role) - { - return QVariant::fromValue(currentItem); - } - return QVariant(); } -QVariant QmitkLesionTreeModel::headerData(int section, Qt::Orientation orientation, int role) const +QVariant QmitkStatisticsTreeModel::headerData(int section, Qt::Orientation orientation, int role) const { if (0 == m_RootItem->ChildCount()) { // no lesion items stored, no need to display the header return QVariant(); } if (Qt::Horizontal == orientation && Qt::DisplayRole == role) { if (0 == section) { return QVariant("Lesion"); } if (static_cast(m_ControlPoints.size()) >= section) { mitk::SemanticTypes::ControlPoint currentControlPoint = m_ControlPoints.at(section-1); return QVariant(QString::fromStdString(currentControlPoint.ToString())); } } return QVariant(); } -const mitk::DataNode* QmitkLesionTreeModel::GetLastSegmentation() const -{ - return m_LastSegmentation; -} - -void QmitkLesionTreeModel::NodeAdded(const mitk::DataNode* dataNode) -{ - if (mitk::NodePredicates::GetSegmentationPredicate()->CheckNode(dataNode)) - { - m_LastSegmentation = dataNode; - } -} - -void QmitkLesionTreeModel::SetData() +void QmitkStatisticsTreeModel::SetData() { m_RootItem = std::make_shared(mitk::LesionData()); // get all control points of current case m_ControlPoints = mitk::RelationStorage::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 = mitk::RelationStorage::GetAllInformationTypesOfCase(m_CaseID); + SetLesionData(); - SetSelectedDataNodesPresence(); } -void QmitkLesionTreeModel::SetLesionData() +void QmitkStatisticsTreeModel::SetLesionData() { m_CurrentLesions = mitk::RelationStorage::GetAllLesionsOfCase(m_CaseID); for (auto& lesion : m_CurrentLesions) { AddLesion(lesion); } } -void QmitkLesionTreeModel::AddLesion(const mitk::SemanticTypes::Lesion& lesion) +void QmitkStatisticsTreeModel::AddLesion(const mitk::SemanticTypes::Lesion& lesion) { + if (m_DataStorage.IsExpired()) + { + return; + } + + auto dataStorage = m_DataStorage.Lock(); + // create new lesion tree item data and modify it according to the control point data mitk::LesionData lesionData(lesion); - mitk::GenerateAdditionalLesionData(lesionData, m_CaseID); + mitk::GenerateAdditionalLesionData(dataStorage, lesionData, m_CaseID); // add the 1. level lesion item to the root item std::shared_ptr newLesionTreeItem = std::make_shared(lesionData); m_RootItem->AddChild(newLesionTreeItem); -} -void QmitkLesionTreeModel::SetSelectedDataNodesPresence() -{ - m_DataNodePresence.clear(); - for (const auto& dataNode : m_SelectedDataNodes) - { - if (!mitk::SemanticRelationsInference::InstanceExists(dataNode)) - { - continue; - } - - for (const auto& lesion : m_CurrentLesions) - { - if (!mitk::SemanticRelationsInference::InstanceExists(m_CaseID, lesion)) - { - continue; - } - try - { - // set the lesion presence for the current node - bool dataNodePresence = mitk::SemanticRelationsInference::IsLesionPresent(lesion, dataNode); - SetDataNodePresenceOfLesion(&lesion, dataNodePresence); - } - catch (const mitk::SemanticRelationException&) - { - continue; - } - } - } -} - -void QmitkLesionTreeModel::SetDataNodePresenceOfLesion(const mitk::SemanticTypes::Lesion* lesion, bool dataNodePresence) -{ - std::map::iterator iter = m_DataNodePresence.find(lesion->UID); - if (iter != m_DataNodePresence.end()) - { - // key already existing, overwrite already stored bool value - iter->second = dataNodePresence; - } - else + auto informationTypeSize = m_InformationTypes.size(); + for (int i = 0; i < informationTypeSize; ++i) { - m_DataNodePresence.insert(std::make_pair(lesion->UID, dataNodePresence)); + std::shared_ptr volumeItem = std::make_shared(lesionData); + newLesionTreeItem->AddChild(volumeItem); } } -QmitkLesionTreeItem* QmitkLesionTreeModel::GetItemByIndex(const QModelIndex& index) const +QmitkLesionTreeItem* QmitkStatisticsTreeModel::GetItemByIndex(const QModelIndex& index) const { if (index.isValid()) { auto item = static_cast(index.internalPointer()); if (nullptr != item) { return item; } } return m_RootItem.get(); } diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/files.cmake b/Plugins/org.mitk.gui.qt.semanticrelations/files.cmake index 981ff7a377..1250ec9d47 100644 --- a/Plugins/org.mitk.gui.qt.semanticrelations/files.cmake +++ b/Plugins/org.mitk.gui.qt.semanticrelations/files.cmake @@ -1,49 +1,53 @@ set(INTERNAL_CPP_FILES mitkPluginActivator.cpp QmitkAbstractSemanticRelationsAction.cpp QmitkDataNodeAddToSemanticRelationsAction.cpp QmitkDataNodeRemoveFromSemanticRelationsAction.cpp QmitkDataNodeUnlinkFromLesionAction.cpp QmitkDataNodeSetControlPointAction.cpp QmitkDataNodeSetInformationTypeAction.cpp QmitkDataSetOpenInAction.cpp QmitkFocusOnLesionAction.cpp QmitkLabelSetJumpToAction.cpp QmitkLesionInfoWidget.cpp QmitkSemanticRelationsContextMenu.cpp QmitkSemanticRelationsNodeSelectionDialog.cpp + QmitkSemanticRelationsStatisticsView.cpp QmitkSemanticRelationsView.cpp ) set(UI_FILES src/internal/QmitkLesionInfoWidgetControls.ui src/internal/QmitkSemanticRelationsControls.ui + src/internal/QmitkSemanticRelationsStatisticsControls.ui ) set(MOC_H_FILES src/internal/mitkPluginActivator.h src/internal/QmitkDataNodeAddToSemanticRelationsAction.h src/internal/QmitkDataNodeRemoveFromSemanticRelationsAction.h src/internal/QmitkDataNodeUnlinkFromLesionAction.h src/internal/QmitkDataNodeSetControlPointAction.h src/internal/QmitkDataNodeSetInformationTypeAction.h src/internal/QmitkDataSetOpenInAction.h src/internal/QmitkFocusOnLesionAction.h src/internal/QmitkLabelSetJumpToAction.h src/internal/QmitkLesionInfoWidget.h src/internal/QmitkSemanticRelationsContextMenu.h src/internal/QmitkSemanticRelationsNodeSelectionDialog.h + src/internal/QmitkSemanticRelationsStatisticsView.h src/internal/QmitkSemanticRelationsView.h ) set(CACHED_RESOURCE_FILES resources/SemanticRelations_48.png + resources/SemanticRelationsStatistics_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/plugin.xml b/Plugins/org.mitk.gui.qt.semanticrelations/plugin.xml index be0ea613f6..618c2e82f1 100644 --- a/Plugins/org.mitk.gui.qt.semanticrelations/plugin.xml +++ b/Plugins/org.mitk.gui.qt.semanticrelations/plugin.xml @@ -1,11 +1,18 @@ + icon="resources/SemanticRelations_48.png" + category="Semantic Relations"/> + + diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/resources/SemanticRelationsStatistics_48.png b/Plugins/org.mitk.gui.qt.semanticrelations/resources/SemanticRelationsStatistics_48.png new file mode 100644 index 0000000000..182a722caf Binary files /dev/null and b/Plugins/org.mitk.gui.qt.semanticrelations/resources/SemanticRelationsStatistics_48.png differ diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsStatisticsControls.ui b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsStatisticsControls.ui new file mode 100644 index 0000000000..330e1d12c1 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsStatisticsControls.ui @@ -0,0 +1,40 @@ + + + QmitkSemanticRelationsStatisticsControls + + + + 0 + 0 + 350 + 300 + + + + Semantic relations plugin + + + + + + + + + + 0 + 0 + + + + Currently selected patient: + + + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsStatisticsView.cpp b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsStatisticsView.cpp new file mode 100644 index 0000000000..e233be83e0 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsStatisticsView.cpp @@ -0,0 +1,100 @@ +/*=================================================================== + +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 "QmitkSemanticRelationsStatisticsView.h" + +// semantic relations module +#include +#include +#include +#include +#include + +// qt +#include +#include +#include + +const std::string QmitkSemanticRelationsStatisticsView::VIEW_ID = "org.mitk.views.semanticrelationsstatistics"; + +QmitkSemanticRelationsStatisticsView::~QmitkSemanticRelationsStatisticsView() +{ + auto semanticRelationsIntegration = std::make_unique(); + semanticRelationsIntegration->RemoveObserver(this); +} + +void QmitkSemanticRelationsStatisticsView::Update(const mitk::SemanticTypes::CaseID& caseID) +{ + AddToComboBox(caseID); +} + +void QmitkSemanticRelationsStatisticsView::SetFocus() +{ + // nothing here +} + +void QmitkSemanticRelationsStatisticsView::CreateQtPartControl(QWidget* parent) +{ + // create GUI elements + m_Controls.setupUi(parent); + + m_StatisticsTreeModel = new QmitkStatisticsTreeModel(parent); + m_StatisticsTreeModel->SetDataStorage(GetDataStorage()); + m_Controls.statisticsTreeView->setModel(m_StatisticsTreeModel); + + auto semanticRelationsIntegration = std::make_unique(); + semanticRelationsIntegration->AddObserver(this); + + SetUpConnections(); + const auto& allCaseIDs = mitk::RelationStorage::GetAllCaseIDs(); + for (const auto& caseID : allCaseIDs) + { + AddToComboBox(caseID); + } +} + +void QmitkSemanticRelationsStatisticsView::SetUpConnections() +{ + connect(m_Controls.caseIDComboBox, static_cast(&QComboBox::currentIndexChanged), this, &QmitkSemanticRelationsStatisticsView::OnCaseIDSelectionChanged); + connect(m_StatisticsTreeModel, &QmitkStatisticsTreeModel::ModelUpdated, this, &QmitkSemanticRelationsStatisticsView::OnModelUpdated); + +} + +void QmitkSemanticRelationsStatisticsView::OnCaseIDSelectionChanged(const QString& caseID) +{ + m_StatisticsTreeModel->SetCaseID(caseID.toStdString()); +} + +void QmitkSemanticRelationsStatisticsView::OnModelUpdated() +{ + m_Controls.statisticsTreeView->expandAll(); + int columns = m_Controls.statisticsTreeView->model()->columnCount(); + for (int i = 0; i < columns; ++i) + { + m_Controls.statisticsTreeView->resizeColumnToContents(i); + } +} + +void QmitkSemanticRelationsStatisticsView::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)); + } +} \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsStatisticsView.h b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsStatisticsView.h new file mode 100644 index 0000000000..2fb586c512 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsStatisticsView.h @@ -0,0 +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. + +===================================================================*/ + +#ifndef QMITKSEMANTICRELATIONSSTATISTICSVIEW_H +#define QMITKSEMANTICRELATIONSSTATISTICSVIEW_H + +// semantic relations plugin +#include "ui_QmitkSemanticRelationsStatisticsControls.h" +#include "QmitkStatisticsTreeModel.h" + +// semantic relations module +#include + +// mitk qt gui common plugin +#include + +/* +* @brief +*/ +class QmitkSemanticRelationsStatisticsView : public QmitkAbstractView, public mitk::ISemanticRelationsObserver +{ + Q_OBJECT + +public: + + static const std::string VIEW_ID; + + virtual ~QmitkSemanticRelationsStatisticsView() override; + + /* + * @brief Update the view with the data from the semantic relations. + * + * Overridden from 'ISemanticRelationsObserver'. + * In order for the Update-function to be called, this view has to be added as an observer of SemanticRelation + * (e.g. m_SemanticRelations->AddObserver(this);) + * + * @par caseID The current case ID to identify the currently active patient / case. + */ + virtual void Update(const mitk::SemanticTypes::CaseID& caseID) override; + +protected: + + virtual void SetFocus() override; + virtual void CreateQtPartControl(QWidget* parent) override; + +private Q_SLOTS: + + void OnCaseIDSelectionChanged(const QString&); + void OnModelUpdated(); + +private: + + void SetUpConnections(); + void AddToComboBox(const mitk::SemanticTypes::CaseID& caseID); + + Ui::QmitkSemanticRelationsStatisticsControls m_Controls; + + QmitkStatisticsTreeModel* m_StatisticsTreeModel; +}; + +#endif // QMITKSEMANTICRELATIONSSTATISTICSVIEW_H 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 4bca6dd829..3c41a3f2bf 100644 --- a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsView.h +++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsView.h @@ -1,110 +1,110 @@ /*=================================================================== 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 // semantic relations UI module #include // mitk gui common plugin #include // berry #include -// mitk qt +// mitk qt gui common plugin #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; virtual void RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) override; virtual void RenderWindowPartDeactivated(mitk::IRenderWindowPart* renderWindowPart) override; virtual void RenderWindowPartInputChanged(mitk::IRenderWindowPart* renderWindowPart) override; protected: virtual void SetFocus() override; virtual void CreateQtPartControl(QWidget* parent) override; private Q_SLOTS: void OnLesionSelectionChanged(const mitk::SemanticTypes::Lesion&); void OnDataNodeSelectionChanged(const QList&); void OnDataNodeDoubleClicked(const mitk::DataNode*); void OnCaseIDSelectionChanged(const QString&); void OnNodesAdded(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 SetControlledRenderer(); Ui::QmitkSemanticRelationsControls m_Controls; mitk::IRenderWindowPart* m_RenderWindowPart; QmitkLesionInfoWidget* m_LesionInfoWidget; QmitkPatientTableInspector* m_PatientTableInspector; QmitkDnDDataNodeWidget* m_DnDDataNodeWidget; QmitkSemanticRelationsContextMenu* m_ContextMenu; }; #endif // QMITKSEMANTICRELATIONSVIEW_H diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/mitkPluginActivator.cpp b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/mitkPluginActivator.cpp index 9a343753d6..d05c04421d 100644 --- a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/mitkPluginActivator.cpp +++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/mitkPluginActivator.cpp @@ -1,31 +1,34 @@ /*=================================================================== 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 "mitkPluginActivator.h" +#include "QmitkSemanticRelationsStatisticsView.h" #include "QmitkSemanticRelationsView.h" + #include namespace mitk { void SemanticRelationsActivator::start(ctkPluginContext *context) { mitk::PersistenceService::LoadModule(); BERRY_REGISTER_EXTENSION_CLASS(QmitkSemanticRelationsView, context) + BERRY_REGISTER_EXTENSION_CLASS(QmitkSemanticRelationsStatisticsView, context) } void SemanticRelationsActivator::stop(ctkPluginContext *context) { Q_UNUSED(context) } }