From 42e91aee0749bbb629c91c0b318786b08f5892e9 2017-06-15 10:06:42 From: perrinel Date: 2017-06-15 10:06:42 Subject: [PATCH] Merge pull request #150 from SCIQLOP-Initialisation develop Develop --- diff --git a/core/include/DataSource/DataSourceController.h b/core/include/DataSource/DataSourceController.h index 13c2192..3a495e9 100644 --- a/core/include/DataSource/DataSourceController.h +++ b/core/include/DataSource/DataSourceController.h @@ -54,6 +54,12 @@ public: void setDataProvider(const QUuid &dataSourceUid, std::unique_ptr dataProvider) noexcept; + /** + * Loads an item (product) as a variable in SciQlop + * @param productItem the item to load + */ + void loadProductItem(const DataSourceItem &productItem) noexcept; + public slots: /// Manage init/end of the controller void initialize(); diff --git a/core/include/DataSource/DataSourceItem.h b/core/include/DataSource/DataSourceItem.h index 193a495..4ff7629 100644 --- a/core/include/DataSource/DataSourceItem.h +++ b/core/include/DataSource/DataSourceItem.h @@ -6,6 +6,8 @@ #include #include +class DataSourceItemAction; + /** * Possible types of an item */ @@ -21,6 +23,16 @@ class DataSourceItem { public: explicit DataSourceItem(DataSourceItemType type, QVector data = {}); + /// @return the actions of the item as a vector + QVector actions() const noexcept; + + /** + * Adds an action to the item. The item takes ownership of the action, and the action is + * automatically associated to the item + * @param action the action to add + */ + void addAction(std::unique_ptr action) noexcept; + /** * Adds a child to the item. The item takes ownership of the child. * @param child the child to add @@ -43,6 +55,8 @@ public: */ QVariant data(int dataIndex) const noexcept; + QString name() const noexcept; + /** * Get the item's parent * @return a pointer to the parent if it exists, nullptr if the item is a root diff --git a/core/include/DataSource/DataSourceItemAction.h b/core/include/DataSource/DataSourceItemAction.h new file mode 100644 index 0000000..1e64959 --- /dev/null +++ b/core/include/DataSource/DataSourceItemAction.h @@ -0,0 +1,48 @@ +#ifndef SCIQLOP_DATASOURCEITEMACTION_H +#define SCIQLOP_DATASOURCEITEMACTION_H + +#include + +#include +#include + +Q_DECLARE_LOGGING_CATEGORY(LOG_DataSourceItemAction) + +class DataSourceItem; + +/** + * @brief The DataSourceItemAction class represents an action on a data source item. + * + * An action is a function that will be executed when the slot execute() is called. + */ +class DataSourceItemAction : public QObject { + + Q_OBJECT + +public: + /// Signature of the function associated to the action + using ExecuteFunction = std::function; + + /** + * Ctor + * @param name the name of the action + * @param fun the function that will be called when the action is executed + * @sa execute() + */ + explicit DataSourceItemAction(const QString &name, ExecuteFunction fun); + + QString name() const noexcept; + + /// Sets the data source item concerned by the action + void setDataSourceItem(DataSourceItem *dataSourceItem) noexcept; + +public slots: + /// Executes the action + void execute(); + +private: + class DataSourceItemActionPrivate; + spimpl::unique_impl_ptr impl; +}; + +#endif // SCIQLOP_DATASOURCEITEMACTION_H diff --git a/core/src/DataSource/DataSourceController.cpp b/core/src/DataSource/DataSourceController.cpp index aeed99e..fc0bd48 100644 --- a/core/src/DataSource/DataSourceController.cpp +++ b/core/src/DataSource/DataSourceController.cpp @@ -76,6 +76,11 @@ void DataSourceController::setDataProvider(const QUuid &dataSourceUid, } } +void DataSourceController::loadProductItem(const DataSourceItem &productItem) noexcept +{ + /// @todo ALX +} + void DataSourceController::initialize() { qCDebug(LOG_DataSourceController()) << tr("DataSourceController init") diff --git a/core/src/DataSource/DataSourceItem.cpp b/core/src/DataSource/DataSourceItem.cpp index 43c884b..c794bc2 100644 --- a/core/src/DataSource/DataSourceItem.cpp +++ b/core/src/DataSource/DataSourceItem.cpp @@ -1,10 +1,18 @@ #include +#include #include +namespace { + +/// Index of the 'name' value in the item +const auto NAME_INDEX = 0; + +} // namespace + struct DataSourceItem::DataSourceItemPrivate { explicit DataSourceItemPrivate(DataSourceItemType type, QVector data) - : m_Parent{nullptr}, m_Children{}, m_Type{type}, m_Data{std::move(data)} + : m_Parent{nullptr}, m_Children{}, m_Type{type}, m_Data{std::move(data)}, m_Actions{} { } @@ -12,6 +20,7 @@ struct DataSourceItem::DataSourceItemPrivate { std::vector > m_Children; DataSourceItemType m_Type; QVector m_Data; + std::vector > m_Actions; }; DataSourceItem::DataSourceItem(DataSourceItemType type, QVector data) @@ -19,6 +28,22 @@ DataSourceItem::DataSourceItem(DataSourceItemType type, QVector data) { } +QVector DataSourceItem::actions() const noexcept +{ + QVector result{}; + + std::transform(std::cbegin(impl->m_Actions), std::cend(impl->m_Actions), + std::back_inserter(result), [](const auto &action) { return action.get(); }); + + return result; +} + +void DataSourceItem::addAction(std::unique_ptr action) noexcept +{ + action->setDataSourceItem(this); + impl->m_Actions.push_back(std::move(action)); +} + void DataSourceItem::appendChild(std::unique_ptr child) noexcept { child->impl->m_Parent = this; @@ -45,6 +70,11 @@ QVariant DataSourceItem::data(int dataIndex) const noexcept return impl->m_Data.value(dataIndex); } +QString DataSourceItem::name() const noexcept +{ + return data(NAME_INDEX).toString(); +} + DataSourceItem *DataSourceItem::parentItem() const noexcept { return impl->m_Parent; diff --git a/core/src/DataSource/DataSourceItemAction.cpp b/core/src/DataSource/DataSourceItemAction.cpp new file mode 100644 index 0000000..e791e8f --- /dev/null +++ b/core/src/DataSource/DataSourceItemAction.cpp @@ -0,0 +1,42 @@ +#include + +Q_LOGGING_CATEGORY(LOG_DataSourceItemAction, "DataSourceItemAction") + +struct DataSourceItemAction::DataSourceItemActionPrivate { + explicit DataSourceItemActionPrivate(const QString &name, + DataSourceItemAction::ExecuteFunction fun) + : m_Name{name}, m_Fun{std::move(fun)}, m_DataSourceItem{nullptr} + { + } + + QString m_Name; + DataSourceItemAction::ExecuteFunction m_Fun; + /// Item associated to the action (can be null, in which case the action will not be executed) + DataSourceItem *m_DataSourceItem; +}; + +DataSourceItemAction::DataSourceItemAction(const QString &name, ExecuteFunction fun) + : impl{spimpl::make_unique_impl(name, std::move(fun))} +{ +} + +QString DataSourceItemAction::name() const noexcept +{ + return impl->m_Name; +} + +void DataSourceItemAction::setDataSourceItem(DataSourceItem *dataSourceItem) noexcept +{ + impl->m_DataSourceItem = dataSourceItem; +} + +void DataSourceItemAction::execute() +{ + if (impl->m_DataSourceItem) { + impl->m_Fun(*impl->m_DataSourceItem); + } + else { + qCDebug(LOG_DataSourceItemAction()) + << tr("Can't execute action : no item has been associated"); + } +} diff --git a/core/vera-exclusions/exclusions.txt b/core/vera-exclusions/exclusions.txt index d4b3912..24fe3c3 100644 --- a/core/vera-exclusions/exclusions.txt +++ b/core/vera-exclusions/exclusions.txt @@ -8,3 +8,6 @@ DataSourceItem\.h:\d+:.*IPSIS_S01.* ArrayData\.h:\d+:.*IPSIS_S04_VARIABLE.*found: (D) ArrayData\.h:\d+:.*IPSIS_S06.*found: (D) ArrayData\.h:\d+:.*IPSIS_S06.*found: (Dim) + +# Ignore false positive relative to an alias +DataSourceItemAction\.h:\d+:.*IPSIS_S06.*found: (ExecuteFunction) diff --git a/gui/include/DataSource/DataSourceTreeWidgetItem.h b/gui/include/DataSource/DataSourceTreeWidgetItem.h index 02b0122..842e5ba 100644 --- a/gui/include/DataSource/DataSourceTreeWidgetItem.h +++ b/gui/include/DataSource/DataSourceTreeWidgetItem.h @@ -24,6 +24,9 @@ public: virtual QVariant data(int column, int role) const override; virtual void setData(int column, int role, const QVariant &value) override; + /// @return the actions associated to the item + QList actions() const noexcept; + private: class DataSourceTreeWidgetItemPrivate; spimpl::unique_impl_ptr impl; diff --git a/gui/include/DataSource/DataSourceWidget.h b/gui/include/DataSource/DataSourceWidget.h index c661fa2..4134f86 100644 --- a/gui/include/DataSource/DataSourceWidget.h +++ b/gui/include/DataSource/DataSourceWidget.h @@ -29,6 +29,10 @@ public slots: private: Ui::DataSourceWidget *ui; + +private slots: + /// Slot called when right clicking on an item in the tree (displays a menu) + void onTreeMenuRequested(const QPoint &pos) noexcept; }; #endif // SCIQLOP_DATASOURCEWIDGET_H diff --git a/gui/src/DataSource/DataSourceTreeWidgetItem.cpp b/gui/src/DataSource/DataSourceTreeWidgetItem.cpp index 236f0b4..07b8735 100644 --- a/gui/src/DataSource/DataSourceTreeWidgetItem.cpp +++ b/gui/src/DataSource/DataSourceTreeWidgetItem.cpp @@ -1,8 +1,11 @@ #include +#include #include #include +#include + Q_LOGGING_CATEGORY(LOG_DataSourceTreeWidgetItem, "DataSourceTreeWidgetItem") namespace { @@ -40,6 +43,9 @@ struct DataSourceTreeWidgetItem::DataSourceTreeWidgetItemPrivate { /// Model used to retrieve data source information const DataSourceItem *m_Data; + /// Actions associated to the item. The parent of the item (QTreeWidget) takes the ownership of + /// the actions + QList m_Actions; }; DataSourceTreeWidgetItem::DataSourceTreeWidgetItem(const DataSourceItem *data, int type) @@ -54,6 +60,21 @@ DataSourceTreeWidgetItem::DataSourceTreeWidgetItem(QTreeWidget *parent, const Da { // Sets the icon depending on the data source setIcon(0, itemIcon(impl->m_Data)); + + // Generates tree actions based on the item actions + auto createTreeAction = [this, &parent](const auto &itemAction) { + auto treeAction = new QAction{itemAction->name(), parent}; + + // Executes item action when tree action is triggered + QObject::connect(treeAction, &QAction::triggered, itemAction, + &DataSourceItemAction::execute); + + return treeAction; + }; + + auto itemActions = impl->m_Data->actions(); + std::transform(std::cbegin(itemActions), std::cend(itemActions), + std::back_inserter(impl->m_Actions), createTreeAction); } QVariant DataSourceTreeWidgetItem::data(int column, int role) const @@ -73,3 +94,8 @@ void DataSourceTreeWidgetItem::setData(int column, int role, const QVariant &val QTreeWidgetItem::setData(column, role, value); } } + +QList DataSourceTreeWidgetItem::actions() const noexcept +{ + return impl->m_Actions; +} diff --git a/gui/src/DataSource/DataSourceWidget.cpp b/gui/src/DataSource/DataSourceWidget.cpp index 0891a00..0209719 100644 --- a/gui/src/DataSource/DataSourceWidget.cpp +++ b/gui/src/DataSource/DataSourceWidget.cpp @@ -5,6 +5,8 @@ #include #include +#include + namespace { /// Number of columns displayed in the tree @@ -40,6 +42,11 @@ DataSourceWidget::DataSourceWidget(QWidget *parent) : QWidget{parent}, ui{new Ui // Set tree properties ui->treeWidget->setColumnCount(TREE_NB_COLUMNS); ui->treeWidget->setHeaderLabels(TREE_HEADER_LABELS); + ui->treeWidget->setContextMenuPolicy(Qt::CustomContextMenu); + + // Connection to show a menu when right clicking on the tree + connect(ui->treeWidget, &QTreeWidget::customContextMenuRequested, this, + &DataSourceWidget::onTreeMenuRequested); } void DataSourceWidget::addDataSource(DataSourceItem *dataSource) noexcept @@ -50,3 +57,16 @@ void DataSourceWidget::addDataSource(DataSourceItem *dataSource) noexcept ui->treeWidget->addTopLevelItem(createTreeWidgetItem(dataSource)); } } + +void DataSourceWidget::onTreeMenuRequested(const QPoint &pos) noexcept +{ + // Retrieves the selected item in the tree, and build the menu from its actions + if (auto selectedItem = dynamic_cast(ui->treeWidget->itemAt(pos))) { + QMenu treeMenu{}; + treeMenu.addActions(selectedItem->actions()); + + if (!treeMenu.isEmpty()) { + treeMenu.exec(mapToGlobal(pos)); + } + } +} diff --git a/plugins/mockplugin/src/MockPlugin.cpp b/plugins/mockplugin/src/MockPlugin.cpp index 526a2fc..79d95d2 100644 --- a/plugins/mockplugin/src/MockPlugin.cpp +++ b/plugins/mockplugin/src/MockPlugin.cpp @@ -3,6 +3,7 @@ #include #include +#include #include @@ -19,19 +20,30 @@ std::unique_ptr createDataProvider() noexcept return std::make_unique(); } +std::unique_ptr createProductItem(const QString &productName) +{ + auto result = std::make_unique(DataSourceItemType::PRODUCT, + QVector{productName}); + + // Add action to load product from DataSourceController + result->addAction(std::make_unique( + QObject::tr("Load %1 product").arg(productName), [productName](DataSourceItem &item) { + if (auto app = sqpApp) { + app->dataSourceController().loadProductItem(item); + } + })); + + return result; +} + /// Creates the data source item relative to the plugin std::unique_ptr createDataSourceItem() noexcept { // Magnetic field products - auto fgmProduct = std::make_unique(DataSourceItemType::PRODUCT, - QVector{QStringLiteral("FGM")}); - auto scProduct = std::make_unique(DataSourceItemType::PRODUCT, - QVector{QStringLiteral("SC")}); - auto magneticFieldFolder = std::make_unique( DataSourceItemType::NODE, QVector{QStringLiteral("Magnetic field")}); - magneticFieldFolder->appendChild(std::move(fgmProduct)); - magneticFieldFolder->appendChild(std::move(scProduct)); + magneticFieldFolder->appendChild(createProductItem(QStringLiteral("FGM"))); + magneticFieldFolder->appendChild(createProductItem(QStringLiteral("SC"))); // Electric field products auto electricFieldFolder = std::make_unique(