diff --git a/Modules/SemanticRelations/include/mitkDICOMHelper.h b/Modules/SemanticRelations/include/mitkDICOMHelper.h index 74322c0caf..e1d1d047e6 100644 --- a/Modules/SemanticRelations/include/mitkDICOMHelper.h +++ b/Modules/SemanticRelations/include/mitkDICOMHelper.h @@ -1,96 +1,96 @@ /*=================================================================== 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 MITKDICOMHELPER_H #define MITKDICOMHELPER_H #include // semantic relations module #include "mitkSemanticTypes.h" // mitk core #include #include // c++ #include /* * @brief Provides helper functions to convert DICOM Tag information. * * In order to identify the patient of an image or segmentation or to set the control point of DICOM data, * these functions are used to retrieve the DICOM tags from the given data nodes and convert them into semantic types * that can be used by the SemanticRelations class. */ namespace mitk { /* - * @brief Extracts a specific DICOM tag (currently "0x0010, 0x0020": PatientID) from the node's base data + * @brief Extracts a specific DICOM tag from the node's base data * and returns the tag as a string. This tag string is used as an identifier for the patient (case). * * @pre The given data node or the node's base data has to be valid (!nullptr). - * @pre The node's base data has to have the "0x0010, 0x0020" DICOM Tag property set. + * @pre The node's base data has to have the specific DICOM Tag property set. * @throw mitk::Exception if the given data node, the node's base data or the extracted DICOM tag are invalid (==nullptr). * * @par dataNode The data node, of which the DICOM tag should be extracted. * * @return The extracted DICOM tag as string. * An empty string, if the DICOM tag can not be extracted (i.e. the data node or * the underlying base data is invalid or the DICOM tag does not exist for the given data node). */ MITKSEMANTICRELATIONS_EXPORT SemanticTypes::CaseID GetCaseIDFromDataNode(const mitk::DataNode* dataNode); /* * @brief Extracts a specific DICOM tag (currently "0x0020, 0x000e": SeriesInstanceUID) from the node's base data * and returns the tag as a string. This tag string is used as an identifier for the image instance. * * @pre The given data node or the node's base data has to be valid (!nullptr). * @pre The node's base data has to have the "0x0020, 0x000e" DICOM Tag property set. * @throw mitk::Exception if the given data node, the node's base data or the extracted DICOM tag are invalid (==nullptr). * * @par dataNode The data node, of which the DICOM tag should be extracted. * * @return The extracted DICOM tag as string. * An empty string, if the DICOM tag can not be extracted (i.e. the data node or * the underlying base data is invalid or the DICOM tag does not exist for the given data node). */ MITKSEMANTICRELATIONS_EXPORT SemanticTypes::ID GetIDFromDataNode(const mitk::DataNode* dataNode); /* * @brief Extracts a specific DICOM tag (currently "0x0008, 0x0022": AcquisitionDate) from the node's base data * and returns the tag as a string. This tag string is used as the date of the image data. * * @pre The given data node or the node's base data has to be valid (!nullptr). * @pre The node's base data has to have the "0x0008, 0x0022" DICOM Tag property set. * @throw mitk::Exception if the given data node, the node's base data or the extracted DICOM tag are invalid (==nullptr). * * @par dataNode The data node, of which the DICOM tag should be extracted. * * @return The extracted DICOM tag as string. * An empty string, if the DICOM tag can not be extracted (i.e. the data node or * the underlying base data is invalid or the DICOM tag does not exist for the given data node). */ MITKSEMANTICRELATIONS_EXPORT SemanticTypes::Date GetDICOMDateFromDataNode(const mitk::DataNode* dataNode); /* * @brief Removes leading and trailing whitespace from the given string. * * @par identifier The value of a DICOM tag. * * @return The trimmed DICOM tag */ MITKSEMANTICRELATIONS_EXPORT std::string TrimDICOM(const std::string& identifier); } // namespace mitk #endif // MITKDICOMHELPER_H diff --git a/Modules/SemanticRelations/src/mitkDICOMHelper.cpp b/Modules/SemanticRelations/src/mitkDICOMHelper.cpp index f39e4bb8ea..8197d63fed 100644 --- a/Modules/SemanticRelations/src/mitkDICOMHelper.cpp +++ b/Modules/SemanticRelations/src/mitkDICOMHelper.cpp @@ -1,138 +1,138 @@ /*=================================================================== 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 module #include "mitkDICOMHelper.h" #include "mitkUIDGeneratorBoost.h" // mitk core #include // c++ #include mitk::SemanticTypes::Date GetDateFromString(const std::string& dateAsString); mitk::SemanticTypes::CaseID mitk::GetCaseIDFromDataNode(const mitk::DataNode* dataNode) { if (nullptr == dataNode) { mitkThrow() << "Not a valid data node."; } mitk::BaseData* baseData = dataNode->GetData(); if (nullptr == baseData) { mitkThrow() << "No valid base data."; } // extract suitable DICOM tag to use as the case id // two alternatives can be used: // - DICOM tag "0x0010, 0x0010" is PatientName // - DICOM tag "0x0010, 0x0020" is PatientID - // in the current implementation the PatientID (0x0010, 0x0020) is used - mitk::BaseProperty* dicomTag = baseData->GetProperty(mitk::GeneratePropertyNameForDICOMTag(0x0010, 0x0020).c_str()); + // in the current implementation the PatientID (0x0010, 0x0010) is used + mitk::BaseProperty* dicomTag = baseData->GetProperty(mitk::GeneratePropertyNameForDICOMTag(0x0010, 0x0010).c_str()); if (nullptr == dicomTag) { mitkThrow() << "Not a valid DICOM property."; } std::string dicomTagAsString = dicomTag->GetValueAsString(); return dicomTagAsString; } mitk::SemanticTypes::ID mitk::GetIDFromDataNode(const mitk::DataNode* dataNode) { if (nullptr == dataNode) { mitkThrow() << "Not a valid data node."; } mitk::BaseData* baseData = dataNode->GetData(); if (nullptr == baseData) { mitkThrow() << "No valid base data."; } // extract suitable DICOM tag to use as the data node id // DICOM tag "0x0020, 0x000e" is SeriesInstanceUID mitk::BaseProperty* dicomTag = baseData->GetProperty(mitk::GeneratePropertyNameForDICOMTag(0x0020, 0x000e).c_str()); if (nullptr == dicomTag) { mitkThrow() << "Not a valid DICOM property."; } std::string dicomTagAsString = dicomTag->GetValueAsString(); return dicomTagAsString; } mitk::SemanticTypes::Date mitk::GetDICOMDateFromDataNode(const mitk::DataNode* dataNode) { if (nullptr == dataNode) { mitkThrow() << "Not a valid data node."; } mitk::BaseData* baseData = dataNode->GetData(); if (nullptr == baseData) { mitkThrow() << "No valid base data."; } // extract suitable DICOM tag to use as the data node id // DICOM tag "0x0008, 0x0022" is AcquisitionDate mitk::BaseProperty* acquisitionDateProperty = baseData->GetProperty(mitk::GeneratePropertyNameForDICOMTag(0x0008, 0x0022).c_str()); if (nullptr == acquisitionDateProperty) { mitkThrow() << "Not a valid DICOM property."; } std::string acquisitionDateAsString = acquisitionDateProperty->GetValueAsString(); return GetDateFromString(acquisitionDateAsString); } std::string mitk::TrimDICOM(const std::string& identifier) { if (identifier.empty()) { return identifier; } // leading whitespace std::size_t first = identifier.find_first_not_of(' '); if (std::string::npos == first) { return ""; } // trailing whitespace std::size_t last = identifier.find_last_not_of(' '); return identifier.substr(first, last - first + 1); } mitk::SemanticTypes::Date GetDateFromString(const std::string& dateAsString) { if (dateAsString.size() != 8) // string does not represent a DICOM date { return mitk::SemanticTypes::Date(); } mitk::SemanticTypes::Date date; date.UID = mitk::UIDGeneratorBoost::GenerateUID(); // date expected to be YYYYMMDD (8 characters) date.year = std::strtoul(dateAsString.substr(0, 4).c_str(), nullptr, 10); date.month = std::strtoul(dateAsString.substr(4, 2).c_str(), nullptr, 10); date.day = std::strtoul(dateAsString.substr(6, 2).c_str(), nullptr, 10); return date; } diff --git a/Modules/SemanticRelationsUI/files.cmake b/Modules/SemanticRelationsUI/files.cmake index eeddabc6b5..f96627fee0 100644 --- a/Modules/SemanticRelationsUI/files.cmake +++ b/Modules/SemanticRelationsUI/files.cmake @@ -1,27 +1,32 @@ file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*") set(CPP_FILES + mitkModuleActivator.cpp QmitkControlPointDialog.cpp - QmitkPatientTableModel.cpp - QmitkPatientTableWidget.cpp QmitkLesionInfoWidget.cpp + QmitkPatientTableInspector.cpp + QmitkPatientTableModel.cpp QmitkSelectNodeDialog.cpp QmitkSelectionWidget.cpp + QmitkSemanticRelationsModel.cpp + QmitkSemanticRelationsUIHelper.cpp QmitkSimpleDatamanagerWidget.cpp ) set(MOC_H_FILES include/QmitkControlPointDialog.h - include/QmitkPatientTableModel.h - include/QmitkPatientTableWidget.h include/QmitkLesionInfoWidget.h + include/QmitkPatientTableInspector.h + include/QmitkPatientTableModel.h include/QmitkSelectNodeDialog.h include/QmitkSelectionWidget.h + include/QmitkSemanticRelationsModel.h + include/QmitkSimpleDatamanagerWidget.h ) set(UI_FILES - src/QmitkPatientTableWidgetControls.ui src/QmitkLesionInfoWidgetControls.ui + src/QmitkPatientTableInspector.ui src/QmitkSimpleDatamanagerWidgetControls.ui ) diff --git a/Modules/SemanticRelationsUI/include/QmitkPatientTableInspector.h b/Modules/SemanticRelationsUI/include/QmitkPatientTableInspector.h new file mode 100644 index 0000000000..3951704650 --- /dev/null +++ b/Modules/SemanticRelationsUI/include/QmitkPatientTableInspector.h @@ -0,0 +1,84 @@ +/*=================================================================== + +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 QMITKPATIENTTABLEINSPECTOR_H +#define QMITKPATIENTTABLEINSPECTOR_H + +// semantic relations UI module +#include "MitkSemanticRelationsUIExports.h" +#include + +#include "ui_QmitkPatientTableInspector.h" + +// qt widgets module +#include "QmitkAbstractDataStorageInspector.h" +#include "QmitkEnums.h" + +// qt +#include + +/* +* @brief The QmitkPatientTableInspector is a QmitkAbstractDataStorageInspector that shows the currently available data of +* the patient table model in a control point-information type matrix. +* +* The QmitkpatientTableInspector uses the QmitkPatientTableModel, a QmitkAbstractDataStorageModel that +* presents the semantic relations data as a table, showing a QPixmap as thumbnail for the image data. +*/ +class MITKSEMANTICRELATIONSUI_EXPORT QmitkPatientTableInspector : public QmitkAbstractDataStorageInspector +{ + Q_OBJECT + +public: + + QmitkPatientTableInspector(QWidget* parent = nullptr); + + virtual QAbstractItemView* GetView() override; + virtual const QAbstractItemView* GetView() const override; + + virtual void SetSelectionMode(SelectionMode mode) override; + virtual SelectionMode GetSelectionMode() const override; + /** + * @brief Extends the abstract base class to allow setting the current case ID which is needed to access the + * semantic relations storage. The function sets the case ID in the storage model. + * + * @param caseID A case ID as string + */ + void SetCaseID(const mitk::SemanticTypes::CaseID& caseID); + +protected: + + virtual void QmitkPatientTableInspector::Initialize() override; + +private Q_SLOTS: + + void OnPatientTableModelUpdated(); + void OnPatientTableViewContextMenuRequested(const QPoint&); + void OnContextMenuSetInformationType(); + void OnContextMenuSetControlPoint(); + +private: + + void SetUpConnections(); + + Ui::QmitkPatientTableInspector m_Controls; + QmitkPatientTableModel* m_StorageModel; + + QMenu* m_ContextMenu; + mitk::DataNode* m_SelectedDataNode; + +}; + +#endif // QMITKPATIENTTABLEINSPECTOR_H diff --git a/Modules/SemanticRelationsUI/include/QmitkPatientTableModel.h b/Modules/SemanticRelationsUI/include/QmitkPatientTableModel.h index e3e77220d9..bcfec22d63 100644 --- a/Modules/SemanticRelationsUI/include/QmitkPatientTableModel.h +++ b/Modules/SemanticRelationsUI/include/QmitkPatientTableModel.h @@ -1,101 +1,111 @@ /*=================================================================== 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 module -#include #include -// qt -#include +// semantic relations UI module +#include // mitk core #include +// qt +#include + /* -* @brief The QmitkPatientTableModel is the model for the 'QmitkPatientTableWidget' and holds the control point data and information type data of the currently selected case. +* @brief The QmitkPatientTableModel is a subclass of the QmitkSemanticRelationsModel and holds the control point data and information type 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 QmitkPatientTableWidget holds the QPixmaps of the known data nodes in order to return a thumbnail, if needed. -* -* If the 'QmitkPatientTableWidget' is updated, the 'SetCurrentCaseID'-function is called, which leads to a fresh retrieval of the control point data -* and the information type data. +* Additionally the model creates and holds the QPixmaps of the known data nodes in order to return a thumbnail, if needed. */ -class QmitkPatientTableModel : public QAbstractTableModel +class QmitkPatientTableModel : public QmitkSemanticRelationsModel { Q_OBJECT public: - QmitkPatientTableModel(std::shared_ptr semanticRelations, QObject* parent = nullptr); + QmitkPatientTableModel(QObject* parent = nullptr); ~QmitkPatientTableModel(); ////////////////////////////////////////////////////////////////////////// // overridden functions from QAbstractItemModel ////////////////////////////////////////////////////////////////////////// - virtual Qt::ItemFlags flags(const QModelIndex &index) const override; + 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 bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; + virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const override; + virtual Qt::ItemFlags flags(const QModelIndex &index) const override; ////////////////////////////////////////////////////////////////////////// /// end override ///////////////////////////////////////////////////////////////////////// - const mitk::SemanticTypes::CaseID& GetCurrentCaseID() const { return m_CaseID; } - void SetCurrentCaseID(const mitk::SemanticTypes::CaseID& caseID); - void SetPixmapOfNode(const mitk::DataNode* dataNode, QPixmap* pixmapFromImage); - void SetPatientData(); - /* - * @brief Updates the table model with the current control point data and information type data from the semantic relations model, - * if the 'caseID' is equal to the currently selected case ID of the table model. - * This function can be called from an observer of SemanticRelations (e.g. a table view that uses this model) - * in order to propagate the Update-request to this model. + /** + * @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 Update(const mitk::SemanticTypes::CaseID& caseID); + void SetPixmapOfNode(const mitk::DataNode* dataNode, QPixmap* pixmapFromImage); -Q_SIGNALS: - void ModelUpdated(); +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* node) override; + virtual void NodeChanged(const mitk::DataNode* node) override; + virtual void NodeRemoved(const mitk::DataNode* node) override; + /** + * @brief Overridden from 'QmitkSemanticRelationsModel': 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: /* * @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::shared_ptr m_SemanticRelations; - mitk::SemanticTypes::CaseID m_CaseID; - std::map m_PixmapMap; + std::vector m_InformationTypes; std::vector m_ControlPoints; }; #endif // QMITKPATIENTTABLEMODEL_H diff --git a/Modules/SemanticRelationsUI/include/QmitkPatientTableWidget.h b/Modules/SemanticRelationsUI/include/QmitkPatientTableWidget.h deleted file mode 100644 index 511fc480e0..0000000000 --- a/Modules/SemanticRelationsUI/include/QmitkPatientTableWidget.h +++ /dev/null @@ -1,113 +0,0 @@ -/*=================================================================== - -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 QMITKPATIENTTABLEWIDGET_H -#define QMITKPATIENTTABLEWIDGET_H - -// semantic relations UI module -#include "MitkSemanticRelationsUIExports.h" -#include -#include "QmitkSelectionWidget.h" -#include "QmitkPatientTableModel.h" - -// semantic relations module -#include - -// mitk core -#include -#include - -// qt -#include - -/* -* @brief The QmitkPatientTableWidget is a selection widget that shows the currently available data of the semantic relations model in a -* control point-information type matrix. -* -* The QmitkPatientTableWidget has a model that presents the semantic relations data as a table, showing a QPixmap as thumbnail for the image data. -* -* The QmitkPatientTableWidget implements the 'ISemanticRelationsObserver', so that it is automatically updated, if the -* semantic relations model changes. Updating means freshly getting all control point data and information type data. -* This is done by updating the data in the 'QmitkPatientTableModel' model. -* -* The QmitkPatientTableWidget is derived from 'QmitkSelectionWidget', so that the "SelectionChanged"-signal can be emitted. -* This is done in order to inform other widgets about a changed selection in this widget (e.g. the 'QmitkSelectNodeDialog'). -* The QmitkPatientTableWidget is currently injected in the 'QmitkSelectNodeDialog' in the 'QmitkSemanticRelationsView' class. -*/ -class MITKSEMANTICRELATIONSUI_EXPORT QmitkPatientTableWidget : public QmitkSelectionWidget, public mitk::ISemanticRelationsObserver -{ - Q_OBJECT - -public: - - QmitkPatientTableWidget(mitk::DataStorage* dataStorage, QWidget* parent = nullptr); - virtual ~QmitkPatientTableWidget(); - - void SetCurrentCaseID(const mitk::SemanticTypes::CaseID& caseID); - /* - * @brief Propagates the 'Update'-call to the patient table model to update the patient data (control points and information types). - * - * Overridden from 'ISemanticRelationsObserver'. - * In order for Update-function to be called, this widget has to be added as a observer of SemanticRelations - * (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; - - /* - * @brief Sets a QPixmap of a DICOM image. - * - * @par dataNode The data node that holds the image data. - */ - void SetPixmapOfNode(const mitk::DataNode* dataNode); - /* - * @brief Removes the corresponding pixmap of a DICOM image - * - * @par dataNode The data node that holds the image data. - */ - void DeletePixmapOfNode(const mitk::DataNode* dataNode); - -private Q_SLOTS: - - void OnPatientTableModelUpdated(); - void OnPatientTableViewContextMenuRequested(const QPoint&); - void OnContextMenuSetInformationType(); - void OnContextMenuSetControlPoint(); - void OnPatientTableViewSelectionChanged(const QItemSelection&, const QItemSelection&); - -private: - - void Init(); - void SetUpConnections(); - - /* - * @brief Generates a QPixmap of a DICOM image. - * - * The center sagittal image slice is extracted and used as the thumbnail image. - * - * @par dataNode The data node that holds the image data. - */ - QPixmap GetPixmapFromImageNode(const mitk::DataNode* dataNode) const; - - Ui::QmitkPatientTableWidgetControls m_Controls; - std::unique_ptr m_PatientTableModel; - QMenu* m_ContextMenu; - mitk::DataNode* m_SelectedDataNode; - -}; - -#endif // QMITKPATIENTTABLEWIDGET_H diff --git a/Modules/SemanticRelationsUI/include/QmitkSemanticRelationsModel.h b/Modules/SemanticRelationsUI/include/QmitkSemanticRelationsModel.h new file mode 100644 index 0000000000..85833f688a --- /dev/null +++ b/Modules/SemanticRelationsUI/include/QmitkSemanticRelationsModel.h @@ -0,0 +1,82 @@ +/*=================================================================== + +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 QMITKSEMANTICRELATIONSMODEL_H +#define QMITKSEMANTICRELATIONSMODEL_H + +// semantic relations module +#include +#include + +// qt widgets module +#include "QmitkAbstractDataStorageModel.h" + +/* +* @brief The QmitkSemanticRelationsModel is a subclass of 'QmitkAbstractDataStorageModel' and provides additional +* functionality to set and store a semantic relations instance and the current case ID. +*/ +class QmitkSemanticRelationsModel : public QmitkAbstractDataStorageModel +{ + Q_OBJECT + +public: + + QmitkSemanticRelationsModel(QObject* parent = nullptr); + ~QmitkSemanticRelationsModel(); + + 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& GetCurrentCaseID() const { return m_CaseID; } + /* + * @brief Updates the table model with the current control point data and information type 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 table model with the current control point data and information type 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; +}; + +#endif // QMITKSEMANTICRELATIONSMODEL_H diff --git a/Modules/SemanticRelationsUI/include/QmitkSemanticRelationsUIHelper.h b/Modules/SemanticRelationsUI/include/QmitkSemanticRelationsUIHelper.h new file mode 100644 index 0000000000..4c804178f0 --- /dev/null +++ b/Modules/SemanticRelationsUI/include/QmitkSemanticRelationsUIHelper.h @@ -0,0 +1,45 @@ +/*=================================================================== + +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 QMITKSEMANTICRELATIONSUIHELPER_H +#define QMITKSEMANTICRELATIONSUIHELPER_H + +// semantic relations ui module +#include "MitkSemanticRelationsUIExports.h" + +// mitk core +#include + +// qt +#include + +/** +* @brief Provides a helper function to generate a pixmap from a given image node. +*/ +namespace QmitkSemanticRelationsUIHelper +{ + /* + * @brief Generates a QPixmap of a DICOM image. + * + * The center sagittal image slice is extracted and used as the thumbnail image. + * + * @par dataNode The data node that holds the image data. + */ + MITKSEMANTICRELATIONSUI_EXPORT QPixmap GetPixmapFromImageNode(const mitk::DataNode* dataNode); + +} // namespace QmitkSemanticRelationsUIHelper + +#endif // QMITKSEMANTICRELATIONSUIHELPER_H diff --git a/Modules/SemanticRelationsUI/include/mitkModuleActivator.h b/Modules/SemanticRelationsUI/include/mitkModuleActivator.h new file mode 100644 index 0000000000..2fe949967c --- /dev/null +++ b/Modules/SemanticRelationsUI/include/mitkModuleActivator.h @@ -0,0 +1,46 @@ +/*=================================================================== + +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 MITKMODULEACTIVATOR_H +#define MITKMODULEACTIVATOR_H + +// Micro Services +#include +#include +#include +#include + +#include + +// qt widgets module +#include "mitkIDataStorageInspectorProvider.h" + +namespace mitk +{ + /* + * This is the module activator for the "SemanticRelationsUI" module. + */ + class SemanticRelationsUIActivator : public us::ModuleActivator + { + public: + void Load(us::ModuleContext* context) override; + void Unload(us::ModuleContext* context) override; + + private: + std::unique_ptr m_PatientTableInspector; + }; +} +#endif // MITKMODULEACTIVATOR_H diff --git a/Modules/SemanticRelationsUI/src/QmitkPatientTableInspector.cpp b/Modules/SemanticRelationsUI/src/QmitkPatientTableInspector.cpp new file mode 100644 index 0000000000..e2c83f7f54 --- /dev/null +++ b/Modules/SemanticRelationsUI/src/QmitkPatientTableInspector.cpp @@ -0,0 +1,239 @@ +/*=================================================================== + +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 "QmitkPatientTableInspector.h" +#include "QmitkPatientTableModel.h" +#include "QmitkControlPointDialog.h" + +#include "QmitkCustomVariants.h" + +// semantic relations module +#include +#include +#include +#include + +// qt +#include + +QmitkPatientTableInspector::QmitkPatientTableInspector(QWidget* parent/* =nullptr*/) + : QmitkAbstractDataStorageInspector(parent) +{ + m_Controls.setupUi(this); + + m_Controls.view->horizontalHeader()->setHighlightSections(false); + m_Controls.view->verticalHeader()->setHighlightSections(false); + m_Controls.view->setSelectionMode(QAbstractItemView::SingleSelection); + m_Controls.view->setSelectionBehavior(QAbstractItemView::SelectItems); + m_Controls.view->setContextMenuPolicy(Qt::CustomContextMenu); + + m_StorageModel = new QmitkPatientTableModel(this); + + m_Controls.view->setModel(m_StorageModel); + + m_ContextMenu = new QMenu(m_Controls.view); + + SetUpConnections(); +} + +QAbstractItemView* QmitkPatientTableInspector::GetView() +{ + return m_Controls.view; +} + +const QAbstractItemView* QmitkPatientTableInspector::GetView() const +{ + return m_Controls.view; +} + +void QmitkPatientTableInspector::SetSelectionMode(SelectionMode mode) +{ + m_Controls.view->setSelectionMode(mode); +} + +QmitkPatientTableInspector::SelectionMode QmitkPatientTableInspector::GetSelectionMode() const +{ + return m_Controls.view->selectionMode(); +} + +void QmitkPatientTableInspector::SetCaseID(const mitk::SemanticTypes::CaseID& caseID) +{ + m_StorageModel->SetCaseID(caseID); +} + +void QmitkPatientTableInspector::Initialize() +{ + m_StorageModel->SetDataStorage(m_DataStorage.Lock()); + m_StorageModel->SetNodePredicate(m_NodePredicate); + + m_Connector->SetView(m_Controls.view); +} + +void QmitkPatientTableInspector::OnPatientTableModelUpdated() +{ + m_Controls.view->resizeRowsToContents(); + m_Controls.view->resizeColumnsToContents(); +} + +void QmitkPatientTableInspector::OnPatientTableViewContextMenuRequested(const QPoint& pos) +{ + QModelIndex selectedIndex = m_Controls.view->indexAt(pos); + if (!selectedIndex.isValid()) + { + return; + } + + QVariant qvariantDataNode = m_StorageModel->data(selectedIndex, QmitkDataNodeRawPointerRole); + if (qvariantDataNode.canConvert()) + { + m_SelectedDataNode = qvariantDataNode.value(); + + m_ContextMenu->clear(); + + QAction* setInformationTypeAction = new QAction("Set information type", m_ContextMenu); + m_ContextMenu->addAction(setInformationTypeAction); + connect(setInformationTypeAction, SIGNAL(triggered()), this, SLOT(OnContextMenuSetInformationType())); + + QAction* setControlPointAction = new QAction("Set control point", m_ContextMenu); + m_ContextMenu->addAction(setControlPointAction); + connect(setControlPointAction, SIGNAL(triggered()), this, SLOT(OnContextMenuSetControlPoint())); + + m_ContextMenu->popup(QCursor::pos()); + } +} + +void QmitkPatientTableInspector::OnContextMenuSetInformationType() +{ + bool ok = false; + QString text = QInputDialog::getText(m_Controls.view, tr("Set information type of selected node"), tr("Information type:"), QLineEdit::Normal, "", &ok); + if (ok && !text.isEmpty()) + { + m_StorageModel->GetSemanticRelations()->RemoveInformationTypeFromImage(m_SelectedDataNode); + m_StorageModel->GetSemanticRelations()->AddInformationTypeToImage(m_SelectedDataNode, text.toStdString()); + m_StorageModel->UpdateModelData(); + } +} + +void QmitkPatientTableInspector::OnContextMenuSetControlPoint() +{ + QmitkControlPointDialog* inputDialog = new QmitkControlPointDialog(m_Controls.view); + inputDialog->setWindowTitle("Set control point"); + inputDialog->SetCurrentDate(mitk::GetDICOMDateFromDataNode(m_SelectedDataNode)); + + int dialogReturnValue = inputDialog->exec(); + if (QDialog::Rejected == dialogReturnValue) + { + return; + } + + // store the current control point to relink it, if anything goes wrong + mitk::SemanticTypes::ControlPoint originalControlPoint = m_StorageModel->GetSemanticRelations()->GetControlPointOfData(m_SelectedDataNode); + // unlink the data, that is about to receive a new date + // this is needed in order to not extend a single control point, to which the selected node is currently linked + m_StorageModel->GetSemanticRelations()->UnlinkDataFromControlPoint(m_SelectedDataNode); + + const QDate& userSelectedDate = inputDialog->GetCurrentDate(); + mitk::SemanticTypes::Date date; + date.UID = mitk::UIDGeneratorBoost::GenerateUID(); + date.year = userSelectedDate.year(); + date.month = userSelectedDate.month(); + date.day = userSelectedDate.day(); + + std::vector allControlPoints = m_StorageModel->GetSemanticRelations()->GetAllControlPointsOfCase(m_StorageModel->GetCurrentCaseID()); + if (!allControlPoints.empty()) + { + // need to check if an already existing control point fits/contains the user control point + mitk::SemanticTypes::ControlPoint fittingControlPoint = mitk::FindFittingControlPoint(date, allControlPoints); + if (!fittingControlPoint.UID.empty()) + { + try + { + // found a fitting control point + m_StorageModel->GetSemanticRelations()->LinkDataToControlPoint(m_SelectedDataNode, fittingControlPoint, false); + m_StorageModel->UpdateModelData(); + } + catch (const mitk::SemanticRelationException&) + { + MITK_INFO << "The data can not be linked to the fitting control point."; + try + { + // link to the original control point + m_StorageModel->GetSemanticRelations()->LinkDataToControlPoint(m_SelectedDataNode, originalControlPoint, false); + } + catch (const mitk::SemanticRelationException&) + { + MITK_INFO << "The data can not be linked to its original control point. Inconsistency in the semantic relations storage assumed."; + } + } + return; + } + + // did not find a fitting control point, although some control points already exist + // need to check if a close control point can be found and extended + mitk::SemanticTypes::ControlPoint extendedControlPoint = mitk::ExtendClosestControlPoint(date, allControlPoints); + if (!extendedControlPoint.UID.empty()) + { + try + { + // found and extended a close control point + m_StorageModel->GetSemanticRelations()->OverwriteControlPointAndLinkData(m_SelectedDataNode, extendedControlPoint, false); + m_StorageModel->UpdateModelData(); + } + catch (const mitk::SemanticRelationException&) + { + MITK_INFO << "The extended control point can not be overwritten and the data can not be linked to this control point."; + try + { + // link to the original control point + m_StorageModel->GetSemanticRelations()->LinkDataToControlPoint(m_SelectedDataNode, originalControlPoint, false); + } + catch (const mitk::SemanticRelationException&) + { + MITK_INFO << "The data can not be linked to its original control point. Inconsistency in the semantic relations storage assumed."; + } + } + return; + } + } + + // generate a control point from the user-given date + mitk::SemanticTypes::ControlPoint controlPointFromUserDate = mitk::GenerateControlPoint(date); + try + { + m_StorageModel->GetSemanticRelations()->AddControlPointAndLinkData(m_SelectedDataNode, controlPointFromUserDate, false); + m_StorageModel->UpdateModelData(); + } + catch (const mitk::SemanticRelationException&) + { + MITK_INFO << "The control point can not be added and the data can not be linked to this control point."; + try + { + // link to the original control point + m_StorageModel->GetSemanticRelations()->LinkDataToControlPoint(m_SelectedDataNode, originalControlPoint, false); + } + catch (const mitk::SemanticRelationException&) + { + MITK_INFO << "The data can not be linked to its original control point. Inconsistency in the semantic relations storage assumed."; + } + } +} + +void QmitkPatientTableInspector::SetUpConnections() +{ + connect(m_StorageModel, SIGNAL(ModelUpdated()), SLOT(OnPatientTableModelUpdated())); + connect(m_Controls.view, SIGNAL(customContextMenuRequested(const QPoint&)), SLOT(OnPatientTableViewContextMenuRequested(const QPoint&))); +} diff --git a/Modules/SemanticRelationsUI/src/QmitkPatientTableInspector.ui b/Modules/SemanticRelationsUI/src/QmitkPatientTableInspector.ui new file mode 100644 index 0000000000..71ac6b26e6 --- /dev/null +++ b/Modules/SemanticRelationsUI/src/QmitkPatientTableInspector.ui @@ -0,0 +1,36 @@ + + + QmitkPatientTableInspector + + + + 0 + 0 + 350 + 300 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + diff --git a/Modules/SemanticRelationsUI/src/QmitkPatientTableModel.cpp b/Modules/SemanticRelationsUI/src/QmitkPatientTableModel.cpp index 9b96295cee..26aca39b5e 100644 --- a/Modules/SemanticRelationsUI/src/QmitkPatientTableModel.cpp +++ b/Modules/SemanticRelationsUI/src/QmitkPatientTableModel.cpp @@ -1,193 +1,217 @@ /*=================================================================== 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 +// semantic relations ui plugin #include "QmitkPatientTableModel.h" +#include "QmitkSemanticRelationsUIHelper.h" #include "QmitkCustomVariants.h" +#include "QmitkEnums.h" -// qt -#include - -QmitkPatientTableModel::QmitkPatientTableModel(std::shared_ptr semanticRelations, QObject* parent /*= nullptr*/) - : QAbstractTableModel(parent) - , m_SemanticRelations(semanticRelations) +QmitkPatientTableModel::QmitkPatientTableModel(QObject* parent /*= nullptr*/) + : QmitkSemanticRelationsModel(parent) { // nothing here } QmitkPatientTableModel::~QmitkPatientTableModel() { // nothing here } -Qt::ItemFlags QmitkPatientTableModel::flags(const QModelIndex &index) const +QModelIndex QmitkPatientTableModel::index(int row, int column, const QModelIndex &parent/* = QModelIndex()*/) const { - Qt::ItemFlags flags; - mitk::DataNode* dataNode = GetCurrentDataNode(index); - if (nullptr != dataNode) + bool hasIndex = this->hasIndex(row, column, parent); + if (hasIndex) { - flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable; + return this->createIndex(row, column); } - return flags; + return QModelIndex(); } -int QmitkPatientTableModel::rowCount(const QModelIndex &parent /*= QModelIndex()*/) const +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 +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 +QVariant QmitkPatientTableModel::data(const QModelIndex &index, int role/* = Qt::DisplayRole*/) const { if (!index.isValid()) { return QVariant(); } - mitk::DataNode* dataNode = GetCurrentDataNode(index); - if (nullptr == dataNode) + if (index.row() < 0 || index.row() >= static_cast(m_InformationTypes.size()) + || index.column() < 0 || index.column() >= static_cast(m_ControlPoints.size())) { return QVariant(); } - if (Qt::UserRole == role) + mitk::DataNode* dataNode = GetCurrentDataNode(index); + if (nullptr == dataNode) { - // user role always returns a reference to the data node, - // which can be used to modify the data node in the data storage - return QVariant::fromValue(dataNode); + return QVariant(); } - else if (Qt::DecorationRole == role) + + if (Qt::DecorationRole == role) { auto it = m_PixmapMap.find(mitk::GetIDFromDataNode(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(); } -void QmitkPatientTableModel::SetCurrentCaseID(const mitk::SemanticTypes::CaseID& caseID) +Qt::ItemFlags QmitkPatientTableModel::flags(const QModelIndex &index) const { - m_CaseID = caseID; - SetPatientData(); + Qt::ItemFlags flags; + mitk::DataNode* dataNode = GetCurrentDataNode(index); + if (nullptr != dataNode) + { + flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable; + } + + return flags; +} + +void QmitkPatientTableModel::NodePredicateChanged() +{ + // does not work with node predicates +} + +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) { mitk::SemanticTypes::ID nodeID = mitk::GetIDFromDataNode(dataNode); std::map::iterator iter = m_PixmapMap.find(nodeID); 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(nodeID, pixmapFromImage->scaled(120, 120, Qt::IgnoreAspectRatio))); } } -void QmitkPatientTableModel::SetPatientData() +void QmitkPatientTableModel::SetData() { - if (nullptr == m_SemanticRelations) - { - return; - } - - // update the model, so that the table will be filled with the new patient information - beginResetModel(); - - // update current data // 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); - endResetModel(); - emit ModelUpdated(); -} - -void QmitkPatientTableModel::Update(const mitk::SemanticTypes::CaseID& caseID) -{ - // if the case ID of updated instance is equal to the currently active caseID - if (caseID == m_CaseID) + std::vector allDataNodes = m_SemanticRelations->GetAllImagesOfCase(m_CaseID); + for (const auto& dataNode : allDataNodes) { - SetPatientData(); + QPixmap pixmapFromImage = QmitkSemanticRelationsUIHelper::GetPixmapFromImageNode(dataNode); + SetPixmapOfNode(dataNode, &pixmapFromImage); } } 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()); std::vector filteredDataNodes = m_SemanticRelations->GetFilteredData(m_CaseID, currentControlPoint, currentInformationType); if (filteredDataNodes.empty()) { return nullptr; } return filteredDataNodes.front(); } diff --git a/Modules/SemanticRelationsUI/src/QmitkPatientTableWidget.cpp b/Modules/SemanticRelationsUI/src/QmitkPatientTableWidget.cpp deleted file mode 100644 index 83b6cd1707..0000000000 --- a/Modules/SemanticRelationsUI/src/QmitkPatientTableWidget.cpp +++ /dev/null @@ -1,337 +0,0 @@ -/*=================================================================== - -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 "QmitkPatientTableWidget.h" -#include "QmitkControlPointDialog.h" - -#include "QmitkCustomVariants.h" - -// semantic relations module -#include -#include -#include -#include - -// mitk core -#include -#include -#include -#include -#include -#include - -// vtk -#include - -// qt -#include -#include - -QmitkPatientTableWidget::QmitkPatientTableWidget(mitk::DataStorage* dataStorage, QWidget* parent /*=nullptr*/) - : QmitkSelectionWidget(dataStorage, parent) -{ - Init(); -} - -QmitkPatientTableWidget::~QmitkPatientTableWidget() -{ - m_SemanticRelations->RemoveObserver(this); -} - -void QmitkPatientTableWidget::Init() -{ - // create GUI from the Qt Designer's .ui file - m_Controls.setupUi(this); - - // create a new model - m_PatientTableModel = std::make_unique(m_SemanticRelations, this); - - m_Controls.patientTableView->setModel(m_PatientTableModel.get()); - m_Controls.patientTableView->horizontalHeader()->setHighlightSections(false); - m_Controls.patientTableView->verticalHeader()->setHighlightSections(false); - m_Controls.patientTableView->setSelectionBehavior(QAbstractItemView::SelectItems); - m_Controls.patientTableView->setSelectionMode(QAbstractItemView::SingleSelection); - m_Controls.patientTableView->setContextMenuPolicy(Qt::CustomContextMenu); - - m_ContextMenu = new QMenu(m_Controls.patientTableView); - - SetUpConnections(); - - m_SemanticRelations->AddObserver(this); -} - -void QmitkPatientTableWidget::SetUpConnections() -{ - connect(m_PatientTableModel.get(), SIGNAL(ModelUpdated()), SLOT(OnPatientTableModelUpdated())); - connect(m_Controls.patientTableView, SIGNAL(customContextMenuRequested(const QPoint&)), SLOT(OnPatientTableViewContextMenuRequested(const QPoint&))); - connect(m_Controls.patientTableView->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), SLOT(OnPatientTableViewSelectionChanged(const QItemSelection&, const QItemSelection&))); -} - -void QmitkPatientTableWidget::SetCurrentCaseID(const mitk::SemanticTypes::CaseID& caseID) -{ - m_PatientTableModel->SetCurrentCaseID(caseID); -} - -void QmitkPatientTableWidget::Update(const mitk::SemanticTypes::CaseID& caseID) -{ - m_PatientTableModel->Update(caseID); -} - -void QmitkPatientTableWidget::SetPixmapOfNode(const mitk::DataNode* dataNode) -{ - QPixmap pixmapFromImage = GetPixmapFromImageNode(dataNode); - m_PatientTableModel->SetPixmapOfNode(dataNode, &pixmapFromImage); -} - -void QmitkPatientTableWidget::DeletePixmapOfNode(const mitk::DataNode* dataNode) -{ - m_PatientTableModel->SetPixmapOfNode(dataNode, nullptr); -} - -void QmitkPatientTableWidget::OnPatientTableModelUpdated() -{ - m_Controls.patientTableView->resizeRowsToContents(); - m_Controls.patientTableView->resizeColumnsToContents(); -} - -void QmitkPatientTableWidget::OnPatientTableViewContextMenuRequested(const QPoint& pos) -{ - QModelIndex selectedIndex = m_Controls.patientTableView->indexAt(pos); - if (!selectedIndex.isValid()) - { - return; - } - - QVariant qvariantDataNode = m_PatientTableModel->data(selectedIndex, Qt::UserRole); - if (qvariantDataNode.canConvert()) - { - m_SelectedDataNode = qvariantDataNode.value(); - - m_ContextMenu->clear(); - - QAction* setInformationTypeAction = new QAction("Set information type", m_ContextMenu); - m_ContextMenu->addAction(setInformationTypeAction); - connect(setInformationTypeAction, SIGNAL(triggered()), this, SLOT(OnContextMenuSetInformationType())); - - QAction* setControlPointAction = new QAction("Set control point", m_ContextMenu); - m_ContextMenu->addAction(setControlPointAction); - connect(setControlPointAction, SIGNAL(triggered()), this, SLOT(OnContextMenuSetControlPoint())); - - m_ContextMenu->popup(QCursor::pos()); - } -} - -void QmitkPatientTableWidget::OnContextMenuSetInformationType() -{ - bool ok = false; - QString text = QInputDialog::getText(m_Controls.patientTableView, tr("Set information type of selected node"), tr("Information type:"), QLineEdit::Normal, "", &ok); - if (ok && !text.isEmpty()) - { - m_SemanticRelations->RemoveInformationTypeFromImage(m_SelectedDataNode); - m_SemanticRelations->AddInformationTypeToImage(m_SelectedDataNode, text.toStdString()); - m_PatientTableModel->SetPatientData(); - } -} - -void QmitkPatientTableWidget::OnContextMenuSetControlPoint() -{ - QmitkControlPointDialog* inputDialog = new QmitkControlPointDialog(m_Controls.patientTableView); - inputDialog->setWindowTitle("Set control point"); - inputDialog->SetCurrentDate(mitk::GetDICOMDateFromDataNode(m_SelectedDataNode)); - - int dialogReturnValue = inputDialog->exec(); - if (QDialog::Rejected == dialogReturnValue) - { - return; - } - - // store the current control point to relink it, if anything goes wrong - mitk::SemanticTypes::ControlPoint originalControlPoint = m_SemanticRelations->GetControlPointOfData(m_SelectedDataNode); - // unlink the data, that is about to receive a new date - // this is needed in order to not extend a single control point, to which the selected node is currently linked - m_SemanticRelations->UnlinkDataFromControlPoint(m_SelectedDataNode); - - const QDate& userSelectedDate = inputDialog->GetCurrentDate(); - mitk::SemanticTypes::Date date; - date.UID = mitk::UIDGeneratorBoost::GenerateUID(); - date.year = userSelectedDate.year(); - date.month = userSelectedDate.month(); - date.day = userSelectedDate.day(); - - std::vector allControlPoints = m_SemanticRelations->GetAllControlPointsOfCase(m_PatientTableModel->GetCurrentCaseID()); - if (!allControlPoints.empty()) - { - // need to check if an already existing control point fits/contains the user control point - mitk::SemanticTypes::ControlPoint fittingControlPoint = mitk::FindFittingControlPoint(date, allControlPoints); - if (!fittingControlPoint.UID.empty()) - { - try - { - // found a fitting control point - m_SemanticRelations->LinkDataToControlPoint(m_SelectedDataNode, fittingControlPoint, false); - m_PatientTableModel->SetPatientData(); - } - catch (const mitk::SemanticRelationException&) - { - MITK_INFO << "The data can not be linked to the fitting control point."; - try - { - // link to the original control point - m_SemanticRelations->LinkDataToControlPoint(m_SelectedDataNode, originalControlPoint, false); - } - catch (const mitk::SemanticRelationException&) - { - MITK_INFO << "The data can not be linked to its original control point. Inconsistency in the semantic relations storage assumed."; - } - } - return; - } - - // did not find a fitting control point, although some control points already exist - // need to check if a close control point can be found and extended - mitk::SemanticTypes::ControlPoint extendedControlPoint = mitk::ExtendClosestControlPoint(date, allControlPoints); - if (!extendedControlPoint.UID.empty()) - { - try - { - // found and extended a close control point - m_SemanticRelations->OverwriteControlPointAndLinkData(m_SelectedDataNode, extendedControlPoint, false); - m_PatientTableModel->SetPatientData(); - } - catch (const mitk::SemanticRelationException&) - { - MITK_INFO << "The extended control point can not be overwritten and the data can not be linked to this control point."; - try - { - // link to the original control point - m_SemanticRelations->LinkDataToControlPoint(m_SelectedDataNode, originalControlPoint, false); - } - catch (const mitk::SemanticRelationException&) - { - MITK_INFO << "The data can not be linked to its original control point. Inconsistency in the semantic relations storage assumed."; - } - } - return; - } - } - - // generate a control point from the user-given date - mitk::SemanticTypes::ControlPoint controlPointFromUserDate = mitk::GenerateControlPoint(date); - try - { - m_SemanticRelations->AddControlPointAndLinkData(m_SelectedDataNode, controlPointFromUserDate, false); - m_PatientTableModel->SetPatientData(); - } - catch (const mitk::SemanticRelationException&) - { - MITK_INFO << "The control point can not be added and the data can not be linked to this control point."; - try - { - // link to the original control point - m_SemanticRelations->LinkDataToControlPoint(m_SelectedDataNode, originalControlPoint, false); - } - catch (const mitk::SemanticRelationException&) - { - MITK_INFO << "The data can not be linked to its original control point. Inconsistency in the semantic relations storage assumed."; - } - } -} - -void QmitkPatientTableWidget::OnPatientTableViewSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected) -{ - QModelIndex selectedIndex = m_Controls.patientTableView->currentIndex(); - if (!selectedIndex.isValid()) - { - return; - } - - QVariant qvariantDataNode = m_PatientTableModel->data(selectedIndex, Qt::UserRole); - if (qvariantDataNode.canConvert()) - { - m_SelectedDataNode = qvariantDataNode.value(); - - emit SelectionChanged(m_SelectedDataNode); - } -} - -QPixmap QmitkPatientTableWidget::GetPixmapFromImageNode(const mitk::DataNode* dataNode) const -{ - if (nullptr == dataNode) - { - return QPixmap(); - } - - const mitk::Image* image = static_cast(dataNode->GetData()); - if (nullptr == image || !image->IsInitialized()) - { - return QPixmap(); - } - - if (image->GetPixelType().GetNumberOfComponents() != 1) // for now only single component are allowed - { - return QPixmap(); - } - - mitk::PlaneGeometry::Pointer sagittalPlaneGeometry = mitk::PlaneGeometry::New(); - int sliceNumber = image->GetDimension(1) / 2; - sagittalPlaneGeometry->InitializeStandardPlane(image->GetGeometry(), mitk::PlaneGeometry::Sagittal, sliceNumber); - - mitk::ExtractSliceFilter::Pointer extractSliceFilter = mitk::ExtractSliceFilter::New(); - extractSliceFilter->SetInput(image); - extractSliceFilter->SetInterpolationMode(mitk::ExtractSliceFilter::RESLICE_CUBIC); - extractSliceFilter->SetResliceTransformByGeometry(image->GetGeometry()); - extractSliceFilter->SetWorldGeometry(sagittalPlaneGeometry); - extractSliceFilter->SetOutputDimensionality(2); - extractSliceFilter->SetVtkOutputRequest(true); - extractSliceFilter->Update(); - - /* - mitk::Vector3D spacing; - mitk::FillVector3D(spacing,1.0,1.0,1.0); - slice->GetGeometry()->SetSpacing(spacing); - // save image slice - mitk::IOUtil::SaveImage( slice, d->m_Path + fileName + ".png" ); - */ - - vtkImageData* imageData = extractSliceFilter->GetVtkOutput(); - - mitk::LevelWindow levelWindow; - dataNode->GetLevelWindow(levelWindow); - vtkSmartPointer lookupTable = vtkSmartPointer::New(); - lookupTable->SetRange(levelWindow.GetLowerWindowBound(), levelWindow.GetUpperWindowBound()); - lookupTable->SetSaturationRange(0.0, 0.0); - lookupTable->SetValueRange(0.0, 1.0); - lookupTable->SetHueRange(0.0, 0.0); - lookupTable->SetRampToLinear(); - - vtkSmartPointer levelWindowFilter = vtkSmartPointer::New(); - levelWindowFilter->SetLookupTable(lookupTable); - levelWindowFilter->SetInputData(imageData); - levelWindowFilter->SetMinOpacity(0.0); - levelWindowFilter->SetMaxOpacity(1.0); - int dims[3]; - imageData->GetDimensions(dims); - double clippingBounds[] = { 0.0, static_cast(dims[0]), 0.0, static_cast(dims[1]) }; - levelWindowFilter->SetClippingBounds(clippingBounds); - levelWindowFilter->Update(); - imageData = levelWindowFilter->GetOutput(); - - QImage thumbnailImage(reinterpret_cast(imageData->GetScalarPointer()), dims[0], dims[1], QImage::Format_ARGB32); - - thumbnailImage = thumbnailImage.rgbSwapped().mirrored(false, true); - return QPixmap::fromImage(thumbnailImage); -} diff --git a/Modules/SemanticRelationsUI/src/QmitkPatientTableWidgetControls.ui b/Modules/SemanticRelationsUI/src/QmitkPatientTableWidgetControls.ui deleted file mode 100644 index 28843900bc..0000000000 --- a/Modules/SemanticRelationsUI/src/QmitkPatientTableWidgetControls.ui +++ /dev/null @@ -1,31 +0,0 @@ - - - QmitkPatientTableWidgetControls - - - true - - - - 0 - 0 - 350 - 300 - - - - - - - Available patient data - - - - - - - - - - - diff --git a/Modules/SemanticRelationsUI/src/QmitkSemanticRelationsModel.cpp b/Modules/SemanticRelationsUI/src/QmitkSemanticRelationsModel.cpp new file mode 100644 index 0000000000..d7b04c2240 --- /dev/null +++ b/Modules/SemanticRelationsUI/src/QmitkSemanticRelationsModel.cpp @@ -0,0 +1,69 @@ +/*=================================================================== + +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 "QmitkPatientTableModel.h" + +#include "QmitkCustomVariants.h" + +QmitkSemanticRelationsModel::QmitkSemanticRelationsModel(QObject* parent /*= nullptr*/) + : QmitkAbstractDataStorageModel(parent) + , m_SemanticRelations(nullptr) +{ + // nothing here +} + +QmitkSemanticRelationsModel::~QmitkSemanticRelationsModel() +{ + // nothing here +} + +void QmitkSemanticRelationsModel::SetCaseID(const mitk::SemanticTypes::CaseID& caseID) +{ + m_CaseID = caseID; + UpdateModelData(); +} + +void QmitkSemanticRelationsModel::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 QmitkSemanticRelationsModel::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 QmitkSemanticRelationsModel::DataStorageChanged() +{ + m_SemanticRelations = std::make_shared(m_DataStorage.Lock()); + UpdateModelData(); +} diff --git a/Modules/SemanticRelationsUI/src/QmitkSemanticRelationsUIHelper.cpp b/Modules/SemanticRelationsUI/src/QmitkSemanticRelationsUIHelper.cpp new file mode 100644 index 0000000000..31ba46b7d2 --- /dev/null +++ b/Modules/SemanticRelationsUI/src/QmitkSemanticRelationsUIHelper.cpp @@ -0,0 +1,95 @@ +/*=================================================================== + +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 + +// mitk core +#include +#include +#include +#include + +// vtk +#include + +QPixmap QmitkSemanticRelationsUIHelper::GetPixmapFromImageNode(const mitk::DataNode* dataNode) +{ + if (nullptr == dataNode) + { + return QPixmap(); + } + + const mitk::Image* image = static_cast(dataNode->GetData()); + if (nullptr == image || !image->IsInitialized()) + { + return QPixmap(); + } + + if (image->GetPixelType().GetNumberOfComponents() != 1) // for now only single component are allowed + { + return QPixmap(); + } + + mitk::PlaneGeometry::Pointer sagittalPlaneGeometry = mitk::PlaneGeometry::New(); + int sliceNumber = image->GetDimension(1) / 2; + sagittalPlaneGeometry->InitializeStandardPlane(image->GetGeometry(), mitk::PlaneGeometry::Sagittal, sliceNumber); + + mitk::ExtractSliceFilter::Pointer extractSliceFilter = mitk::ExtractSliceFilter::New(); + extractSliceFilter->SetInput(image); + extractSliceFilter->SetInterpolationMode(mitk::ExtractSliceFilter::RESLICE_CUBIC); + extractSliceFilter->SetResliceTransformByGeometry(image->GetGeometry()); + extractSliceFilter->SetWorldGeometry(sagittalPlaneGeometry); + extractSliceFilter->SetOutputDimensionality(2); + extractSliceFilter->SetVtkOutputRequest(true); + extractSliceFilter->Update(); + + /* + mitk::Vector3D spacing; + mitk::FillVector3D(spacing,1.0,1.0,1.0); + slice->GetGeometry()->SetSpacing(spacing); + // save image slice + mitk::IOUtil::SaveImage( slice, d->m_Path + fileName + ".png" ); + */ + + vtkImageData* imageData = extractSliceFilter->GetVtkOutput(); + + mitk::LevelWindow levelWindow; + dataNode->GetLevelWindow(levelWindow); + vtkSmartPointer lookupTable = vtkSmartPointer::New(); + lookupTable->SetRange(levelWindow.GetLowerWindowBound(), levelWindow.GetUpperWindowBound()); + lookupTable->SetSaturationRange(0.0, 0.0); + lookupTable->SetValueRange(0.0, 1.0); + lookupTable->SetHueRange(0.0, 0.0); + lookupTable->SetRampToLinear(); + + vtkSmartPointer levelWindowFilter = vtkSmartPointer::New(); + levelWindowFilter->SetLookupTable(lookupTable); + levelWindowFilter->SetInputData(imageData); + levelWindowFilter->SetMinOpacity(0.0); + levelWindowFilter->SetMaxOpacity(1.0); + int dims[3]; + imageData->GetDimensions(dims); + double clippingBounds[] = { 0.0, static_cast(dims[0]), 0.0, static_cast(dims[1]) }; + levelWindowFilter->SetClippingBounds(clippingBounds); + levelWindowFilter->Update(); + imageData = levelWindowFilter->GetOutput(); + + QImage thumbnailImage(reinterpret_cast(imageData->GetScalarPointer()), dims[0], dims[1], QImage::Format_ARGB32); + + thumbnailImage = thumbnailImage.rgbSwapped().mirrored(false, true); + return QPixmap::fromImage(thumbnailImage); +} diff --git a/Modules/SemanticRelationsUI/src/mitkModuleActivator.cpp b/Modules/SemanticRelationsUI/src/mitkModuleActivator.cpp new file mode 100644 index 0000000000..fedf06d13f --- /dev/null +++ b/Modules/SemanticRelationsUI/src/mitkModuleActivator.cpp @@ -0,0 +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 "mitkModuleActivator.h" + +// semantic relations ui module +#include "QmitkPatientTableInspector.h" + +// qt widgets module +#include "QmitkDataStorageInspectorProviderBase.h" + +void mitk::SemanticRelationsUIActivator::Load(us::ModuleContext* /*context*/) +{ + m_PatientTableInspector.reset(new QmitkDataStorageInspectorProviderBase("org.mitk.QmitkPatientTableInspector", "Patient table", "Displays the content of the semantic relations storage in a control-point - modality table.")); + } + +void mitk::SemanticRelationsUIActivator::Unload(us::ModuleContext* /*context*/) +{ +} + +US_EXPORT_MODULE_ACTIVATOR(mitk::SemanticRelationsUIActivator) diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionDialog.cpp b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionDialog.cpp index cdba488356..1406db1518 100644 --- a/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionDialog.cpp +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionDialog.cpp @@ -1,186 +1,186 @@ /*=================================================================== 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 "QmitkNodeSelectionDialog.h" #include #include #include QmitkNodeSelectionDialog::QmitkNodeSelectionDialog(QWidget* parent, QString title, QString hint) : QDialog(parent), m_NodePredicate(nullptr), m_SelectOnlyVisibleNodes(false), m_SelectedNodes(NodeList()), m_SelectionMode(QAbstractItemView::SingleSelection) { m_Controls.setupUi(this); auto providers = mitk::DataStorageInspectorGenerator::GetProviders(); auto visibleProviders = mitk::GetVisibleDataStorageInspectors(); auto favoriteID = mitk::GetFavoriteDataStorageInspector(); if (visibleProviders.empty()) { MITK_DEBUG << "No presets for visible node selection inspectors available. Use fallback (show all available inspectors)"; unsigned int order = 0; for (auto proIter : providers) { visibleProviders.insert(std::make_pair(order, proIter.first)); } } int favIndex = 0; bool favoriteFound = false; for (auto proIter : visibleProviders) { auto finding = providers.find(proIter.second); if (finding != providers.end()) { auto inspector = finding->second->CreateInspector(); QString name = QString::fromStdString(finding->second->GetInspectorDisplayName()); QString desc = QString::fromStdString(finding->second->GetInspectorDescription()); AddPanel(inspector, name, desc); favoriteFound = favoriteFound || proIter.second == favoriteID; if (!favoriteFound) { ++favIndex; } } else { MITK_DEBUG << "No provider registered for inspector that is defined as visible in the preferences. Illegal inspector ID: " << proIter.second; } } m_Controls.tabWidget->setCurrentIndex(favIndex); this->setWindowTitle(title); this->setToolTip(hint); m_Controls.hint->setText(hint); m_Controls.hint->setVisible(!hint.isEmpty()); connect(m_Controls.buttonBox, SIGNAL(accepted()), this, SLOT(OnOK())); connect(m_Controls.buttonBox, SIGNAL(rejected()), this, SLOT(OnCancel())); } void QmitkNodeSelectionDialog::SetDataStorage(mitk::DataStorage* dataStorage) { if (m_DataStorage != dataStorage) { m_DataStorage = dataStorage; if (!m_DataStorage.IsExpired()) { for (auto panel : m_Panels) { panel->SetDataStorage(dataStorage); } } } -}; +} void QmitkNodeSelectionDialog::SetNodePredicate(mitk::NodePredicateBase* nodePredicate) { if (m_NodePredicate != nodePredicate) { m_NodePredicate = nodePredicate; for (auto panel : m_Panels) { panel->SetNodePredicate(m_NodePredicate); } } -}; +} mitk::NodePredicateBase* QmitkNodeSelectionDialog::GetNodePredicate() const { return m_NodePredicate; } QmitkNodeSelectionDialog::NodeList QmitkNodeSelectionDialog::GetSelectedNodes() const { return m_SelectedNodes; -}; +} void QmitkNodeSelectionDialog::SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes) { if (m_SelectOnlyVisibleNodes != selectOnlyVisibleNodes) { m_SelectOnlyVisibleNodes = selectOnlyVisibleNodes; for (auto panel : m_Panels) { panel->SetSelectOnlyVisibleNodes(m_SelectOnlyVisibleNodes); } } -}; +} void QmitkNodeSelectionDialog::SetCurrentSelection(NodeList selectedNodes) { m_SelectedNodes = selectedNodes; for (auto panel : m_Panels) { panel->SetCurrentSelection(selectedNodes); } -}; +} void QmitkNodeSelectionDialog::OnSelectionChanged(NodeList selectedNodes) { SetCurrentSelection(selectedNodes); emit CurrentSelectionChanged(selectedNodes); -}; +} void QmitkNodeSelectionDialog::AddPanel(QmitkAbstractDataStorageInspector* view, QString name, QString desc) { view->setParent(this); view->SetSelectionMode(m_SelectionMode); auto tabPanel = new QWidget(); tabPanel->setObjectName(QString("tab_")+name); tabPanel->setToolTip(desc); m_Controls.tabWidget->insertTab(m_Controls.tabWidget->count(), tabPanel, name); auto verticalLayout = new QVBoxLayout(tabPanel); verticalLayout->setSpacing(0); verticalLayout->setContentsMargins(0, 0, 0, 0); verticalLayout->addWidget(view); m_Panels.push_back(view); connect(view, &QmitkAbstractDataStorageInspector::CurrentSelectionChanged, this, &QmitkNodeSelectionDialog::OnSelectionChanged); -}; +} void QmitkNodeSelectionDialog::OnOK() { this->accept(); -}; +} void QmitkNodeSelectionDialog::OnCancel() { this->reject(); -}; +} void QmitkNodeSelectionDialog::SetSelectionMode(SelectionMode mode) { m_SelectionMode = mode; for (auto panel : m_Panels) { panel->SetSelectionMode(mode); } -}; +} QmitkNodeSelectionDialog::SelectionMode QmitkNodeSelectionDialog::GetSelectionMode() const { return m_SelectionMode; } diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/CMakeLists.txt b/Plugins/org.mitk.gui.qt.semanticrelations/CMakeLists.txt index ade7a57843..2d9453bace 100644 --- a/Plugins/org.mitk.gui.qt.semanticrelations/CMakeLists.txt +++ b/Plugins/org.mitk.gui.qt.semanticrelations/CMakeLists.txt @@ -1,7 +1,7 @@ project(org_mitk_gui_qt_semanticrelations) mitk_create_plugin( EXPORT_DIRECTIVE MITK_GUI_SEMANTICRELATIONS_EXPORT EXPORTED_INCLUDE_SUFFIXES src - MODULE_DEPENDS MitkQtWidgetsExt MitkPersistence MitkSemanticRelationsUI + MODULE_DEPENDS MitkPersistence MitkSemanticRelationsUI ) diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/files.cmake b/Plugins/org.mitk.gui.qt.semanticrelations/files.cmake index cf794d078c..d1fe5933d4 100644 --- a/Plugins/org.mitk.gui.qt.semanticrelations/files.cmake +++ b/Plugins/org.mitk.gui.qt.semanticrelations/files.cmake @@ -1,25 +1,27 @@ set(INTERNAL_CPP_FILES mitkPluginActivator.cpp + QmitkSemanticRelationsNodeSelectionDialog.cpp QmitkSemanticRelationsView.cpp ) set(UI_FILES src/internal/QmitkSemanticRelationsControls.ui ) set(MOC_H_FILES src/internal/mitkPluginActivator.h + src/internal/QmitkSemanticRelationsNodeSelectionDialog.h src/internal/QmitkSemanticRelationsView.h ) set(CACHED_RESOURCE_FILES resources/SemanticRelations_48.png plugin.xml ) set(QRC_FILES ) foreach(file ${INTERNAL_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/internal/${file}) endforeach(file ${INTERNAL_CPP_FILES}) diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsNodeSelectionDialog.cpp b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsNodeSelectionDialog.cpp new file mode 100644 index 0000000000..9ce37a1394 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsNodeSelectionDialog.cpp @@ -0,0 +1,39 @@ +/*=================================================================== + +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 "QmitkSemanticRelationsNodeSelectionDialog.h" + +#include +#include +#include + +QmitkSemanticRelationsNodeSelectionDialog::QmitkSemanticRelationsNodeSelectionDialog(QWidget* parent, QString title, QString hint) + : QmitkNodeSelectionDialog(parent, title, hint) +{ + // nothing here +} + +void QmitkSemanticRelationsNodeSelectionDialog::SetCaseID(const mitk::SemanticTypes::CaseID& caseID) +{ + for (auto panel : m_Panels) + { + QmitkPatientTableInspector* patientTableInspector = dynamic_cast(panel); + if (nullptr != patientTableInspector) + { + patientTableInspector->SetCaseID(caseID); + } + } +} diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsNodeSelectionDialog.h b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsNodeSelectionDialog.h new file mode 100644 index 0000000000..521db92180 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsNodeSelectionDialog.h @@ -0,0 +1,50 @@ +/*=================================================================== + +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 QMITKSEMANTICRELATIONSSELECTIONDIALOG_H +#define QMITKSEMANTICRELATIONSSELECTIONDIALOG_H + +// semantic relations module +#include + +// semantic relations ui module +#include + +// org.mitk.gui.qt.common plugin +#include + +/* +* @brief The QmitkSemanticRelationsNodeSelectionDialog extends the QmitkNodeSelectionDialog so that a case ID can be set +* for each known panel that is of type 'QmitkPatientTableInspector'. +*/ +class QmitkSemanticRelationsNodeSelectionDialog : public QmitkNodeSelectionDialog +{ + Q_OBJECT + +public: + + explicit QmitkSemanticRelationsNodeSelectionDialog(QWidget* parent = nullptr, QString caption = "", QString hint = ""); + /** + * @brief Extends the base class to allow setting the current case ID which is needed to access the + * semantic relations storage. The function sets the case ID of each 'QmitkPatientTableInspector'. + * + * @param caseID A case ID as string + */ + virtual void SetCaseID(const mitk::SemanticTypes::CaseID& caseID); + +}; + +#endif // QMITKSEMANTICRELATIONSSELECTIONDIALOG_H diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsView.cpp b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsView.cpp index 8797c8af8b..c4fcb1583c 100644 --- a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsView.cpp +++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsView.cpp @@ -1,317 +1,288 @@ /*=================================================================== 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"; QmitkSemanticRelationsView::QmitkSemanticRelationsView() - : m_PatientTableWidget(nullptr) - , m_SimpleDatamanagerWidget(nullptr) - , m_SelectPatientNodeDialog(nullptr) - , m_SimpleDatamanagerNodeDialog(nullptr) - , m_SemanticRelations(nullptr) + : m_SemanticRelations(nullptr) { // nothing here } void QmitkSemanticRelationsView::SetFocus() { // nothing here } void QmitkSemanticRelationsView::CreateQtPartControl(QWidget* parent) { // create GUI widgets + m_Parent = parent; m_Controls.setupUi(parent); // initialize the semantic relations m_SemanticRelations = std::make_unique(GetDataStorage()); connect(m_Controls.caseIDComboBox, SIGNAL(currentIndexChanged(const QString&)), SLOT(OnCaseIDSelectionChanged(const QString&))); connect(m_Controls.selectPatientNodePushButton, SIGNAL(clicked()), SLOT(OnSelectPatientNodeButtonClicked())); m_LesionInfoWidget = new QmitkLesionInfoWidget(GetDataStorage()); m_Controls.gridLayout->addWidget(m_LesionInfoWidget, 3, 0, 1, 3); connect(m_LesionInfoWidget, SIGNAL(JumpToPosition(const mitk::Point3D&)), SLOT(OnJumpToPosition(const mitk::Point3D&))); connect(m_LesionInfoWidget, SIGNAL(ImageRemoved(const mitk::DataNode*)), SLOT(OnImageRemoved(const mitk::DataNode*))); - m_PatientTableWidget = new QmitkPatientTableWidget(GetDataStorage()); - - m_SelectPatientNodeDialog = new QmitkSelectNodeDialog(parent); - m_SelectPatientNodeDialog->setWindowTitle("Select patient image node"); - m_SelectPatientNodeDialog->SetSelectionWidget(m_PatientTableWidget); - - m_SimpleDatamanagerWidget = new QmitkSimpleDatamanagerWidget(GetDataStorage()); - m_SimpleDatamanagerNodeDialog = new QmitkSelectNodeDialog(parent); - m_SimpleDatamanagerNodeDialog->setWindowTitle("Select node"); - m_SimpleDatamanagerNodeDialog->SetSelectionWidget(m_SimpleDatamanagerWidget); - // connect buttons to modify semantic relations connect(m_Controls.addLesionPushButton, SIGNAL(clicked()), SLOT(OnAddLesionButtonClicked())); connect(m_Controls.addSegmentationPushButton, SIGNAL(clicked()), SLOT(OnAddSegmentationButtonClicked())); connect(m_Controls.addImagePushButton, SIGNAL(clicked()), SLOT(OnAddImageButtonClicked())); } void QmitkSemanticRelationsView::NodeRemoved(const mitk::DataNode* node) { - // ToDo: automatically remove node from storage, so that there will be no access anymore + OnImageRemoved(node); } void QmitkSemanticRelationsView::OnCaseIDSelectionChanged(const QString& caseID) { m_CaseID = caseID.toStdString(); m_LesionInfoWidget->SetCurrentCaseID(m_CaseID); - m_PatientTableWidget->SetCurrentCaseID(m_CaseID); } void QmitkSemanticRelationsView::OnSelectPatientNodeButtonClicked() { - int dialogReturnValue = m_SelectPatientNodeDialog->exec(); - if (QDialog::Rejected == dialogReturnValue) - { - return; - } - - mitk::DataNode* selectedDataNode = m_SelectPatientNodeDialog->GetSelectedDataNode(); - if (nullptr == selectedDataNode) - { - m_Controls.selectedPatientNodeLineEdit->clear(); - } - else + QmitkSemanticRelationsNodeSelectionDialog* dialog = new QmitkSemanticRelationsNodeSelectionDialog(m_Parent, "Select patient image to set a current patient", ""); + dialog->SetDataStorage(GetDataStorage()); + dialog->setWindowTitle("Select patient image node"); + dialog->SetNodePredicate(mitk::NodePredicates::GetImagePredicate()); + dialog->SetSelectOnlyVisibleNodes(true); + dialog->SetSelectionMode(QAbstractItemView::SingleSelection); + dialog->SetCaseID(m_CaseID); + + if (QDialog::Accepted == dialog->exec()) { - m_Controls.selectedPatientNodeLineEdit->setText(QString::fromStdString(selectedDataNode->GetName())); + auto nodes = dialog->GetSelectedNodes(); + for (mitk::DataNode* dataNode : nodes) + { + if (nullptr != dataNode) + { + m_Controls.selectedPatientNodeLineEdit->setText(QString::fromStdString(dataNode->GetName())); + //m_PatientInfoWidget->SetPatientInfo(node); + //m_PatientInfoWidget->show(); + } + else + { + m_Controls.selectedPatientNodeLineEdit->clear(); + } + } } - //m_PatientInfoWidget->SetPatientInfo(node); - //m_PatientInfoWidget->show(); } void QmitkSemanticRelationsView::OnJumpToPosition(const mitk::Point3D& position) { mitk::IRenderWindowPart* renderWindowPart = GetRenderWindowPart(); if (nullptr != renderWindowPart) { renderWindowPart->SetSelectedPosition(position); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkSemanticRelationsView::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; newLesion.UID = mitk::UIDGeneratorBoost::GenerateUID(); newLesion.lesionClass = mitk::SemanticTypes::LesionClass(); newLesion.lesionClass.UID = mitk::UIDGeneratorBoost::GenerateUID(); try { m_SemanticRelations->AddLesion(m_CaseID, newLesion); } catch (mitk::SemanticRelationException& e) { MITK_INFO << "Could not add a new lesion. " << e; } } void QmitkSemanticRelationsView::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; } - int dialogReturnValue = m_SimpleDatamanagerNodeDialog->exec(); - if (QDialog::Rejected == dialogReturnValue) - { - return; - } + QmitkSemanticRelationsNodeSelectionDialog* dialog = new QmitkSemanticRelationsNodeSelectionDialog(m_Parent, "Select segmentations to add to the semantic relations storage", ""); + dialog->SetDataStorage(GetDataStorage()); + dialog->setWindowTitle("Select segmentation node"); + dialog->SetNodePredicate(mitk::NodePredicates::GetSegmentationPredicate()); + dialog->SetSelectOnlyVisibleNodes(true); + dialog->SetSelectionMode(QAbstractItemView::MultiSelection); + dialog->SetCaseID(m_CaseID); - mitk::DataNode* selectedDataNode = m_SimpleDatamanagerNodeDialog->GetSelectedDataNode(); - if (nullptr == selectedDataNode) + if (QDialog::Accepted == dialog->exec()) { - QMessageBox msgBox; - msgBox.setWindowTitle("No valid segmentation node selected."); - msgBox.setText("In order to add a segmentation, please specify a valid segmentation node."); - msgBox.setIcon(QMessageBox::Warning); - msgBox.exec(); - return; - } - - if (!mitk::NodePredicates::GetSegmentationPredicate()->CheckNode(selectedDataNode)) - { - QMessageBox msgBox; - msgBox.setWindowTitle("No segmentation selected"); - msgBox.setText("In order to add 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; - } - - // continue with valid segmentation data - // get parent node of the current segmentation node with the node predicate - mitk::DataStorage::SetOfObjects::ConstPointer parentNodes = GetDataStorage()->GetSources(selectedDataNode, 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(selectedDataNode, parentNodes->front()); - } - catch (mitk::Exception& 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(); + 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 = GetDataStorage()->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 (mitk::Exception& 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(); + } + } } } void QmitkSemanticRelationsView::OnAddImageButtonClicked() { - int dialogReturnValue = m_SimpleDatamanagerNodeDialog->exec(); - if (QDialog::Rejected == dialogReturnValue) - { - return; - } - - mitk::DataNode* selectedDataNode = m_SimpleDatamanagerNodeDialog->GetSelectedDataNode(); - if (nullptr == selectedDataNode) - { - QMessageBox msgBox; - msgBox.setWindowTitle("No valid image node selected."); - msgBox.setText("In order to add an image, please specify a valid image node."); - msgBox.setIcon(QMessageBox::Warning); - msgBox.exec(); - return; - } - - if (!mitk::NodePredicates::GetImagePredicate()->CheckNode(selectedDataNode)) + QmitkSemanticRelationsNodeSelectionDialog* dialog = new QmitkSemanticRelationsNodeSelectionDialog(m_Parent, "Select images to add to the semantic relations storage", ""); + dialog->SetDataStorage(GetDataStorage()); + dialog->setWindowTitle("Select image node"); + dialog->SetNodePredicate(mitk::NodePredicates::GetImagePredicate()); + dialog->SetSelectOnlyVisibleNodes(true); + dialog->SetSelectionMode(QAbstractItemView::MultiSelection); + dialog->SetCaseID(m_CaseID); + + if (QDialog::Accepted == dialog->exec()) { - QMessageBox msgBox; - msgBox.setWindowTitle("No image selected"); - msgBox.setText("In order to add an image, please specify a valid image node."); - msgBox.setIcon(QMessageBox::Warning); - msgBox.exec(); - return; - } - - try - { - // add the image to the semantic relations storage - m_SemanticRelations->AddImage(selectedDataNode); - m_PatientTableWidget->SetPixmapOfNode(selectedDataNode); - mitk::SemanticTypes::CaseID caseID = mitk::GetCaseIDFromDataNode(selectedDataNode); - AddToComboBox(caseID); - } - catch (mitk::Exception& 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 image.\n" - "Reason:\n" + QString::fromStdString(exceptionMessage.str())); - msgBox.setIcon(QMessageBox::Warning); - msgBox.exec(); + 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); + AddToComboBox(caseID); + } + catch (mitk::Exception& 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(); + } + } + } } } void QmitkSemanticRelationsView::OnImageRemoved(const mitk::DataNode* imageNode) { - m_PatientTableWidget->DeletePixmapOfNode(imageNode); mitk::SemanticTypes::CaseID caseID = mitk::GetCaseIDFromDataNode(imageNode); RemoveFromComboBox(caseID); } 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); } } \ No newline at end of file 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 fcff8cac3c..9e6d3cdf8a 100644 --- a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsView.h +++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsView.h @@ -1,97 +1,91 @@ /*=================================================================== 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" // semantic relations module #include #include // semantic relations UI module #include -#include -#include -#include // blueberry #include // mitk qt #include /* * @brief The QmitkSemanticRelationsView is a MITK view to combine and show the widgets of the 'SemanticRelationsUI'-module. * * It allows the MITK user to see and modify the content of the SemanticRelations-session. * It provides a dialog to add images from the data storage to the semantic relations model and a dialog to select * data nodes that were added to the semantic relations model before. * If provides functionality to create new lesions and link them with segmentation nodes. * 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; QmitkSemanticRelationsView(); protected: virtual void SetFocus() override; virtual void CreateQtPartControl(QWidget* parent) override; private Q_SLOTS: void OnCaseIDSelectionChanged(const QString&); void OnSelectPatientNodeButtonClicked(); void OnJumpToPosition(const mitk::Point3D&); /* * @brief Generates a new, empty lesion to add to the semantic relations model for the current case ID. */ void OnAddLesionButtonClicked(); void OnAddSegmentationButtonClicked(); void OnAddImageButtonClicked(); void OnImageRemoved(const mitk::DataNode*); private: virtual void NodeRemoved(const mitk::DataNode* node) override; void AddToComboBox(const mitk::SemanticTypes::CaseID& caseID); void RemoveFromComboBox(const mitk::SemanticTypes::CaseID& caseID); + QWidget* m_Parent; Ui::QmitkSemanticRelationsControls m_Controls; QmitkLesionInfoWidget* m_LesionInfoWidget; - QmitkPatientTableWidget* m_PatientTableWidget; - QmitkSimpleDatamanagerWidget* m_SimpleDatamanagerWidget; - QmitkSelectNodeDialog* m_SelectPatientNodeDialog; - QmitkSelectNodeDialog* m_SimpleDatamanagerNodeDialog; mitk::SemanticTypes::CaseID m_CaseID; std::unique_ptr m_SemanticRelations; }; #endif // QMITKSEMANTICRELATIONSVIEW_H