diff --git a/Modules/QtWidgets/files.cmake b/Modules/QtWidgets/files.cmake index fc924b63fb..3caa14abb6 100644 --- a/Modules/QtWidgets/files.cmake +++ b/Modules/QtWidgets/files.cmake @@ -1,87 +1,107 @@ file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*") set(CPP_FILES -QmitkApplicationCursor.cpp -QmitkDataStorageComboBox.cpp -QmitkDataStorageListModel.cpp -QmitkDataStorageTableModel.cpp -QmitkDataStorageTreeModel.cpp -QmitkFileReaderOptionsDialog.cpp -QmitkFileReaderWriterOptionsWidget.cpp -QmitkFileWriterOptionsDialog.cpp -QmitkIOUtil.cpp -QmitkLevelWindowPresetDefinitionDialog.cpp -QmitkLevelWindowRangeChangeDialog.cpp -QmitkLevelWindowWidgetContextMenu.cpp -QmitkLevelWindowWidget.cpp -QmitkLineEditLevelWindowWidget.cpp -QmitkMemoryUsageIndicatorView.cpp -QmitkMimeTypes.cpp -QmitkNodeDescriptor.cpp -QmitkColoredNodeDescriptor.cpp -QmitkNodeDescriptorManager.cpp -QmitkRenderWindowMenu.cpp -QmitkProgressBar.cpp -QmitkPropertiesTableEditor.cpp -QmitkPropertiesTableModel.cpp -QmitkPropertyDelegate.cpp -QmitkRegisterClasses.cpp -QmitkRenderingManager.cpp -QmitkRenderingManagerFactory.cpp -QmitkRenderWindow.cpp -QmitkServiceListWidget.cpp -QmitkSliderLevelWindowWidget.cpp -QmitkStdMultiWidget.cpp -QmitkMouseModeSwitcher.cpp -QmitkDataStorageFilterProxyModel.cpp -QmitkDataStorageComboBoxWithSelectNone.cpp -QmitkPropertyItem.cpp -QmitkPropertyItemDelegate.cpp -QmitkPropertyItemModel.cpp -QmitkStyleManager.cpp + QmitkAbstractDataStorageModel.cpp + QmitkApplicationCursor.cpp + QmitkDataStorageComboBox.cpp + QmitkDataStorageDefaultListModel.cpp + QmitkDataStorageListModel.cpp + QmitkDataStorageTableModel.cpp + QmitkDataStorageSimpleTreeModel.cpp + QmitkDataStorageTreeModel.cpp + QmitkDataStorageTreeModelInternalItem.cpp + QmitkFileReaderOptionsDialog.cpp + QmitkFileReaderWriterOptionsWidget.cpp + QmitkFileWriterOptionsDialog.cpp + QmitkIOUtil.cpp + QmitkLevelWindowPresetDefinitionDialog.cpp + QmitkLevelWindowRangeChangeDialog.cpp + QmitkLevelWindowWidgetContextMenu.cpp + QmitkLevelWindowWidget.cpp + QmitkLineEditLevelWindowWidget.cpp + QmitkMemoryUsageIndicatorView.cpp + QmitkMimeTypes.cpp + QmitkNodeDescriptor.cpp + QmitkColoredNodeDescriptor.cpp + QmitkNodeDescriptorManager.cpp + QmitkRenderWindowMenu.cpp + QmitkProgressBar.cpp + QmitkPropertiesTableEditor.cpp + QmitkPropertiesTableModel.cpp + QmitkPropertyDelegate.cpp + QmitkRegisterClasses.cpp + QmitkRenderingManager.cpp + QmitkRenderingManagerFactory.cpp + QmitkRenderWindow.cpp + QmitkServiceListWidget.cpp + QmitkSliderLevelWindowWidget.cpp + QmitkStdMultiWidget.cpp + QmitkMouseModeSwitcher.cpp + QmitkDataStorageFilterProxyModel.cpp + QmitkDataStorageComboBoxWithSelectNone.cpp + QmitkPropertyItem.cpp + QmitkPropertyItemDelegate.cpp + QmitkPropertyItemModel.cpp + QmitkStyleManager.cpp + QmitkAbstractDataStorageInspector.cpp + QmitkDataStorageListInspector.cpp + QmitkDataStorageTreeInspector.cpp + QmitkModelViewSelectionConnector.cpp + QmitkIDataStorageInspectorProvider.cpp + mitkQtWidgetsActivator.cpp + QmitkDataStorageInspectorGenerator.cpp ) set(MOC_H_FILES + include/QmitkAbstractDataStorageModel.h include/QmitkDataStorageComboBox.h include/QmitkDataStorageTableModel.h include/QmitkDataStorageTreeModel.h + include/QmitkDataStorageSimpleTreeModel.h + include/QmitkDataStorageDefaultListModel.h include/QmitkFileReaderOptionsDialog.h include/QmitkFileReaderWriterOptionsWidget.h include/QmitkFileWriterOptionsDialog.h include/QmitkLevelWindowPresetDefinitionDialog.h include/QmitkLevelWindowRangeChangeDialog.h include/QmitkLevelWindowWidgetContextMenu.h include/QmitkLevelWindowWidget.h include/QmitkLineEditLevelWindowWidget.h include/QmitkMemoryUsageIndicatorView.h include/QmitkNodeDescriptor.h include/QmitkColoredNodeDescriptor.h include/QmitkNodeDescriptorManager.h include/QmitkRenderWindowMenu.h include/QmitkProgressBar.h include/QmitkPropertiesTableEditor.h include/QmitkPropertyDelegate.h include/QmitkRenderingManager.h include/QmitkRenderWindow.h include/QmitkServiceListWidget.h include/QmitkSliderLevelWindowWidget.h include/QmitkStdMultiWidget.h include/QmitkMouseModeSwitcher.h include/QmitkDataStorageComboBoxWithSelectNone.h include/QmitkPropertyItemDelegate.h include/QmitkPropertyItemModel.h + include/QmitkDataStorageListInspector.h + include/QmitkAbstractDataStorageInspector.h + include/QmitkDataStorageTreeInspector.h + include/QmitkModelViewSelectionConnector.h ) set(UI_FILES src/QmitkFileReaderOptionsDialog.ui src/QmitkFileWriterOptionsDialog.ui src/QmitkLevelWindowPresetDefinition.ui src/QmitkLevelWindowWidget.ui src/QmitkLevelWindowRangeChange.ui src/QmitkMemoryUsageIndicator.ui src/QmitkServiceListWidgetControls.ui + src/QmitkDataStorageListInspector.ui + src/QmitkDataStorageTreeInspector.ui ) set(QRC_FILES resource/Qmitk.qrc ) diff --git a/Modules/QtWidgets/include/QmitkAbstractDataStorageInspector.h b/Modules/QtWidgets/include/QmitkAbstractDataStorageInspector.h new file mode 100644 index 0000000000..3a6e8ad903 --- /dev/null +++ b/Modules/QtWidgets/include/QmitkAbstractDataStorageInspector.h @@ -0,0 +1,131 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +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 QMITKABSTRACTDATASTORAGEINSPECTOR_H +#define QMITKABSTRACTDATASTORAGEINSPECTOR_H + +#include + +#include + +// mitk core +#include +#include + +// qt +#include + +class QAbstractItemVew; + +/** +* @brief This abstract class is a convinient base class for easy implementation of widgets that +* offer a specific view onto a given DataStorage instance to inspect its contents. +* One may also get the selection in this inspector of the data storage. +*/ +class MITKQTWIDGETS_EXPORT QmitkAbstractDataStorageInspector : public QWidget +{ + Q_OBJECT + +public: + virtual ~QmitkAbstractDataStorageInspector(); + + /** + * @brief Sets the data storage that will be used /monitored by the widget. + * + * @param dataStorage A pointer to the data storage to set. + */ + void SetDataStorage(mitk::DataStorage* dataStorage); + + /** + * @brief Sets the node predicate and updates the widget, according to the node predicate. + * + * @param nodePredicate A pointer to node predicate. + */ + virtual void SetNodePredicate(mitk::NodePredicateBase* nodePredicate); + + mitk::NodePredicateBase* GetNodePredicate() const; + + using NodeList = QList; + + /** Returns the list of currently selected nodes.*/ + NodeList GetSelectedNodes() const; + + /** Returns an pointer to the view that is used in the inspector to show the content.*/ + virtual QAbstractItemView* GetView() = 0; + virtual const QAbstractItemView* GetView() const = 0; + + /** Returns the setting of the internal connector. It can be changed by SetSelectOnlyVisibleNodes()*/ + bool GetSelectOnlyVisibleNodes() const; + + using SelectionMode = QAbstractItemView::SelectionMode; + /** Sets the selection mode of the inspector.*/ + virtual void SetSelectionMode(SelectionMode mode) = 0; + virtual SelectionMode GetSelectionMode() const = 0; + +Q_SIGNALS: + /** + * @brief A signal that will be emitted if the selected node has changed. + * + * @param nodes A list of data nodes that are newly selected. + */ + void CurrentSelectionChanged(NodeList nodes); + + public Q_SLOTS: + /** + * @brief Change the selection modus of the item view's selection model. + * + * If true, an incoming selection will be filtered (reduced) to only those nodes that are visible by the current view. + * An outgoing selection can then at most contain the filtered nodes. + * If false, the incoming non-visible selection will be stored and later added to the outgoing selection, + * to include the original selection that could not be modified. + * The part of the original selection, that is non-visible are the nodes that are not + * + * @param selectOnlyVisibleNodes The bool value to define the selection modus. + */ + void SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes); + + /** + * @brief Transform a list of data nodes into a model selection and set this as a new selection of the + * selection model of the private member item view. + * + * The function filters the given list of nodes according to the 'm_SelectOnlyVisibleNodes' member variable. If + * necessary, the non-visible nodes are stored. This is done if 'm_SelectOnlyVisibleNodes' is false: In this case + * the selection may be filtered and only a subset of the selected nodes may be visible and therefore (de-)selectable + * in the data storage viewer. By storing the non-visible nodes it is possible to send the new, modified selection + * but also include the selected nodes from the original selection that could not be modified (see 'SetSelectOnlyVisibleNodes'). + * + * @param nodes A list of data nodes that should be newly selected. + */ + void SetCurrentSelection(NodeList selectedNodes); + +protected Q_SLOTS: + void OnSelectionChanged(NodeList selectedNodes); + +protected: + /** Helper function is called if data storage or predicate is changed to (re) initialize the widget correctly. + Implement the function in derived classes.*/ + virtual void Initialize() = 0; + + mitk::WeakPointer m_DataStorage; + mitk::NodePredicateBase::Pointer m_NodePredicate; + + std::unique_ptr m_Connector; + + QmitkAbstractDataStorageInspector(QWidget* parent = nullptr); + +}; + +#endif // QMITKABSTRACTDATASTORAGEMODEL_H diff --git a/Modules/QtWidgets/include/QmitkAbstractDataStorageModel.h b/Modules/QtWidgets/include/QmitkAbstractDataStorageModel.h new file mode 100644 index 0000000000..30faaec032 --- /dev/null +++ b/Modules/QtWidgets/include/QmitkAbstractDataStorageModel.h @@ -0,0 +1,92 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +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 QMITKABSTRACTDATASTORAGEMODEL_H +#define QMITKABSTRACTDATASTORAGEMODEL_H + +#include + +// mitk core +#include +#include +#include + +// qt +#include + +/* +* @brief This abstract class extends the 'QAbstractItemModel' to accept an 'mitk::DataStorage' and a 'mitk::NodePredicateBase'. +* It registers itself as a node event listener of the data storage. +* The 'QmitkAbstractDataStorageModel' provides three empty functions, 'NodeAdded', 'NodeChanged' and 'NodeRemoved', that +* may be implemented by subclasses. These functions allow to react to the 'AddNodeEvent', 'ChangedNodeEvent' and +* 'RemoveNodeEvent' of the data storage. This might be useful to force an update on a custom view to correctly +* represent the content of the data storage. +* +* A concrete implementation of this class is used to store the temporarily shown data nodes of the data storage. +* These nodes may be a subset of all the nodes inside the data storage, if a specific node predicate is set. +* +* A model that implements this class has to return mitk::DataNode::Pointer objects for model indexes when the +* role is QmitkDataNodeRole. +*/ +class MITKQTWIDGETS_EXPORT QmitkAbstractDataStorageModel : public QAbstractItemModel +{ + Q_OBJECT + +public: + + virtual ~QmitkAbstractDataStorageModel(); + /* + * @brief Sets the data storage and adds listener for node events. + * + * @param dataStorage A pointer to the data storage to set. + */ + void SetDataStorage(mitk::DataStorage* dataStorage); + + mitk::DataStorage* GetDataStorage() { return m_DataStorage.Lock().GetPointer(); } + /* + * @brief Sets the node predicate and updates the model data, according to the node predicate. + * + * @param nodePredicate A pointer to node predicate. + */ + void SetNodePredicate(mitk::NodePredicateBase* nodePredicate); + + mitk::NodePredicateBase* GetNodePredicate() { return m_NodePredicate; } + +protected: + + virtual void DataStorageChanged() = 0; + virtual void NodePredicateChanged() = 0; + + virtual void NodeAdded(const mitk::DataNode* node) = 0; + virtual void NodeChanged(const mitk::DataNode* node) = 0; + virtual void NodeRemoved(const mitk::DataNode* node) = 0; + + QmitkAbstractDataStorageModel(QObject* parent = nullptr); + QmitkAbstractDataStorageModel(mitk::DataStorage* dataStorage, QObject* parent = nullptr); + + mitk::WeakPointer m_DataStorage; + mitk::NodePredicateBase::Pointer m_NodePredicate; + +private: + + /** Helper triggered on the storage delete event */ + void SetDataStorageDeleted(); + + unsigned long m_DataStorageDeletedTag; + +}; + +#endif // QMITKABSTRACTDATASTORAGEMODEL_H diff --git a/Modules/QtWidgets/include/QmitkDataStorageDefaultListModel.h b/Modules/QtWidgets/include/QmitkDataStorageDefaultListModel.h new file mode 100644 index 0000000000..cbfdf81916 --- /dev/null +++ b/Modules/QtWidgets/include/QmitkDataStorageDefaultListModel.h @@ -0,0 +1,82 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +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 QMITKDATASTORAGEDEFAULTLISTMODEL_H +#define QMITKDATASTORAGEDEFAULTLISTMODEL_H + +#include + +// qt widgets module +#include + +/** +* @brief The 'QmitkDataStorageDefaultListModel' is a basic list model, derived from the 'QmitkAbstractDataStorageModel'. +* It provides functions to accept a data storage and a node predicate in order to customize the model data nodes. +* Furthermore it overrides the functions of 'QAbstractItemModel' to create a simple qt list model. +* This model can be used in conjunction with a 'QmitkDataStorageSelectionConnector'. +*/ +class MITKQTWIDGETS_EXPORT QmitkDataStorageDefaultListModel : public QmitkAbstractDataStorageModel +{ + Q_OBJECT + +public: + + QmitkDataStorageDefaultListModel(QObject *parent); + + // override from 'QmitkAbstractDataStorageModel' + /* + * @brief See 'QmitkAbstractDataStorageModel' + */ + void DataStorageChanged() override; + /* + * @brief See 'QmitkAbstractDataStorageModel' + */ + void NodePredicateChanged() override; + /* + * @brief See 'QmitkAbstractDataStorageModel' + */ + void NodeAdded(const mitk::DataNode* node) override; + /* + * @brief See 'QmitkAbstractDataStorageModel' + */ + void NodeChanged(const mitk::DataNode* node) override; + /* + * @brief See 'QmitkAbstractDataStorageModel' + */ + void NodeRemoved(const mitk::DataNode* node) override; + + // override pure virtual from 'QAbstractItemModel' + QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; + QModelIndex parent(const QModelIndex &child) const override; + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + + // override for customization + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; + Qt::ItemFlags flags(const QModelIndex &index) const override; + +private: + + void UpdateModelData(); + + std::vector m_DataNodes; + +}; + +#endif // QMITKDATASTORAGEDEFAULTLISTMODEL_H diff --git a/Modules/QtWidgets/include/QmitkDataStorageInspectorGenerator.h b/Modules/QtWidgets/include/QmitkDataStorageInspectorGenerator.h new file mode 100644 index 0000000000..d8fc1dd641 --- /dev/null +++ b/Modules/QtWidgets/include/QmitkDataStorageInspectorGenerator.h @@ -0,0 +1,41 @@ +/*=================================================================== + +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 QmitkDataStorageInspectorGenerator_H +#define QmitkDataStorageInspectorGenerator_H + +#include "QmitkIDataStorageInspectorProvider.h" + +#include + +class MITKQTWIDGETS_EXPORT QmitkDataStorageInspectorGenerator +{ +public: + using IDType = std::string; + + using ProviderMapType = std::map; + static ProviderMapType GetProviders(); + + static mitk::IDataStorageInspectorProvider *GetProvider(const IDType &id); + +protected: + QmitkDataStorageInspectorGenerator(); + virtual ~QmitkDataStorageInspectorGenerator(); + QmitkDataStorageInspectorGenerator(const QmitkDataStorageInspectorGenerator &source) = delete; + QmitkDataStorageInspectorGenerator& operator=(const QmitkDataStorageInspectorGenerator &) = delete; +}; + +#endif diff --git a/Modules/QtWidgets/include/QmitkDataStorageInspectorProviderBase.h b/Modules/QtWidgets/include/QmitkDataStorageInspectorProviderBase.h new file mode 100644 index 0000000000..2e964cf019 --- /dev/null +++ b/Modules/QtWidgets/include/QmitkDataStorageInspectorProviderBase.h @@ -0,0 +1,79 @@ +/*=================================================================== + +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 __QMITK_DATA_STORAGE_INSPECTOR_PROVIDER_BASE_H +#define __QMITK_DATA_STORAGE_INSPECTOR_PROVIDER_BASE_H + +#include + +// Microservices +#include +#include +#include + +// MITK +#include + + +/** + * @brief Base class for DataStorage inspector provider. + */ +template +class QmitkDataStorageInspectorProviderBase : public mitk::IDataStorageInspectorProvider +{ +public: + virtual QmitkAbstractDataStorageInspector* CreateInspector() const override; + + virtual std::string GetInspectorID() const override; + virtual std::string GetInspectorDisplayName() const override; + virtual std::string GetInspectorDescription() const override; + + us::ServiceRegistration RegisterService( + us::ModuleContext *context = us::GetModuleContext()); + + void UnregisterService(); + + QmitkDataStorageInspectorProviderBase(const std::string& id); + QmitkDataStorageInspectorProviderBase(const std::string& id, const std::string& displayName, const std::string& desc= "" ); + virtual ~QmitkDataStorageInspectorProviderBase(); + +protected: + QmitkDataStorageInspectorProviderBase(const QmitkDataStorageInspectorProviderBase &other); + QmitkDataStorageInspectorProviderBase &operator=(const QmitkDataStorageInspectorProviderBase &other) = delete; + + virtual us::ServiceProperties GetServiceProperties() const; + + /** + * \brief Set the service ranking for this file reader. + * + * Default is zero and should only be chosen differently for a reason. + * The ranking is used to determine which reader to use if several + * equivalent providers have been found. + * It may be used to replace a default provider from MITK in your own project. + */ + void SetRanking(int ranking); + int GetRanking() const; + +private: + class Impl; + std::unique_ptr d; +}; + +#ifndef ITK_MANUAL_INSTANTIATION +#include "QmitkDataStorageInspectorProviderBase.tpp" +#endif + +#endif /* __MODEL_FIT_PROVIDER_BASE_H */ diff --git a/Modules/QtWidgets/include/QmitkDataStorageInspectorProviderBase.tpp b/Modules/QtWidgets/include/QmitkDataStorageInspectorProviderBase.tpp new file mode 100644 index 0000000000..f7982f867c --- /dev/null +++ b/Modules/QtWidgets/include/QmitkDataStorageInspectorProviderBase.tpp @@ -0,0 +1,149 @@ +/*=================================================================== + +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 +#include + +#include +#include +#include + + template + class QmitkDataStorageInspectorProviderBase::Impl + { + public: + Impl(const std::string& id, const std::string& displayName, const std::string& desc) : m_Ranking(0), m_ID(id), m_DisplayName(displayName), m_Desc(desc) + { + }; + + Impl(const Impl &other) = default; + + void SetRanking(int ranking) + { + m_Ranking = ranking; + }; + + int GetRanking() const + { + return m_Ranking; + }; + + us::ServiceRegistration m_Reg; + int m_Ranking; + std::string m_ID; + std::string m_DisplayName; + std::string m_Desc; + }; + + template + QmitkDataStorageInspectorProviderBase::QmitkDataStorageInspectorProviderBase(const std::string& id) : QmitkDataStorageInspectorProviderBase(id, id) + { + } + + template + QmitkDataStorageInspectorProviderBase::QmitkDataStorageInspectorProviderBase(const std::string& id, const std::string& displayName, const std::string& desc) + { + d.reset(new Impl(id, displayName, desc)); + RegisterService(); + } + + template + QmitkDataStorageInspectorProviderBase::~QmitkDataStorageInspectorProviderBase() + { + UnregisterService(); + } + + template + QmitkDataStorageInspectorProviderBase::QmitkDataStorageInspectorProviderBase(const QmitkDataStorageInspectorProviderBase &other) : IDataStorageInspectorProvider(), d(new Impl(*other.d.get())) + { + } + + template + QmitkAbstractDataStorageInspector* + QmitkDataStorageInspectorProviderBase::CreateInspector() const + { + return new TInspector; + }; + + template + std::string + QmitkDataStorageInspectorProviderBase::GetInspectorID() const + { + return d->m_ID; + }; + + template + std::string + QmitkDataStorageInspectorProviderBase::GetInspectorDisplayName() const + { + return d->m_DisplayName; + }; + + template + std::string + QmitkDataStorageInspectorProviderBase::GetInspectorDescription() const + { + return d->m_Desc; + }; + + template + us::ServiceRegistration + QmitkDataStorageInspectorProviderBase::RegisterService(us::ModuleContext *context) + { + if (d->m_Reg) + return d->m_Reg; + + if (context == nullptr) + { + context = us::GetModuleContext(); + } + + us::ServiceProperties props = this->GetServiceProperties(); + d->m_Reg = context->RegisterService(this, props); + return d->m_Reg; + } + + template + void + QmitkDataStorageInspectorProviderBase::UnregisterService() + { + try + { + d->m_Reg.Unregister(); + } + catch (const std::exception &) + { + } + } + + template + us::ServiceProperties + QmitkDataStorageInspectorProviderBase::GetServiceProperties() const + { + us::ServiceProperties result; + + result[IDataStorageInspectorProvider::PROP_INSPECTOR_ID()] = this->d->m_ID; + result[us::ServiceConstants::SERVICE_RANKING()] = this->GetRanking(); + return result; + } + + template + void + QmitkDataStorageInspectorProviderBase::SetRanking(int ranking) { d->SetRanking(ranking); } + + template + int + QmitkDataStorageInspectorProviderBase::GetRanking() const { return d->GetRanking(); } diff --git a/Modules/QtWidgets/include/QmitkDataStorageListInspector.h b/Modules/QtWidgets/include/QmitkDataStorageListInspector.h new file mode 100644 index 0000000000..393469b6f3 --- /dev/null +++ b/Modules/QtWidgets/include/QmitkDataStorageListInspector.h @@ -0,0 +1,50 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +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 QMITKDATASTORAGELISTVIEWWIDGET_H +#define QMITKDATASTORAGELISTVIEWWIDGET_H + +#include + +#include +#include + +#include "ui_QmitkDataStorageListInspector.h" + +/* +* @brief This is an inspector that offers a simple list view on a data storage. +*/ +class MITKQTWIDGETS_EXPORT QmitkDataStorageListInspector : public QmitkAbstractDataStorageInspector +{ + Q_OBJECT + +public: + QmitkDataStorageListInspector(QWidget* parent = nullptr); + + virtual QAbstractItemView* GetView() override; + virtual const QAbstractItemView* GetView() const override; + + virtual void SetSelectionMode(SelectionMode mode) override; + virtual SelectionMode GetSelectionMode() const override; + +protected: + virtual void Initialize() override; + + QmitkAbstractDataStorageModel* m_StorageModel; + Ui_QmitkDataStorageListInspector m_Controls; +}; + +#endif // QMITKABSTRACTDATASTORAGEMODEL_H diff --git a/Modules/QtWidgets/include/QmitkDataStorageSimpleTreeModel.h b/Modules/QtWidgets/include/QmitkDataStorageSimpleTreeModel.h new file mode 100644 index 0000000000..e2dd6b31f9 --- /dev/null +++ b/Modules/QtWidgets/include/QmitkDataStorageSimpleTreeModel.h @@ -0,0 +1,105 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +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 QMITKDATASTORAGESIMPLETREEMODEL_H +#define QMITKDATASTORAGESIMPLETREEMODEL_H + +#include + +// qt widgets module +#include + +class QmitkDataStorageTreeModelInternalItem; + +/** +* @brief The 'QmitkDataStorageSimpleTreeModel' is a basic tree model, derived from the 'QmitkAbstractDataStorageModel'. +* It provides functions to accept a data storage and a node predicate in order to customize the model data nodes. +* Furthermore it overrides the functions of 'QAbstractItemModel' to create a simple qt list model.* +* This model can be used in conjunction with a 'QmitkDataStorageSelectionConnector'. +* This model is a "light" version of the classic QmitkDataStorgageTreeModel. The differences between both are the following: +* - This class currently does not support DragNDrop. +* - This class does not have the ability to change hirarchy or changes the layer property +*of nodes. This was skipped on purpose, because that is not the job of the storage model. +* - If a tree item A is removed this class does not attach children of A to the parent +*of A. Instead the complete tree representation is updated. This was changed on purpose +*because otherwise the internal representation of the model would not reflect the data storage graph anymore. +*/ +class MITKQTWIDGETS_EXPORT QmitkDataStorageSimpleTreeModel : public QmitkAbstractDataStorageModel +{ + Q_OBJECT + +public: + QmitkDataStorageSimpleTreeModel(QObject *parent); + virtual ~QmitkDataStorageSimpleTreeModel(); + + // override from 'QmitkAbstractDataStorageModel' + /* + * @brief See 'QmitkAbstractDataStorageModel' + */ + void DataStorageChanged() override; + /* + * @brief See 'QmitkAbstractDataStorageModel' + */ + void NodePredicateChanged() override; + /* + * @brief See 'QmitkAbstractDataStorageModel' + */ + void NodeAdded(const mitk::DataNode *node) override; + /* + * @brief See 'QmitkAbstractDataStorageModel' + */ + void NodeChanged(const mitk::DataNode *node) override; + /* + * @brief See 'QmitkAbstractDataStorageModel' + */ + void NodeRemoved(const mitk::DataNode *node) override; + + // override pure virtual from 'QAbstractItemModel' + QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; + QModelIndex parent(const QModelIndex &child) const override; + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + + bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; + + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; + Qt::ItemFlags flags(const QModelIndex &index) const override; + +protected: + using TreeItem = QmitkDataStorageTreeModelInternalItem; + +private: + void UpdateModelData(); + void AddNodeInternal(const mitk::DataNode *node); + + mitk::DataNode *GetParentNode(const mitk::DataNode *node) const; + + TreeItem *TreeItemFromIndex(const QModelIndex &index) const; + QModelIndex IndexFromTreeItem(TreeItem *item) const; + + void ResetTree(); + + TreeItem *m_Root; + + /**helper structure to check, if a tree item is realy part of the model. + Prefered over iterating over the tree by hand because we can use std::find.*/ + std::list m_TreeItems; +}; + +#endif // QmitkDataStorageSimpleTreeModel_H diff --git a/Modules/QtWidgets/include/QmitkDataStorageTreeInspector.h b/Modules/QtWidgets/include/QmitkDataStorageTreeInspector.h new file mode 100644 index 0000000000..90e90de04b --- /dev/null +++ b/Modules/QtWidgets/include/QmitkDataStorageTreeInspector.h @@ -0,0 +1,52 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +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 QMITKDATASTORAGETREEINSPECTOR_H +#define QMITKDATASTORAGETREEINSPECTOR_H + +#include + +#include +#include + +#include "ui_QmitkDataStorageTreeInspector.h" + +/* +* @brief This is an inspector that offers a simple tree view on a data storage. +* Something like the "data manager plugin", but in simple/light (with less functionality) +* It uses the QmitkDataStorageSimpleTreeModel. +*/ +class MITKQTWIDGETS_EXPORT QmitkDataStorageTreeInspector : public QmitkAbstractDataStorageInspector +{ + Q_OBJECT + +public: + QmitkDataStorageTreeInspector(QWidget* parent = nullptr); + + virtual QAbstractItemView* GetView() override; + virtual const QAbstractItemView* GetView() const override; + + virtual void SetSelectionMode(SelectionMode mode) override; + virtual SelectionMode GetSelectionMode() const override; + +protected: + virtual void Initialize() override; + + QmitkAbstractDataStorageModel* m_StorageModel; + Ui_QmitkDataStorageTreeInspector m_Controls; +}; + +#endif // QMITKABSTRACTDATASTORAGEMODEL_H diff --git a/Modules/QtWidgets/include/QmitkDataStorageTreeModel.h b/Modules/QtWidgets/include/QmitkDataStorageTreeModel.h index 1449714dd2..03ee7de417 100644 --- a/Modules/QtWidgets/include/QmitkDataStorageTreeModel.h +++ b/Modules/QtWidgets/include/QmitkDataStorageTreeModel.h @@ -1,277 +1,213 @@ /*=================================================================== 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 QMITKDATASTORAGETREEMODEL_H_ #define QMITKDATASTORAGETREEMODEL_H_ #include #include #include #include #include #include "QmitkCustomVariants.h" #include "QmitkEnums.h" #include #include #include -/// \ingroup QmitkModule +class QmitkDataStorageTreeModelInternalItem; + +/** \ingroup QmitkModule + @warning This class causes invalid point exception when used with invalid QModelIndex instances. + The index validation is not sufficient. This may cause unspecific crashes in situation where + this class is used multiple times or with multiple selection models. See https://phabricator.mitk.org/T24348 + for more information. +*/ class MITKQTWIDGETS_EXPORT QmitkDataStorageTreeModel : public QAbstractItemModel { Q_OBJECT //# CONSTANTS,TYPEDEFS public: static const std::string COLUMN_NAME; static const std::string COLUMN_TYPE; static const std::string COLUMN_VISIBILITY; //# CTORS,DTOR public: QmitkDataStorageTreeModel(mitk::DataStorage *_DataStorage, bool _PlaceNewNodesOnTop = false, QObject *parent = nullptr); ~QmitkDataStorageTreeModel() override; //# GETTER public: /// /// Get node at a specific model index. /// This function is used to get a node from a QModelIndex /// mitk::DataNode::Pointer GetNode(const QModelIndex &index) const; /// /// Returns a copy of the node-vector that is shown by this model /// virtual QList GetNodeSet() const; /// /// Get the DataStorage. /// const mitk::DataStorage::Pointer GetDataStorage() const; /// /// Get the top placement flag /// bool GetPlaceNewNodesOnTopFlag() { return m_PlaceNewNodesOnTop; } /// /// Set the top placement flag /// void SetPlaceNewNodesOnTop(bool _PlaceNewNodesOnTop); //# (Re-)implemented from QAbstractItemModel //# Read model Qt::ItemFlags flags(const QModelIndex &index) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; int rowCount(const QModelIndex &parent = QModelIndex()) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override; //# hierarchical model /// /// called whenever the model or the view needs to create a QModelIndex for a particular /// child item (or a top-level item if parent is an invalid QModelIndex) /// QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; QModelIndex parent(const QModelIndex &index) const override; //# editable model bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role = Qt::EditRole) override; bool dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override; Qt::DropActions supportedDropActions() const override; Qt::DropActions supportedDragActions() const override; QStringList mimeTypes() const override; QMimeData *mimeData(const QModelIndexList &indexes) const override; static QMimeData *mimeDataFromModelIndexList(const QModelIndexList &indexes); //# End of QAbstractItemModel //# SETTER public: /// /// Sets the DataStorage. The whole model will be resetted. /// void SetDataStorage(mitk::DataStorage *_DataStorage); /// /// Notify that the DataStorage was deleted. The whole model will be resetted. /// void SetDataStorageDeleted(); /// /// Adds a node to this model. /// If a predicate is set (not null) the node will be checked against it.The node has to have a data object (no one /// wants to see empty nodes). /// virtual void AddNode(const mitk::DataNode *node); /// /// Removes a node from this model. Also removes any event listener from the node. /// virtual void RemoveNode(const mitk::DataNode *node); /// /// Sets a node to modfified. Called by the DataStorage /// virtual void SetNodeModified(const mitk::DataNode *node); /// /// \return an index for the given datatreenode in the tree. If the node is not found /// QModelIndex GetIndex(const mitk::DataNode *) const; /// Set whether to allow hierarchy changes by dragging and dropping void SetAllowHierarchyChange(bool allowHierarchyChange); signals: void nodeVisibilityChanged(); //# MISC protected: - /// - /// Helper class to represent a tree structure of DataNodes - /// - class TreeItem - { - public: - /// - /// Constructs a new TreeItem with the given DataNode (must not be 0) - /// - TreeItem(mitk::DataNode *_DataNode, TreeItem *_Parent = nullptr); - /// - /// Removes itself as child from its parent-> Does not delete its children - /// \sa Delete() - /// - virtual ~TreeItem(); - /// - /// Find the index of an item - /// - int IndexOfChild(const TreeItem *item) const; - /// - /// \return The child at pos index or 0 if it not exists - /// - TreeItem *GetChild(int index) const; - /// - /// Find the TreeItem containing a special tree node (recursive tree function) - /// - TreeItem *Find(const mitk::DataNode *_DataNode) const; - /// - /// Get the amount of children - /// - int GetChildCount() const; - /// - /// \return the index of this node in its parent list - /// - int GetIndex() const; - /// - /// \return the parent of this tree item - /// - TreeItem *GetParent() const; - /// - /// Return the DataNode associated with this node - /// - mitk::DataNode::Pointer GetDataNode() const; - /// - /// Get all children as vector - /// - std::vector GetChildren() const; - - /// - /// add another item as a child of this (only if not already in that list) - /// - void AddChild(TreeItem *item); - /// - /// remove another item as child from this - /// - void RemoveChild(TreeItem *item); - /// - /// inserts a child at the given position. if pos is not in range - /// the element is added at the end - /// - void InsertChild(TreeItem *item, int index = -1); - /// Sets the parent on the treeitem - void SetParent(TreeItem *_Parent); - /// - /// Deletes the whole tree branch - /// - void Delete(); - - protected: - TreeItem *m_Parent; - std::vector m_Children; - mitk::DataNode::Pointer m_DataNode; - }; + + using TreeItem = QmitkDataStorageTreeModelInternalItem; QList ToTreeItemPtrList(const QMimeData *mimeData); QList ToTreeItemPtrList(const QByteArray &ba); /// /// Adjusts the LayerProperty according to the nodes position /// void AdjustLayerProperty(); /// /// invoked after m_DataStorage or m_Predicate changed /// TreeItem *TreeItemFromIndex(const QModelIndex &index) const; /// /// Gives a ModelIndex for the Tree Item /// QModelIndex IndexFromTreeItem(TreeItem *) const; /// /// Returns the first element in the nodes sources list (if available) or 0 /// mitk::DataNode *GetParentNode(const mitk::DataNode *node) const; /// /// Adds all Childs in parent to vec. Before a child is added the function is called recursively /// void TreeToVector(TreeItem *parent, std::vector &vec) const; /// /// Adds all Childs in parent to vec. Before a child is added the function is called recursively /// void TreeToNodeSet(TreeItem *parent, QList &vec) const; /// /// Update Tree Model /// void Update(); //# ATTRIBUTES protected: mitk::WeakPointer m_DataStorage; mitk::NodePredicateBase::Pointer m_Predicate; bool m_PlaceNewNodesOnTop; TreeItem *m_Root; /// Flag to block the data storage events if nodes are added/removed by this class. bool m_BlockDataStorageEvents; /// This decides whether or not it is allowed to assign a different parent to a node /// If it is false, it is not possible to change the hierarchy of nodes by dragging /// and dropping. /// If it is true, dragging nodes on another node will replace all of their parents /// with that one. bool m_AllowHierarchyChange; private: void AddNodeInternal(const mitk::DataNode *); void RemoveNodeInternal(const mitk::DataNode *); /// /// Checks if dicom properties patient name, study names and series name exists /// bool DicomPropertiesExists(const mitk::DataNode &) const; unsigned long m_DataStorageDeletedTag; }; #endif /* QMITKDATASTORAGETREEMODEL_H_ */ diff --git a/Modules/QtWidgets/include/QmitkDataStorageTreeModelInternalItem.h b/Modules/QtWidgets/include/QmitkDataStorageTreeModelInternalItem.h new file mode 100644 index 0000000000..e61d5c8819 --- /dev/null +++ b/Modules/QtWidgets/include/QmitkDataStorageTreeModelInternalItem.h @@ -0,0 +1,101 @@ +/*=================================================================== + +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 QMITKDATASTORAGETREEMODELINTERNALITEM_H_ +#define QMITKDATASTORAGETREEMODELINTERNALITEM_H_ + +#include + +#include + +#include +#include + + /// + /// Helper class to represent a tree structure of DataNodes + /// + class MITKQTWIDGETS_EXPORT QmitkDataStorageTreeModelInternalItem + { + public: + /// + /// Constructs a new QmitkDataStorageTreeModelInternalItem with the given DataNode (must not be 0) + /// + QmitkDataStorageTreeModelInternalItem(mitk::DataNode *_DataNode, QmitkDataStorageTreeModelInternalItem *_Parent = 0); + /// + /// Removes itself as child from its parent-> Does not delete its children + /// \sa Delete() + /// + virtual ~QmitkDataStorageTreeModelInternalItem(); + /// + /// Find the index of an item + /// + int IndexOfChild(const QmitkDataStorageTreeModelInternalItem *item) const; + /// + /// \return The child at pos index or 0 if it not exists + /// + QmitkDataStorageTreeModelInternalItem *GetChild(int index) const; + /// + /// Find the QmitkDataStorageTreeModelInternalItem containing a special tree node (recursive tree function) + /// + QmitkDataStorageTreeModelInternalItem *Find(const mitk::DataNode *_DataNode) const; + /// + /// Get the amount of children + /// + int GetChildCount() const; + /// + /// \return the index of this node in its parent list + /// + int GetIndex() const; + /// + /// \return the parent of this tree item + /// + QmitkDataStorageTreeModelInternalItem *GetParent() const; + /// + /// Return the DataNode associated with this node + /// + mitk::DataNode* GetDataNode() const; + /// + /// Get all children as vector + /// + std::vector GetChildren() const; + + /// + /// add another item as a child of this (only if not already in that list) + /// + void AddChild(QmitkDataStorageTreeModelInternalItem *item); + /// + /// remove another item as child from this + /// + void RemoveChild(QmitkDataStorageTreeModelInternalItem *item); + /// + /// inserts a child at the given position. if pos is not in range + /// the element is added at the end + /// + void InsertChild(QmitkDataStorageTreeModelInternalItem *item, int index = -1); + /// Sets the parent on the QmitkDataStorageTreeModelInternalItem + void SetParent(QmitkDataStorageTreeModelInternalItem *_Parent); + /// + /// Deletes the whole tree branch + /// + void Delete(); + + protected: + QmitkDataStorageTreeModelInternalItem *m_Parent; + std::vector m_Children; + mitk::DataNode::Pointer m_DataNode; + }; + +#endif /* QMITKDATASTORAGETREEMODEL_H_ */ diff --git a/Modules/QtWidgets/include/QmitkIDataStorageInspectorProvider.h b/Modules/QtWidgets/include/QmitkIDataStorageInspectorProvider.h new file mode 100644 index 0000000000..d5cfb53ede --- /dev/null +++ b/Modules/QtWidgets/include/QmitkIDataStorageInspectorProvider.h @@ -0,0 +1,71 @@ +/*=================================================================== + +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 __I_ABSTRACT_DATA_STORAGE_PROVIDER_H +#define __I_ABSTRACT_DATA_STORAGE_PROVIDER_H + +#include + +#include + +class QmitkAbstractDataStorageInspector; + +namespace mitk +{ + /** + * \ingroup MicroServices_Interfaces + * + * \brief The common interface for all DataStorage inspector providers. + * + * Implementations of this interface must be registered as a service + * to make themselves available via the service registry. + * + * It is recommended to derive new implementations from QmitkDataStorageInspectorProviderBase + * which provide correct service registration semantics. + * + * \sa QmitkDataStorageInspectorProviderBase + */ + struct MITKQTWIDGETS_EXPORT IDataStorageInspectorProvider + { + virtual ~IDataStorageInspectorProvider(); + + /** + * \brief returns an inspector instance represented by the provider. + */ + virtual QmitkAbstractDataStorageInspector* CreateInspector() const = 0; + + /** Return the uniqe ID for the inspector type provided.*/ + virtual std::string GetInspectorID() const = 0; + /** Return the display name (e.g. used in the UI) for the inspector type provided.*/ + virtual std::string GetInspectorDisplayName() const = 0; + /** Returns a description of the inspector type provided.*/ + virtual std::string GetInspectorDescription() const = 0; + + /** + * @brief Service property name for the inspector ID. + * + * The property value must be of type \c std::string. + * + * @return The property name. + */ + static std::string PROP_INSPECTOR_ID(); + }; + +} // namespace mitk + +MITK_DECLARE_SERVICE_INTERFACE(mitk::IDataStorageInspectorProvider, "org.mitk.IDataStorageInspectorProvider") + +#endif /* __I_MODEL_FIT_PROVIDER_H */ diff --git a/Modules/QtWidgets/include/QmitkModelViewSelectionConnector.h b/Modules/QtWidgets/include/QmitkModelViewSelectionConnector.h new file mode 100644 index 0000000000..5b2d361a58 --- /dev/null +++ b/Modules/QtWidgets/include/QmitkModelViewSelectionConnector.h @@ -0,0 +1,155 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +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 QMITKMODELVIEWSELECTIONCONNECTOR_H +#define QMITKMODELVIEWSELECTIONCONNECTOR_H + +#include + +// qt widgets module +#include + + // qt +#include + +/** +* @brief The 'QmitkModelViewSelectionConnector' is used to handle the selections of a model-view-pair. +* +* The class accepts a view and a model, which are used to react to selection changes. This class is able to propagate selection changes +* to and receive from its surrounding class. +* +* The model-view-pair can be added as a selection listener to a selection service. This should be done by using 'AddPostSelectionListener' +* with the existing selection service of the surrounding 'QmitkAbstractView'. +* The model-view-pair can be set as a selection provider. This should be done by using 'SetAsSelectionProvider' with the existing +* selection provider of the surrounding 'QmitkAbstractView'. +* +* The 'QmitkModelViewSelectionConnector' offers a public slot and signal that can be used to set / propagate the selected +* nodes in the current view: +* The 'SetCurrentSelection'-slot finds the indices of the given selected nodes in its internal data storage model and +* changes the selection of the internal data storage model accordingly. +* The 'CurrentSelectionChanged'-signal sends a list of selected nodes to its environment. +* The 'CurrentSelectionChanged'-signal is emitted by the 'ChangeModelSelection'-function, which transforms the internal item view's +* selection into a data node list. The 'ChangeModelSelection'-function is called whenever the selection of the item view's +* selection model changes. +*/ +class MITKQTWIDGETS_EXPORT QmitkModelViewSelectionConnector : public QObject +{ + Q_OBJECT + +public: + + QmitkModelViewSelectionConnector(); + /** + * @brief Set the view whose selection model is used to propagate or receive selection changes. Use the view's data model + * to transform selected nodes into model indexes and vice versa. + * + * @pre The view's data model needs to be a 'QmitkAbstractDataStorageModel'. If so, the data model is received from + * the view and stored as a private member. + * The data model must return 'mitk::DataNode::Pointer' objects for model indexes if the role is 'QmitkDataNodeRole'. + * @throw mitk::Exception, if the view is invalid or the view's data model is not a valid 'QmitkAbstractDataStorageModel'. + * + * @param view The view to set. + */ + void SetView(QAbstractItemView* view); + + /** + * @brief Retrieve the currently selected nodes (equals the last CurrentSelectionChanged values). + */ + QList GetSelectedNodes() const; + + bool GetSelectOnlyVisibleNodes() const; + +Q_SIGNALS: + /** + * @brief A signal that will be emitted by the 'ChangeModelSelection'-function. This happens if the selection model + * of the private member item view has changed. + * + * @param nodes A list of data nodes that are newly selected. + */ + void CurrentSelectionChanged(QList nodes); + +public Q_SLOTS: + /** + * @brief Change the selection mode of the item view's selection model. + * + * If true, an incoming selection will be filtered (reduced) to only those nodes that are visible to the current view. + * An outgoing selection can then at most contain the filtered nodes. + * If false, the incoming non-visible selection will be stored and later added to the outgoing selection, + * to include the part of the original selection that was not visible. + * The part of the original selection, that is non-visible are the nodes that do not met the predicate of the + * associated QmitkAbstractDataStorageModel. + * + * @param selectOnlyVisibleNodes The bool value to define the selection modus. + */ + void SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes); + + /** + * @brief Transform a list of data nodes into a model selection and set this as a new selection of the + * selection model of the private member item view. + * + * The function filters the given list of nodes according to the 'm_SelectOnlyVisibleNodes' member variable. If + * necessary, the non-visible nodes are stored. This is done if 'm_SelectOnlyVisibleNodes' is false: In this case + * the selection may be filtered and only a subset of the selected nodes may be visible and therefore (de-)selectable + * in the data storage viewer. By storing the non-visible nodes it is possible to send the new, modified selection + * but also include the selected nodes from the original selection that could not be modified (see 'SetSelectOnlyVisibleNodes'). + * + * @param nodes A list of data nodes that should be newly selected. + */ + void SetCurrentSelection(QList selectedNodes); + +private Q_SLOTS: + /** + * @brief Transform a model selection into a data node list and emit the 'CurrentSelectionChanged'-signal. + * + * The function adds the selected nodes from the original selection that could not be modified, if + * 'm_SelectOnlyVisibleNodes' is false. + * This slot is internally connected to the 'selectionChanged'-signal of the selection model of the private member item view. + * + * @param selected The newly selected items. + * @param deselected The newly deselected items. + */ + void ChangeModelSelection(const QItemSelection& selected, const QItemSelection& deselected); + +private: + + QmitkAbstractDataStorageModel* m_Model; + QAbstractItemView* m_View; + + bool m_SelectOnlyVisibleNodes; + QList m_NonVisibleSelection; + + /* + * @brief Retrieve the currently selected nodes from the selection model of the private member item view by + * transforming the selection indexes into a data node list. + * + * In order to transform the indices into data nodes, the private data storage model must return + * 'mitk::DataNode::Pointer' objects for model indexes if the role is QmitkDataNodeRole. + */ + QList GetInternalSelectedNodes() const; + /* + * @brief Filter the list of given nodes such that only those nodes are used that are valid + * when using the data storage model's node predicate. + * If no node predicate was set or the data storage model is invalid, the input list + * of given nodes is returned. + */ + QList FilterNodeList(const QList& nodes) const; +}; + +/* +* @brief Return true, if the nodes in the list of two given selections are equal (Sorting is ignored. Any permutation is valid.)*/ +bool MITKQTWIDGETS_EXPORT EqualNodeSelections(const QList& selection1, const QList& selection2); + +#endif // QMITKMODELVIEWSELECTIONCONNECTOR_H diff --git a/Modules/QtWidgets/src/QmitkAbstractDataStorageInspector.cpp b/Modules/QtWidgets/src/QmitkAbstractDataStorageInspector.cpp new file mode 100644 index 0000000000..d42d6846f8 --- /dev/null +++ b/Modules/QtWidgets/src/QmitkAbstractDataStorageInspector.cpp @@ -0,0 +1,83 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +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 + +QmitkAbstractDataStorageInspector::QmitkAbstractDataStorageInspector(QWidget* parent/* = nullptr*/) + : QWidget(parent) + , m_NodePredicate(nullptr) +{ + m_Connector = std::make_unique(); + + connect(m_Connector.get(), &QmitkModelViewSelectionConnector::CurrentSelectionChanged, this, &QmitkAbstractDataStorageInspector::OnSelectionChanged); +} + +QmitkAbstractDataStorageInspector::~QmitkAbstractDataStorageInspector() +{ +} + +void QmitkAbstractDataStorageInspector::SetDataStorage(mitk::DataStorage* dataStorage) +{ + if (m_DataStorage != dataStorage) + { + m_DataStorage = dataStorage; + + if (!m_DataStorage.IsExpired()) + { + this->Initialize(); + } + } +} + +void QmitkAbstractDataStorageInspector::SetNodePredicate(mitk::NodePredicateBase* nodePredicate) +{ + if (m_NodePredicate != nodePredicate) + { + m_NodePredicate = nodePredicate; + + this->Initialize(); + } +} + +mitk::NodePredicateBase* QmitkAbstractDataStorageInspector::GetNodePredicate() const +{ + return m_NodePredicate; +} + +QmitkAbstractDataStorageInspector::NodeList QmitkAbstractDataStorageInspector::GetSelectedNodes() const +{ + return m_Connector->GetSelectedNodes(); +}; + +bool QmitkAbstractDataStorageInspector::GetSelectOnlyVisibleNodes() const +{ + return m_Connector->GetSelectOnlyVisibleNodes(); +}; + +void QmitkAbstractDataStorageInspector::SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes) +{ + m_Connector->SetSelectOnlyVisibleNodes(selectOnlyVisibleNodes); +}; + +void QmitkAbstractDataStorageInspector::SetCurrentSelection(NodeList selectedNodes) +{ + m_Connector->SetCurrentSelection(selectedNodes); +}; + +void QmitkAbstractDataStorageInspector::OnSelectionChanged(NodeList selectedNodes) +{ + emit CurrentSelectionChanged(selectedNodes); +}; diff --git a/Modules/QtWidgets/src/QmitkAbstractDataStorageModel.cpp b/Modules/QtWidgets/src/QmitkAbstractDataStorageModel.cpp new file mode 100644 index 0000000000..9afb4d48f6 --- /dev/null +++ b/Modules/QtWidgets/src/QmitkAbstractDataStorageModel.cpp @@ -0,0 +1,115 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +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 + +QmitkAbstractDataStorageModel::QmitkAbstractDataStorageModel(QObject* parent/* = nullptr*/) + : QAbstractItemModel(parent) + , m_DataStorage(nullptr) + , m_NodePredicate(nullptr) +{ + // nothing here +} + +QmitkAbstractDataStorageModel::QmitkAbstractDataStorageModel(mitk::DataStorage* dataStorage, QObject* parent/* = nullptr*/) + : QAbstractItemModel(parent) + , m_DataStorage(nullptr) + , m_NodePredicate(nullptr) +{ + SetDataStorage(dataStorage); +} + +QmitkAbstractDataStorageModel::~QmitkAbstractDataStorageModel() +{ + if (!m_DataStorage.IsExpired()) + { + auto dataStorage = m_DataStorage.Lock(); + + // remove Listener for the data storage itself + dataStorage->RemoveObserver(m_DataStorageDeletedTag); + + // remove listener from data storage + dataStorage->AddNodeEvent.RemoveListener( + mitk::MessageDelegate1(this, &QmitkAbstractDataStorageModel::NodeAdded)); + dataStorage->RemoveNodeEvent.RemoveListener( + mitk::MessageDelegate1(this, &QmitkAbstractDataStorageModel::NodeRemoved)); + dataStorage->ChangedNodeEvent.RemoveListener( + mitk::MessageDelegate1(this, &QmitkAbstractDataStorageModel::NodeChanged)); + } +} + +void QmitkAbstractDataStorageModel::SetDataStorage(mitk::DataStorage* dataStorage) +{ + if (m_DataStorage == dataStorage) + { + return; + } + + if (!m_DataStorage.IsExpired()) + { + auto dataStorage = m_DataStorage.Lock(); + + // remove Listener for the data storage itself + dataStorage->RemoveObserver(m_DataStorageDeletedTag); + + // remove listener from old data storage + dataStorage->AddNodeEvent.RemoveListener( + mitk::MessageDelegate1(this, &QmitkAbstractDataStorageModel::NodeAdded)); + dataStorage->RemoveNodeEvent.RemoveListener( + mitk::MessageDelegate1(this, &QmitkAbstractDataStorageModel::NodeRemoved)); + dataStorage->ChangedNodeEvent.RemoveListener( + mitk::MessageDelegate1(this, &QmitkAbstractDataStorageModel::NodeChanged)); + } + + m_DataStorage = dataStorage; + + if (!m_DataStorage.IsExpired()) + { + auto dataStorage = m_DataStorage.Lock(); + + // add Listener for the data storage itself + auto command = itk::SimpleMemberCommand::New(); + command->SetCallbackFunction(this, &QmitkAbstractDataStorageModel::SetDataStorageDeleted); + m_DataStorageDeletedTag = dataStorage->AddObserver(itk::DeleteEvent(), command); + + // add listener for new data storage + dataStorage->AddNodeEvent.AddListener( + mitk::MessageDelegate1(this, &QmitkAbstractDataStorageModel::NodeAdded)); + dataStorage->RemoveNodeEvent.AddListener( + mitk::MessageDelegate1(this, &QmitkAbstractDataStorageModel::NodeRemoved)); + dataStorage->ChangedNodeEvent.AddListener( + mitk::MessageDelegate1(this, &QmitkAbstractDataStorageModel::NodeChanged)); + } + // update model if the data storage has been changed + DataStorageChanged(); +} + +void QmitkAbstractDataStorageModel::SetDataStorageDeleted() +{ + this->SetDataStorage(nullptr); +} + +void QmitkAbstractDataStorageModel::SetNodePredicate(mitk::NodePredicateBase* nodePredicate) +{ + if (m_NodePredicate == nodePredicate) + { + return; + } + + m_NodePredicate = nodePredicate; + // update model if the node predicate has been changed + NodePredicateChanged(); +} diff --git a/Modules/QtWidgets/src/QmitkDataStorageDefaultListModel.cpp b/Modules/QtWidgets/src/QmitkDataStorageDefaultListModel.cpp new file mode 100644 index 0000000000..6f3a9db5ad --- /dev/null +++ b/Modules/QtWidgets/src/QmitkDataStorageDefaultListModel.cpp @@ -0,0 +1,172 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +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 + +// qt widgets module +#include "QmitkCustomVariants.h" +#include "QmitkEnums.h" +#include "QmitkNodeDescriptorManager.h" + +QmitkDataStorageDefaultListModel::QmitkDataStorageDefaultListModel(QObject *parent) : QmitkAbstractDataStorageModel(parent) +{ +} + +void QmitkDataStorageDefaultListModel::DataStorageChanged() +{ + UpdateModelData(); +} + +void QmitkDataStorageDefaultListModel::NodePredicateChanged() +{ + UpdateModelData(); +} + +void QmitkDataStorageDefaultListModel::NodeAdded(const mitk::DataNode* /*node*/) +{ + UpdateModelData(); +} + +void QmitkDataStorageDefaultListModel::NodeChanged(const mitk::DataNode* /*node*/) +{ + // nothing here, since the "'NodeChanged'-event is currently sent far too often + //UpdateModelData(); +} + +void QmitkDataStorageDefaultListModel::NodeRemoved(const mitk::DataNode* /*node*/) +{ + UpdateModelData(); +} + +QModelIndex QmitkDataStorageDefaultListModel::index(int row, int column, const QModelIndex &parent) const +{ + bool hasIndex = this->hasIndex(row, column, parent); + if (hasIndex) + { + return this->createIndex(row, column); + } + + return QModelIndex(); +} + +QModelIndex QmitkDataStorageDefaultListModel::parent(const QModelIndex &/*child*/) const +{ + return QModelIndex(); +} + +int QmitkDataStorageDefaultListModel::rowCount(const QModelIndex &parent) const +{ + if (parent.isValid()) + { + return 0; + } + + return m_DataNodes.size(); +} + +int QmitkDataStorageDefaultListModel::columnCount(const QModelIndex &parent) const +{ + if (parent.isValid()) + { + return 0; + } + + return 1; +} + +QVariant QmitkDataStorageDefaultListModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid() || index.model() != this) + { + return QVariant(); + } + + if(index.row() < 0 || index.row() >= static_cast(m_DataNodes.size())) + { + return QVariant(); + } + + mitk::DataNode::Pointer dataNode = m_DataNodes.at(index.row()); + QString nodeName = QString::fromStdString(dataNode->GetName()); + if (nodeName.isEmpty()) + nodeName = "unnamed"; + + if (role == Qt::DisplayRole) + return nodeName; + else if (role == Qt::ToolTipRole) + return nodeName; + else if (role == Qt::DecorationRole) + { + QmitkNodeDescriptor *nodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor(dataNode); + return nodeDescriptor->GetIcon(dataNode); + } + else if (role == QmitkDataNodeRole) + { + return QVariant::fromValue(mitk::DataNode::Pointer(dataNode)); + } + else if (role == QmitkDataNodeRawPointerRole) + { + return QVariant::fromValue(dataNode); + } + + return QVariant(); +} + +QVariant QmitkDataStorageDefaultListModel::headerData(int /*section*/, Qt::Orientation /*orientation*/, int /*role*/) const +{ + return QVariant(tr("Nodes")); +} + +Qt::ItemFlags QmitkDataStorageDefaultListModel::flags(const QModelIndex &index) const +{ + if (index.isValid() && index.model() == this) + { + return Qt::ItemIsEnabled | Qt::ItemIsSelectable; + } + + return Qt::NoItemFlags; +} + +void QmitkDataStorageDefaultListModel::UpdateModelData() +{ + mitk::DataStorage::SetOfObjects::ConstPointer dataNodes; + if (!m_DataStorage.IsExpired()) + { + auto dataStorage = m_DataStorage.Lock(); + if (m_NodePredicate.IsNotNull()) + { + dataNodes = dataStorage->GetSubset(m_NodePredicate); + } + else + { + dataNodes = dataStorage->GetAll(); + } + } + + // update the model, so that it will be filled with the nodes of the new data storage + beginResetModel(); + m_DataNodes.clear(); + + // add all (filtered) nodes to the vector of nodes + if (dataNodes != nullptr) + { + for (auto& node : *dataNodes) + { + m_DataNodes.push_back(node); + } + } + endResetModel(); +} diff --git a/Modules/QtWidgets/src/QmitkDataStorageInspectorGenerator.cpp b/Modules/QtWidgets/src/QmitkDataStorageInspectorGenerator.cpp new file mode 100644 index 0000000000..188c4d1029 --- /dev/null +++ b/Modules/QtWidgets/src/QmitkDataStorageInspectorGenerator.cpp @@ -0,0 +1,61 @@ +/*=================================================================== + +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 "usModuleContext.h" +#include "usGetModuleContext.h" + +#include "mitkLogMacros.h" +#include "QmitkDataStorageInspectorGenerator.h" + +mitk::IDataStorageInspectorProvider* QmitkDataStorageInspectorGenerator::GetProvider(const IDType& id) +{ + mitk::IDataStorageInspectorProvider* result = nullptr; + + std::string filter = "(" + mitk::IDataStorageInspectorProvider::PROP_INSPECTOR_ID() + "=" + id + ")"; + std::vector > providerRegisters = us::GetModuleContext()->GetServiceReferences(filter); + + if (!providerRegisters.empty()) + { + if (providerRegisters.size() > 1) + { + MITK_WARN << "Multiple provider for class id'" << id << "' found. Using just one."; + } + result = us::GetModuleContext()->GetService(providerRegisters.front()); + } + + return result; +}; + +QmitkDataStorageInspectorGenerator::ProviderMapType QmitkDataStorageInspectorGenerator::GetProviders() +{ + std::vector > providerRegisters = us::GetModuleContext()->GetServiceReferences(); + + ProviderMapType result; + + for (auto regs : providerRegisters) + { + auto provider = us::GetModuleContext()->GetService(regs); + result.insert(std::make_pair(provider->GetInspectorID(), provider)); + } + + return result; +}; + +QmitkDataStorageInspectorGenerator::QmitkDataStorageInspectorGenerator() += default; + +QmitkDataStorageInspectorGenerator::~QmitkDataStorageInspectorGenerator() += default; \ No newline at end of file diff --git a/Modules/QtWidgets/src/QmitkDataStorageListInspector.cpp b/Modules/QtWidgets/src/QmitkDataStorageListInspector.cpp new file mode 100644 index 0000000000..a5d3182d1f --- /dev/null +++ b/Modules/QtWidgets/src/QmitkDataStorageListInspector.cpp @@ -0,0 +1,61 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +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 + +#include + +QmitkDataStorageListInspector::QmitkDataStorageListInspector(QWidget* parent/* = nullptr*/) + : QmitkAbstractDataStorageInspector(parent) +{ + m_Controls.setupUi(this); + + m_Controls.view->setSelectionMode(QAbstractItemView::ExtendedSelection); + m_Controls.view->setSelectionBehavior(QAbstractItemView::SelectRows); + m_Controls.view->setAlternatingRowColors(true); + + m_StorageModel = new QmitkDataStorageDefaultListModel(this); + + m_Controls.view->setModel(m_StorageModel); +} + +QAbstractItemView* QmitkDataStorageListInspector::GetView() +{ + return m_Controls.view; +}; + +const QAbstractItemView* QmitkDataStorageListInspector::GetView() const +{ + return m_Controls.view; +}; + +void QmitkDataStorageListInspector::Initialize() +{ + m_StorageModel->SetDataStorage(m_DataStorage.Lock()); + m_StorageModel->SetNodePredicate(m_NodePredicate); + + m_Connector->SetView(m_Controls.view); +} + +void QmitkDataStorageListInspector::SetSelectionMode(SelectionMode mode) +{ + m_Controls.view->setSelectionMode(mode); +} + +QmitkDataStorageListInspector::SelectionMode QmitkDataStorageListInspector::GetSelectionMode() const +{ + return m_Controls.view->selectionMode(); +}; diff --git a/Modules/QtWidgets/src/QmitkDataStorageListInspector.ui b/Modules/QtWidgets/src/QmitkDataStorageListInspector.ui new file mode 100644 index 0000000000..abce896fce --- /dev/null +++ b/Modules/QtWidgets/src/QmitkDataStorageListInspector.ui @@ -0,0 +1,46 @@ + + + QmitkDataStorageListInspector + + + + 0 + 0 + 400 + 300 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QAbstractItemView::NoEditTriggers + + + true + + + + + + + + diff --git a/Modules/QtWidgets/src/QmitkDataStorageSimpleTreeModel.cpp b/Modules/QtWidgets/src/QmitkDataStorageSimpleTreeModel.cpp new file mode 100644 index 0000000000..0189f5df4d --- /dev/null +++ b/Modules/QtWidgets/src/QmitkDataStorageSimpleTreeModel.cpp @@ -0,0 +1,370 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +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 +#include +#include + +// qt widgets module +#include "QmitkCustomVariants.h" +#include "QmitkEnums.h" + +QmitkDataStorageSimpleTreeModel::QmitkDataStorageSimpleTreeModel(QObject *parent) + : QmitkAbstractDataStorageModel(parent), m_Root(nullptr) +{ + ResetTree(); +} + +QmitkDataStorageSimpleTreeModel::~QmitkDataStorageSimpleTreeModel() +{ + m_Root->Delete(); + m_Root = nullptr; +}; + +void QmitkDataStorageSimpleTreeModel::ResetTree() +{ + mitk::DataNode::Pointer rootDataNode = mitk::DataNode::New(); + rootDataNode->SetName("Data Storage"); + m_Root = new TreeItem(rootDataNode, 0); +} + +void QmitkDataStorageSimpleTreeModel::DataStorageChanged() +{ + if (m_Root) + { + m_Root->Delete(); + } + + ResetTree(); + UpdateModelData(); +} + +void QmitkDataStorageSimpleTreeModel::NodePredicateChanged() +{ + ResetTree(); + UpdateModelData(); +} + +void QmitkDataStorageSimpleTreeModel::NodeAdded(const mitk::DataNode *node) +{ + if (node == nullptr || m_DataStorage.IsExpired() || !m_DataStorage.Lock()->Exists(node) || + m_Root->Find(node) != nullptr) + return; + + this->AddNodeInternal(node); +} + +void QmitkDataStorageSimpleTreeModel::NodeChanged(const mitk::DataNode *node) +{ + TreeItem *treeItem = m_Root->Find(node); + if (treeItem) + { + TreeItem *parentTreeItem = treeItem->GetParent(); + // as the root node should not be removed one should always have a parent item + if (!parentTreeItem) + return; + QModelIndex index = this->createIndex(treeItem->GetIndex(), 0, treeItem); + + // now emit the dataChanged signal + emit dataChanged(index, index); + } +} + +void QmitkDataStorageSimpleTreeModel::NodeRemoved(const mitk::DataNode *node) +{ + if (node == nullptr || !m_Root) + return; + + TreeItem *treeItem = m_Root->Find(node); + if (!treeItem) + return; // return because there is no treeitem containing this node + + TreeItem *parentTreeItem = treeItem->GetParent(); + QModelIndex parentIndex = this->IndexFromTreeItem(parentTreeItem); + + // emit beginRemoveRows event (QModelIndex is empty because we dont have a tree model) + this->beginRemoveRows(parentIndex, treeItem->GetIndex(), treeItem->GetIndex()); + + // remove node + std::vector children = treeItem->GetChildren(); + m_TreeItems.remove(treeItem); + delete treeItem; //delete in tree + + if (!children.empty()) + { + //if not empty we have to rebuild the whole representation, + //because the children could be now top level, or at another + //source/parent. + this->UpdateModelData(); + } +} + +QModelIndex QmitkDataStorageSimpleTreeModel::index(int row, int column, const QModelIndex &parent) const +{ + TreeItem *parentItem; + + if (!parent.isValid() || parent.model() != this) + parentItem = m_Root; + else + parentItem = static_cast(parent.internalPointer()); + + if (parentItem) + { + TreeItem *childItem = parentItem->GetChild(row); + if (childItem) + return createIndex(row, column, childItem); + } + + return QModelIndex(); +} + +QModelIndex QmitkDataStorageSimpleTreeModel::parent(const QModelIndex &child) const +{ + if (!child.isValid() || !m_Root || child.model() != this) + return QModelIndex(); + + TreeItem *childItem = this->TreeItemFromIndex(child); + + if (!childItem) + return QModelIndex(); + + TreeItem *parentItem = childItem->GetParent(); + + if (parentItem == m_Root) + return QModelIndex(); + + return this->createIndex(parentItem->GetIndex(), 0, parentItem); +} + +QmitkDataStorageSimpleTreeModel::TreeItem *QmitkDataStorageSimpleTreeModel::TreeItemFromIndex( + const QModelIndex &index) const +{ + if (index.isValid() && index.model() == this) + { + auto item = static_cast(index.internalPointer()); + auto finding = std::find(std::begin(m_TreeItems), std::end(m_TreeItems), item); + if (finding == std::end(m_TreeItems)) + { + return nullptr; + } + return item; + } + else + return m_Root; +} + +int QmitkDataStorageSimpleTreeModel::rowCount(const QModelIndex &parent) const +{ + TreeItem *parentTreeItem = this->TreeItemFromIndex(parent); + if (parentTreeItem) + return parentTreeItem->GetChildCount(); + else + return 0; +} + +int QmitkDataStorageSimpleTreeModel::columnCount(const QModelIndex &/*parent*/) const +{ + return 1; +} + +QVariant QmitkDataStorageSimpleTreeModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid() || index.model() != this) + { + return QVariant(); + } + + auto treeItem = this->TreeItemFromIndex(index); + if (!treeItem) + return QVariant(); + + mitk::DataNode *dataNode = treeItem->GetDataNode(); + + QString nodeName = QString::fromStdString(dataNode->GetName()); + if (nodeName.isEmpty()) + { + nodeName = "unnamed"; + } + + if (role == Qt::DisplayRole) + return nodeName; + else if (role == Qt::ToolTipRole) + return nodeName; + else if (role == Qt::DecorationRole) + { + QmitkNodeDescriptor *nodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor(dataNode); + return nodeDescriptor->GetIcon(dataNode); + } + else if (role == QmitkDataNodeRole) + { + return QVariant::fromValue(mitk::DataNode::Pointer(dataNode)); + } + else if (role == QmitkDataNodeRawPointerRole) + { + return QVariant::fromValue(dataNode); + } + + return QVariant(); +} + +bool QmitkDataStorageSimpleTreeModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + if (!index.isValid() || index.model() != this) + return false; + + auto treeItem = this->TreeItemFromIndex(index); + if (!treeItem) + return false; + + mitk::DataNode *dataNode = treeItem->GetDataNode(); + if (!dataNode) + return false; + + if (role == Qt::EditRole && !value.toString().isEmpty()) + { + dataNode->SetName(value.toString().toStdString().c_str()); + } + else if (role == Qt::CheckStateRole) + { + // Please note: value.toInt() returns 2, independentely from the actual checkstate of the index element. + // Therefore the checkstate is being estimated again here. + + QVariant qcheckstate = index.data(Qt::CheckStateRole); + int checkstate = qcheckstate.toInt(); + bool isVisible = bool(checkstate); + dataNode->SetVisibility(!isVisible); + } + // inform listeners about changes + emit dataChanged(index, index); + return true; +} + +QVariant QmitkDataStorageSimpleTreeModel::headerData(int /*section*/, Qt::Orientation orientation, int role) const +{ + if (orientation == Qt::Horizontal && role == Qt::DisplayRole && m_Root) + return QString::fromStdString(m_Root->GetDataNode()->GetName()); + + return QVariant(); +} + +Qt::ItemFlags QmitkDataStorageSimpleTreeModel::flags(const QModelIndex &index) const +{ + if (index.isValid() && index.model() == this) + { + auto treeItem = this->TreeItemFromIndex(index); + if (!treeItem) + return Qt::NoItemFlags; + + const auto dataNode = treeItem->GetDataNode(); + if (m_NodePredicate.IsNull() || m_NodePredicate->CheckNode(dataNode)) + { + return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable; + } + else + { + return Qt::NoItemFlags; + } + + } + + return Qt::NoItemFlags; +} + +mitk::DataNode *QmitkDataStorageSimpleTreeModel::GetParentNode(const mitk::DataNode *node) const +{ + mitk::DataNode *dataNode = nullptr; + + mitk::DataStorage::SetOfObjects::ConstPointer _Sources = m_DataStorage.Lock()->GetSources(node); + + if (_Sources->Size() > 0) + dataNode = _Sources->front(); + + return dataNode; +} + +void QmitkDataStorageSimpleTreeModel::AddNodeInternal(const mitk::DataNode *node) +{ + if (node == nullptr || m_DataStorage.IsExpired() || !m_DataStorage.Lock()->Exists(node) || m_Root->Find(node) != 0) + return; + + // find out if we have a root node + TreeItem *parentTreeItem = m_Root; + QModelIndex index; + mitk::DataNode *parentDataNode = this->GetParentNode(node); + + if (parentDataNode) // no top level data node + { + parentTreeItem = m_Root->Find(parentDataNode); // find the corresponding tree item + if (!parentTreeItem) + { + this->NodeAdded(parentDataNode); + parentTreeItem = m_Root->Find(parentDataNode); + if (!parentTreeItem) + return; + } + + // get the index of this parent with the help of the grand parent + index = this->createIndex(parentTreeItem->GetIndex(), 0, parentTreeItem); + } + + int firstRowWithASiblingBelow = 0; + int nodeLayer = -1; + node->GetIntProperty("layer", nodeLayer); + for (TreeItem *siblingTreeItem : parentTreeItem->GetChildren()) + { + int siblingLayer = -1; + if (mitk::DataNode *siblingNode = siblingTreeItem->GetDataNode()) + { + siblingNode->GetIntProperty("layer", siblingLayer); + } + if (nodeLayer > siblingLayer) + { + break; + } + ++firstRowWithASiblingBelow; + } + beginInsertRows(index, firstRowWithASiblingBelow, firstRowWithASiblingBelow); + auto newNode = new TreeItem(const_cast(node)); + parentTreeItem->InsertChild(newNode, firstRowWithASiblingBelow); + m_TreeItems.push_back(newNode); + + endInsertRows(); +} + +QModelIndex QmitkDataStorageSimpleTreeModel::IndexFromTreeItem(TreeItem *item) const +{ + if (item == m_Root) + return QModelIndex(); + else + return this->createIndex(item->GetIndex(), 0, item); +} + +void QmitkDataStorageSimpleTreeModel::UpdateModelData() +{ + if (!m_DataStorage.IsExpired()) + { + auto nodeset = m_DataStorage.Lock()->GetAll(); + if (m_NodePredicate != nullptr) + { + nodeset = m_DataStorage.Lock()->GetSubset(m_NodePredicate); + } + + for (const auto& node : *nodeset) + { + this->AddNodeInternal(node); + } + } +} diff --git a/Modules/QtWidgets/src/QmitkDataStorageTreeInspector.cpp b/Modules/QtWidgets/src/QmitkDataStorageTreeInspector.cpp new file mode 100644 index 0000000000..c8bb5c952b --- /dev/null +++ b/Modules/QtWidgets/src/QmitkDataStorageTreeInspector.cpp @@ -0,0 +1,65 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +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 + +#include + +QmitkDataStorageTreeInspector::QmitkDataStorageTreeInspector(QWidget* parent/* = nullptr*/) + : QmitkAbstractDataStorageInspector(parent) +{ + m_Controls.setupUi(this); + + m_Controls.view->setSelectionMode(QAbstractItemView::ExtendedSelection); + m_Controls.view->setSelectionBehavior(QAbstractItemView::SelectRows); + m_Controls.view->setAlternatingRowColors(true); + m_Controls.view->setHeaderHidden(true); + m_Controls.view->setTextElideMode(Qt::ElideMiddle); + + m_StorageModel = new QmitkDataStorageSimpleTreeModel(this); + + m_Controls.view->setModel(m_StorageModel); +} + +QAbstractItemView* QmitkDataStorageTreeInspector::GetView() +{ + return m_Controls.view; +}; + +const QAbstractItemView* QmitkDataStorageTreeInspector::GetView() const +{ + return m_Controls.view; +}; + +void QmitkDataStorageTreeInspector::Initialize() +{ + m_StorageModel->SetDataStorage(m_DataStorage.Lock()); + m_StorageModel->SetNodePredicate(m_NodePredicate); + + m_Connector->SetView(m_Controls.view); + + m_Controls.view->expandAll(); +} + +void QmitkDataStorageTreeInspector::SetSelectionMode(SelectionMode mode) +{ + m_Controls.view->setSelectionMode(mode); +} + +QmitkDataStorageTreeInspector::SelectionMode QmitkDataStorageTreeInspector::GetSelectionMode() const +{ + return m_Controls.view->selectionMode(); +}; diff --git a/Modules/QtWidgets/src/QmitkDataStorageTreeInspector.ui b/Modules/QtWidgets/src/QmitkDataStorageTreeInspector.ui new file mode 100644 index 0000000000..4517c402e4 --- /dev/null +++ b/Modules/QtWidgets/src/QmitkDataStorageTreeInspector.ui @@ -0,0 +1,46 @@ + + + QmitkDataStorageTreeInspector + + + + 0 + 0 + 400 + 300 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QAbstractItemView::NoEditTriggers + + + true + + + + + + + + diff --git a/Modules/QtWidgets/src/QmitkDataStorageTreeModel.cpp b/Modules/QtWidgets/src/QmitkDataStorageTreeModel.cpp index c27f72a607..d83c8d96cd 100644 --- a/Modules/QtWidgets/src/QmitkDataStorageTreeModel.cpp +++ b/Modules/QtWidgets/src/QmitkDataStorageTreeModel.cpp @@ -1,1005 +1,884 @@ /*=================================================================== 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 #include #include #include #include #include #include #include #include #include #include #include "QmitkDataStorageTreeModel.h" +#include "QmitkDataStorageTreeModelInternalItem.h" #include "QmitkNodeDescriptorManager.h" #include #include #include #include #include #include #include #include #include QmitkDataStorageTreeModel::QmitkDataStorageTreeModel(mitk::DataStorage *_DataStorage, bool _PlaceNewNodesOnTop, QObject *parent) : QAbstractItemModel(parent), m_DataStorage(nullptr), m_PlaceNewNodesOnTop(_PlaceNewNodesOnTop), m_Root(nullptr), m_BlockDataStorageEvents(false), m_AllowHierarchyChange(false) { this->SetDataStorage(_DataStorage); } QmitkDataStorageTreeModel::~QmitkDataStorageTreeModel() { // set data storage to 0 = remove all listeners this->SetDataStorage(nullptr); m_Root->Delete(); m_Root = nullptr; } mitk::DataNode::Pointer QmitkDataStorageTreeModel::GetNode(const QModelIndex &index) const { return this->TreeItemFromIndex(index)->GetDataNode(); } const mitk::DataStorage::Pointer QmitkDataStorageTreeModel::GetDataStorage() const { return m_DataStorage.Lock(); } QModelIndex QmitkDataStorageTreeModel::index(int row, int column, const QModelIndex &parent) const { TreeItem *parentItem; if (!parent.isValid()) parentItem = m_Root; else parentItem = static_cast(parent.internalPointer()); TreeItem *childItem = parentItem->GetChild(row); if (childItem) return createIndex(row, column, childItem); else return QModelIndex(); } int QmitkDataStorageTreeModel::rowCount(const QModelIndex &parent) const { TreeItem *parentTreeItem = this->TreeItemFromIndex(parent); return parentTreeItem->GetChildCount(); } Qt::ItemFlags QmitkDataStorageTreeModel::flags(const QModelIndex &index) const { if (index.isValid()) { return Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; } else { return Qt::ItemIsDropEnabled; } } int QmitkDataStorageTreeModel::columnCount(const QModelIndex & /* parent = QModelIndex() */) const { return 1; } QModelIndex QmitkDataStorageTreeModel::parent(const QModelIndex &index) const { if (!index.isValid()) return QModelIndex(); TreeItem *childItem = this->TreeItemFromIndex(index); TreeItem *parentItem = childItem->GetParent(); if (parentItem == m_Root) return QModelIndex(); return this->createIndex(parentItem->GetIndex(), 0, parentItem); } QmitkDataStorageTreeModel::TreeItem *QmitkDataStorageTreeModel::TreeItemFromIndex(const QModelIndex &index) const { if (index.isValid()) return static_cast(index.internalPointer()); else return m_Root; } Qt::DropActions QmitkDataStorageTreeModel::supportedDropActions() const { return Qt::CopyAction | Qt::MoveAction; } Qt::DropActions QmitkDataStorageTreeModel::supportedDragActions() const { return Qt::CopyAction | Qt::MoveAction; } bool QmitkDataStorageTreeModel::dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int /*column*/, const QModelIndex &parent) { // Early exit, returning true, but not actually doing anything (ignoring data). if (action == Qt::IgnoreAction) { return true; } // Note, we are returning true if we handled it, and false otherwise bool returnValue = false; if (data->hasFormat("application/x-qabstractitemmodeldatalist")) { returnValue = true; // First we extract a Qlist of TreeItem* pointers. QList listOfItemsToDrop = ToTreeItemPtrList(data); if (listOfItemsToDrop.empty()) { return false; } // Retrieve the TreeItem* where we are dropping stuff, and its parent. TreeItem *dropItem = this->TreeItemFromIndex(parent); TreeItem *parentItem = dropItem->GetParent(); // If item was dropped onto empty space, we select the root node if (dropItem == m_Root) { parentItem = m_Root; } // Dragging and Dropping is only allowed within the same parent, so use the first item in list to validate. // (otherwise, you could have a derived image such as a segmentation, and assign it to another image). // NOTE: We are assuming the input list is valid... i.e. when it was dragged, all the items had the same parent. // Determine whether or not the drag and drop operation is a valid one. // Examples of invalid operations include: // - dragging nodes with different parents // - dragging nodes from one parent to another parent, if m_AllowHierarchyChange is false // - dragging a node on one of its child nodes (only relevant if m_AllowHierarchyChange is true) bool isValidDragAndDropOperation(true); // different parents { TreeItem *firstParent = listOfItemsToDrop[0]->GetParent(); QList::iterator diIter; for (diIter = listOfItemsToDrop.begin() + 1; diIter != listOfItemsToDrop.end(); diIter++) { if (firstParent != (*diIter)->GetParent()) { isValidDragAndDropOperation = false; break; } } } // dragging from one parent to another if ((!m_AllowHierarchyChange) && isValidDragAndDropOperation) { if (row == -1) // drag onto a node { isValidDragAndDropOperation = listOfItemsToDrop[0]->GetParent() == parentItem; } else // drag between nodes { isValidDragAndDropOperation = listOfItemsToDrop[0]->GetParent() == dropItem; } } // dragging on a child node of one the dragged nodes { QList::iterator diIter; for (diIter = listOfItemsToDrop.begin(); diIter != listOfItemsToDrop.end(); diIter++) { TreeItem *tempItem = dropItem; while (tempItem != m_Root) { tempItem = tempItem->GetParent(); if (tempItem == *diIter) { isValidDragAndDropOperation = false; } } } } if (!isValidDragAndDropOperation) return isValidDragAndDropOperation; if (listOfItemsToDrop[0] != dropItem && isValidDragAndDropOperation) { // Retrieve the index of where we are dropping stuff. QModelIndex parentModelIndex = this->IndexFromTreeItem(parentItem); int dragIndex = 0; // Iterate through the list of TreeItem (which may be at non-consecutive indexes). QList::iterator diIter; for (diIter = listOfItemsToDrop.begin(); diIter != listOfItemsToDrop.end(); diIter++) { TreeItem *itemToDrop = *diIter; // if the item is dragged down we have to compensate its final position for the // fact it is deleted lateron, this only applies if it is dragged within the same level if ((itemToDrop->GetIndex() < row) && (itemToDrop->GetParent() == dropItem)) { dragIndex = 1; } // Here we assume that as you remove items, one at a time, that GetIndex() will be valid. this->beginRemoveRows( this->IndexFromTreeItem(itemToDrop->GetParent()), itemToDrop->GetIndex(), itemToDrop->GetIndex()); itemToDrop->GetParent()->RemoveChild(itemToDrop); this->endRemoveRows(); } // row = -1 dropped on an item, row != -1 dropped in between two items // Select the target index position, or put it at the end of the list. int dropIndex = 0; if (row != -1) { if (dragIndex == 0) dropIndex = std::min(row, parentItem->GetChildCount() - 1); else dropIndex = std::min(row - 1, parentItem->GetChildCount() - 1); } else { dropIndex = dropItem->GetIndex(); } QModelIndex dropItemModelIndex = this->IndexFromTreeItem(dropItem); if ((row == -1 && dropItemModelIndex.row() == -1) || dropItemModelIndex.row() > parentItem->GetChildCount()) dropIndex = parentItem->GetChildCount() - 1; // Now insert items again at the drop item position if (m_AllowHierarchyChange) { this->beginInsertRows(dropItemModelIndex, dropIndex, dropIndex + listOfItemsToDrop.size() - 1); } else { this->beginInsertRows(parentModelIndex, dropIndex, dropIndex + listOfItemsToDrop.size() - 1); } for (diIter = listOfItemsToDrop.begin(); diIter != listOfItemsToDrop.end(); diIter++) { // dropped on node, behaviour depends on preference setting if (m_AllowHierarchyChange) { auto dataStorage = m_DataStorage.Lock(); m_BlockDataStorageEvents = true; mitk::DataNode *droppedNode = (*diIter)->GetDataNode(); mitk::DataNode *dropOntoNode = dropItem->GetDataNode(); dataStorage->Remove(droppedNode); dataStorage->Add(droppedNode, dropOntoNode); m_BlockDataStorageEvents = false; dropItem->InsertChild((*diIter), dropIndex); } else { if (row == -1) // drag onto a node { parentItem->InsertChild((*diIter), dropIndex); } else // drag between nodes { dropItem->InsertChild((*diIter), dropIndex); } } dropIndex++; } this->endInsertRows(); // Change Layers to match. this->AdjustLayerProperty(); } } else if (data->hasFormat("application/x-mitk-datanodes")) { returnValue = true; int numberOfNodesDropped = 0; QList dataNodeList = QmitkMimeTypes::ToDataNodePtrList(data); mitk::DataNode *node = nullptr; foreach (node, dataNodeList) { if (node && !m_DataStorage.IsExpired() && !m_DataStorage.Lock()->Exists(node)) { m_DataStorage.Lock()->Add(node); mitk::BaseData::Pointer basedata = node->GetData(); if (basedata.IsNotNull()) { mitk::RenderingManager::GetInstance()->InitializeViews( basedata->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); numberOfNodesDropped++; } } } // Only do a rendering update, if we actually dropped anything. if (numberOfNodesDropped > 0) { mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } return returnValue; } QStringList QmitkDataStorageTreeModel::mimeTypes() const { QStringList types = QAbstractItemModel::mimeTypes(); types << "application/x-qabstractitemmodeldatalist"; types << "application/x-mitk-datanodes"; return types; } QMimeData *QmitkDataStorageTreeModel::mimeData(const QModelIndexList &indexes) const { return mimeDataFromModelIndexList(indexes); } QMimeData *QmitkDataStorageTreeModel::mimeDataFromModelIndexList(const QModelIndexList &indexes) { QMimeData *ret = new QMimeData; QString treeItemAddresses(""); QString dataNodeAddresses(""); QByteArray baTreeItemPtrs; QByteArray baDataNodePtrs; QDataStream dsTreeItemPtrs(&baTreeItemPtrs, QIODevice::WriteOnly); QDataStream dsDataNodePtrs(&baDataNodePtrs, QIODevice::WriteOnly); for (int i = 0; i < indexes.size(); i++) { TreeItem *treeItem = static_cast(indexes.at(i).internalPointer()); dsTreeItemPtrs << reinterpret_cast(treeItem); - dsDataNodePtrs << reinterpret_cast(treeItem->GetDataNode().GetPointer()); + dsDataNodePtrs << reinterpret_cast(treeItem->GetDataNode()); // --------------- deprecated ----------------- unsigned long long treeItemAddress = reinterpret_cast(treeItem); - unsigned long long dataNodeAddress = reinterpret_cast(treeItem->GetDataNode().GetPointer()); + unsigned long long dataNodeAddress = reinterpret_cast(treeItem->GetDataNode()); QTextStream(&treeItemAddresses) << treeItemAddress; QTextStream(&dataNodeAddresses) << dataNodeAddress; if (i != indexes.size() - 1) { QTextStream(&treeItemAddresses) << ","; QTextStream(&dataNodeAddresses) << ","; } // -------------- end deprecated ------------- } // ------------------ deprecated ----------------- ret->setData("application/x-qabstractitemmodeldatalist", QByteArray(treeItemAddresses.toLatin1())); ret->setData("application/x-mitk-datanodes", QByteArray(dataNodeAddresses.toLatin1())); // --------------- end deprecated ----------------- ret->setData(QmitkMimeTypes::DataStorageTreeItemPtrs, baTreeItemPtrs); ret->setData(QmitkMimeTypes::DataNodePtrs, baDataNodePtrs); return ret; } QVariant QmitkDataStorageTreeModel::data(const QModelIndex &index, int role) const { mitk::DataNode *dataNode = this->TreeItemFromIndex(index)->GetDataNode(); // get name of treeItem (may also be edited) QString nodeName = QString::fromStdString(dataNode->GetName()); if (nodeName.isEmpty()) { nodeName = "unnamed"; } if (role == Qt::DisplayRole) return nodeName; else if (role == Qt::ToolTipRole) return nodeName; else if (role == Qt::DecorationRole) { QmitkNodeDescriptor *nodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor(dataNode); return nodeDescriptor->GetIcon(dataNode); } else if (role == Qt::CheckStateRole) { return dataNode->IsVisible(nullptr); } else if (role == QmitkDataNodeRole) { return QVariant::fromValue(mitk::DataNode::Pointer(dataNode)); } else if (role == QmitkDataNodeRawPointerRole) { return QVariant::fromValue(dataNode); } return QVariant(); } bool QmitkDataStorageTreeModel::DicomPropertiesExists(const mitk::DataNode &node) const { bool propertiesExists = false; mitk::BaseProperty *seriesDescription_deprecated = (node.GetProperty("dicom.series.SeriesDescription")); mitk::BaseProperty *studyDescription_deprecated = (node.GetProperty("dicom.study.StudyDescription")); mitk::BaseProperty *patientsName_deprecated = (node.GetProperty("dicom.patient.PatientsName")); mitk::BaseProperty *seriesDescription = (node.GetProperty(mitk::GeneratePropertyNameForDICOMTag(0x0008, 0x103e).c_str())); mitk::BaseProperty *studyDescription = (node.GetProperty(mitk::GeneratePropertyNameForDICOMTag(0x0008, 0x1030).c_str())); mitk::BaseProperty *patientsName = (node.GetProperty(mitk::GeneratePropertyNameForDICOMTag(0x0010, 0x0010).c_str())); if (patientsName != nullptr && studyDescription != nullptr && seriesDescription != nullptr) { if ((!patientsName->GetValueAsString().empty()) && (!studyDescription->GetValueAsString().empty()) && (!seriesDescription->GetValueAsString().empty())) { propertiesExists = true; } } /** Code coveres the deprecated property naming for backwards compatibility */ if (patientsName_deprecated != nullptr && studyDescription_deprecated != nullptr && seriesDescription_deprecated != nullptr) { if ((!patientsName_deprecated->GetValueAsString().empty()) && (!studyDescription_deprecated->GetValueAsString().empty()) && (!seriesDescription_deprecated->GetValueAsString().empty())) { propertiesExists = true; } } return propertiesExists; } QVariant QmitkDataStorageTreeModel::headerData(int /*section*/, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole && m_Root) return QString::fromStdString(m_Root->GetDataNode()->GetName()); return QVariant(); } void QmitkDataStorageTreeModel::SetDataStorage(mitk::DataStorage *_DataStorage) { if (m_DataStorage != _DataStorage) // dont take the same again { if (!m_DataStorage.IsExpired()) { auto dataStorage = m_DataStorage.Lock(); // remove Listener for the data storage itself dataStorage->RemoveObserver(m_DataStorageDeletedTag); // remove listeners for the nodes dataStorage->AddNodeEvent.RemoveListener( mitk::MessageDelegate1(this, &QmitkDataStorageTreeModel::AddNode)); dataStorage->ChangedNodeEvent.RemoveListener( mitk::MessageDelegate1( this, &QmitkDataStorageTreeModel::SetNodeModified)); dataStorage->RemoveNodeEvent.RemoveListener( mitk::MessageDelegate1( this, &QmitkDataStorageTreeModel::RemoveNode)); } // take over the new data storage m_DataStorage = _DataStorage; // delete the old root (if necessary, create new) if (m_Root) m_Root->Delete(); mitk::DataNode::Pointer rootDataNode = mitk::DataNode::New(); rootDataNode->SetName("Data Manager"); m_Root = new TreeItem(rootDataNode, nullptr); this->beginResetModel(); this->endResetModel(); if (!m_DataStorage.IsExpired()) { auto dataStorage = m_DataStorage.Lock(); // add Listener for the data storage itself auto command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &QmitkDataStorageTreeModel::SetDataStorageDeleted); m_DataStorageDeletedTag = dataStorage->AddObserver(itk::DeleteEvent(), command); // add listeners for the nodes dataStorage->AddNodeEvent.AddListener(mitk::MessageDelegate1( this, &QmitkDataStorageTreeModel::AddNode)); dataStorage->ChangedNodeEvent.AddListener( mitk::MessageDelegate1( this, &QmitkDataStorageTreeModel::SetNodeModified)); dataStorage->RemoveNodeEvent.AddListener( mitk::MessageDelegate1( this, &QmitkDataStorageTreeModel::RemoveNode)); mitk::DataStorage::SetOfObjects::ConstPointer _NodeSet = dataStorage->GetSubset(m_Predicate); // finally add all nodes to the model this->Update(); } } } void QmitkDataStorageTreeModel::SetDataStorageDeleted() { this->SetDataStorage(nullptr); } void QmitkDataStorageTreeModel::AddNodeInternal(const mitk::DataNode *node) { if (node == nullptr || m_DataStorage.IsExpired() || !m_DataStorage.Lock()->Exists(node) || m_Root->Find(node) != nullptr) return; // find out if we have a root node TreeItem *parentTreeItem = m_Root; QModelIndex index; mitk::DataNode *parentDataNode = this->GetParentNode(node); if (parentDataNode) // no top level data node { parentTreeItem = m_Root->Find(parentDataNode); // find the corresponding tree item if (!parentTreeItem) { this->AddNode(parentDataNode); parentTreeItem = m_Root->Find(parentDataNode); if (!parentTreeItem) return; } // get the index of this parent with the help of the grand parent index = this->createIndex(parentTreeItem->GetIndex(), 0, parentTreeItem); } // add node if (m_PlaceNewNodesOnTop) { // emit beginInsertRows event beginInsertRows(index, 0, 0); parentTreeItem->InsertChild(new TreeItem(const_cast(node)), 0); } else { int firstRowWithASiblingBelow = 0; int nodeLayer = -1; node->GetIntProperty("layer", nodeLayer); for (TreeItem* siblingTreeItem: parentTreeItem->GetChildren()) { int siblingLayer = -1; if (mitk::DataNode* siblingNode = siblingTreeItem->GetDataNode()) { siblingNode->GetIntProperty("layer", siblingLayer); } if (nodeLayer > siblingLayer) { break; } ++firstRowWithASiblingBelow; } beginInsertRows(index, firstRowWithASiblingBelow, firstRowWithASiblingBelow); parentTreeItem->InsertChild(new TreeItem(const_cast(node)), firstRowWithASiblingBelow); } // emit endInsertRows event endInsertRows(); if(m_PlaceNewNodesOnTop) { this->AdjustLayerProperty(); } } void QmitkDataStorageTreeModel::AddNode(const mitk::DataNode *node) { if (node == nullptr || m_BlockDataStorageEvents || m_DataStorage.IsExpired() || !m_DataStorage.Lock()->Exists(node) || m_Root->Find(node) != nullptr) return; this->AddNodeInternal(node); } void QmitkDataStorageTreeModel::SetPlaceNewNodesOnTop(bool _PlaceNewNodesOnTop) { m_PlaceNewNodesOnTop = _PlaceNewNodesOnTop; } void QmitkDataStorageTreeModel::RemoveNodeInternal(const mitk::DataNode *node) { if (!m_Root) return; TreeItem *treeItem = m_Root->Find(node); if (!treeItem) return; // return because there is no treeitem containing this node TreeItem *parentTreeItem = treeItem->GetParent(); QModelIndex parentIndex = this->IndexFromTreeItem(parentTreeItem); // emit beginRemoveRows event (QModelIndex is empty because we dont have a tree model) this->beginRemoveRows(parentIndex, treeItem->GetIndex(), treeItem->GetIndex()); // remove node std::vector children = treeItem->GetChildren(); delete treeItem; // emit endRemoveRows event endRemoveRows(); // move all children of deleted node into its parent for (std::vector::iterator it = children.begin(); it != children.end(); it++) { // emit beginInsertRows event beginInsertRows(parentIndex, parentTreeItem->GetChildCount(), parentTreeItem->GetChildCount()); // add nodes again parentTreeItem->AddChild(*it); // emit endInsertRows event endInsertRows(); } this->AdjustLayerProperty(); } void QmitkDataStorageTreeModel::RemoveNode(const mitk::DataNode *node) { if (node == nullptr || m_BlockDataStorageEvents) return; this->RemoveNodeInternal(node); } void QmitkDataStorageTreeModel::SetNodeModified(const mitk::DataNode *node) { TreeItem *treeItem = m_Root->Find(node); if (treeItem) { TreeItem *parentTreeItem = treeItem->GetParent(); // as the root node should not be removed one should always have a parent item if (!parentTreeItem) return; QModelIndex index = this->createIndex(treeItem->GetIndex(), 0, treeItem); // now emit the dataChanged signal emit dataChanged(index, index); } } mitk::DataNode *QmitkDataStorageTreeModel::GetParentNode(const mitk::DataNode *node) const { mitk::DataNode *dataNode = nullptr; mitk::DataStorage::SetOfObjects::ConstPointer _Sources = m_DataStorage.Lock()->GetSources(node); if (_Sources->Size() > 0) dataNode = _Sources->front(); return dataNode; } bool QmitkDataStorageTreeModel::setData(const QModelIndex &index, const QVariant &value, int role) { mitk::DataNode *dataNode = this->TreeItemFromIndex(index)->GetDataNode(); if (!dataNode) return false; if (role == Qt::EditRole && !value.toString().isEmpty()) { dataNode->SetStringProperty("name", value.toString().toStdString().c_str()); mitk::PlanarFigure *planarFigure = dynamic_cast(dataNode->GetData()); if (planarFigure != nullptr) mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } else if (role == Qt::CheckStateRole) { // Please note: value.toInt() returns 2, independentely from the actual checkstate of the index element. // Therefore the checkstate is being estimated again here. QVariant qcheckstate = index.data(Qt::CheckStateRole); int checkstate = qcheckstate.toInt(); bool isVisible = bool(checkstate); dataNode->SetVisibility(!isVisible); emit nodeVisibilityChanged(); } // inform listeners about changes emit dataChanged(index, index); return true; } bool QmitkDataStorageTreeModel::setHeaderData(int /*section*/, Qt::Orientation /*orientation*/, const QVariant & /* value */, int /*role = Qt::EditRole*/) { return false; } void QmitkDataStorageTreeModel::AdjustLayerProperty() { /// transform the tree into an array and set the layer property descending std::vector vec; this->TreeToVector(m_Root, vec); int i = vec.size() - 1; for (std::vector::const_iterator it = vec.begin(); it != vec.end(); ++it) { mitk::DataNode::Pointer dataNode = (*it)->GetDataNode(); bool fixedLayer = false; if (!(dataNode->GetBoolProperty("fixedLayer", fixedLayer) && fixedLayer)) dataNode->SetIntProperty("layer", i); --i; } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkDataStorageTreeModel::TreeToVector(TreeItem *parent, std::vector &vec) const { TreeItem *current; for (int i = 0; i < parent->GetChildCount(); ++i) { current = parent->GetChild(i); this->TreeToVector(current, vec); vec.push_back(current); } } QModelIndex QmitkDataStorageTreeModel::IndexFromTreeItem(TreeItem *item) const { if (item == m_Root) return QModelIndex(); else return this->createIndex(item->GetIndex(), 0, item); } QList QmitkDataStorageTreeModel::GetNodeSet() const { QList res; if (m_Root) this->TreeToNodeSet(m_Root, res); return res; } void QmitkDataStorageTreeModel::TreeToNodeSet(TreeItem *parent, QList &vec) const { TreeItem *current; for (int i = 0; i < parent->GetChildCount(); ++i) { current = parent->GetChild(i); vec.push_back(current->GetDataNode()); this->TreeToNodeSet(current, vec); } } QModelIndex QmitkDataStorageTreeModel::GetIndex(const mitk::DataNode *node) const { if (m_Root) { TreeItem *item = m_Root->Find(node); if (item) return this->IndexFromTreeItem(item); } return QModelIndex(); } QList QmitkDataStorageTreeModel::ToTreeItemPtrList(const QMimeData *mimeData) { if (mimeData == nullptr || !mimeData->hasFormat(QmitkMimeTypes::DataStorageTreeItemPtrs)) { return QList(); } return ToTreeItemPtrList(mimeData->data(QmitkMimeTypes::DataStorageTreeItemPtrs)); } QList QmitkDataStorageTreeModel::ToTreeItemPtrList(const QByteArray &ba) { QList result; QDataStream ds(ba); while (!ds.atEnd()) { quintptr treeItemPtr; ds >> treeItemPtr; result.push_back(reinterpret_cast(treeItemPtr)); } return result; } -QmitkDataStorageTreeModel::TreeItem::TreeItem(mitk::DataNode *_DataNode, TreeItem *_Parent) - : m_Parent(_Parent), m_DataNode(_DataNode) -{ - if (m_Parent) - m_Parent->AddChild(this); -} - -QmitkDataStorageTreeModel::TreeItem::~TreeItem() -{ - if (m_Parent) - m_Parent->RemoveChild(this); -} - -void QmitkDataStorageTreeModel::TreeItem::Delete() -{ - while (m_Children.size() > 0) - delete m_Children.back(); - - delete this; -} - -QmitkDataStorageTreeModel::TreeItem *QmitkDataStorageTreeModel::TreeItem::Find(const mitk::DataNode *_DataNode) const -{ - QmitkDataStorageTreeModel::TreeItem *item = nullptr; - if (_DataNode) - { - if (m_DataNode == _DataNode) - item = const_cast(this); - else - { - for (std::vector::const_iterator it = m_Children.begin(); it != m_Children.end(); ++it) - { - if (item) - break; - item = (*it)->Find(_DataNode); - } - } - } - return item; -} - -int QmitkDataStorageTreeModel::TreeItem::IndexOfChild(const TreeItem *item) const -{ - std::vector::const_iterator it = std::find(m_Children.begin(), m_Children.end(), item); - return it != m_Children.end() ? std::distance(m_Children.begin(), it) : -1; -} - -QmitkDataStorageTreeModel::TreeItem *QmitkDataStorageTreeModel::TreeItem::GetChild(int index) const -{ - return (m_Children.size() > 0 && index >= 0 && index < (int)m_Children.size()) ? m_Children.at(index) : nullptr; -} - -void QmitkDataStorageTreeModel::TreeItem::AddChild(TreeItem *item) -{ - this->InsertChild(item); -} - -void QmitkDataStorageTreeModel::TreeItem::RemoveChild(TreeItem *item) -{ - std::vector::iterator it = std::find(m_Children.begin(), m_Children.end(), item); - if (it != m_Children.end()) - { - m_Children.erase(it); - item->SetParent(nullptr); - } -} - -int QmitkDataStorageTreeModel::TreeItem::GetChildCount() const -{ - return m_Children.size(); -} - -int QmitkDataStorageTreeModel::TreeItem::GetIndex() const -{ - if (m_Parent) - return m_Parent->IndexOfChild(this); - - return 0; -} - -QmitkDataStorageTreeModel::TreeItem *QmitkDataStorageTreeModel::TreeItem::GetParent() const -{ - return m_Parent; -} - -mitk::DataNode::Pointer QmitkDataStorageTreeModel::TreeItem::GetDataNode() const -{ - return m_DataNode; -} - -void QmitkDataStorageTreeModel::TreeItem::InsertChild(TreeItem *item, int index) -{ - std::vector::iterator it = std::find(m_Children.begin(), m_Children.end(), item); - if (it == m_Children.end()) - { - if (m_Children.size() > 0 && index >= 0 && index < (int)m_Children.size()) - { - it = m_Children.begin(); - std::advance(it, index); - m_Children.insert(it, item); - } - else - m_Children.push_back(item); - - // add parent if necessary - if (item->GetParent() != this) - item->SetParent(this); - } -} - -std::vector QmitkDataStorageTreeModel::TreeItem::GetChildren() const -{ - return m_Children; -} - -void QmitkDataStorageTreeModel::TreeItem::SetParent(TreeItem *_Parent) -{ - m_Parent = _Parent; - if (m_Parent) - m_Parent->AddChild(this); -} - void QmitkDataStorageTreeModel::Update() { if (!m_DataStorage.IsExpired()) { mitk::DataStorage::SetOfObjects::ConstPointer _NodeSet = m_DataStorage.Lock()->GetAll(); /// Regardless the value of this preference, the new nodes must not be inserted /// at the top now, but at the position according to their layer. bool newNodesWereToBePlacedOnTop = m_PlaceNewNodesOnTop; m_PlaceNewNodesOnTop = false; for (const auto& node: *_NodeSet) { this->AddNodeInternal(node); } m_PlaceNewNodesOnTop = newNodesWereToBePlacedOnTop; /// Adjust the layers to ensure that derived nodes are above their sources. this->AdjustLayerProperty(); } } void QmitkDataStorageTreeModel::SetAllowHierarchyChange(bool allowHierarchyChange) { m_AllowHierarchyChange = allowHierarchyChange; } diff --git a/Modules/QtWidgets/src/QmitkDataStorageTreeModelInternalItem.cpp b/Modules/QtWidgets/src/QmitkDataStorageTreeModelInternalItem.cpp new file mode 100644 index 0000000000..ae7741b899 --- /dev/null +++ b/Modules/QtWidgets/src/QmitkDataStorageTreeModelInternalItem.cpp @@ -0,0 +1,144 @@ +/*=================================================================== + +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 "QmitkDataStorageTreeModelInternalItem.h" + +#include "QmitkNodeDescriptorManager.h" +#include +#include +#include + +QmitkDataStorageTreeModelInternalItem::QmitkDataStorageTreeModelInternalItem(mitk::DataNode *_DataNode, QmitkDataStorageTreeModelInternalItem *_Parent) + : m_Parent(_Parent), m_DataNode(_DataNode) +{ + if (m_Parent) + m_Parent->AddChild(this); +} + +QmitkDataStorageTreeModelInternalItem::~QmitkDataStorageTreeModelInternalItem() +{ + if (m_Parent) + m_Parent->RemoveChild(this); +} + +void QmitkDataStorageTreeModelInternalItem::Delete() +{ + while (m_Children.size() > 0) + delete m_Children.back(); + + delete this; +} + +QmitkDataStorageTreeModelInternalItem *QmitkDataStorageTreeModelInternalItem::Find(const mitk::DataNode *_DataNode) const +{ + QmitkDataStorageTreeModelInternalItem *item = nullptr; + if (_DataNode) + { + if (m_DataNode == _DataNode) + item = const_cast(this); + else + { + for (std::vector::const_iterator it = m_Children.begin(); it != m_Children.end(); ++it) + { + if (item) + break; + item = (*it)->Find(_DataNode); + } + } + } + return item; +} + +int QmitkDataStorageTreeModelInternalItem::IndexOfChild(const QmitkDataStorageTreeModelInternalItem *item) const +{ + std::vector::const_iterator it = std::find(m_Children.begin(), m_Children.end(), item); + return it != m_Children.end() ? std::distance(m_Children.begin(), it) : -1; +} + +QmitkDataStorageTreeModelInternalItem *QmitkDataStorageTreeModelInternalItem::GetChild(int index) const +{ + return (m_Children.size() > 0 && index >= 0 && index < (int)m_Children.size()) ? m_Children.at(index) : 0; +} + +void QmitkDataStorageTreeModelInternalItem::AddChild(QmitkDataStorageTreeModelInternalItem *item) +{ + this->InsertChild(item); +} + +void QmitkDataStorageTreeModelInternalItem::RemoveChild(QmitkDataStorageTreeModelInternalItem *item) +{ + std::vector::iterator it = std::find(m_Children.begin(), m_Children.end(), item); + if (it != m_Children.end()) + { + m_Children.erase(it); + item->SetParent(0); + } +} + +int QmitkDataStorageTreeModelInternalItem::GetChildCount() const +{ + return m_Children.size(); +} + +int QmitkDataStorageTreeModelInternalItem::GetIndex() const +{ + if (m_Parent) + return m_Parent->IndexOfChild(this); + + return 0; +} + +QmitkDataStorageTreeModelInternalItem *QmitkDataStorageTreeModelInternalItem::GetParent() const +{ + return m_Parent; +} + +mitk::DataNode* QmitkDataStorageTreeModelInternalItem::GetDataNode() const +{ + return m_DataNode; +} + +void QmitkDataStorageTreeModelInternalItem::InsertChild(QmitkDataStorageTreeModelInternalItem *item, int index) +{ + std::vector::iterator it = std::find(m_Children.begin(), m_Children.end(), item); + if (it == m_Children.end()) + { + if (m_Children.size() > 0 && index >= 0 && index < (int)m_Children.size()) + { + it = m_Children.begin(); + std::advance(it, index); + m_Children.insert(it, item); + } + else + m_Children.push_back(item); + + // add parent if necessary + if (item->GetParent() != this) + item->SetParent(this); + } +} + +std::vector QmitkDataStorageTreeModelInternalItem::GetChildren() const +{ + return m_Children; +} + +void QmitkDataStorageTreeModelInternalItem::SetParent(QmitkDataStorageTreeModelInternalItem *_Parent) +{ + m_Parent = _Parent; + if (m_Parent) + m_Parent->AddChild(this); +} diff --git a/Modules/QtWidgets/src/QmitkIDataStorageInspectorProvider.cpp b/Modules/QtWidgets/src/QmitkIDataStorageInspectorProvider.cpp new file mode 100644 index 0000000000..a78f82850c --- /dev/null +++ b/Modules/QtWidgets/src/QmitkIDataStorageInspectorProvider.cpp @@ -0,0 +1,29 @@ +/*=================================================================== + +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 "QmitkIDataStorageInspectorProvider.h" + +namespace mitk +{ + IDataStorageInspectorProvider::~IDataStorageInspectorProvider() {} + + std::string mitk::IDataStorageInspectorProvider::PROP_INSPECTOR_ID() + { + static std::string s = "org.mitk.IDataStorageInspectorProvider.inspectorid"; + return s; + } + +} \ No newline at end of file diff --git a/Modules/QtWidgets/src/QmitkModelViewSelectionConnector.cpp b/Modules/QtWidgets/src/QmitkModelViewSelectionConnector.cpp new file mode 100644 index 0000000000..b582b9e240 --- /dev/null +++ b/Modules/QtWidgets/src/QmitkModelViewSelectionConnector.cpp @@ -0,0 +1,189 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +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. + +===================================================================*/ + +// mitk gui qt common plugin +#include "QmitkModelViewSelectionConnector.h" + +// qt widgets module +#include "QmitkCustomVariants.h" +#include "QmitkEnums.h" + +QmitkModelViewSelectionConnector::QmitkModelViewSelectionConnector() + : m_Model(nullptr) + , m_View(nullptr) + , m_SelectOnlyVisibleNodes(false) +{ + // nothing here +} + +void QmitkModelViewSelectionConnector::SetView(QAbstractItemView* view) +{ + if (nullptr != m_View) + { + disconnect(m_View->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), this, SLOT(ChangeModelSelection(const QItemSelection&, const QItemSelection&))); + } + + // reset model-view pair and check for valid function argument + m_View = nullptr; + if (nullptr == view) + { + mitkThrow() << "Invalid item view. To use the model-view selection connector please specify a valid 'QAbstractItemView'."; + } + + auto storageModel = dynamic_cast(view->model()); + + if (storageModel == nullptr) + { + mitkThrow() << "Invalid data model. To use the model-view selection connector please set a valid 'QmitkAbstractDataStorageModel' for the given item view."; + } + + // a valid item view and a valid data model was found + m_View = view; + m_Model = storageModel; + connect(m_View->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), SLOT(ChangeModelSelection(const QItemSelection&, const QItemSelection&))); +} + +void QmitkModelViewSelectionConnector::SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes) +{ + m_SelectOnlyVisibleNodes = selectOnlyVisibleNodes; +} + +void QmitkModelViewSelectionConnector::SetCurrentSelection(QList selectedNodes) +{ + if (nullptr == m_Model || nullptr == m_View) + { + return; + } + + // filter input nodes and return the modified input node list + QList filteredNodes = FilterNodeList(selectedNodes); + + bool equal = EqualNodeSelections(this->GetInternalSelectedNodes(), filteredNodes); + if (equal) + { + return; + } + + if (!m_SelectOnlyVisibleNodes) + { + // store the unmodified selection + m_NonVisibleSelection = selectedNodes; + // remove the nodes in the original selection that are already contained in the filtered input node list + // this will keep the selection of the original nodes that are not presented by the current view unmodified, but allows to change the selection of the filtered nodes + // later, the nodes of the 'm_NonVisibleSelection' member have to be added again to the list of selected (filtered) nodes, if a selection is sent from the current view (see 'ModelSelectionChanged') + auto lambda = [&filteredNodes](mitk::DataNode::Pointer original) { return filteredNodes.contains(original); }; + m_NonVisibleSelection.erase(std::remove_if(m_NonVisibleSelection.begin(), m_NonVisibleSelection.end(), lambda), m_NonVisibleSelection.end()); + } + + // create new selection by retrieving the corresponding indices of the (filtered) nodes + QItemSelection newCurrentSelection; + for (const auto& node : filteredNodes) + { + QModelIndexList matched = m_Model->match(m_Model->index(0, 0), QmitkDataNodeRole, QVariant::fromValue(node), 1, Qt::MatchRecursive); + if (!matched.empty()) + { + newCurrentSelection.select(matched.front(), matched.front()); + } + } + + m_View->selectionModel()->select(newCurrentSelection, QItemSelectionModel::ClearAndSelect); +} + +void QmitkModelViewSelectionConnector::ChangeModelSelection(const QItemSelection& /*selected*/, const QItemSelection& /*deselected*/) +{ + emit CurrentSelectionChanged(GetSelectedNodes()); +} + +bool QmitkModelViewSelectionConnector::GetSelectOnlyVisibleNodes() const +{ + return m_SelectOnlyVisibleNodes; +} + +QList QmitkModelViewSelectionConnector::GetSelectedNodes() const +{ + auto nodes = GetInternalSelectedNodes(); + + if (!m_SelectOnlyVisibleNodes) + { + // add the non-visible nodes from the original selection + nodes.append(m_NonVisibleSelection); + } + + return nodes; +} + +QList QmitkModelViewSelectionConnector::GetInternalSelectedNodes() const +{ + if (nullptr == m_Model || nullptr == m_View) + { + return QList(); + } + + QList nodes; + QModelIndexList selectedIndexes = m_View->selectionModel()->selectedIndexes(); + for (const auto& index : selectedIndexes) + { + QVariant qvariantDataNode = m_Model->data(index, QmitkDataNodeRole); + if (qvariantDataNode.canConvert()) + { + nodes.push_back(qvariantDataNode.value()); + } + } + return nodes; +} + +QList QmitkModelViewSelectionConnector::FilterNodeList(const QList& nodes) const +{ + if (nodes.isEmpty()) + { + return QList(); + } + + if (nullptr == m_Model) + { + return nodes; + } + + mitk::NodePredicateBase* nodePredicate = m_Model->GetNodePredicate(); + if (nullptr == nodePredicate) + { + // no filter set + return nodes; + } + + QList result; + for (const auto& node : nodes) + { + if (true == nodePredicate->CheckNode(node)) + { + result.push_back(node); + } + } + + return result; +} + +bool MITKQTWIDGETS_EXPORT EqualNodeSelections(const QList& selection1, const QList& selection2) +{ + if (selection1.size() == selection2.size()) + { + // lambda to compare node pointer inside both lists + auto lambda = [](mitk::DataNode::Pointer lhs, mitk::DataNode::Pointer rhs) { return lhs == rhs; }; + return std::is_permutation(selection1.begin(), selection1.end(), selection2.begin(), selection2.end(), lambda); + } + + return false; +} diff --git a/Modules/QtWidgets/src/mitkQtWidgetsActivator.cpp b/Modules/QtWidgets/src/mitkQtWidgetsActivator.cpp new file mode 100644 index 0000000000..8763ca1435 --- /dev/null +++ b/Modules/QtWidgets/src/mitkQtWidgetsActivator.cpp @@ -0,0 +1,38 @@ +/*=================================================================== + +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 "mitkQtWidgetsActivator.h" + +// Micro Services +#include +#include + +// Qmitk +#include "QmitkDataStorageInspectorProviderBase.h" +#include "QmitkDataStorageListInspector.h" +#include "QmitkDataStorageTreeInspector.h" + +void MitkQtWidgetsActivator::Load(us::ModuleContext * /*context*/) +{ + m_TreeInspector.reset(new QmitkDataStorageInspectorProviderBase("org.mitk.QmitkDataStorageListInspector", "Simple list", "Displays the filtered content of the data storage in a simple list.")); + m_ListInspector.reset(new QmitkDataStorageInspectorProviderBase("org.mitk.QmitkDataStorageTreeInspector", "Rendering tree", "Displays the filtered content of the data storage as the current rendering tree. \n(Equals the old data manager view)")); +} + +void MitkQtWidgetsActivator::Unload(us::ModuleContext *) +{ +} + +US_EXPORT_MODULE_ACTIVATOR(MitkQtWidgetsActivator) \ No newline at end of file diff --git a/Modules/QtWidgets/src/mitkQtWidgetsActivator.h b/Modules/QtWidgets/src/mitkQtWidgetsActivator.h new file mode 100644 index 0000000000..5536b275d9 --- /dev/null +++ b/Modules/QtWidgets/src/mitkQtWidgetsActivator.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 MITKQTWIDGETSACTIVATOR_H_ +#define MITKQTWIDGETSACTIVATOR_H_ + +// Micro Services +#include +#include +#include +#include + +#include + +#include "QmitkIDataStorageInspectorProvider.h" + +/* + * This is the module activator for the "QtWidgets" module. + */ +class MitkQtWidgetsActivator : public us::ModuleActivator +{ +public: + void Load(us::ModuleContext *context) override; + void Unload(us::ModuleContext *) override; + +private: + std::unique_ptr m_TreeInspector; + std::unique_ptr m_ListInspector; + + us::ModuleContext *m_Context; +}; + +#endif // MITKCOREACTIVATOR_H_ diff --git a/Plugins/PluginList.cmake b/Plugins/PluginList.cmake index 03f3de6e54..ecfb25c700 100644 --- a/Plugins/PluginList.cmake +++ b/Plugins/PluginList.cmake @@ -1,102 +1,103 @@ # Plug-ins must be ordered according to their dependencies set(MITK_PLUGINS org.blueberry.core.runtime:ON org.blueberry.core.expressions:OFF org.blueberry.core.commands:OFF org.blueberry.core.jobs:OFF org.blueberry.ui.qt:OFF org.blueberry.ui.qt.help:ON org.blueberry.ui.qt.log:ON org.blueberry.ui.qt.objectinspector:OFF #org.blueberry.test:ON #org.blueberry.uitest:ON #Testing/org.blueberry.core.runtime.tests:ON #Testing/org.blueberry.osgi.tests:ON org.mitk.core.services:ON org.mitk.gui.common:ON org.mitk.planarfigure:ON org.mitk.core.ext:OFF org.mitk.core.jobs:OFF org.mitk.gui.qt.application:ON org.mitk.gui.qt.coreapplication:OFF org.mitk.gui.qt.ext:OFF org.mitk.gui.qt.extapplication:OFF org.mitk.gui.qt.common:ON org.mitk.gui.qt.stdmultiwidgeteditor:ON org.mitk.gui.qt.common.legacy:OFF org.mitk.gui.qt.cmdlinemodules:OFF org.mitk.gui.qt.diffusionimagingapp:OFF org.mitk.gui.qt.datamanager:ON org.mitk.gui.qt.datamanagerlight:OFF + org.mitk.gui.qt.datastorageviewertest:OFF org.mitk.gui.qt.properties:ON org.mitk.gui.qt.basicimageprocessing:OFF org.mitk.gui.qt.dicom:OFF org.mitk.gui.qt.dicominspector:OFF org.mitk.gui.qt.diffusionimaging:OFF org.mitk.gui.qt.diffusionimaging.connectomics:OFF org.mitk.gui.qt.diffusionimaging.denoising:OFF org.mitk.gui.qt.diffusionimaging.fiberfox:OFF org.mitk.gui.qt.diffusionimaging.fiberprocessing:OFF org.mitk.gui.qt.diffusionimaging.ivim:OFF org.mitk.gui.qt.diffusionimaging.odfpeaks:OFF org.mitk.gui.qt.diffusionimaging.partialvolume:OFF org.mitk.gui.qt.diffusionimaging.preprocessing:OFF org.mitk.gui.qt.diffusionimaging.reconstruction:OFF org.mitk.gui.qt.diffusionimaging.registration:OFF org.mitk.gui.qt.diffusionimaging.tbss:OFF org.mitk.gui.qt.diffusionimaging.tractography:OFF org.mitk.gui.qt.diffusionimaging.python:OFF org.mitk.gui.qt.dosevisualization:OFF org.mitk.gui.qt.geometrytools:OFF org.mitk.gui.qt.igtexamples:OFF org.mitk.gui.qt.igttracking:OFF org.mitk.gui.qt.lasercontrol:OFF org.mitk.gui.qt.openigtlink:OFF org.mitk.gui.qt.imagecropper:OFF org.mitk.gui.qt.imagenavigator:ON org.mitk.gui.qt.viewnavigator:OFF org.mitk.gui.qt.materialeditor:OFF org.mitk.gui.qt.measurementtoolbox:OFF org.mitk.gui.qt.moviemaker:OFF org.mitk.gui.qt.pointsetinteraction:OFF org.mitk.gui.qt.pointsetinteractionmultispectrum:OFF org.mitk.gui.qt.python:OFF org.mitk.gui.qt.remeshing:OFF org.mitk.gui.qt.segmentation:OFF org.mitk.gui.qt.aicpregistration:OFF org.mitk.gui.qt.renderwindowmanager:OFF org.mitk.gui.qt.toftutorial:OFF org.mitk.gui.qt.tofutil:OFF org.mitk.gui.qt.tubegraph:OFF org.mitk.gui.qt.ugvisualization:OFF org.mitk.gui.qt.photoacoustics.pausviewer:OFF org.mitk.gui.qt.photoacoustics.imageprocessing:OFF org.mitk.gui.qt.photoacoustics.simulation:OFF org.mitk.gui.qt.ultrasound:OFF org.mitk.gui.qt.volumevisualization:OFF org.mitk.gui.qt.eventrecorder:OFF org.mitk.gui.qt.xnat:OFF org.mitk.gui.qt.igt.app.echotrack:OFF org.mitk.gui.qt.spectrocamrecorder:OFF org.mitk.gui.qt.classificationsegmentation:OFF org.mitk.gui.qt.overlaymanager:OFF org.mitk.gui.qt.igt.app.hummelprotocolmeasurements:OFF org.mitk.gui.qt.multilabelsegmentation:OFF org.mitk.matchpoint.core.helper:OFF org.mitk.gui.qt.matchpoint.algorithm.browser:OFF org.mitk.gui.qt.matchpoint.algorithm.control:OFF org.mitk.gui.qt.matchpoint.algorithm.batch:OFF org.mitk.gui.qt.matchpoint.mapper:OFF org.mitk.gui.qt.matchpoint.framereg:OFF org.mitk.gui.qt.matchpoint.visualizer:OFF org.mitk.gui.qt.matchpoint.evaluator:OFF org.mitk.gui.qt.matchpoint.manipulator:OFF org.mitk.gui.qt.preprocessing.resampling:OFF org.mitk.gui.qt.cest:OFF ) diff --git a/Plugins/org.mitk.gui.qt.common/files.cmake b/Plugins/org.mitk.gui.qt.common/files.cmake index 14f29d65ff..00eee0b30e 100755 --- a/Plugins/org.mitk.gui.qt.common/files.cmake +++ b/Plugins/org.mitk.gui.qt.common/files.cmake @@ -1,38 +1,63 @@ set(SRC_CPP_FILES QmitkAbstractRenderEditor.cpp QmitkAbstractView.cpp QmitkDataNodeSelectionProvider.cpp QmitkDnDFrameWidget.cpp + QmitkSelectionServiceConnector.cpp QmitkSliceNavigationListener.cpp + QmitkSingleNodeSelectionWidget.cpp + QmitkNodeSelectionDialog.cpp + QmitkAbstractNodeSelectionWidget.cpp + QmitkMultiNodeSelectionWidget.cpp + QmitkNodeSelectionPreferenceHelper.cpp + QmitkNodeSelectionButton.cpp ) set(INTERNAL_CPP_FILES QmitkCommonActivator.cpp QmitkDataNodeItemModel.cpp QmitkDataNodeSelection.cpp QmitkViewCoordinator.cpp + QmitkNodeSelectionConstants.cpp + QmitkNodeSelectionPreferencePage.cpp +) + +set(UI_FILES + src/QmitkSingleNodeSelectionWidget.ui + src/QmitkMultiNodeSelectionWidget.ui + src/QmitkNodeSelectionDialog.ui + src/internal/QmitkNodeSelectionPreferencePage.ui ) set(MOC_H_FILES src/QmitkAbstractRenderEditor.h src/QmitkDnDFrameWidget.h + src/QmitkSelectionServiceConnector.h src/QmitkSliceNavigationListener.h src/ImporterUtil.h + src/QmitkSingleNodeSelectionWidget.h + src/QmitkNodeSelectionDialog.h + src/QmitkAbstractNodeSelectionWidget.h + src/QmitkMultiNodeSelectionWidget.h + src/QmitkNodeSelectionButton.h src/internal/QmitkCommonActivator.h + src/internal/QmitkNodeSelectionPreferencePage.h ) set(CACHED_RESOURCE_FILES + plugin.xml + resources/times.svg ) set(QRC_FILES ) set(CPP_FILES ) foreach(file ${SRC_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/${file}) endforeach(file ${SRC_CPP_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.common/plugin.xml b/Plugins/org.mitk.gui.qt.common/plugin.xml new file mode 100644 index 0000000000..e81a484d36 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/plugin.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/Plugins/org.mitk.gui.qt.common/resources/times.svg b/Plugins/org.mitk.gui.qt.common/resources/times.svg new file mode 100644 index 0000000000..571a32a122 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/resources/times.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkAbstractNodeSelectionWidget.cpp b/Plugins/org.mitk.gui.qt.common/src/QmitkAbstractNodeSelectionWidget.cpp new file mode 100644 index 0000000000..669c0b128f --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkAbstractNodeSelectionWidget.cpp @@ -0,0 +1,114 @@ +/*=================================================================== + +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 "QmitkAbstractNodeSelectionWidget.h" + +#include +#include + +QmitkAbstractNodeSelectionWidget::QmitkAbstractNodeSelectionWidget(QWidget* parent) : QWidget(parent), m_InvalidInfo("Error. Select data."), +m_EmptyInfo("Empty. Make a selection."), m_PopUpTitel("Select a data node"), m_PopUpHint(""), +m_IsOptional(false), m_SelectOnlyVisibleNodes(true) +{ +} + +void QmitkAbstractNodeSelectionWidget::SetDataStorage(mitk::DataStorage* dataStorage) +{ + if (m_DataStorage != dataStorage) + { + m_DataStorage = dataStorage; + } +}; + +void QmitkAbstractNodeSelectionWidget::SetNodePredicate(mitk::NodePredicateBase* nodePredicate) +{ + if (m_NodePredicate != nodePredicate) + { + m_NodePredicate = nodePredicate; + + this->OnNodePredicateChanged(nodePredicate); + this->UpdateInfo(); + } +}; + +mitk::NodePredicateBase* QmitkAbstractNodeSelectionWidget::GetNodePredicate() const +{ + return m_NodePredicate; +} + +QString QmitkAbstractNodeSelectionWidget::GetInvalidInfo() const +{ + return m_InvalidInfo; +}; + +QString QmitkAbstractNodeSelectionWidget::GetEmptyInfo() const +{ + return m_EmptyInfo; +}; + +QString QmitkAbstractNodeSelectionWidget::GetPopUpTitel() const +{ + return m_PopUpTitel; +}; + +QString QmitkAbstractNodeSelectionWidget::GetPopUpHint() const +{ + return m_PopUpHint; +}; + +bool QmitkAbstractNodeSelectionWidget::GetSelectionIsOptional() const +{ + return m_IsOptional; +}; + +bool QmitkAbstractNodeSelectionWidget::GetSelectOnlyVisibleNodes() const +{ + return m_SelectOnlyVisibleNodes; +}; + +void QmitkAbstractNodeSelectionWidget::SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes) +{ + m_SelectOnlyVisibleNodes = selectOnlyVisibleNodes; +}; + +void QmitkAbstractNodeSelectionWidget::SetInvalidInfo(QString info) +{ + m_InvalidInfo = info; + this->UpdateInfo(); +}; + +void QmitkAbstractNodeSelectionWidget::SetEmptyInfo(QString info) +{ + m_EmptyInfo = info; + this->UpdateInfo(); +}; + +void QmitkAbstractNodeSelectionWidget::SetPopUpTitel(QString info) +{ + m_PopUpTitel = info; +}; + +void QmitkAbstractNodeSelectionWidget::SetPopUpHint(QString info) +{ + m_PopUpHint = info; +}; + +void QmitkAbstractNodeSelectionWidget::SetSelectionIsOptional(bool isOptional) +{ + m_IsOptional = isOptional; + this->UpdateInfo(); +}; diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkAbstractNodeSelectionWidget.h b/Plugins/org.mitk.gui.qt.common/src/QmitkAbstractNodeSelectionWidget.h new file mode 100644 index 0000000000..0292dca521 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkAbstractNodeSelectionWidget.h @@ -0,0 +1,149 @@ +/*=================================================================== + +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 QMITK_ABSTRACT_NODE_SELECTION_WIDGET_H +#define QMITK_ABSTRACT_NODE_SELECTION_WIDGET_H + +#include + +#include +#include +#include + +#include "org_mitk_gui_qt_common_Export.h" + +#include + +class QmitkAbstractDataStorageModel; +class QAbstractItemVew; + +/** +* \class QmitkAbstractNodeSelectionWidget +* \brief Abstract base class for the selection of data from a data storage. +*/ +class MITK_QT_COMMON QmitkAbstractNodeSelectionWidget : public QWidget +{ + Q_OBJECT + +public: + explicit QmitkAbstractNodeSelectionWidget(QWidget* parent = nullptr); + + /** + * @brief Sets the data storage that will be used /monitored by widget. + * + * @par dataStorage A pointer to the data storage to set. + */ + void SetDataStorage(mitk::DataStorage* dataStorage); + + /** + * Sets the node predicate and updates the widget, according to the node predicate. + * Implement OnNodePredicateChange() for custom actualization of a derived widget class. + * + * @par nodePredicate A pointer to node predicate. + */ + void SetNodePredicate(mitk::NodePredicateBase* nodePredicate); + + mitk::NodePredicateBase* GetNodePredicate() const; + + QString GetInvalidInfo() const; + QString GetEmptyInfo() const; + QString GetPopUpTitel() const; + QString GetPopUpHint() const; + + bool GetSelectionIsOptional() const; + + bool GetSelectOnlyVisibleNodes() const; + + using NodeList = QList; + +Q_SIGNALS: + /* + * @brief A signal that will be emitted if the selected node has changed. + * + * @par nodes A list of data nodes that are newly selected. + */ + void CurrentSelectionChanged(QList nodes); + +public Q_SLOTS: + /* + * @brief Change the selection modus of the item view's selection model. + * + * If true, an incoming selection will be filtered (reduced) to only those nodes that are visible by the current view. + * An outgoing selection can then at most contain the filtered nodes. + * If false, the incoming non-visible selection will be stored and later added to the outgoing selection, + * to include the original selection that could not be modified. + * The part of the original selection, that is non-visible are the nodes that are not + * + * @par selectOnlyVisibleNodes The bool value to define the selection modus. + */ + virtual void SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes); + + /* + * @brief Transform a list of data nodes into a model selection and set this as a new selection of the + * selection model of the private member item view. + * + * The function filters the given list of nodes according to the 'm_SelectOnlyVisibleNodes' member variable. If + * necessary, the non-visible nodes are stored. This is done if 'm_SelectOnlyVisibleNodes' is false: In this case + * the selection may be filtered and only a subset of the selected nodes may be visible and therefore (de-)selectable + * in the data storage viewer. By storing the non-visible nodes it is possible to send the new, modified selection + * but also include the selected nodes from the original selection that could not be modified (see 'SetSelectOnlyVisibleNodes'). + * + * @par nodes A list of data nodes that should be newly selected. + */ + virtual void SetCurrentSelection(NodeList selectedNodes) = 0; + + /** Set the info text that should be displayed if no (valid) node is selected, + * but a selection is mandatory. + * The string can contain HTML code. if wanted*/ + void SetInvalidInfo(QString info); + + /** Set the info text that should be displayed if no (valid) node is selected, + * but a selection is optional. + * The string can contain HTML code. if wanted*/ + void SetEmptyInfo(QString info); + + /** Set the caption of the popup that is displayed to alter the selection. + * The string can contain HTML code. if wanted*/ + void SetPopUpTitel(QString info); + + /** Set the hint text of the popup that is displayed to alter the selection. + * The string can contain HTML code. if wanted*/ + void SetPopUpHint(QString info); + + /** Set the widget into an optional mode. Optional means that the selection of no valid + node does not mean an invalid state. Thus no node is a valid "node" selection too.*/ + void SetSelectionIsOptional(bool isOptional); + +protected: + /**Member is called if the display of the selected nodes should be updated.*/ + virtual void UpdateInfo() = 0; + + /**Member is called if the predicate has changed. Thus the selection might change to.*/ + virtual void OnNodePredicateChanged(mitk::NodePredicateBase* newPredicate) = 0; + + mitk::WeakPointer m_DataStorage; + mitk::NodePredicateBase::Pointer m_NodePredicate; + + QString m_InvalidInfo; + QString m_EmptyInfo; + QString m_PopUpTitel; + QString m_PopUpHint; + + bool m_IsOptional; + bool m_SelectOnlyVisibleNodes; +}; +#endif // QmitkAbstractNodeSelectionWidget_H diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkMultiNodeSelectionWidget.cpp b/Plugins/org.mitk.gui.qt.common/src/QmitkMultiNodeSelectionWidget.cpp new file mode 100644 index 0000000000..47b5f1d2cc --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkMultiNodeSelectionWidget.cpp @@ -0,0 +1,167 @@ +/*=================================================================== + +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 "QmitkMultiNodeSelectionWidget.h" + +#include +#include +#include + +QmitkMultiNodeSelectionWidget::QmitkMultiNodeSelectionWidget(QWidget* parent) : QmitkAbstractNodeSelectionWidget(parent) +{ + m_Controls.setupUi(this); + + this->UpdateList(); + this->UpdateInfo(); + + connect(m_Controls.btnChange, SIGNAL(clicked(bool)), this, SLOT(OnEditSelection())); +} + +QmitkMultiNodeSelectionWidget::NodeList QmitkMultiNodeSelectionWidget::CompileEmitSelection() const +{ + NodeList result; + + for (int i = 0; i < m_Controls.list->count(); ++i) + { + QListWidgetItem* item = m_Controls.list->item(i); + + auto node = item->data(Qt::UserRole).value(); + result.append(node); + } + + + if (!m_SelectOnlyVisibleNodes) + { + for (auto node : m_CurrentSelection) + { + if (!result.contains(node)) + { + result.append(node); + } + } + } + + return result; +} + +void QmitkMultiNodeSelectionWidget::OnNodePredicateChanged(mitk::NodePredicateBase* /*newPredicate*/) +{ + this->UpdateInfo(); + this->UpdateList(); +}; + +QmitkMultiNodeSelectionWidget::NodeList QmitkMultiNodeSelectionWidget::GetSelectedNodes() const +{ + return m_CurrentSelection; +}; + +void QmitkMultiNodeSelectionWidget::OnEditSelection() +{ + QmitkNodeSelectionDialog* dialog = new QmitkNodeSelectionDialog(this, m_PopUpTitel, m_PopUpHint); + + dialog->SetDataStorage(m_DataStorage.Lock()); + dialog->SetNodePredicate(m_NodePredicate); + dialog->SetCurrentSelection(this->CompileEmitSelection()); + dialog->SetSelectOnlyVisibleNodes(m_SelectOnlyVisibleNodes); + dialog->SetSelectionMode(QAbstractItemView::MultiSelection); + + m_Controls.btnChange->setChecked(true); + if (dialog->exec()) + { + auto lastEmission = this->CompileEmitSelection(); + + m_CurrentSelection = dialog->GetSelectedNodes(); + this->UpdateList(); + this->UpdateInfo(); + + auto newEmission = this->CompileEmitSelection(); + + if (!EqualNodeSelections(lastEmission, newEmission)) + { + emit CurrentSelectionChanged(newEmission); + } + } + m_Controls.btnChange->setChecked(false); + + delete dialog; +}; + +void QmitkMultiNodeSelectionWidget::UpdateInfo() +{ + m_Controls.infoLabel->setVisible(m_Controls.list->count()==0); + + if (!m_Controls.list->count()) + { + if (m_IsOptional) + { + m_Controls.infoLabel->setText(m_EmptyInfo); + } + else + { + m_Controls.infoLabel->setText(m_InvalidInfo); + } + } +}; + +void QmitkMultiNodeSelectionWidget::UpdateList() +{ + m_Controls.list->clear(); + + for (auto node : m_CurrentSelection) + { + if (m_NodePredicate.IsNull() || m_NodePredicate->CheckNode(node)) + { + QListWidgetItem *newItem = new QListWidgetItem; + newItem->setText(QString::fromStdString(node->GetName())); + newItem->setData(Qt::UserRole, QVariant::fromValue(node)); + + m_Controls.list->addItem(newItem); + } + } +}; + +void QmitkMultiNodeSelectionWidget::SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes) +{ + auto lastEmission = this->CompileEmitSelection(); + + m_SelectOnlyVisibleNodes = selectOnlyVisibleNodes; + + auto newEmission = this->CompileEmitSelection(); + + if (!EqualNodeSelections(lastEmission, newEmission)) + { + emit CurrentSelectionChanged(newEmission); + this->UpdateList(); + this->UpdateInfo(); + } +}; + +void QmitkMultiNodeSelectionWidget::SetCurrentSelection(NodeList selectedNodes) +{ + auto lastEmission = this->CompileEmitSelection(); + + m_CurrentSelection = selectedNodes; + this->UpdateList(); + + auto newEmission = this->CompileEmitSelection(); + + if (!EqualNodeSelections(lastEmission, newEmission)) + { + emit CurrentSelectionChanged(newEmission); + this->UpdateInfo(); + } +}; diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkMultiNodeSelectionWidget.h b/Plugins/org.mitk.gui.qt.common/src/QmitkMultiNodeSelectionWidget.h new file mode 100644 index 0000000000..d1f736be51 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkMultiNodeSelectionWidget.h @@ -0,0 +1,76 @@ +/*=================================================================== + +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 QMITK_MULTI_NODE_SELECTION_WIDGET_H +#define QMITK_MULTI_NODE_SELECTION_WIDGET_H + +#include + +#include +#include +#include + +#include "org_mitk_gui_qt_common_Export.h" + +#include "ui_QmitkMultiNodeSelectionWidget.h" + +#include + +class QmitkAbstractDataStorageModel; +class QAbstractItemVew; + +/** +* \class QmitkMultiNodeSelectionWidget +* \brief Widget that allows to show and edit the content of an mitk::IsoDoseLevel instance. +*/ +class MITK_QT_COMMON QmitkMultiNodeSelectionWidget : public QmitkAbstractNodeSelectionWidget +{ + Q_OBJECT + +public: + explicit QmitkMultiNodeSelectionWidget(QWidget* parent = nullptr); + + using NodeList = QmitkAbstractNodeSelectionWidget::NodeList; + + NodeList GetSelectedNodes() const; + +Q_SIGNALS: + /* + * @brief A signal that will be emitted if the selected node has changed. + * + * @par nodes A list of data nodes that are newly selected. + */ + void CurrentSelectionChanged(QList nodes); + + public Q_SLOTS: + virtual void SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes) override; + virtual void SetCurrentSelection(NodeList selectedNodes) override; + void OnEditSelection(); + +protected: + NodeList CompileEmitSelection() const; + + virtual void UpdateInfo() override; + virtual void UpdateList(); + + virtual void OnNodePredicateChanged(mitk::NodePredicateBase* newPredicate); + + NodeList m_CurrentSelection; + + Ui_QmitkMultiNodeSelectionWidget m_Controls; +}; +#endif // QmitkMultiNodeSelectionWidget_H diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkMultiNodeSelectionWidget.ui b/Plugins/org.mitk.gui.qt.common/src/QmitkMultiNodeSelectionWidget.ui new file mode 100644 index 0000000000..87eae80c7e --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkMultiNodeSelectionWidget.ui @@ -0,0 +1,92 @@ + + + QmitkMultiNodeSelectionWidget + + + + 0 + 0 + 391 + 265 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QAbstractItemView::NoEditTriggers + + + false + + + QAbstractItemView::NoDragDrop + + + Qt::MoveAction + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + + + + TextLabel + + + true + + + + + + + Change selection + + + true + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionButton.cpp b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionButton.cpp new file mode 100644 index 0000000000..fa21db2d4b --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionButton.cpp @@ -0,0 +1,163 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + + +#include "QmitkNodeSelectionButton.h" + +#include "QPainter" +#include "QTextDocument" + +#include +#include + + +// mitk core +#include +#include +#include +#include +#include +#include + +// vtk +#include + +QPixmap GetPixmapFromImageNode(const mitk::DataNode* dataNode, int height) +{ + if (nullptr == dataNode) + { + return QPixmap(); + } + + const mitk::Image* image = dynamic_cast(dataNode->GetData()); + if ((nullptr == image || !image->IsInitialized()) || // -> must be an image + (image->GetPixelType().GetNumberOfComponents() != 1)) // -> for now only single component are allowed + { + auto descManager = QmitkNodeDescriptorManager::GetInstance(); + auto desc = descManager->GetDescriptor(dataNode); + auto icon = desc->GetIcon(dataNode); + auto fallBackMap = icon.pixmap(height, height); + return fallBackMap; + } + + mitk::PlaneGeometry::Pointer planeGeometry = mitk::PlaneGeometry::New(); + int sliceNumber = image->GetDimension(2) / 2; + planeGeometry->InitializeStandardPlane(image->GetGeometry(), mitk::PlaneGeometry::Axial, sliceNumber); + + mitk::ExtractSliceFilter::Pointer extractSliceFilter = mitk::ExtractSliceFilter::New(); + extractSliceFilter->SetInput(image); + extractSliceFilter->SetInterpolationMode(mitk::ExtractSliceFilter::RESLICE_CUBIC); + extractSliceFilter->SetResliceTransformByGeometry(image->GetGeometry()); + extractSliceFilter->SetWorldGeometry(planeGeometry); + extractSliceFilter->SetOutputDimensionality(2); + extractSliceFilter->SetVtkOutputRequest(true); + extractSliceFilter->Update(); + + 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.scaledToHeight(height,Qt::SmoothTransformation).rgbSwapped(); + return QPixmap::fromImage(thumbnailImage); +} + +QmitkNodeSelectionButton::QmitkNodeSelectionButton(QWidget *parent) + : QPushButton(parent), m_OutDatedThumpNail(true) +{ } + +QmitkNodeSelectionButton::~QmitkNodeSelectionButton() +{ + this->m_SelectedNode = nullptr; +} + +void QmitkNodeSelectionButton::SetSelectedNode(mitk::DataNode* node) +{ + if (m_SelectedNode != node) + { + this->m_SelectedNode = node; //mitk::WeakPointer(node); + this->m_OutDatedThumpNail = true; + } + + this->update(); +}; + +void QmitkNodeSelectionButton::SetNodeInfo(QString info) +{ + this->m_Info = info; + this->update(); +}; + +void QmitkNodeSelectionButton::paintEvent(QPaintEvent *p) +{ + QPushButton::paintEvent(p); + + QPainter painter(this); + + QTextDocument td; + + auto widgetSize = this->size(); + QPoint origin = QPoint(5, 5); + + if (this->m_SelectedNode) + { + auto iconLength = widgetSize.height() - 10; + auto node = this->m_SelectedNode; // .Lock(); + + if (this->m_OutDatedThumpNail) + { + this->m_ThumpNail = GetPixmapFromImageNode(node, iconLength); + this->m_OutDatedThumpNail = false; + } + + painter.drawPixmap(origin, m_ThumpNail); + origin.setX(origin.x() + iconLength + 5); + + td.setHtml(QString::fromStdString(node->GetName())); + } + else + { + td.setHtml(m_Info); + } + + auto textSize = td.size(); + + origin.setY( (widgetSize.height() - textSize.height()) / 2.); + + painter.translate(origin); + td.drawContents(&painter); + +} diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionButton.h b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionButton.h new file mode 100644 index 0000000000..74ea357652 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionButton.h @@ -0,0 +1,56 @@ +/*=================================================================== + +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 QMITK_NODE_SELECTION_BUTTON_H +#define QMITK_NODE_SELECTION_BUTTON_H + +#include +#include + +#include "org_mitk_gui_qt_common_Export.h" + +#include "QPushButton" +#include "QPixmap" + + +/** Button class that can be used to display informations about a passed node. + * If the passed node is a null ptr the node info text will be shown. + * In difference to the normal push button text property. The node info can + * be formated text (e.g. HTML code; like the tooltip text).*/ +class MITK_QT_COMMON QmitkNodeSelectionButton : public QPushButton +{ + Q_OBJECT + +public: + explicit QmitkNodeSelectionButton(QWidget *parent = nullptr); + ~QmitkNodeSelectionButton(); + +public Q_SLOTS : + virtual void SetSelectedNode(mitk::DataNode* node); + virtual void SetNodeInfo(QString info); + +protected: + void paintEvent(QPaintEvent *p) override; + + mitk::DataNode::Pointer m_SelectedNode; + QString m_Info; + bool m_OutDatedThumpNail; + QPixmap m_ThumpNail; +}; + + +#endif // QmitkSingleNodeSelectionWidget_H diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionDialog.cpp b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionDialog.cpp new file mode 100644 index 0000000000..702baa98c9 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionDialog.cpp @@ -0,0 +1,185 @@ +/*=================================================================== + +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_Controls.setupUi(this); + + auto providers = QmitkDataStorageInspectorGenerator::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.common/src/QmitkNodeSelectionDialog.h b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionDialog.h new file mode 100644 index 0000000000..02f828bcc5 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionDialog.h @@ -0,0 +1,127 @@ +/*=================================================================== + +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 QMITK_NODE_SELECTION_DIALOG_H +#define QMITK_NODE_SELECTION_DIALOG_H + + +#include +#include +#include + +#include + +#include "org_mitk_gui_qt_common_Export.h" + +#include "ui_QmitkNodeSelectionDialog.h" + +#include + +/** +* \class QmitkNodeSelectionDialog +* \brief Widget that allows to show and edit the content of an mitk::IsoDoseLevel instance. +*/ +class MITK_QT_COMMON QmitkNodeSelectionDialog : public QDialog +{ + Q_OBJECT + +public: + explicit QmitkNodeSelectionDialog(QWidget* parent = nullptr, QString caption = "", QString hint = ""); + + /* + * @brief Sets the data storage that will be used /monitored by widget. + * + * @param dataStorage A pointer to the data storage to set. + */ + void SetDataStorage(mitk::DataStorage* dataStorage); + + /* + * @brief Sets the node predicate and updates the widget, according to the node predicate. + * + * @param nodePredicate A pointer to node predicate. + */ + virtual void SetNodePredicate(mitk::NodePredicateBase* nodePredicate); + + mitk::NodePredicateBase* GetNodePredicate() const; + + using NodeList = QList; + + NodeList GetSelectedNodes() const; + + bool GetSelectOnlyVisibleNodes() const; + + using SelectionMode = QAbstractItemView::SelectionMode; + void SetSelectionMode(SelectionMode mode); + SelectionMode GetSelectionMode() const; + +Q_SIGNALS: + /* + * @brief A signal that will be emitted if the selected node has changed. + * + * @param nodes A list of data nodes that are newly selected. + */ + void CurrentSelectionChanged(NodeList nodes); + + public Q_SLOTS: + /* + * @brief Change the selection modus of the item view's selection model. + * + * If true, an incoming selection will be filtered (reduced) to only those nodes that are visible by the current view. + * An outgoing selection can then at most contain the filtered nodes. + * If false, the incoming non-visible selection will be stored and later added to the outgoing selection, + * to include the original selection that could not be modified. + * The part of the original selection, that is non-visible are the nodes that are not + * + * @param selectOnlyVisibleNodes The bool value to define the selection modus. + */ + void SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes); + + /* + * @brief Transform a list of data nodes into a model selection and set this as a new selection of the + * selection model of the private member item view. + * + * The function filters the given list of nodes according to the 'm_SelectOnlyVisibleNodes' member variable. If + * necessary, the non-visible nodes are stored. This is done if 'm_SelectOnlyVisibleNodes' is false: In this case + * the selection may be filtered and only a subset of the selected nodes may be visible and therefore (de-)selectable + * in the data storage viewer. By storing the non-visible nodes it is possible to send the new, modified selection + * but also include the selected nodes from the original selection that could not be modified (see 'SetSelectOnlyVisibleNodes'). + * + * @param nodes A list of data nodes that should be newly selected. + */ + void SetCurrentSelection(NodeList selectedNodes); + +protected Q_SLOTS: + void OnSelectionChanged(NodeList selectedNodes); + void OnOK(); + void OnCancel(); + +protected: + void AddPanel(QmitkAbstractDataStorageInspector* view, QString name, QString desc); + + mitk::WeakPointer m_DataStorage; + mitk::NodePredicateBase::Pointer m_NodePredicate; + bool m_SelectOnlyVisibleNodes; + NodeList m_SelectedNodes; + + SelectionMode m_SelectionMode; + + using PanelVectorType = std::vector; + PanelVectorType m_Panels; + + Ui_QmitkNodeSelectionDialog m_Controls; +}; +#endif // QmitkNodeSelectionDialog_H diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionDialog.ui b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionDialog.ui new file mode 100644 index 0000000000..190293767e --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionDialog.ui @@ -0,0 +1,82 @@ + + + QmitkNodeSelectionDialog + + + + 0 + 0 + 596 + 539 + + + + Dialog + + + true + + + true + + + + 5 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 6 + + + 6 + + + 6 + + + + + QFrame::NoFrame + + + Info text ... + + + true + + + + + + + + + -1 + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionPreferenceHelper.cpp b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionPreferenceHelper.cpp new file mode 100644 index 0000000000..1e739cc705 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionPreferenceHelper.cpp @@ -0,0 +1,123 @@ +/*=================================================================== + +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 "QmitkNodeSelectionPreferenceHelper.h" + +#include + +#include + +#include +#include +#include + + +#include "mitkExceptionMacro.h" + +void mitk::PutVisibleDataStorageInspectors(const VisibleDataStorageInspectorMapType &inspectors) +{ + berry::IPreferencesService *prefService = berry::Platform::GetPreferencesService(); + berry::IPreferences::Pointer prefNode = + prefService->GetSystemPreferences()->Node(mitk::NodeSelectionConstants::ROOT_PREFERENCE_NODE_ID.c_str()); + berry::IPreferences::Pointer visNode = + prefNode->Node(mitk::NodeSelectionConstants::VISIBLE_INSPECTORS_NODE_ID.c_str()); + + visNode->RemoveNode(); + prefNode->Flush(); + + // new empty preset node + visNode = prefNode->Node(mitk::NodeSelectionConstants::VISIBLE_INSPECTORS_NODE_ID.c_str()); + + // store map in new node + for (const auto &inspector : inspectors) + { + std::ostringstream sstr; + sstr << inspector.first; + berry::IPreferences::Pointer aNode = visNode->Node(QString::fromStdString(sstr.str())); + + aNode->Put(mitk::NodeSelectionConstants::VISIBLE_INSPECTOR_ID.c_str(), inspector.second.c_str()); + aNode->Flush(); + } + + visNode->Flush(); +} + +mitk::VisibleDataStorageInspectorMapType mitk::GetVisibleDataStorageInspectors() +{ + berry::IPreferencesService *prefService = berry::Platform::GetPreferencesService(); + + berry::IPreferences::Pointer prefNode = + prefService->GetSystemPreferences()->Node(mitk::NodeSelectionConstants::ROOT_PREFERENCE_NODE_ID.c_str()); + berry::IPreferences::Pointer visNode = + prefNode->Node(mitk::NodeSelectionConstants::VISIBLE_INSPECTORS_NODE_ID.c_str()); + + typedef QStringList NamesType; + NamesType names = visNode->ChildrenNames(); + + VisibleDataStorageInspectorMapType visMap; + + if (!names.empty()) + { + for (NamesType::const_iterator pos = names.begin(); pos != names.end(); ++pos) + { + berry::IPreferences::Pointer aNode = visNode->Node(*pos); + + if (aNode.IsNull()) + { + mitkThrow() << "Error in preference interface. Cannot find preset node under given name. Name: " + << (*pos).toStdString(); + } + + std::istringstream isstr(pos->toStdString()); + unsigned int order = 0; + isstr >> order; + + auto id = aNode->Get(mitk::NodeSelectionConstants::VISIBLE_INSPECTOR_ID.c_str(), ""); + if (id.isEmpty()) + { + mitkThrow() << "Error in preference interface. ID of visible inspector is not set. Inspector position: " + << order; + } + + visMap.insert(std::make_pair(order, id.toStdString())); + } + } + return visMap; +} + +mitk::DataStorageInspectorIDType mitk::GetFavoriteDataStorageInspector() +{ + berry::IPreferencesService *prefService = berry::Platform::GetPreferencesService(); + + berry::IPreferences::Pointer prefNode = + prefService->GetSystemPreferences()->Node(mitk::NodeSelectionConstants::ROOT_PREFERENCE_NODE_ID.c_str()); + + auto id = prefNode->Get(mitk::NodeSelectionConstants::FAVORITE_INSPECTOR_ID.c_str(), ""); + + mitk::DataStorageInspectorIDType result = id.toStdString(); + return result; +} + +void mitk::PutFavoriteDataStorageInspector(const DataStorageInspectorIDType &id) +{ + berry::IPreferencesService *prefService = berry::Platform::GetPreferencesService(); + + berry::IPreferences::Pointer prefNode = + prefService->GetSystemPreferences()->Node(mitk::NodeSelectionConstants::ROOT_PREFERENCE_NODE_ID.c_str()); + + prefNode->Put(mitk::NodeSelectionConstants::FAVORITE_INSPECTOR_ID.c_str(), id.c_str()); + prefNode->Flush(); +} diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionPreferenceHelper.h b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionPreferenceHelper.h new file mode 100644 index 0000000000..09bc4a719c --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionPreferenceHelper.h @@ -0,0 +1,44 @@ +/*=================================================================== + +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 __QMITK_NODE_SELECTION_PREFERENCE_HELPER_H +#define __QMITK_NODE_SELECTION_PREFERENCE_HELPER_H + +#include +#include + +namespace mitk +{ + using DataStorageInspectorIDType = std::string; + + using VisibleDataStorageInspectorMapType = std::map; + + /** Stores the given ID as favorite inspector.*/ + void PutFavoriteDataStorageInspector(const DataStorageInspectorIDType& id); + + /** Gets the ID of the current favorite data storage inspector. + * If empty string is returned, no favorite is set.*/ + DataStorageInspectorIDType GetFavoriteDataStorageInspector(); + + /** Stores the given map of visible inspectors.*/ + void PutVisibleDataStorageInspectors(const VisibleDataStorageInspectorMapType& inspectors); + + /** Gets the map of current visible inspectors.*/ + VisibleDataStorageInspectorMapType GetVisibleDataStorageInspectors(); +} + +#endif diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkSelectionServiceConnector.cpp b/Plugins/org.mitk.gui.qt.common/src/QmitkSelectionServiceConnector.cpp new file mode 100644 index 0000000000..10a89c0be3 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkSelectionServiceConnector.cpp @@ -0,0 +1,130 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +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. + +===================================================================*/ + +// mitk gui qt common plugin +#include "QmitkSelectionServiceConnector.h" +#include "internal/QmitkDataNodeSelection.h" + +// qt widgets module +#include "QmitkCustomVariants.h" +#include "QmitkEnums.h" + +// blueberry ui qt plugin +#include + +QmitkSelectionServiceConnector::QmitkSelectionServiceConnector() + : m_SelectionService(nullptr) + , m_SelectionProvider(nullptr) +{ + m_DataNodeItemModel = std::make_shared(); + m_DataNodeSelectionModel = std::make_shared(m_DataNodeItemModel.get()); +} + +QmitkSelectionServiceConnector::~QmitkSelectionServiceConnector() +{ + RemovePostSelectionListener(); + RemoveAsSelectionProvider(); +} + +void QmitkSelectionServiceConnector::AddPostSelectionListener(berry::ISelectionService* selectionService) +{ + if (nullptr == selectionService) + { + return; + } + + m_SelectionService = selectionService; + m_BerrySelectionListener.reset(new berry::NullSelectionChangedAdapter(this, &QmitkSelectionServiceConnector::OnServiceSelectionChanged)); + m_SelectionService->AddPostSelectionListener(m_BerrySelectionListener.get()); +} + +void QmitkSelectionServiceConnector::RemovePostSelectionListener() +{ + if (nullptr == m_SelectionService) + { + return; + } + + m_SelectionService->RemovePostSelectionListener(m_BerrySelectionListener.get()); + m_SelectionService = nullptr; +} + +void QmitkSelectionServiceConnector::SetAsSelectionProvider(QmitkDataNodeSelectionProvider* selectionProvider) +{ + m_SelectionProvider = selectionProvider; +} + +void QmitkSelectionServiceConnector::RemoveAsSelectionProvider() +{ + m_SelectionProvider = nullptr; +} + +void QmitkSelectionServiceConnector::ChangeServiceSelection(QList nodes) +{ + if (nullptr == m_SelectionProvider) + { + return; + } + + m_SelectionProvider->SetItemSelectionModel(m_DataNodeSelectionModel.get()); + + if (nodes.empty()) + { + m_DataNodeSelectionModel->clearSelection(); + m_DataNodeItemModel->clear(); + } + else + { + m_DataNodeItemModel->clear(); + // fill the temporary helper data node item model with the nodes to select + for (const auto& node : nodes) + { + m_DataNodeItemModel->AddDataNode(node); + } + + m_DataNodeSelectionModel->select(QItemSelection(m_DataNodeItemModel->index(0, 0), m_DataNodeItemModel->index(nodes.size() - 1, 0)), QItemSelectionModel::ClearAndSelect); + } +} + +void QmitkSelectionServiceConnector::OnServiceSelectionChanged(const berry::IWorkbenchPart::Pointer& sourcePart, const berry::ISelection::ConstPointer& selection) +{ + if (sourcePart.IsNull()) + { + return; + } + + QList nodes; + if (selection.IsNull()) + { + // propagate an empty list + nodes = QList(); + } + + // transform valid selection to DataNodeSelection, which allows to retrieve the selected nodes + mitk::DataNodeSelection::ConstPointer dataNodeSelection = selection.Cast(); + if (dataNodeSelection.IsNull()) + { + // propagate an empty list + nodes = QList(); + } + else + { + nodes = QList::fromStdList(dataNodeSelection->GetSelectedDataNodes()); + } + + // send new (possibly empty) list of selected nodes + emit ServiceSelectionChanged(nodes); +} diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkSelectionServiceConnector.h b/Plugins/org.mitk.gui.qt.common/src/QmitkSelectionServiceConnector.h new file mode 100644 index 0000000000..21c1f8f7f1 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkSelectionServiceConnector.h @@ -0,0 +1,133 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +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 QMITKSELECTIONSERVICECONNECTOR_H +#define QMITKSELECTIONSERVICECONNECTOR_H + +#include + +// qt widgets module +#include + +// mitk gui qt common plugin +#include "QmitkDataNodeSelectionProvider.h" +#include "internal/QmitkDataNodeItemModel.h" + + // blueberry ui qt plugin +#include + +/* +* @brief The 'QmitkSelectionServiceConnector' is used to handle the selections of the global selection bus (selection service). +* +* The selection service connector can listen to a selection service. This should be done by using 'AddPostSelectionListener' +* with the existing selection service of the surrounding 'QmitkAbstractView'. +* The selection service connector can provide selections. This should be done by using 'SetAsSelectionProvider' +* with the existing selection provider of the surrounding 'QmitkAbstractView'. +* +* The 'QmitkSelectionServiceConnector' offers a public slot and signal that can be used to propagate the selected +* nodes from or to the global selection bus: +* The 'ChangeServiceSelection'-slot transforms the given list of selected nodes into a QItemSelection of a temporary +* data node selection model. This data node selection model is set as the item selection model of the member selection provider. +* So by temporary adding a new data node selection model and changing its selection the selection provider sends a new selection +* that can be received at any place in the workbench. +* +* The 'ServiceSelectionChanged'-signal sends a list of selected nodes to it's local environment (e.g. containing widget). +* The 'ServiceSelectionChanged'-signal is emitted by the 'ServiceSelectionChanged'-function, which transforms the +* berry selection of the selection into a data node list. The 'ServiceSelectionChanged'-function is called whenever +* the selection service sends a selection changed event. +* +* In order to connect the 'QmitkSelectionServiceConnector' with a model-view pair, a 'QmitkModelViewSelectionConnector' needs to be used: +* The 'QmitkModelViewSelectionConnector' offers a 'SetCurrentSelection'-slot that can be connected with the +* 'ServiceSelectionChanged'-signal of this class. +* The 'QmitkModelViewSelectionConnector' offers a 'CurrentSelectionChanged'-signal that can be connected with the +* 'ChangeServiceSelection'-slot of this class. +*/ +class MITK_QT_COMMON QmitkSelectionServiceConnector : public QObject +{ + Q_OBJECT + +public: + + QmitkSelectionServiceConnector(); + ~QmitkSelectionServiceConnector(); + + /* + * @brief Create a selection listener and add it to the list of selection listener of the given selection service. + * + * The selection listener is connected to the 'ServiceSelectionChanged' member function, which is + * called if a berry selection is changed in the workbench. + */ + void AddPostSelectionListener(berry::ISelectionService* selectionService); + /* + * @brief Remove a selection listener from the list of selection listener of the selection service member. + */ + void RemovePostSelectionListener(); + /* + * @brief Store the given selection provider as a private member. + * In order to use the public slot 'ChangeServiceSelection'-function, the selection provider member had to be + * previously set. + */ + void SetAsSelectionProvider(QmitkDataNodeSelectionProvider* selectionProvider); + /* + * @brief Set the selection provider member to a nullptr. This will prevent the public slot + * 'ChangeServiceSelection'-function from working. + */ + void RemoveAsSelectionProvider(); + +Q_SIGNALS: + /* + * @brief A signal that will be emitted by the private 'ServiceSelectionChanged'-function. This happens if a selection is changed + * via the selection service. + * + * @par nodes A list of data nodes that are newly selected. + */ + void ServiceSelectionChanged(QList nodes); + +public Q_SLOTS: + /* + * @brief Send new selections to the selection service via the private selection provider member. + * + * This slot-function is called whenever a local selection is changed in the surrounding widget and a selection provider was set. + * The newly selected data nodes are added temporary to a 'QmitkDataNodeItemModel', which is then used to define + * the indices to select. + * The 'QItemSelectionModel' is set as the item selection model of the selection provider member and its items are + * selected by the indices previously defined by the 'QmitkDataNodeItemModel'. + */ + void ChangeServiceSelection(QList nodes); + +private: + + std::unique_ptr m_BerrySelectionListener; + berry::ISelectionService* m_SelectionService; + QmitkDataNodeSelectionProvider* m_SelectionProvider; + std::shared_ptr m_DataNodeItemModel; + std::shared_ptr m_DataNodeSelectionModel; + + /* + * @brief Handle a selection received from the selection service. + * + * This function is called whenever a berry selection of the selection service is changed in the workbench. + * The new selection is transformed into a data node selection and the contained data nodes are propagated + * as the new current selection of the item view member. + * + * @par sourcePart The workbench part containing the selection. + * @par selection The current selection. + */ + void OnServiceSelectionChanged(const berry::IWorkbenchPart::Pointer& sourcePart, const berry::ISelection::ConstPointer& selection); + +}; + +#endif // QMITKSELECTIONSERVICECONNECTOR_H diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkSingleNodeSelectionWidget.cpp b/Plugins/org.mitk.gui.qt.common/src/QmitkSingleNodeSelectionWidget.cpp new file mode 100644 index 0000000000..7bfe3d420c --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkSingleNodeSelectionWidget.cpp @@ -0,0 +1,212 @@ +/*=================================================================== + +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 "QmitkSingleNodeSelectionWidget.h" + +#include +#include + +#include "QPainter" +#include "QTextDocument" + +QmitkSingleNodeSelectionWidget::QmitkSingleNodeSelectionWidget(QWidget* parent) : QmitkAbstractNodeSelectionWidget(parent) +{ + m_Controls.setupUi(this); + + m_Controls.btnSelect->installEventFilter(this); + m_Controls.btnSelect->setVisible(true); + m_Controls.btnClear->setVisible(false); + + this->UpdateInfo(); + + connect(m_Controls.btnClear, SIGNAL(clicked(bool)), this, SLOT(OnClearSelection())); +} + +QmitkSingleNodeSelectionWidget::~QmitkSingleNodeSelectionWidget() +{ +} + +mitk::DataNode::Pointer QmitkSingleNodeSelectionWidget::ExtractCurrentValidSelection(const NodeList& nodes) const +{ + mitk::DataNode::Pointer result = nullptr; + + for (auto node : nodes) + { + bool valid = true; + if (m_NodePredicate.IsNotNull()) + { + valid = m_NodePredicate->CheckNode(node); + } + if (valid) + { + result = node; + break; + } + } + + return result; +} + +QmitkSingleNodeSelectionWidget::NodeList QmitkSingleNodeSelectionWidget::CompileEmitSelection() const +{ + NodeList result; + + if (!m_SelectOnlyVisibleNodes) + { + result = m_ExternalSelection; + } + + if (m_SelectedNode.IsNotNull() && !result.contains(m_SelectedNode)) + { + result.append(m_SelectedNode); + } + + return result; +} + +void QmitkSingleNodeSelectionWidget::OnNodePredicateChanged(mitk::NodePredicateBase* /*newPredicate*/) +{ + m_SelectedNode = this->ExtractCurrentValidSelection(m_ExternalSelection); +}; + +void QmitkSingleNodeSelectionWidget::OnClearSelection() +{ + if (m_IsOptional) + { + NodeList emptyList; + this->SetCurrentSelection(emptyList); + } + + this->UpdateInfo(); +} + +mitk::DataNode::Pointer QmitkSingleNodeSelectionWidget::GetSelectedNode() const +{ + return m_SelectedNode; +}; + +bool QmitkSingleNodeSelectionWidget::eventFilter(QObject *obj, QEvent *ev) +{ + if (obj == m_Controls.btnSelect) + { + if (ev->type() == QEvent::MouseButtonRelease) + { + this->EditSelection(); + return true; + } + } + + return false; +} + +void QmitkSingleNodeSelectionWidget::EditSelection() +{ + QmitkNodeSelectionDialog* dialog = new QmitkNodeSelectionDialog(this, m_PopUpTitel, m_PopUpHint); + + dialog->SetDataStorage(m_DataStorage.Lock()); + dialog->SetNodePredicate(m_NodePredicate); + NodeList list; + if (m_SelectedNode.IsNotNull()) + { + list.append(m_SelectedNode); + } + dialog->SetCurrentSelection(list); + dialog->SetSelectOnlyVisibleNodes(m_SelectOnlyVisibleNodes); + dialog->SetSelectionMode(QAbstractItemView::SingleSelection); + + m_Controls.btnSelect->setChecked(true); + + if (dialog->exec()) + { + auto lastEmission = this->CompileEmitSelection(); + + auto nodes = dialog->GetSelectedNodes(); + if (nodes.empty()) + { + m_SelectedNode = nullptr; + } + else + { + m_SelectedNode = nodes.first(); + } + + auto newEmission = this->CompileEmitSelection(); + + if (!EqualNodeSelections(lastEmission, newEmission)) + { + emit CurrentSelectionChanged(newEmission); + this->UpdateInfo(); + } + } + + m_Controls.btnSelect->setChecked(false); + + delete dialog; +}; + +void QmitkSingleNodeSelectionWidget::UpdateInfo() +{ + if (m_SelectedNode.IsNull()) + { + if (m_IsOptional) + { + m_Controls.btnSelect->SetNodeInfo(m_EmptyInfo); + } + else + { + m_Controls.btnSelect->SetNodeInfo(m_InvalidInfo); + } + m_Controls.btnClear->setVisible(false); + } + else + { + m_Controls.btnClear->setVisible(m_IsOptional); + } + + m_Controls.btnSelect->SetSelectedNode(m_SelectedNode); +}; + +void QmitkSingleNodeSelectionWidget::SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes) +{ + auto lastEmission = this->CompileEmitSelection(); + + m_SelectOnlyVisibleNodes = selectOnlyVisibleNodes; + + auto newEmission = this->CompileEmitSelection(); + + if (!EqualNodeSelections(lastEmission, newEmission)) + { + emit CurrentSelectionChanged(newEmission); + this->UpdateInfo(); + } +}; + +void QmitkSingleNodeSelectionWidget::SetCurrentSelection(NodeList selectedNodes) +{ + auto lastEmission = this->CompileEmitSelection(); + + m_ExternalSelection = selectedNodes; + m_SelectedNode = this->ExtractCurrentValidSelection(selectedNodes); + + auto newEmission = this->CompileEmitSelection(); + + if (!EqualNodeSelections(lastEmission, newEmission)) + { + emit CurrentSelectionChanged(newEmission); + this->UpdateInfo(); + } +}; diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkSingleNodeSelectionWidget.h b/Plugins/org.mitk.gui.qt.common/src/QmitkSingleNodeSelectionWidget.h new file mode 100644 index 0000000000..9fbe2c040d --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkSingleNodeSelectionWidget.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 QMITK_SINGLE_NODE_SELECTION_WIDGET_H +#define QMITK_SINGLE_NODE_SELECTION_WIDGET_H + +#include + +#include +#include +#include + +#include "org_mitk_gui_qt_common_Export.h" + +#include "ui_QmitkSingleNodeSelectionWidget.h" + +#include +#include + +class QmitkAbstractDataStorageModel; + +/** +* \class QmitkSingleNodeSelectionWidget +* \brief Widget that that represents a node selection. It acts like a button. Clicking on it +* allows to change the selection. +*/ +class MITK_QT_COMMON QmitkSingleNodeSelectionWidget : public QmitkAbstractNodeSelectionWidget +{ + Q_OBJECT + +public: + explicit QmitkSingleNodeSelectionWidget(QWidget* parent = nullptr); + ~QmitkSingleNodeSelectionWidget(); + + mitk::DataNode::Pointer GetSelectedNode() const; + + using NodeList = QmitkAbstractNodeSelectionWidget::NodeList; + +Q_SIGNALS: + /* + * @brief A signal that will be emitted if the selected node has changed. + * + * @param nodes A list of data nodes that are newly selected. + */ + void CurrentSelectionChanged(QList nodes); + +public Q_SLOTS: + virtual void SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes) override; + virtual void SetCurrentSelection(NodeList selectedNodes) override; + +protected Q_SLOTS: + virtual void OnClearSelection(); + +protected: + mitk::DataNode::Pointer ExtractCurrentValidSelection(const NodeList& nodes) const; + NodeList CompileEmitSelection() const; + + virtual bool eventFilter(QObject *obj, QEvent *ev) override; + void EditSelection(); + virtual void UpdateInfo() override; + + virtual void OnNodePredicateChanged(mitk::NodePredicateBase* newPredicate); + + NodeList m_ExternalSelection; + mitk::DataNode::Pointer m_SelectedNode; + + Ui_QmitkSingleNodeSelectionWidget m_Controls; +}; + +#endif // QmitkSingleNodeSelectionWidget_H diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkSingleNodeSelectionWidget.ui b/Plugins/org.mitk.gui.qt.common/src/QmitkSingleNodeSelectionWidget.ui new file mode 100644 index 0000000000..7a13c0bbe2 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkSingleNodeSelectionWidget.ui @@ -0,0 +1,121 @@ + + + QmitkSingleNodeSelectionWidget + + + + 0 + 0 + 348 + 25 + + + + + 0 + 0 + + + + + 0 + 25 + + + + + 16777215 + 40 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 0 + 25 + + + + + + + true + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + + 25 + 16777215 + + + + Press to remove the current selection. + + + + + + + :/org.mitk.gui.qt.common/resources/times.svg:/org.mitk.gui.qt.common/resources/times.svg + + + + 19 + 19 + + + + + + + + + QmitkNodeSelectionButton + QPushButton +
QmitkNodeSelectionButton.h
+
+
+ + +
diff --git a/Plugins/org.mitk.gui.qt.common/src/internal/QmitkCommonActivator.cpp b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkCommonActivator.cpp index 8116c685e3..188d1d6738 100644 --- a/Plugins/org.mitk.gui.qt.common/src/internal/QmitkCommonActivator.cpp +++ b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkCommonActivator.cpp @@ -1,70 +1,73 @@ /*=================================================================== 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 "QmitkCommonActivator.h" #include #include +#include "QmitkNodeSelectionPreferencePage.h" QmitkCommonActivator* QmitkCommonActivator::m_Instance = nullptr; ctkPluginContext* QmitkCommonActivator::m_Context = nullptr; ctkPluginContext* QmitkCommonActivator::GetContext() { return m_Context; } QmitkCommonActivator* QmitkCommonActivator::GetInstance() { return m_Instance; } berry::IPreferencesService* QmitkCommonActivator::GetPreferencesService() { return m_PrefServiceTracker->getService(); } void QmitkCommonActivator::start(ctkPluginContext* context) { this->m_Instance = this; this->m_Context = context; this->m_PrefServiceTracker.reset(new ctkServiceTracker(context)); if(berry::PlatformUI::IsWorkbenchRunning()) { m_ViewCoordinator.reset(new QmitkViewCoordinator); m_ViewCoordinator->Start(); } else { MITK_ERROR << "BlueBerry Workbench not running!"; } + + BERRY_REGISTER_EXTENSION_CLASS(QmitkNodeSelectionPreferencePage, context) } void QmitkCommonActivator::stop(ctkPluginContext* context) { Q_UNUSED(context) m_ViewCoordinator->Stop(); m_ViewCoordinator.reset(); this->m_PrefServiceTracker.reset(); this->m_Context = nullptr; this->m_Instance = nullptr; } diff --git a/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionConstants.cpp b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionConstants.cpp new file mode 100644 index 0000000000..2f6a3ceaf1 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionConstants.cpp @@ -0,0 +1,22 @@ +/*=================================================================== + +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 "QmitkNodeSelectionConstants.h" + +const std::string mitk::NodeSelectionConstants::ROOT_PREFERENCE_NODE_ID = "/NODESELECTION/UI"; +const std::string mitk::NodeSelectionConstants::VISIBLE_INSPECTORS_NODE_ID = "visibleInspectors"; +const std::string mitk::NodeSelectionConstants::FAVORITE_INSPECTOR_ID = "inspectorID"; +const std::string mitk::NodeSelectionConstants::VISIBLE_INSPECTOR_ID = "inspectorID"; diff --git a/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionConstants.h b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionConstants.h new file mode 100644 index 0000000000..170ec1840c --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionConstants.h @@ -0,0 +1,51 @@ +/*=================================================================== + +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 _QMITK_NODE_SELECTION_CONSTANTS_H_ +#define _QMITK_NODE_SELECTION_CONSTANTS_H_ + +#include + +#include "org_mitk_gui_qt_common_Export.h" + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4251) +#endif + +namespace mitk +{ +struct MITK_QT_COMMON NodeSelectionConstants +{ + /** ID/Path of main preference node for node selections. */ + static const std::string ROOT_PREFERENCE_NODE_ID; + + /** ID of main preference node where all visible inspectors are stored (e.g. ROOT_PREFERENCE_NODE_ID+"/"+VISIBLE_INSPECTORS_NODE_ID+"/[orderering #]"). + The sub node naming encodes the ordering number of the visible inspector.*/ + static const std::string VISIBLE_INSPECTORS_NODE_ID; + /** ID for the value that stores the favorite inspector ID in the root preference node.*/ + static const std::string FAVORITE_INSPECTOR_ID; + /** ID for the value that stores the inspector ID in the preference node.*/ + static const std::string VISIBLE_INSPECTOR_ID; +}; + +} + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif diff --git a/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionPreferencePage.cpp b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionPreferencePage.cpp new file mode 100644 index 0000000000..86fe16b1de --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionPreferencePage.cpp @@ -0,0 +1,198 @@ +/*=================================================================== + +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 "QmitkNodeSelectionPreferencePage.h" + +#include "QmitkNodeSelectionPreferenceHelper.h" + +//----------------------------------------------------------------------------- +QmitkNodeSelectionPreferencePage::QmitkNodeSelectionPreferencePage() + : m_MainControl(0), m_Controls(0) +{ + +} + + +//----------------------------------------------------------------------------- +QmitkNodeSelectionPreferencePage::~QmitkNodeSelectionPreferencePage() +{ + delete m_Controls; +} + + +//----------------------------------------------------------------------------- +void QmitkNodeSelectionPreferencePage::Init(berry::IWorkbench::Pointer ) +{ + +} + + +//----------------------------------------------------------------------------- +void QmitkNodeSelectionPreferencePage::CreateQtControl(QWidget* parent) +{ + m_MainControl = new QWidget(parent); + m_Controls = new Ui::QmitkNodeSelectionPreferencePage; + m_Controls->setupUi( m_MainControl ); + + connect(m_Controls->comboFavorite, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateWidgets())); + connect(m_Controls->btnUp, SIGNAL(clicked(bool)), this, SLOT(MoveUp())); + connect(m_Controls->btnDown, SIGNAL(clicked(bool)), this, SLOT(MoveDown())); + connect(m_Controls->listInspectors, SIGNAL(itemSelectionChanged()), this, SLOT(UpdateWidgets())); + + this->Update(); +} + + +//----------------------------------------------------------------------------- +QWidget* QmitkNodeSelectionPreferencePage::GetQtControl() const +{ + return m_MainControl; +} + +//----------------------------------------------------------------------------- +bool QmitkNodeSelectionPreferencePage::PerformOk() +{ + //store favorite + auto id = m_Controls->comboFavorite->currentData().toString(); + mitk::PutFavoriteDataStorageInspector(id.toStdString()); + + //store visible + mitk::VisibleDataStorageInspectorMapType visibles; + + unsigned int visiblePos = 0; + + for (int i = 0; i < m_Controls->listInspectors->count(); ++i) + { + auto item = m_Controls->listInspectors->item(i); + if (item->checkState() == Qt::Checked) + { + visibles.insert(std::make_pair(visiblePos++, item->data(Qt::UserRole).toString().toStdString())); + } + } + mitk::PutVisibleDataStorageInspectors(visibles); + + return true; +} + + +//----------------------------------------------------------------------------- +void QmitkNodeSelectionPreferencePage::PerformCancel() +{ +} + + +//----------------------------------------------------------------------------- +void QmitkNodeSelectionPreferencePage::Update() +{ + m_Providers = QmitkDataStorageInspectorGenerator::GetProviders(); + + auto visibleProviders = mitk::GetVisibleDataStorageInspectors(); + auto allProviders = QmitkDataStorageInspectorGenerator::GetProviders(); + auto favorite = mitk::GetFavoriteDataStorageInspector(); + + auto finding = m_Providers.find(favorite); + if (finding == m_Providers.cend()) + { + favorite = m_Providers.begin()->first; + } + + //fill favorite combo + int index = 0; + int currentIndex = 0; + m_Controls->comboFavorite->clear(); + for (auto iter : m_Providers) + { + m_Controls->comboFavorite->addItem(QString::fromStdString(iter.second->GetInspectorDisplayName()),QVariant::fromValue(QString::fromStdString(iter.first))); + if (iter.first == favorite) + { + currentIndex = index; + }; + ++index; + } + m_Controls->comboFavorite->setCurrentIndex(currentIndex); + + //fill inspector list + m_Controls->listInspectors->clear(); + for (const auto iter : allProviders) + { + auto currentID = iter.first; + QListWidgetItem* item = new QListWidgetItem; + item->setText(QString::fromStdString(iter.second->GetInspectorDisplayName())); + item->setData(Qt::UserRole, QVariant::fromValue(QString::fromStdString(currentID))); + item->setToolTip(QString::fromStdString(iter.second->GetInspectorDescription())); + + auto finding = std::find_if(visibleProviders.cbegin(), visibleProviders.cend(), [¤tID](auto v) {return v.second == currentID; }); + if (finding == visibleProviders.cend()) + { + item->setCheckState(Qt::Unchecked); + m_Controls->listInspectors->addItem(item); + } + else + { + item->setCheckState(Qt::Checked); + m_Controls->listInspectors->insertItem(finding->first, item); + } + } + + this->UpdateWidgets(); +} + +void QmitkNodeSelectionPreferencePage::UpdateWidgets() +{ + int currentIndex = m_Controls->listInspectors->currentRow(); + m_Controls->btnUp->setEnabled(!m_Controls->listInspectors->selectedItems().empty() && currentIndex > 0); + m_Controls->btnDown->setEnabled(!m_Controls->listInspectors->selectedItems().empty() && currentIndex + 1 < m_Controls->listInspectors->count()); + + for (int i = 0; i < m_Controls->listInspectors->count(); ++i) + { + auto item = m_Controls->listInspectors->item(i); + if (item->data(Qt::UserRole).toString() == m_Controls->comboFavorite->currentData().toString()) + { + //favorites are always visible. + item->setCheckState(Qt::Checked); + item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled); + } + else + { + item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsUserCheckable); + } + } +}; + +void QmitkNodeSelectionPreferencePage::MoveDown() +{ + int currentIndex = m_Controls->listInspectors->currentRow(); + if (currentIndex+1 < m_Controls->listInspectors->count()) + { + QListWidgetItem *currentItem = m_Controls->listInspectors->takeItem(currentIndex); + m_Controls->listInspectors->insertItem(currentIndex + 1, currentItem); + m_Controls->listInspectors->setCurrentRow(currentIndex + 1); + } + this->UpdateWidgets(); +}; + +void QmitkNodeSelectionPreferencePage::MoveUp() +{ + int currentIndex = m_Controls->listInspectors->currentRow(); + if (currentIndex > 0) + { + QListWidgetItem *currentItem = m_Controls->listInspectors->takeItem(currentIndex); + m_Controls->listInspectors->insertItem(currentIndex - 1, currentItem); + m_Controls->listInspectors->setCurrentRow(currentIndex - 1); + } + this->UpdateWidgets(); +}; diff --git a/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionPreferencePage.h b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionPreferencePage.h new file mode 100644 index 0000000000..2e959c43c5 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionPreferencePage.h @@ -0,0 +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 __QMITK_NODE_SELECTION_PREFERENCE_PAGE_H +#define __QMITK_NODE_SELECTION_PREFERENCE_PAGE_H + +#include "berryIQtPreferencePage.h" +#include "berryIPreferences.h" + +#include "QmitkDataStorageInspectorGenerator.h" + +#include "ui_QmitkNodeSelectionPreferencePage.h" + +class QWidget; + +/** +* \class QmitkNodeSelectionPreferencePage +* \brief Preference page for general node selection settings. +*/ +class QmitkNodeSelectionPreferencePage : public QObject, public berry::IQtPreferencePage +{ + Q_OBJECT + Q_INTERFACES(berry::IPreferencePage) + +public: + QmitkNodeSelectionPreferencePage(); + ~QmitkNodeSelectionPreferencePage(); + + /** + * \brief Called by framework to initialize this preference page, but currently does nothing. + * \param workbench The workbench. + */ + void Init(berry::IWorkbench::Pointer workbench); + + /** + * \brief Called by framework to create the GUI, and connect signals and slots. + * \param widget The Qt widget that acts as parent to all GUI components, as this class itself is not derived from QWidget. + */ + void CreateQtControl(QWidget* widget); + + /** + * \brief Required by framework to get hold of the GUI. + * \return QWidget* the top most QWidget for the GUI. + */ + QWidget* GetQtControl() const; + + /** + * \see IPreferencePage::PerformOk + */ + virtual bool PerformOk(); + + /** + * \see IPreferencePage::PerformCancel + */ + virtual void PerformCancel(); + + /** + * \see IPreferencePage::Update + */ + virtual void Update(); + +protected slots: + + void UpdateWidgets(); + void MoveDown(); + void MoveUp(); + +protected: + + QWidget *m_MainControl; + Ui::QmitkNodeSelectionPreferencePage* m_Controls; + + QmitkDataStorageInspectorGenerator::ProviderMapType m_Providers; + +}; + +#endif diff --git a/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionPreferencePage.ui b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionPreferencePage.ui new file mode 100644 index 0000000000..c88f7330f2 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionPreferencePage.ui @@ -0,0 +1,145 @@ + + + QmitkNodeSelectionPreferencePage + + + + 0 + 0 + 715 + 713 + + + + Form + + + + + + + + Up + + + + + + + Down + + + + + + + + + Favorite inspector: + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + <html><head/><body><p>The favorite inspector is always visible.</p><p>Additionally the favorite inspector has always the focus when opening a node selection dialoge.</p></body></html> + + + + Neues Element + + + + + 2 + + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Instruction:</span><br/>Only checked inspectors will be shown in node selection dialogs.<br/>You may change the order in the inspector list, to change the order of the tabs in the node selection dialog.</p></body></html> + + + true + + + + + + + + + Inspector visiblitiy and order: + + + + + + + + 16777215 + 16777215 + + + + List of all available inspectors. Checked inspectores will be display + + + + TreeInspector + + + ffffff + + + Checked + + + + + List + + + Checked + + + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.datastorageviewertest/CMakeLists.txt b/Plugins/org.mitk.gui.qt.datastorageviewertest/CMakeLists.txt new file mode 100644 index 0000000000..add23310bd --- /dev/null +++ b/Plugins/org.mitk.gui.qt.datastorageviewertest/CMakeLists.txt @@ -0,0 +1,7 @@ +project(org_mitk_gui_qt_datastorageviewertest) + +mitk_create_plugin( + EXPORT_DIRECTIVE DATASTORAGEVIEWERTEST_EXPORT + EXPORTED_INCLUDE_SUFFIXES src + MODULE_DEPENDS MitkQtWidgets +) diff --git a/Plugins/org.mitk.gui.qt.datastorageviewertest/files.cmake b/Plugins/org.mitk.gui.qt.datastorageviewertest/files.cmake new file mode 100644 index 0000000000..7346b84a06 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.datastorageviewertest/files.cmake @@ -0,0 +1,32 @@ +set(SRC_CPP_FILES +) + +set(INTERNAL_CPP_FILES + mitkPluginActivator.cpp + QmitkDataStorageViewerTestView.cpp +) + +set(UI_FILES + src/internal/QmitkDataStorageViewerTestControls.ui +) + +set(MOC_H_FILES + src/internal/mitkPluginActivator.h + src/internal/QmitkDataStorageViewerTestView.h +) + +set(CACHED_RESOURCE_FILES + resources/DataStorageViewer_48.png + plugin.xml +) + +set(QRC_FILES +) + +foreach(file ${SRC_CPP_FILES}) + set(CPP_FILES ${CPP_FILES} src/${file}) +endforeach(file ${SRC_CPP_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.datastorageviewertest/manifest_headers.cmake b/Plugins/org.mitk.gui.qt.datastorageviewertest/manifest_headers.cmake new file mode 100644 index 0000000000..3189816295 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.datastorageviewertest/manifest_headers.cmake @@ -0,0 +1,5 @@ +set(Plugin-Name "MITK Data storage viewer test") +set(Plugin-Version "0.1") +set(Plugin-Vendor "DKFZ") +set(Plugin-ContactAddress "http://www.mitk.org") +set(Require-Plugin org.mitk.gui.qt.common) diff --git a/Plugins/org.mitk.gui.qt.datastorageviewertest/plugin.xml b/Plugins/org.mitk.gui.qt.datastorageviewertest/plugin.xml new file mode 100644 index 0000000000..9b1f6fd52c --- /dev/null +++ b/Plugins/org.mitk.gui.qt.datastorageviewertest/plugin.xml @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.datastorageviewertest/resources/DataStorageViewer_48.png b/Plugins/org.mitk.gui.qt.datastorageviewertest/resources/DataStorageViewer_48.png new file mode 100644 index 0000000000..d297828a0d Binary files /dev/null and b/Plugins/org.mitk.gui.qt.datastorageviewertest/resources/DataStorageViewer_48.png differ diff --git a/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/QmitkDataStorageViewerTestControls.ui b/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/QmitkDataStorageViewerTestControls.ui new file mode 100644 index 0000000000..66866a9712 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/QmitkDataStorageViewerTestControls.ui @@ -0,0 +1,158 @@ + + + QmitkDataStorageViewerTestControls + + + + 0 + 0 + 945 + 728 + + + + + 0 + 0 + + + + Data storage viewer test + + + + + + + + + + + + Set as selection provider + + + + + + + Set as selection provider + + + + + + + Set as selection listener + + + + + + + Set as selection listener + + + + + + + + 0 + 40 + + + + + + + + + + + Set as selection provider + + + + + + + Set as selection listner + + + + + + + Only valid nodes + + + + + + + Allow only images + + + + + + + Is Optional + + + + + + + Set as selection provider + + + + + + + Set as selection listner + + + + + + + Only valid nodes + + + + + + + Allow only images + + + + + + + Is Optional + + + + + + + + QmitkSingleNodeSelectionWidget + QWidget +
QmitkSingleNodeSelectionWidget.h
+ 1 +
+ + QmitkMultiNodeSelectionWidget + QWidget +
QmitkMultiNodeSelectionWidget.h
+ 1 +
+
+ + +
diff --git a/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/QmitkDataStorageViewerTestView.cpp b/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/QmitkDataStorageViewerTestView.cpp new file mode 100644 index 0000000000..dbe3bd1cc8 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/QmitkDataStorageViewerTestView.cpp @@ -0,0 +1,247 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +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. + +===================================================================*/ + +// data storage viewer test plugin +#include "QmitkDataStorageViewerTestView.h" + +#include "mitkNodePredicateDataType.h" + +// berry +#include + +// qt +#include + +const std::string QmitkDataStorageViewerTestView::VIEW_ID = "org.mitk.views.datastorageviewertest"; + +void QmitkDataStorageViewerTestView::SetFocus() +{ + // nothing here +} + +void QmitkDataStorageViewerTestView::CreateQtPartControl(QWidget* parent) +{ + // create GUI widgets + m_Controls.setupUi(parent); + + m_DataStorageDefaultListModel = new QmitkDataStorageDefaultListModel(this); + m_DataStorageDefaultListModel->SetDataStorage(GetDataStorage()); + m_Controls.selectionListView->setSelectionMode(QAbstractItemView::ExtendedSelection); + m_Controls.selectionListView->setSelectionBehavior(QAbstractItemView::SelectRows); + m_Controls.selectionListView->setAlternatingRowColors(true); + m_Controls.selectionListView->setModel(m_DataStorageDefaultListModel); + + m_DataStorageDefaultListModel2 = new QmitkDataStorageDefaultListModel(this); + m_DataStorageDefaultListModel2->SetDataStorage(GetDataStorage()); + m_Controls.selectionListView2->setSelectionMode(QAbstractItemView::ExtendedSelection); + m_Controls.selectionListView2->setSelectionBehavior(QAbstractItemView::SelectRows); + m_Controls.selectionListView2->setAlternatingRowColors(true); + m_Controls.selectionListView2->setModel(m_DataStorageDefaultListModel2); + + m_Controls.singleSlot->SetDataStorage(GetDataStorage()); + m_Controls.singleSlot->SetEmptyInfo(QString("EmptyInfo: Set this to display info in empty state")); + m_Controls.singleSlot->SetInvalidInfo(QString("InvalidInfo: is displayed for invalid states")); + m_Controls.singleSlot->SetPopUpTitel(QString("This is the definable caption. Choose your data now!")); + m_Controls.singleSlot->SetPopUpHint(QString("I am an optional hint, that can be set by the developer

