From b575895e82451958e5cc4a3c221af51ac55f4ab6 2017-06-22 12:29:36 From: Alexandre Leroux Date: 2017-06-22 12:29:36 Subject: [PATCH] Merge branch 'feature/VariableMenu1' into develop --- diff --git a/formatting/vera-exclusions/exclusions.txt b/formatting/vera-exclusions/exclusions.txt index 18e7e8b..79da9f4 100644 --- a/formatting/vera-exclusions/exclusions.txt +++ b/formatting/vera-exclusions/exclusions.txt @@ -10,3 +10,7 @@ # Ignore false positive relative to 'override' keyword .*IPSIS_S04_VARIABLE.*found: override .*IPSIS_S06.*found: override + +# Ignore false positive relative to 'final' keyword +.*IPSIS_S04_VARIABLE.*found: final +.*IPSIS_S06.*found: final diff --git a/gui/include/Visualization/IVariableContainer.h b/gui/include/Visualization/IVariableContainer.h new file mode 100644 index 0000000..fa4791b --- /dev/null +++ b/gui/include/Visualization/IVariableContainer.h @@ -0,0 +1,19 @@ +#ifndef SCIQLOP_IVARIABLECONTAINER_H +#define SCIQLOP_IVARIABLECONTAINER_H + +class Variable; + +/** + * @brief The IVariableContainer interface represents an UI object that can accommodate a variable + */ +class IVariableContainer { + +public: + virtual ~IVariableContainer() = default; + + /// Checks if the container can handle the variable passed in parameter + virtual bool canDrop(const Variable &variable) const = 0; +}; + + +#endif // SCIQLOP_IVARIABLECONTAINER_H diff --git a/gui/include/Visualization/IVisualizationWidget.h b/gui/include/Visualization/IVisualizationWidget.h index 18a4fd8..4bbafbb 100644 --- a/gui/include/Visualization/IVisualizationWidget.h +++ b/gui/include/Visualization/IVisualizationWidget.h @@ -1,21 +1,23 @@ #ifndef SCIQLOP_IVISUALIZATIONWIDGET_H #define SCIQLOP_IVISUALIZATIONWIDGET_H -#include "Visualization/IVisualizationWidgetVisitor.h" +#include "Visualization/IVariableContainer.h" #include #include +class IVisualizationWidgetVisitor; + /** * @brief The IVisualizationWidget handles the visualization widget. */ -class IVisualizationWidget { +class IVisualizationWidget : public IVariableContainer { public: virtual ~IVisualizationWidget() = default; /// Initializes the plugin - virtual void accept(IVisualizationWidget *visitor) = 0; + virtual void accept(IVisualizationWidgetVisitor *visitor) = 0; virtual void close() = 0; virtual QString name() const = 0; }; diff --git a/gui/include/Visualization/IVisualizationWidgetVisitor.h b/gui/include/Visualization/IVisualizationWidgetVisitor.h index 33ce5b9..67f86df 100644 --- a/gui/include/Visualization/IVisualizationWidgetVisitor.h +++ b/gui/include/Visualization/IVisualizationWidgetVisitor.h @@ -15,9 +15,12 @@ class IVisualizationWidgetVisitor { public: virtual ~IVisualizationWidgetVisitor() = default; - virtual void visit(VisualizationWidget *widget) = 0; - virtual void visit(VisualizationTabWidget *tabWidget) = 0; - virtual void visit(VisualizationZoneWidget *zoneWidget) = 0; + virtual void visitEnter(VisualizationWidget *widget) = 0; + virtual void visitLeave(VisualizationWidget *widget) = 0; + virtual void visitEnter(VisualizationTabWidget *tabWidget) = 0; + virtual void visitLeave(VisualizationTabWidget *tabWidget) = 0; + virtual void visitEnter(VisualizationZoneWidget *zoneWidget) = 0; + virtual void visitLeave(VisualizationZoneWidget *zoneWidget) = 0; virtual void visit(VisualizationGraphWidget *graphWidget) = 0; }; diff --git a/gui/include/Visualization/VisualizationGraphWidget.h b/gui/include/Visualization/VisualizationGraphWidget.h index cd68182..07db804 100644 --- a/gui/include/Visualization/VisualizationGraphWidget.h +++ b/gui/include/Visualization/VisualizationGraphWidget.h @@ -25,7 +25,8 @@ public: void addVariable(std::shared_ptr variable); // IVisualizationWidget interface - void accept(IVisualizationWidget *visitor) override; + void accept(IVisualizationWidgetVisitor *visitor) override; + bool canDrop(const Variable &variable) const override; void close() override; QString name() const; diff --git a/gui/include/Visualization/VisualizationTabWidget.h b/gui/include/Visualization/VisualizationTabWidget.h index e955860..ac5a39d 100644 --- a/gui/include/Visualization/VisualizationTabWidget.h +++ b/gui/include/Visualization/VisualizationTabWidget.h @@ -36,7 +36,8 @@ public: void removeZone(VisualizationZoneWidget *zone); // IVisualizationWidget interface - void accept(IVisualizationWidget *visitor) override; + void accept(IVisualizationWidgetVisitor *visitor) override; + bool canDrop(const Variable &variable) const override; void close() override; QString name() const override; diff --git a/gui/include/Visualization/VisualizationWidget.h b/gui/include/Visualization/VisualizationWidget.h index 4d12b0e..77e43f7 100644 --- a/gui/include/Visualization/VisualizationWidget.h +++ b/gui/include/Visualization/VisualizationWidget.h @@ -32,7 +32,8 @@ public: void removeTab(VisualizationTabWidget *tab); // IVisualizationWidget interface - void accept(IVisualizationWidget *visitor) override; + void accept(IVisualizationWidgetVisitor *visitor) override; + bool canDrop(const Variable &variable) const override; void close() override; QString name() const; diff --git a/gui/include/Visualization/VisualizationZoneWidget.h b/gui/include/Visualization/VisualizationZoneWidget.h index 82f5418..b6bafaf 100644 --- a/gui/include/Visualization/VisualizationZoneWidget.h +++ b/gui/include/Visualization/VisualizationZoneWidget.h @@ -33,7 +33,8 @@ public: void removeGraph(VisualizationGraphWidget *graph); // IVisualizationWidget interface - void accept(IVisualizationWidget *visitor) override; + void accept(IVisualizationWidgetVisitor *visitor) override; + bool canDrop(const Variable &variable) const override; void close() override; QString name() const override; diff --git a/gui/include/Visualization/operations/GenerateVariableMenuOperation.h b/gui/include/Visualization/operations/GenerateVariableMenuOperation.h new file mode 100644 index 0000000..6849015 --- /dev/null +++ b/gui/include/Visualization/operations/GenerateVariableMenuOperation.h @@ -0,0 +1,42 @@ +#ifndef SCIQLOP_GENERATEVARIABLEMENUOPERATION_H +#define SCIQLOP_GENERATEVARIABLEMENUOPERATION_H + +#include "Visualization/IVisualizationWidgetVisitor.h" + +#include + +#include + +class QMenu; +class Variable; + +Q_DECLARE_LOGGING_CATEGORY(LOG_GenerateVariableMenuOperation) + +/** + * @brief The GenerateVariableMenuOperation class defines an operation that traverses all of + * visualization widgets to determine which can accommodate a variable. The result of the operation + * is a menu that contains actions to add the variable into the containers. + */ +class GenerateVariableMenuOperation : public IVisualizationWidgetVisitor { +public: + /** + * Ctor + * @param menu the menu to which to attach the generated menu + * @param variable the variable for which to generate the menu + */ + explicit GenerateVariableMenuOperation(QMenu *menu, std::shared_ptr variable); + + void visitEnter(VisualizationWidget *widget) override final; + void visitLeave(VisualizationWidget *widget) override final; + void visitEnter(VisualizationTabWidget *tabWidget) override final; + void visitLeave(VisualizationTabWidget *tabWidget) override final; + void visitEnter(VisualizationZoneWidget *zoneWidget) override final; + void visitLeave(VisualizationZoneWidget *zoneWidget) override final; + void visit(VisualizationGraphWidget *graphWidget) override final; + +private: + class GenerateVariableMenuOperationPrivate; + spimpl::unique_impl_ptr impl; +}; + +#endif // SCIQLOP_GENERATEVARIABLEMENUOPERATION_H diff --git a/gui/src/Visualization/VisualizationGraphWidget.cpp b/gui/src/Visualization/VisualizationGraphWidget.cpp index f8133c1..7f8ebd9 100644 --- a/gui/src/Visualization/VisualizationGraphWidget.cpp +++ b/gui/src/Visualization/VisualizationGraphWidget.cpp @@ -1,5 +1,6 @@ #include "Visualization/VisualizationGraphWidget.h" #include "Visualization/GraphPlottablesFactory.h" +#include "Visualization/IVisualizationWidgetVisitor.h" #include "ui_VisualizationGraphWidget.h" #include @@ -56,9 +57,18 @@ void VisualizationGraphWidget::addVariable(std::shared_ptr variable) } } -void VisualizationGraphWidget::accept(IVisualizationWidget *visitor) +void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor) { - // TODO: manage the visitor + if (visitor) { + visitor->visit(this); + } +} + +bool VisualizationGraphWidget::canDrop(const Variable &variable) const +{ + /// @todo : for the moment, a graph can always accomodate a variable + Q_UNUSED(variable); + return true; } void VisualizationGraphWidget::close() diff --git a/gui/src/Visualization/VisualizationTabWidget.cpp b/gui/src/Visualization/VisualizationTabWidget.cpp index ddc297d..69825a9 100644 --- a/gui/src/Visualization/VisualizationTabWidget.cpp +++ b/gui/src/Visualization/VisualizationTabWidget.cpp @@ -1,4 +1,5 @@ #include "Visualization/VisualizationTabWidget.h" +#include "Visualization/IVisualizationWidgetVisitor.h" #include "ui_VisualizationTabWidget.h" #include "Visualization/VisualizationZoneWidget.h" @@ -60,9 +61,30 @@ void VisualizationTabWidget::removeZone(VisualizationZoneWidget *zone) { } -void VisualizationTabWidget::accept(IVisualizationWidget *visitor) +void VisualizationTabWidget::accept(IVisualizationWidgetVisitor *visitor) { - // TODO: manage the visitor + if (visitor) { + visitor->visitEnter(this); + + // Apply visitor to zone children + for (auto i = 0; i < layout()->count(); ++i) { + if (auto item = layout()->itemAt(i)) { + if (auto visualizationZoneWidget + = dynamic_cast(item->widget())) { + visualizationZoneWidget->accept(visitor); + } + } + } + + visitor->visitLeave(this); + } +} + +bool VisualizationTabWidget::canDrop(const Variable &variable) const +{ + // A tab can always accomodate a variable + Q_UNUSED(variable); + return true; } void VisualizationTabWidget::close() diff --git a/gui/src/Visualization/VisualizationWidget.cpp b/gui/src/Visualization/VisualizationWidget.cpp index ecf4e06..4e65d64 100644 --- a/gui/src/Visualization/VisualizationWidget.cpp +++ b/gui/src/Visualization/VisualizationWidget.cpp @@ -1,4 +1,5 @@ #include "Visualization/VisualizationWidget.h" +#include "Visualization/IVisualizationWidgetVisitor.h" #include "Visualization/VisualizationGraphWidget.h" #include "Visualization/VisualizationTabWidget.h" #include "Visualization/VisualizationZoneWidget.h" @@ -81,9 +82,28 @@ void VisualizationWidget::removeTab(VisualizationTabWidget *tab) // lambda function (in the constructor) } -void VisualizationWidget::accept(IVisualizationWidget *visitor) +void VisualizationWidget::accept(IVisualizationWidgetVisitor *visitor) { - // TODO: manage the visitor + if (visitor) { + visitor->visitEnter(this); + + // Apply visitor for tab children + for (auto i = 0; i < ui->tabWidget->count(); ++i) { + if (auto visualizationTabWidget + = dynamic_cast(ui->tabWidget->widget(i))) { + visualizationTabWidget->accept(visitor); + } + } + + visitor->visitLeave(this); + } +} + +bool VisualizationWidget::canDrop(const Variable &variable) const +{ + // The main widget can never accomodate a variable + Q_UNUSED(variable); + return false; } void VisualizationWidget::close() diff --git a/gui/src/Visualization/VisualizationZoneWidget.cpp b/gui/src/Visualization/VisualizationZoneWidget.cpp index a57c84e..ae4e841 100644 --- a/gui/src/Visualization/VisualizationZoneWidget.cpp +++ b/gui/src/Visualization/VisualizationZoneWidget.cpp @@ -1,4 +1,5 @@ #include "Visualization/VisualizationZoneWidget.h" +#include "Visualization/IVisualizationWidgetVisitor.h" #include "ui_VisualizationZoneWidget.h" #include "Visualization/VisualizationGraphWidget.h" @@ -54,9 +55,31 @@ void VisualizationZoneWidget::removeGraph(VisualizationGraphWidget *graph) { } -void VisualizationZoneWidget::accept(IVisualizationWidget *visitor) +void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor) { - // TODO: manage the visitor + if (visitor) { + visitor->visitEnter(this); + + // Apply visitor to graph children + auto layout = ui->visualizationZoneFrame->layout(); + for (auto i = 0; i < layout->count(); ++i) { + if (auto item = layout->itemAt(i)) { + if (auto visualizationGraphWidget + = dynamic_cast(item->widget())) { + visualizationGraphWidget->accept(visitor); + } + } + } + + visitor->visitLeave(this); + } +} + +bool VisualizationZoneWidget::canDrop(const Variable &variable) const +{ + // A tab can always accomodate a variable + Q_UNUSED(variable); + return true; } void VisualizationZoneWidget::close() diff --git a/gui/src/Visualization/operations/GenerateVariableMenuOperation.cpp b/gui/src/Visualization/operations/GenerateVariableMenuOperation.cpp new file mode 100644 index 0000000..336211e --- /dev/null +++ b/gui/src/Visualization/operations/GenerateVariableMenuOperation.cpp @@ -0,0 +1,200 @@ +#include "Visualization/operations/GenerateVariableMenuOperation.h" + +#include "Visualization/VisualizationGraphWidget.h" +#include "Visualization/VisualizationTabWidget.h" +#include "Visualization/VisualizationZoneWidget.h" + +#include + +#include +#include + +Q_LOGGING_CATEGORY(LOG_GenerateVariableMenuOperation, "GenerateVariableMenuOperation") + +namespace { + +/// Helper assigned to build the hierarchical menu associated with a variable +struct MenuBuilder { + /** + * Ctor + * @param menu the parent menu + */ + explicit MenuBuilder(QMenu *menu) + { + if (menu) { + m_Menus.push(menu); + } + else { + qCCritical(LOG_GenerateVariableMenuOperation()) + << QObject::tr("No parent menu has been defined"); + } + } + + /** + * Adds action to the current menu + * @param actionName the name of the action + * @param actionFunction the function that will be executed when the action is triggered + */ + template + void addAction(const QString &actionName, ActionFun actionFunction) + { + if (auto currMenu = currentMenu()) { + currMenu->addAction(actionName, actionFunction); + } + else { + qCCritical(LOG_GenerateVariableMenuOperation()) + << QObject::tr("No current menu to attach the action"); + } + } + + /** + * Adds a new menu to the current menu + * @param name the name of the menu + */ + void addMenu(const QString &name) + { + if (auto currMenu = currentMenu()) { + m_Menus.push(currMenu->addMenu(name)); + } + else { + qCCritical(LOG_GenerateVariableMenuOperation()) + << QObject::tr("No current menu to attach the new menu"); + } + } + + /// Adds a separator to the current menu. The separator is added only if the menu already + /// contains entries + void addSeparator() + { + if (auto currMenu = currentMenu()) { + if (!currMenu->isEmpty()) { + currMenu->addSeparator(); + } + } + else { + qCCritical(LOG_GenerateVariableMenuOperation()) + << QObject::tr("No current menu to attach the separator"); + } + } + + /// Closes the current menu + void closeMenu() + { + if (!m_Menus.isEmpty()) { + if (auto closedMenu = m_Menus.pop()) { + // Purge menu : if the closed menu has no entries, we remove it from its parent (the + // current menu) + if (auto currMenu = currentMenu()) { + if (closedMenu->isEmpty()) { + currMenu->removeAction(closedMenu->menuAction()); + } + } + } + } + } + + /// Gets the current menu (i.e. the top menu of the stack) + QMenu *currentMenu() const { return !m_Menus.isEmpty() ? m_Menus.top() : nullptr; } + + /// Stack of all menus currently opened + QStack m_Menus{}; +}; + +} // namespace + +struct GenerateVariableMenuOperation::GenerateVariableMenuOperationPrivate { + explicit GenerateVariableMenuOperationPrivate(QMenu *menu, std::shared_ptr variable) + : m_Variable{variable}, m_MenuBuilder{menu} + { + } + + void visitNodeEnter(const IVisualizationWidget &container) + { + // Opens a new menu associated to the node + m_MenuBuilder.addMenu(container.name()); + } + + template + void visitNodeLeave(const IVisualizationWidget &container, const QString &actionName, + ActionFun actionFunction) + { + if (m_Variable && container.canDrop(*m_Variable)) { + m_MenuBuilder.addSeparator(); + m_MenuBuilder.addAction(actionName, actionFunction); + } + + // Closes the menu associated to the node + m_MenuBuilder.closeMenu(); + } + + template + void visitLeaf(const IVisualizationWidget &container, const QString &actionName, + ActionFun actionFunction) + { + if (m_Variable && container.canDrop(*m_Variable)) { + m_MenuBuilder.addAction(actionName, actionFunction); + } + } + + std::shared_ptr m_Variable; + MenuBuilder m_MenuBuilder; +}; + +GenerateVariableMenuOperation::GenerateVariableMenuOperation(QMenu *menu, + std::shared_ptr variable) + : impl{spimpl::make_unique_impl(menu, variable)} +{ +} + +void GenerateVariableMenuOperation::visitEnter(VisualizationWidget *widget) +{ + // VisualizationWidget is not intended to accommodate a variable + Q_UNUSED(widget) +} + +void GenerateVariableMenuOperation::visitLeave(VisualizationWidget *widget) +{ + // VisualizationWidget is not intended to accommodate a variable + Q_UNUSED(widget) +} + +void GenerateVariableMenuOperation::visitEnter(VisualizationTabWidget *tabWidget) +{ + if (tabWidget) { + impl->visitNodeEnter(*tabWidget); + } +} + +void GenerateVariableMenuOperation::visitLeave(VisualizationTabWidget *tabWidget) +{ + if (tabWidget) { + impl->visitNodeLeave( + *tabWidget, QObject::tr("Open in a new zone"), + [ var = impl->m_Variable, tabWidget ]() { tabWidget->createZone(var); }); + } +} + +void GenerateVariableMenuOperation::visitEnter(VisualizationZoneWidget *zoneWidget) +{ + if (zoneWidget) { + impl->visitNodeEnter(*zoneWidget); + } +} + +void GenerateVariableMenuOperation::visitLeave(VisualizationZoneWidget *zoneWidget) +{ + if (zoneWidget) { + impl->visitNodeLeave( + *zoneWidget, QObject::tr("Open in a new graph"), + [ var = impl->m_Variable, zoneWidget ]() { zoneWidget->createGraph(var); }); + } +} + +void GenerateVariableMenuOperation::visit(VisualizationGraphWidget *graphWidget) +{ + if (graphWidget) { + impl->visitLeaf( + *graphWidget, QObject::tr("Open in %1").arg(graphWidget->name()), + [ var = impl->m_Variable, graphWidget ]() { graphWidget->addVariable(var); }); + } +} diff --git a/gui/vera-exclusions/exclusions.txt b/gui/vera-exclusions/exclusions.txt index 72b8768..7a8ee04 100644 --- a/gui/vera-exclusions/exclusions.txt +++ b/gui/vera-exclusions/exclusions.txt @@ -8,6 +8,7 @@ SqpApplication\.h:\d+:.IPSIS_S04_VARIABLE.*found: sqpApp # Ignore false positive relative to unnamed namespace DataSourceTreeWidgetItem\.cpp:\d+:.*IPSIS_F13.* +GenerateVariableMenuOperation\.cpp:\d+:.*IPSIS_F13.* VisualizationTabWidget\.cpp:\d+:.*IPSIS_F13.* VisualizationZoneWidget\.cpp:\d+:.*IPSIS_F13.*