diff --git a/core/include/Data/IDataProvider.h b/core/include/Data/IDataProvider.h index 0b83f2b..628d123 100644 --- a/core/include/Data/IDataProvider.h +++ b/core/include/Data/IDataProvider.h @@ -3,6 +3,8 @@ #include +#include + class DataProviderParameters; class IDataSeries; @@ -22,4 +24,7 @@ public: retrieveData(const DataProviderParameters ¶meters) const = 0; }; +// Required for using shared_ptr in signals/slots +Q_DECLARE_METATYPE(std::shared_ptr) + #endif // SCIQLOP_IDATAPROVIDER_H diff --git a/core/include/DataSource/DataSourceController.h b/core/include/DataSource/DataSourceController.h index 3a495e9..d274f88 100644 --- a/core/include/DataSource/DataSourceController.h +++ b/core/include/DataSource/DataSourceController.h @@ -56,9 +56,11 @@ public: /** * Loads an item (product) as a variable in SciQlop + * @param dataSourceUid the unique id of the data source containing the item. It is used to get + * the data provider associated to the data source, and pass it to for the variable creation * @param productItem the item to load */ - void loadProductItem(const DataSourceItem &productItem) noexcept; + void loadProductItem(const QUuid &dataSourceUid, const DataSourceItem &productItem) noexcept; public slots: /// Manage init/end of the controller @@ -69,6 +71,15 @@ signals: /// Signal emitted when a structure has been set for a data source void dataSourceItemSet(DataSourceItem *dataSourceItem); + /** + * Signal emitted when a variable creation is asked for a product + * @param variableName the name of the variable + * @param variableProvider the provider that will be used to retrieve the data of the variable + * (can be null) + */ + void variableCreationRequested(const QString &variableName, + std::shared_ptr variableProvider); + private: void waitForFinish(); diff --git a/core/include/Variable/Variable.h b/core/include/Variable/Variable.h index ff5f718..d67e115 100644 --- a/core/include/Variable/Variable.h +++ b/core/include/Variable/Variable.h @@ -1,20 +1,32 @@ #ifndef SCIQLOP_VARIABLE_H #define SCIQLOP_VARIABLE_H -#include +#include + +#include + +class IDataSeries; +class QString; /** - * @brief The Variable struct represents a variable in SciQlop. + * @brief The Variable class represents a variable in SciQlop. */ -struct Variable { - explicit Variable(const QString &name, const QString &unit, const QString &mission) - : m_Name{name}, m_Unit{unit}, m_Mission{mission} - { - } - - QString m_Name; - QString m_Unit; - QString m_Mission; +class Variable { +public: + explicit Variable(const QString &name, const QString &unit, const QString &mission); + + QString name() const noexcept; + QString mission() const noexcept; + QString unit() const noexcept; + + void addDataSeries(std::unique_ptr dataSeries) noexcept; + +private: + class VariablePrivate; + spimpl::unique_impl_ptr impl; }; +// Required for using shared_ptr in signals/slots +Q_DECLARE_METATYPE(std::shared_ptr) + #endif // SCIQLOP_VARIABLE_H diff --git a/core/include/Variable/VariableController.h b/core/include/Variable/VariableController.h index d25da2b..f7fdba5 100644 --- a/core/include/Variable/VariableController.h +++ b/core/include/Variable/VariableController.h @@ -6,6 +6,7 @@ #include +class IDataProvider; class Variable; class VariableModel; @@ -20,16 +21,20 @@ public: explicit VariableController(QObject *parent = 0); virtual ~VariableController(); + VariableModel *variableModel() noexcept; + +signals: + /// Signal emitted when a variable has been created + void variableCreated(std::shared_ptr variable); + +public slots: /** - * Creates a new variable + * Creates a new variable and adds it to the model * @param name the name of the new variable - * @return the variable if it was created successfully, nullptr otherwise + * @param provider the data provider for the new variable */ - Variable *createVariable(const QString &name) noexcept; + void createVariable(const QString &name, std::shared_ptr provider) noexcept; - VariableModel *variableModel() noexcept; - -public slots: void initialize(); void finalize(); diff --git a/core/include/Variable/VariableModel.h b/core/include/Variable/VariableModel.h index 074da18..140a02a 100644 --- a/core/include/Variable/VariableModel.h +++ b/core/include/Variable/VariableModel.h @@ -8,6 +8,7 @@ Q_DECLARE_LOGGING_CATEGORY(LOG_VariableModel) +class IDataSeries; class Variable; /** @@ -20,9 +21,11 @@ public: /** * Creates a new variable in the model * @param name the name of the new variable - * @return the variable if it was created successfully, nullptr otherwise + * @param defaultDataSeries the default data of the new variable + * @return the pointer to the new variable */ - Variable *createVariable(const QString &name) noexcept; + std::shared_ptr + createVariable(const QString &name, std::unique_ptr defaultDataSeries) noexcept; // /////////////////////////// // // QAbstractTableModel methods // diff --git a/core/include/Visualization/VisualizationController.h b/core/include/Visualization/VisualizationController.h index 09a53ff..5a34df3 100644 --- a/core/include/Visualization/VisualizationController.h +++ b/core/include/Visualization/VisualizationController.h @@ -10,6 +10,7 @@ Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationController) class DataSourceItem; +class Variable; /** * @brief The VisualizationController class aims to make the link between SciQlop and its plugins. @@ -25,6 +26,9 @@ public: virtual ~VisualizationController(); public slots: + /// Slot called when a variable has been created in SciQlop + void onVariableCreated(std::shared_ptr variable) noexcept; + /// Manage init/end of the controller void initialize(); void finalize(); diff --git a/core/src/DataSource/DataSourceController.cpp b/core/src/DataSource/DataSourceController.cpp index fc0bd48..bb87e87 100644 --- a/core/src/DataSource/DataSourceController.cpp +++ b/core/src/DataSource/DataSourceController.cpp @@ -1,5 +1,5 @@ -#include -#include +#include "DataSource/DataSourceController.h" +#include "DataSource/DataSourceItem.h" #include @@ -19,7 +19,9 @@ public: /// Data sources structures std::map > m_DataSourceItems; /// Data providers registered - std::map > m_DataProviders; + /// @remarks Data providers are stored as shared_ptr as they can be sent to a variable and + /// continue to live without necessarily the data source controller + std::map > m_DataProviders; }; DataSourceController::DataSourceController(QObject *parent) @@ -48,6 +50,7 @@ void DataSourceController::setDataSourceItem( const QUuid &dataSourceUid, std::unique_ptr dataSourceItem) noexcept { if (impl->m_DataSources.contains(dataSourceUid)) { + // The data provider is implicitly converted to a shared_ptr impl->m_DataSourceItems.insert(std::make_pair(dataSourceUid, std::move(dataSourceItem))); // Retrieves the data source item to emit the signal with it @@ -76,9 +79,20 @@ void DataSourceController::setDataProvider(const QUuid &dataSourceUid, } } -void DataSourceController::loadProductItem(const DataSourceItem &productItem) noexcept +void DataSourceController::loadProductItem(const QUuid &dataSourceUid, + const DataSourceItem &productItem) noexcept { - /// @todo ALX + if (productItem.type() == DataSourceItemType::PRODUCT) { + /// Retrieves the data provider of the data source (if any) + auto it = impl->m_DataProviders.find(dataSourceUid); + auto dataProvider = (it != impl->m_DataProviders.end()) ? it->second : nullptr; + + /// @todo retrieve timerange, and pass it to the signal + emit variableCreationRequested(productItem.name(), dataProvider); + } + else { + qCWarning(LOG_DataSourceController()) << tr("Can't load an item that is not a product"); + } } void DataSourceController::initialize() diff --git a/core/src/DataSource/DataSourceItem.cpp b/core/src/DataSource/DataSourceItem.cpp index c794bc2..16e0c53 100644 --- a/core/src/DataSource/DataSourceItem.cpp +++ b/core/src/DataSource/DataSourceItem.cpp @@ -30,7 +30,7 @@ DataSourceItem::DataSourceItem(DataSourceItemType type, QVector data) QVector DataSourceItem::actions() const noexcept { - QVector result{}; + auto result = QVector{}; std::transform(std::cbegin(impl->m_Actions), std::cend(impl->m_Actions), std::back_inserter(result), [](const auto &action) { return action.get(); }); diff --git a/core/src/Variable/Variable.cpp b/core/src/Variable/Variable.cpp new file mode 100644 index 0000000..02a2713 --- /dev/null +++ b/core/src/Variable/Variable.cpp @@ -0,0 +1,43 @@ +#include "Variable/Variable.h" + +#include + +struct Variable::VariablePrivate { + explicit VariablePrivate(const QString &name, const QString &unit, const QString &mission) + : m_Name{name}, m_Unit{unit}, m_Mission{mission}, m_DataSeries{nullptr} + { + } + + QString m_Name; + QString m_Unit; + QString m_Mission; + std::unique_ptr m_DataSeries; +}; + +Variable::Variable(const QString &name, const QString &unit, const QString &mission) + : impl{spimpl::make_unique_impl(name, unit, mission)} +{ +} + +QString Variable::name() const noexcept +{ + return impl->m_Name; +} + +QString Variable::mission() const noexcept +{ + return impl->m_Mission; +} + +QString Variable::unit() const noexcept +{ + return impl->m_Unit; +} + +void Variable::addDataSeries(std::unique_ptr dataSeries) noexcept +{ + if (!impl->m_DataSeries) { + impl->m_DataSeries = std::move(dataSeries); + } + /// @todo : else, merge the two data series (if possible) +} diff --git a/core/src/Variable/VariableController.cpp b/core/src/Variable/VariableController.cpp index 8c05bd9..7651e40 100644 --- a/core/src/Variable/VariableController.cpp +++ b/core/src/Variable/VariableController.cpp @@ -1,11 +1,34 @@ #include #include +#include +#include +#include + +#include #include #include Q_LOGGING_CATEGORY(LOG_VariableController, "VariableController") +namespace { + +/// @todo Generates default dataseries, according to the provider passed in parameter. This method +/// will be deleted when the timerange is recovered from SciQlop +std::unique_ptr generateDefaultDataSeries(const IDataProvider &provider) noexcept +{ + auto parameters = DataProviderParameters{ + // Remarks : we don't use toSecsSinceEpoch() here (method is for Qt 5.8 or above) + static_cast(QDateTime{QDate{2017, 01, 01}, QTime{12, 00}}.toMSecsSinceEpoch() + / 1000.), + static_cast(QDateTime{QDate{2017, 01, 01}, QTime{12, 01}}.toMSecsSinceEpoch()) + / 1000.}; + + return provider.retrieveData(parameters); +} + +} // namespace + struct VariableController::VariableControllerPrivate { explicit VariableControllerPrivate(VariableController *parent) : m_WorkingMutex{}, m_VariableModel{new VariableModel{parent}} @@ -31,14 +54,23 @@ VariableController::~VariableController() this->waitForFinish(); } -Variable *VariableController::createVariable(const QString &name) noexcept +VariableModel *VariableController::variableModel() noexcept { - return impl->m_VariableModel->createVariable(name); + return impl->m_VariableModel; } -VariableModel *VariableController::variableModel() noexcept +void VariableController::createVariable(const QString &name, + std::shared_ptr provider) noexcept { - return impl->m_VariableModel; + /// @todo : for the moment : + /// - the provider is only used to retrieve data from the variable for its initialization, but + /// it will be retained later + /// - default data are generated for the variable, without taking into account the timerange set + /// in sciqlop + if (auto newVariable + = impl->m_VariableModel->createVariable(name, generateDefaultDataSeries(*provider))) { + emit variableCreated(newVariable); + } } void VariableController::initialize() diff --git a/core/src/Variable/VariableModel.cpp b/core/src/Variable/VariableModel.cpp index 75389d5..25edb92 100644 --- a/core/src/Variable/VariableModel.cpp +++ b/core/src/Variable/VariableModel.cpp @@ -1,6 +1,7 @@ +#include #include -#include +#include Q_LOGGING_CATEGORY(LOG_VariableModel, "VariableModel") @@ -16,7 +17,7 @@ const auto NB_COLUMNS = 3; struct VariableModel::VariableModelPrivate { /// Variables created in SciQlop - std::vector > m_Variables; + std::vector > m_Variables; }; VariableModel::VariableModel(QObject *parent) @@ -24,19 +25,23 @@ VariableModel::VariableModel(QObject *parent) { } -Variable *VariableModel::createVariable(const QString &name) noexcept +std::shared_ptr +VariableModel::createVariable(const QString &name, + std::unique_ptr defaultDataSeries) noexcept { auto insertIndex = rowCount(); beginInsertRows({}, insertIndex, insertIndex); /// @todo For the moment, the other data of the variable is initialized with default values auto variable - = std::make_unique(name, QStringLiteral("unit"), QStringLiteral("mission")); - impl->m_Variables.push_back(std::move(variable)); + = std::make_shared(name, QStringLiteral("unit"), QStringLiteral("mission")); + variable->addDataSeries(std::move(defaultDataSeries)); + + impl->m_Variables.push_back(variable); endInsertRows(); - return impl->m_Variables.at(insertIndex).get(); + return variable; } int VariableModel::columnCount(const QModelIndex &parent) const @@ -67,11 +72,11 @@ QVariant VariableModel::data(const QModelIndex &index, int role) const if (auto variable = impl->m_Variables.at(index.row()).get()) { switch (index.column()) { case NAME_COLUMN: - return variable->m_Name; + return variable->name(); case UNIT_COLUMN: - return variable->m_Unit; + return variable->unit(); case MISSION_COLUMN: - return variable->m_Mission; + return variable->mission(); default: // No action break; diff --git a/core/src/Visualization/VisualizationController.cpp b/core/src/Visualization/VisualizationController.cpp index d87cbee..6e3bcc6 100644 --- a/core/src/Visualization/VisualizationController.cpp +++ b/core/src/Visualization/VisualizationController.cpp @@ -1,5 +1,7 @@ #include +#include + #include #include @@ -27,6 +29,12 @@ VisualizationController::~VisualizationController() this->waitForFinish(); } +void VisualizationController::onVariableCreated(std::shared_ptr variable) noexcept +{ + /// @todo ALX : make new graph for the variable + qCDebug(LOG_VisualizationController()) << "new variable to display"; +} + void VisualizationController::initialize() { qCDebug(LOG_VisualizationController()) << tr("VisualizationController init") diff --git a/core/vera-exclusions/exclusions.txt b/core/vera-exclusions/exclusions.txt index 24fe3c3..7946185 100644 --- a/core/vera-exclusions/exclusions.txt +++ b/core/vera-exclusions/exclusions.txt @@ -11,3 +11,6 @@ ArrayData\.h:\d+:.*IPSIS_S06.*found: (Dim) # Ignore false positive relative to an alias DataSourceItemAction\.h:\d+:.*IPSIS_S06.*found: (ExecuteFunction) + +# Ignore false positive relative to unnamed namespace +VariableController\.cpp:\d+:.*IPSIS_F13.* diff --git a/gui/src/SqpApplication.cpp b/gui/src/SqpApplication.cpp index dc45d7f..8f2d0fa 100644 --- a/gui/src/SqpApplication.cpp +++ b/gui/src/SqpApplication.cpp @@ -1,7 +1,9 @@ #include "SqpApplication.h" +#include #include #include +#include #include #include @@ -14,6 +16,23 @@ public: m_VariableController{std::make_unique()}, m_VisualizationController{std::make_unique()} { + // /////////////////////////////// // + // Connections between controllers // + // /////////////////////////////// // + + // VariableController <-> DataSourceController + qRegisterMetaType >(); + connect(m_DataSourceController.get(), + SIGNAL(variableCreationRequested(const QString &, std::shared_ptr)), + m_VariableController.get(), + SLOT(createVariable(const QString &, std::shared_ptr))); + + // VariableController <-> VisualizationController + qRegisterMetaType >(); + connect(m_VariableController.get(), SIGNAL(variableCreated(std::shared_ptr)), + m_VisualizationController.get(), + SLOT(onVariableCreated(std::shared_ptr))); + m_DataSourceController->moveToThread(&m_DataSourceControllerThread); m_VariableController->moveToThread(&m_VariableControllerThread); m_VisualizationController->moveToThread(&m_VisualizationControllerThread); @@ -61,7 +80,6 @@ SqpApplication::SqpApplication(int &argc, char **argv) connect(&impl->m_VisualizationControllerThread, &QThread::finished, impl->m_VisualizationController.get(), &VisualizationController::finalize); - impl->m_DataSourceControllerThread.start(); impl->m_VariableControllerThread.start(); impl->m_VisualizationControllerThread.start(); diff --git a/plugins/mockplugin/src/MockPlugin.cpp b/plugins/mockplugin/src/MockPlugin.cpp index 79d95d2..adc3bf6 100644 --- a/plugins/mockplugin/src/MockPlugin.cpp +++ b/plugins/mockplugin/src/MockPlugin.cpp @@ -20,16 +20,18 @@ std::unique_ptr createDataProvider() noexcept return std::make_unique(); } -std::unique_ptr createProductItem(const QString &productName) +std::unique_ptr createProductItem(const QString &productName, + const QUuid &dataSourceUid) { 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) { + QObject::tr("Load %1 product").arg(productName), + [productName, dataSourceUid](DataSourceItem &item) { if (auto app = sqpApp) { - app->dataSourceController().loadProductItem(item); + app->dataSourceController().loadProductItem(dataSourceUid, item); } })); @@ -37,13 +39,13 @@ std::unique_ptr createProductItem(const QString &productName) } /// Creates the data source item relative to the plugin -std::unique_ptr createDataSourceItem() noexcept +std::unique_ptr createDataSourceItem(const QUuid &dataSourceUid) noexcept { // Magnetic field products auto magneticFieldFolder = std::make_unique( DataSourceItemType::NODE, QVector{QStringLiteral("Magnetic field")}); - magneticFieldFolder->appendChild(createProductItem(QStringLiteral("FGM"))); - magneticFieldFolder->appendChild(createProductItem(QStringLiteral("SC"))); + magneticFieldFolder->appendChild(createProductItem(QStringLiteral("FGM"), dataSourceUid)); + magneticFieldFolder->appendChild(createProductItem(QStringLiteral("SC"), dataSourceUid)); // Electric field products auto electricFieldFolder = std::make_unique( @@ -68,7 +70,7 @@ void MockPlugin::initialize() auto dataSourceUid = dataSourceController.registerDataSource(DATA_SOURCE_NAME); // Sets data source tree - dataSourceController.setDataSourceItem(dataSourceUid, createDataSourceItem()); + dataSourceController.setDataSourceItem(dataSourceUid, createDataSourceItem(dataSourceUid)); // Sets data provider dataSourceController.setDataProvider(dataSourceUid, createDataProvider());