If not set the widget is invisible.")); + + m_Controls.multiSlot->SetDataStorage(GetDataStorage()); + m_Controls.multiSlot->SetEmptyInfo(QString("EmptyInfo: Set this to display info in empty state")); + m_Controls.multiSlot->SetInvalidInfo(QString("InvalidInfo: is displayed for invalid states")); + m_Controls.multiSlot->SetPopUpTitel(QString("This is the definable caption. Choose your data now!")); + m_Controls.multiSlot->SetPopUpHint(QString("I am an optional hint, that can be set by the developer

If not set the widget is invisible.")); + + m_ModelViewSelectionConnector = std::make_unique(); + try + { + m_ModelViewSelectionConnector->SetView(m_Controls.selectionListView); + } + catch (mitk::Exception& e) + { + mitkReThrow(e) << "Cannot connect the model-view pair signals and slots."; + } + m_SelectionServiceConnector = std::make_unique(); + + m_ModelViewSelectionConnector2 = std::make_unique(); + try + { + m_ModelViewSelectionConnector2->SetView(m_Controls.selectionListView2); + } + catch (mitk::Exception& e) + { + mitkReThrow(e) << "Cannot connect the model-view pair signals and slots."; + } + m_SelectionServiceConnector2 = std::make_unique(); + + m_SelectionServiceConnector3 = std::make_unique(); + m_SelectionServiceConnector4 = std::make_unique(); + + connect(m_Controls.selectionProviderCheckBox, SIGNAL(toggled(bool)), this, SLOT(SetAsSelectionProvider1(bool))); + connect(m_Controls.selectionProviderCheckBox2, SIGNAL(toggled(bool)), this, SLOT(SetAsSelectionProvider2(bool))); + + connect(m_Controls.selectionListenerCheckBox, SIGNAL(toggled(bool)), this, SLOT(SetAsSelectionListener1(bool))); + connect(m_Controls.selectionListenerCheckBox2, SIGNAL(toggled(bool)), this, SLOT(SetAsSelectionListener2(bool))); + + connect(m_Controls.selectionProviderCheckBox3, SIGNAL(toggled(bool)), this, SLOT(SetAsSelectionProvider3(bool))); + connect(m_Controls.selectionListenerCheckBox3, SIGNAL(toggled(bool)), this, SLOT(SetAsSelectionListener3(bool))); + + connect(m_Controls.checkOnlyVisible, SIGNAL(toggled(bool)), m_Controls.singleSlot, SLOT(SetSelectOnlyVisibleNodes(bool))); + connect(m_Controls.checkOptional, SIGNAL(toggled(bool)), m_Controls.singleSlot, SLOT(SetSelectionIsOptional(bool))); + connect(m_Controls.checkOnlyImages, SIGNAL(toggled(bool)), this, SLOT(OnOnlyImages(bool))); + + connect(m_Controls.selectionProviderCheckBox4, SIGNAL(toggled(bool)), this, SLOT(SetAsSelectionProvider4(bool))); + connect(m_Controls.selectionListenerCheckBox4, SIGNAL(toggled(bool)), this, SLOT(SetAsSelectionListener4(bool))); + + connect(m_Controls.checkOnlyVisible_2, SIGNAL(toggled(bool)), m_Controls.multiSlot, SLOT(SetSelectOnlyVisibleNodes(bool))); + connect(m_Controls.checkOptional_2, SIGNAL(toggled(bool)), m_Controls.multiSlot, SLOT(SetSelectionIsOptional(bool))); + connect(m_Controls.checkOnlyImages_2, SIGNAL(toggled(bool)), this, SLOT(OnOnlyImages2(bool))); +} + +void QmitkDataStorageViewerTestView::SetAsSelectionProvider1(bool checked) +{ + if (checked) + { + m_SelectionServiceConnector->SetAsSelectionProvider(GetSite()->GetSelectionProvider().Cast().GetPointer()); + connect(m_ModelViewSelectionConnector.get(), SIGNAL(CurrentSelectionChanged(QList)), m_SelectionServiceConnector.get(), SLOT(ChangeServiceSelection(QList))); + } + else + { + m_SelectionServiceConnector->RemoveAsSelectionProvider(); + disconnect(m_ModelViewSelectionConnector.get(), SIGNAL(CurrentSelectionChanged(QList)), m_SelectionServiceConnector.get(), SLOT(ChangeServiceSelection(QList))); + } +} + +void QmitkDataStorageViewerTestView::SetAsSelectionListener1(bool checked) +{ + if (checked) + { + m_SelectionServiceConnector->AddPostSelectionListener(GetSite()->GetWorkbenchWindow()->GetSelectionService()); + connect(m_SelectionServiceConnector.get(), SIGNAL(ServiceSelectionChanged(QList)), m_ModelViewSelectionConnector.get(), SLOT(SetCurrentSelection(QList))); + } + else + { + m_SelectionServiceConnector->RemovePostSelectionListener(); + disconnect(m_SelectionServiceConnector.get(), SIGNAL(ServiceSelectionChanged(QList)), m_ModelViewSelectionConnector.get(), SLOT(SetCurrentSelection(QList))); + + } +} + +void QmitkDataStorageViewerTestView::SetAsSelectionProvider2(bool checked) +{ + if (checked) + { + m_SelectionServiceConnector2->SetAsSelectionProvider(GetSite()->GetSelectionProvider().Cast().GetPointer()); + connect(m_ModelViewSelectionConnector2.get(), SIGNAL(CurrentSelectionChanged(QList)), m_SelectionServiceConnector2.get(), SLOT(ChangeServiceSelection(QList))); + } + else + { + m_SelectionServiceConnector2->RemoveAsSelectionProvider(); + disconnect(m_ModelViewSelectionConnector2.get(), SIGNAL(CurrentSelectionChanged(QList)), m_SelectionServiceConnector2.get(), SLOT(ChangeServiceSelection(QList))); + } +} + +void QmitkDataStorageViewerTestView::SetAsSelectionListener2(bool checked) +{ + if (checked) + { + m_SelectionServiceConnector2->AddPostSelectionListener(GetSite()->GetWorkbenchWindow()->GetSelectionService()); + connect(m_SelectionServiceConnector2.get(), SIGNAL(ServiceSelectionChanged(QList)), m_ModelViewSelectionConnector2.get(), SLOT(SetCurrentSelection(QList))); + } + else + { + m_SelectionServiceConnector2->RemovePostSelectionListener(); + disconnect(m_SelectionServiceConnector2.get(), SIGNAL(ServiceSelectionChanged(QList)), m_ModelViewSelectionConnector2.get(), SLOT(SetCurrentSelection(QList))); + } +} + +void QmitkDataStorageViewerTestView::SetAsSelectionProvider3(bool checked) +{ + if (checked) + { + m_SelectionServiceConnector3->SetAsSelectionProvider(GetSite()->GetSelectionProvider().Cast().GetPointer()); + connect(m_Controls.singleSlot, SIGNAL(CurrentSelectionChanged(QList)), m_SelectionServiceConnector3.get(), SLOT(ChangeServiceSelection(QList))); + } + else + { + m_SelectionServiceConnector3->RemoveAsSelectionProvider(); + disconnect(m_Controls.singleSlot, SIGNAL(CurrentSelectionChanged(QList)), m_SelectionServiceConnector3.get(), SLOT(ChangeServiceSelection(QList))); + } +} + +void QmitkDataStorageViewerTestView::SetAsSelectionListener3(bool checked) +{ + if (checked) + { + m_SelectionServiceConnector3->AddPostSelectionListener(GetSite()->GetWorkbenchWindow()->GetSelectionService()); + connect(m_SelectionServiceConnector3.get(), &QmitkSelectionServiceConnector::ServiceSelectionChanged, m_Controls.singleSlot, &QmitkSingleNodeSelectionWidget::SetCurrentSelection); + } + else + { + m_SelectionServiceConnector3->RemovePostSelectionListener(); + disconnect(m_SelectionServiceConnector3.get(), &QmitkSelectionServiceConnector::ServiceSelectionChanged, m_Controls.singleSlot, &QmitkSingleNodeSelectionWidget::SetCurrentSelection); + } +} + +void QmitkDataStorageViewerTestView::SetAsSelectionProvider4(bool checked) +{ + if (checked) + { + m_SelectionServiceConnector4->SetAsSelectionProvider(GetSite()->GetSelectionProvider().Cast().GetPointer()); + connect(m_Controls.multiSlot, SIGNAL(CurrentSelectionChanged(QList)), m_SelectionServiceConnector4.get(), SLOT(ChangeServiceSelection(QList))); + } + else + { + m_SelectionServiceConnector4->RemoveAsSelectionProvider(); + disconnect(m_Controls.multiSlot, SIGNAL(CurrentSelectionChanged(QList)), m_SelectionServiceConnector4.get(), SLOT(ChangeServiceSelection(QList))); + } +} + +void QmitkDataStorageViewerTestView::SetAsSelectionListener4(bool checked) +{ + if (checked) + { + m_SelectionServiceConnector4->AddPostSelectionListener(GetSite()->GetWorkbenchWindow()->GetSelectionService()); + connect(m_SelectionServiceConnector4.get(), &QmitkSelectionServiceConnector::ServiceSelectionChanged, m_Controls.multiSlot, &QmitkMultiNodeSelectionWidget::SetCurrentSelection); + } + else + { + m_SelectionServiceConnector4->RemovePostSelectionListener(); + disconnect(m_SelectionServiceConnector4.get(), &QmitkSelectionServiceConnector::ServiceSelectionChanged, m_Controls.multiSlot, &QmitkMultiNodeSelectionWidget::SetCurrentSelection); + } +} + +void QmitkDataStorageViewerTestView::OnOnlyImages(bool checked) +{ + if (checked) + { + m_Controls.singleSlot->SetNodePredicate(mitk::NodePredicateDataType::New("Image")); + } + else + { + m_Controls.singleSlot->SetNodePredicate(nullptr); + } +}; + +void QmitkDataStorageViewerTestView::OnOnlyImages2(bool checked) +{ + if (checked) + { + m_Controls.multiSlot->SetNodePredicate(mitk::NodePredicateDataType::New("Image")); + } + else + { + m_Controls.multiSlot->SetNodePredicate(nullptr); + } +}; diff --git a/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/QmitkDataStorageViewerTestView.h b/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/QmitkDataStorageViewerTestView.h new file mode 100644 index 0000000000..ce4042ae3e --- /dev/null +++ b/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/QmitkDataStorageViewerTestView.h @@ -0,0 +1,77 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +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 QMITKDATASTORAGEVIEWERTESTVIEW_H +#define QMITKDATASTORAGEVIEWERTESTVIEW_H + +// mitk gui qt common plugin +#include +#include "QmitkModelViewSelectionConnector.h" +#include "QmitkSelectionServiceConnector.h" + +// data storage viewer test plugin +#include "ui_QmitkDataStorageViewerTestControls.h" + +// qt widgets module +#include "QmitkDataStorageDefaultListModel.h" + +/** +* @brief DataStorageViewerTestView +*/ +class QmitkDataStorageViewerTestView : public QmitkAbstractView +{ + Q_OBJECT + +public: + + static const std::string VIEW_ID; + +protected: + + virtual void SetFocus() override; + + virtual void CreateQtPartControl(QWidget* parent) override; + +private Q_SLOTS: + + void SetAsSelectionProvider1(bool checked); + void SetAsSelectionProvider2(bool checked); + void SetAsSelectionProvider3(bool checked); + void SetAsSelectionProvider4(bool checked); + void SetAsSelectionListener1(bool checked); + void SetAsSelectionListener2(bool checked); + void SetAsSelectionListener3(bool checked); + void SetAsSelectionListener4(bool checked); + + void OnOnlyImages(bool checked); + void OnOnlyImages2(bool checked); + +private: + + Ui::QmitkDataStorageViewerTestControls m_Controls; + QmitkDataStorageDefaultListModel* m_DataStorageDefaultListModel; + QmitkDataStorageDefaultListModel* m_DataStorageDefaultListModel2; + + std::unique_ptr m_ModelViewSelectionConnector; + std::unique_ptr m_SelectionServiceConnector; + std::unique_ptr m_ModelViewSelectionConnector2; + std::unique_ptr m_SelectionServiceConnector2; + + std::unique_ptr m_SelectionServiceConnector3; + std::unique_ptr m_SelectionServiceConnector4; +}; + +#endif // QMITKDATASTORAGEVIEWERTESTVIEW_H diff --git a/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/mitkPluginActivator.cpp b/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/mitkPluginActivator.cpp new file mode 100644 index 0000000000..deb5df0dc0 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/mitkPluginActivator.cpp @@ -0,0 +1,28 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "mitkPluginActivator.h" +#include "QmitkDataStorageViewerTestView.h" + +namespace mitk +{ + void DataStorageViewerTestActivator::start(ctkPluginContext *context) + { + BERRY_REGISTER_EXTENSION_CLASS(QmitkDataStorageViewerTestView, context) + } + + void DataStorageViewerTestActivator::stop(ctkPluginContext *context) { Q_UNUSED(context) } +} diff --git a/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/mitkPluginActivator.h b/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/mitkPluginActivator.h new file mode 100644 index 0000000000..080450ba33 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/mitkPluginActivator.h @@ -0,0 +1,37 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +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 MITKPLUGINACTIVATOR_H +#define MITKPLUGINACTIVATOR_H + +#include + +namespace mitk +{ + class DataStorageViewerTestActivator : public QObject, public ctkPluginActivator + { + Q_OBJECT + Q_PLUGIN_METADATA(IID "org_mitk_gui_qt_datastorageviewertest") + Q_INTERFACES(ctkPluginActivator) + + public: + void start(ctkPluginContext* context) override; + void stop(ctkPluginContext* context) override; + + }; +} + +#endif // MITKPLUGINACTIVATOR_H