##// END OF EJS Templates
Merge branch 'feature/AmdaProviderImprovements' into develop
Alexandre Leroux -
r385:0ec770a1fa8f merge
parent child
Show More
@@ -0,0 +1,16
1 #ifndef SCIQLOP_AMDADEFS_H
2 #define SCIQLOP_AMDADEFS_H
3
4 #include <QString>
5
6 // ////////////// //
7 // AMDA constants //
8 // ////////////// //
9
10 // Relevant keys in JSON file
11 extern const QString AMDA_COMPONENT_KEY;
12 extern const QString AMDA_PRODUCT_KEY;
13 extern const QString AMDA_ROOT_KEY;
14 extern const QString AMDA_XML_ID_KEY;
15
16 #endif // SCIQLOP_AMDADEFS_H
@@ -0,0 +1,6
1 #include "AmdaDefs.h"
2
3 const QString AMDA_COMPONENT_KEY = QStringLiteral("component");
4 const QString AMDA_PRODUCT_KEY = QStringLiteral("parameter");
5 const QString AMDA_ROOT_KEY = QStringLiteral("dataCenter");
6 const QString AMDA_XML_ID_KEY = QStringLiteral("xml:id");
@@ -1,15 +1,18
1 1 #ifndef SCIQLOP_DATAPROVIDERPARAMETERS_H
2 2 #define SCIQLOP_DATAPROVIDERPARAMETERS_H
3 3
4 4 #include "SqpDateTime.h"
5 5
6 6 /**
7 7 * @brief The DataProviderParameters struct holds the information needed to retrieve data from a
8 8 * data provider
9 9 * @sa IDataProvider
10 10 */
11 11 struct DataProviderParameters {
12 SqpDateTime m_Time;
12 /// Times for which retrieve data
13 QVector<SqpDateTime> m_Times;
14 /// Extra data that can be used by the provider to retrieve data
15 QVariantHash m_Data;
13 16 };
14 17
15 18 #endif // SCIQLOP_DATAPROVIDERPARAMETERS_H
@@ -1,60 +1,59
1 1 #ifndef SCIQLOP_IDATAPROVIDER_H
2 2 #define SCIQLOP_IDATAPROVIDER_H
3 3
4 4 #include <memory>
5 5
6 6 #include <QObject>
7 7 #include <QUuid>
8 8
9 9 #include <Common/MetaTypes.h>
10 10
11 11 #include <Data/SqpDateTime.h>
12 12
13 13 class DataProviderParameters;
14 14 class IDataSeries;
15 15 class QNetworkReply;
16 16 class QNetworkRequest;
17 17
18 18 /**
19 19 * @brief The IDataProvider interface aims to declare a data provider.
20 20 *
21 21 * A data provider is an entity that generates data and returns it according to various parameters
22 22 * (time interval, product to retrieve the data, etc.)
23 23 *
24 24 * @sa IDataSeries
25 25 */
26 26 class IDataProvider : public QObject {
27 27
28 28 Q_OBJECT
29 29 public:
30 30 virtual ~IDataProvider() noexcept = default;
31 31
32 32 /**
33 * @brief requestDataLoading provide datas for the data identified by identifier for all
34 * SqpDateTime of dateTimeList
33 * @brief requestDataLoading provide datas for the data identified by identifier and parameters
35 34 */
36 virtual void requestDataLoading(QUuid identifier, const QVector<SqpDateTime> &dateTimeList) = 0;
35 virtual void requestDataLoading(QUuid identifier, const DataProviderParameters &parameters) = 0;
37 36
38 37 signals:
39 38 /**
40 39 * @brief dataProvided send dataSeries under dateTime and that corresponds of the data
41 40 * identified by identifier
42 41 */
43 42 void dataProvided(QUuid identifier, std::shared_ptr<IDataSeries> dateSerie,
44 43 const SqpDateTime &dateTime);
45 44
46 45
47 46 /**
48 47 * @brief requestConstructed send a request for the data identified by identifier
49 48 * @callback is the methode call by the reply of the request when it is finished.
50 49 */
51 50 void requestConstructed(const QNetworkRequest &request, QUuid identifier,
52 51 std::function<void(QNetworkReply *, QUuid)> callback);
53 52 };
54 53
55 54 // Required for using shared_ptr in signals/slots
56 55 SCIQLOP_REGISTER_META_TYPE(IDATAPROVIDER_PTR_REGISTRY, std::shared_ptr<IDataProvider>)
57 56 SCIQLOP_REGISTER_META_TYPE(IDATAPROVIDER_FUNCTION_REGISTRY,
58 57 std::function<void(QNetworkReply *, QUuid)>)
59 58
60 59 #endif // SCIQLOP_IDATAPROVIDER_H
@@ -1,90 +1,92
1 1 #ifndef SCIQLOP_DATASOURCECONTROLLER_H
2 2 #define SCIQLOP_DATASOURCECONTROLLER_H
3 3
4 4 #include <QLoggingCategory>
5 5 #include <QObject>
6 6 #include <QUuid>
7 7
8 8 #include <Common/spimpl.h>
9 9
10 10 Q_DECLARE_LOGGING_CATEGORY(LOG_DataSourceController)
11 11
12 12 class DataSourceItem;
13 13 class IDataProvider;
14 14
15 15 /**
16 16 * @brief The DataSourceController class aims to make the link between SciQlop and its plugins. This
17 17 * is the intermediate class that SciQlop has to use in the way to connect a data source. Please
18 18 * first use register method to initialize a plugin specified by its metadata name (JSON plugin
19 19 * source) then others specifics method will be able to access it. You can load a data source driver
20 20 * plugin then create a data source.
21 21 */
22 22 class DataSourceController : public QObject {
23 23 Q_OBJECT
24 24 public:
25 25 explicit DataSourceController(QObject *parent = 0);
26 26 virtual ~DataSourceController();
27 27
28 28 /**
29 29 * Registers a data source. The method delivers a unique id that can be used afterwards to
30 30 * access to the data source properties (structure, connection parameters, data provider, etc.)
31 31 * @param dataSourceName the name of the data source
32 32 * @return the unique id with which the data source has been registered
33 33 */
34 34 QUuid registerDataSource(const QString &dataSourceName) noexcept;
35 35
36 36 /**
37 37 * Sets the structure of a data source. The controller takes ownership of the structure.
38 38 * @param dataSourceUid the unique id with which the data source has been registered into the
39 39 * controller. If it is invalid, the method has no effect.
40 40 * @param dataSourceItem the structure of the data source. It must be not null to be registered
41 41 * @sa registerDataSource()
42 42 */
43 43 void setDataSourceItem(const QUuid &dataSourceUid,
44 44 std::unique_ptr<DataSourceItem> dataSourceItem) noexcept;
45 45
46 46 /**
47 47 * Sets the data provider used to retrieve data from of a data source. The controller takes
48 48 * ownership of the provider.
49 49 * @param dataSourceUid the unique id with which the data source has been registered into the
50 50 * controller. If it is invalid, the method has no effect.
51 51 * @param dataProvider the provider of the data source
52 52 * @sa registerDataSource()
53 53 */
54 54 void setDataProvider(const QUuid &dataSourceUid,
55 55 std::unique_ptr<IDataProvider> dataProvider) noexcept;
56 56
57 57 /**
58 58 * Loads an item (product) as a variable in SciQlop
59 59 * @param dataSourceUid the unique id of the data source containing the item. It is used to get
60 60 * the data provider associated to the data source, and pass it to for the variable creation
61 61 * @param productItem the item to load
62 62 */
63 63 void loadProductItem(const QUuid &dataSourceUid, const DataSourceItem &productItem) noexcept;
64 64
65 65 public slots:
66 66 /// Manage init/end of the controller
67 67 void initialize();
68 68 void finalize();
69 69
70 70 signals:
71 71 /// Signal emitted when a structure has been set for a data source
72 72 void dataSourceItemSet(DataSourceItem *dataSourceItem);
73 73
74 74 /**
75 75 * Signal emitted when a variable creation is asked for a product
76 76 * @param variableName the name of the variable
77 * @param variableMetadata the metadata of the variable
77 78 * @param variableProvider the provider that will be used to retrieve the data of the variable
78 79 * (can be null)
79 80 */
80 81 void variableCreationRequested(const QString &variableName,
82 const QVariantHash &variableMetadata,
81 83 std::shared_ptr<IDataProvider> variableProvider);
82 84
83 85 private:
84 86 void waitForFinish();
85 87
86 88 class DataSourceControllerPrivate;
87 89 spimpl::unique_impl_ptr<DataSourceControllerPrivate> impl;
88 90 };
89 91
90 92 #endif // SCIQLOP_DATASOURCECONTROLLER_H
@@ -1,94 +1,94
1 1 #ifndef SCIQLOP_DATASOURCEITEM_H
2 2 #define SCIQLOP_DATASOURCEITEM_H
3 3
4 4 #include <Common/spimpl.h>
5 5
6 6 #include <QVariant>
7 7 #include <QVector>
8 8
9 9 class DataSourceItemAction;
10 10
11 11 /**
12 12 * Possible types of an item
13 13 */
14 14 enum class DataSourceItemType { NODE, PRODUCT, COMPONENT };
15 15
16 16 /**
17 17 * @brief The DataSourceItem class aims to represent a structure element of a data source.
18 18 * A data source has a tree structure that is made up of a main DataSourceItem object (root)
19 19 * containing other DataSourceItem objects (children).
20 20 * For each DataSourceItem can be associated a set of data representing it.
21 21 */
22 22 class DataSourceItem {
23 23 public:
24 24 /// Key associated with the name of the item
25 25 static const QString NAME_DATA_KEY;
26 26
27 27 explicit DataSourceItem(DataSourceItemType type, const QString &name);
28 explicit DataSourceItem(DataSourceItemType type, QHash<QString, QVariant> data = {});
28 explicit DataSourceItem(DataSourceItemType type, QVariantHash data = {});
29 29
30 30 /// @return the actions of the item as a vector
31 31 QVector<DataSourceItemAction *> actions() const noexcept;
32 32
33 33 /**
34 34 * Adds an action to the item. The item takes ownership of the action, and the action is
35 35 * automatically associated to the item
36 36 * @param action the action to add
37 37 */
38 38 void addAction(std::unique_ptr<DataSourceItemAction> action) noexcept;
39 39
40 40 /**
41 41 * Adds a child to the item. The item takes ownership of the child.
42 42 * @param child the child to add
43 43 */
44 44 void appendChild(std::unique_ptr<DataSourceItem> child) noexcept;
45 45
46 46 /**
47 47 * Returns the item's child associated to an index
48 48 * @param childIndex the index to search
49 49 * @return a pointer to the child if index is valid, nullptr otherwise
50 50 */
51 51 DataSourceItem *child(int childIndex) const noexcept;
52 52
53 53 int childCount() const noexcept;
54 54
55 55 /**
56 56 * Get the data associated to a key
57 57 * @param key the key to search
58 58 * @return the data found if key is valid, default QVariant otherwise
59 59 */
60 60 QVariant data(const QString &key) const noexcept;
61 61
62 62 /// Gets all data
63 const QHash<QString, QVariant> &data() const noexcept;
63 QVariantHash data() const noexcept;
64 64
65 65 bool isRoot() const noexcept;
66 66
67 67 QString name() const noexcept;
68 68
69 69 /**
70 70 * Get the item's parent
71 71 * @return a pointer to the parent if it exists, nullptr if the item is a root
72 72 */
73 73 DataSourceItem *parentItem() const noexcept;
74 74
75 75 /**
76 76 * Sets or appends a value to a key
77 77 * @param key the key
78 78 * @param value the value
79 79 * @param append if true, the value is added to the values already existing for the key,
80 80 * otherwise it replaces the existing values
81 81 */
82 82 void setData(const QString &key, const QVariant &value, bool append = false) noexcept;
83 83
84 84 DataSourceItemType type() const noexcept;
85 85
86 86 bool operator==(const DataSourceItem &other);
87 87 bool operator!=(const DataSourceItem &other);
88 88
89 89 private:
90 90 class DataSourceItemPrivate;
91 91 spimpl::unique_impl_ptr<DataSourceItemPrivate> impl;
92 92 };
93 93
94 94 #endif // SCIQLOP_DATASOURCEITEMMODEL_H
@@ -1,55 +1,55
1 1 #ifndef SCIQLOP_VARIABLE_H
2 2 #define SCIQLOP_VARIABLE_H
3 3
4 4 #include <Data/SqpDateTime.h>
5 5
6 6 #include <QLoggingCategory>
7 7 #include <QObject>
8 8
9 9 #include <Common/MetaTypes.h>
10 10 #include <Common/spimpl.h>
11 11
12 12 Q_DECLARE_LOGGING_CATEGORY(LOG_Variable)
13 13
14 14 class IDataSeries;
15 15 class QString;
16 16
17 17 /**
18 18 * @brief The Variable class represents a variable in SciQlop.
19 19 */
20 20 class Variable : public QObject {
21 21
22 22 Q_OBJECT
23 23
24 24 public:
25 explicit Variable(const QString &name, const QString &unit, const QString &mission,
26 const SqpDateTime &dateTime);
25 explicit Variable(const QString &name, const SqpDateTime &dateTime,
26 const QVariantHash &metadata = {});
27 27
28 28 QString name() const noexcept;
29 QString mission() const noexcept;
30 QString unit() const noexcept;
31 29 SqpDateTime dateTime() const noexcept;
32 30 void setDateTime(const SqpDateTime &dateTime) noexcept;
33 31
34 32 /// @return the data of the variable, nullptr if there is no data
35 33 IDataSeries *dataSeries() const noexcept;
36 34
35 QVariantHash metadata() const noexcept;
36
37 37 bool contains(const SqpDateTime &dateTime) const noexcept;
38 38 bool intersect(const SqpDateTime &dateTime) const noexcept;
39 39 bool isInside(const SqpDateTime &dateTime) const noexcept;
40 40
41 41 public slots:
42 42 void setDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept;
43 43
44 44 signals:
45 45 void updated();
46 46
47 47 private:
48 48 class VariablePrivate;
49 49 spimpl::unique_impl_ptr<VariablePrivate> impl;
50 50 };
51 51
52 52 // Required for using shared_ptr in signals/slots
53 53 SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_REGISTRY, std::shared_ptr<Variable>)
54 54
55 55 #endif // SCIQLOP_VARIABLE_H
@@ -1,83 +1,85
1 1 #ifndef SCIQLOP_VARIABLECONTROLLER_H
2 2 #define SCIQLOP_VARIABLECONTROLLER_H
3 3
4 4 #include <Data/SqpDateTime.h>
5 5
6 6 #include <QLoggingCategory>
7 7 #include <QObject>
8 8
9 9 #include <Common/spimpl.h>
10 10
11 11 class IDataProvider;
12 12 class QItemSelectionModel;
13 13 class TimeController;
14 14 class Variable;
15 15 class VariableModel;
16 16
17 17 Q_DECLARE_LOGGING_CATEGORY(LOG_VariableController)
18 18
19 19 /**
20 20 * @brief The VariableController class aims to handle the variables in SciQlop.
21 21 */
22 22 class VariableController : public QObject {
23 23 Q_OBJECT
24 24 public:
25 25 explicit VariableController(QObject *parent = 0);
26 26 virtual ~VariableController();
27 27
28 28 VariableModel *variableModel() noexcept;
29 29 QItemSelectionModel *variableSelectionModel() noexcept;
30 30
31 31 void setTimeController(TimeController *timeController) noexcept;
32 32
33 33 /**
34 34 * Deletes from the controller the variable passed in parameter.
35 35 *
36 36 * Delete a variable includes:
37 37 * - the deletion of the various references to the variable in SciQlop
38 38 * - the deletion of the model variable
39 39 * - the deletion of the provider associated with the variable
40 40 * - removing the cache associated with the variable
41 41 *
42 42 * @param variable the variable to delete from the controller.
43 43 */
44 44 void deleteVariable(std::shared_ptr<Variable> variable) noexcept;
45 45
46 46 /**
47 47 * Deletes from the controller the variables passed in parameter.
48 48 * @param variables the variables to delete from the controller.
49 49 * @sa deleteVariable()
50 50 */
51 51 void deleteVariables(const QVector<std::shared_ptr<Variable> > &variables) noexcept;
52 52
53 53 signals:
54 54 /// Signal emitted when a variable is about to be deleted from the controller
55 55 void variableAboutToBeDeleted(std::shared_ptr<Variable> variable);
56 56
57 57 public slots:
58 58 /// Request the data loading of the variable whithin dateTime
59 59 void onRequestDataLoading(std::shared_ptr<Variable> variable, const SqpDateTime &dateTime);
60 60 /**
61 61 * Creates a new variable and adds it to the model
62 62 * @param name the name of the new variable
63 * @param metadata the metadata of the new variable
63 64 * @param provider the data provider for the new variable
64 65 */
65 void createVariable(const QString &name, std::shared_ptr<IDataProvider> provider) noexcept;
66 void createVariable(const QString &name, const QVariantHash &metadata,
67 std::shared_ptr<IDataProvider> provider) noexcept;
66 68
67 69 /// Update the temporal parameters of every selected variable to dateTime
68 70 void onDateTimeOnSelection(const SqpDateTime &dateTime);
69 71
70 72
71 73 void onVariableRetrieveDataInProgress(QUuid identifier, double progress);
72 74
73 75 void initialize();
74 76 void finalize();
75 77
76 78 private:
77 79 void waitForFinish();
78 80
79 81 class VariableControllerPrivate;
80 82 spimpl::unique_impl_ptr<VariableControllerPrivate> impl;
81 83 };
82 84
83 85 #endif // SCIQLOP_VARIABLECONTROLLER_H
@@ -1,70 +1,71
1 1 #ifndef SCIQLOP_VARIABLEMODEL_H
2 2 #define SCIQLOP_VARIABLEMODEL_H
3 3
4 4
5 5 #include <Data/SqpDateTime.h>
6 6
7 7 #include <QAbstractTableModel>
8 8 #include <QLoggingCategory>
9 9
10 10 #include <Common/MetaTypes.h>
11 11 #include <Common/spimpl.h>
12 12
13 13 Q_DECLARE_LOGGING_CATEGORY(LOG_VariableModel)
14 14
15 15 enum VariableRoles { ProgressRole = Qt::UserRole };
16 16
17 17
18 18 class IDataSeries;
19 19 class Variable;
20 20
21 21 /**
22 22 * @brief The VariableModel class aims to hold the variables that have been created in SciQlop
23 23 */
24 24 class VariableModel : public QAbstractTableModel {
25 25 public:
26 26 explicit VariableModel(QObject *parent = nullptr);
27 27
28 28 /**
29 29 * Creates a new variable in the model
30 30 * @param name the name of the new variable
31 31 * @param dateTime the dateTime of the new variable
32 * @param metadata the metadata associated to the new variable
32 33 * @return the pointer to the new variable
33 34 */
34 std::shared_ptr<Variable> createVariable(const QString &name,
35 const SqpDateTime &dateTime) noexcept;
35 std::shared_ptr<Variable> createVariable(const QString &name, const SqpDateTime &dateTime,
36 const QVariantHash &metadata) noexcept;
36 37
37 38 /**
38 39 * Deletes a variable from the model, if it exists
39 40 * @param variable the variable to delete
40 41 */
41 42 void deleteVariable(std::shared_ptr<Variable> variable) noexcept;
42 43
43 44
44 45 std::shared_ptr<Variable> variable(int index) const;
45 46
46 47 void setDataProgress(std::shared_ptr<Variable> variable, double progress);
47 48
48 49 // /////////////////////////// //
49 50 // QAbstractTableModel methods //
50 51 // /////////////////////////// //
51 52
52 53 virtual int columnCount(const QModelIndex &parent = QModelIndex{}) const override;
53 54 virtual int rowCount(const QModelIndex &parent = QModelIndex{}) const override;
54 55 virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
55 56 virtual QVariant headerData(int section, Qt::Orientation orientation,
56 57 int role = Qt::DisplayRole) const override;
57 58
58 59 private:
59 60 class VariableModelPrivate;
60 61 spimpl::unique_impl_ptr<VariableModelPrivate> impl;
61 62
62 63 private slots:
63 64 /// Slot called when data of a variable has been updated
64 65 void onVariableUpdated() noexcept;
65 66 };
66 67
67 68 // Registers QVector<int> metatype so it can be used in VariableModel::dataChanged() signal
68 69 SCIQLOP_REGISTER_META_TYPE(QVECTOR_INT_REGISTRY, QVector<int>)
69 70
70 71 #endif // SCIQLOP_VARIABLEMODEL_H
@@ -1,120 +1,120
1 1 #include "DataSource/DataSourceController.h"
2 2 #include "DataSource/DataSourceItem.h"
3 3
4 4 #include <Data/IDataProvider.h>
5 5
6 6 #include <QMutex>
7 7 #include <QThread>
8 8
9 9 #include <QDir>
10 10 #include <QStandardPaths>
11 11
12 12 Q_LOGGING_CATEGORY(LOG_DataSourceController, "DataSourceController")
13 13
14 14 class DataSourceController::DataSourceControllerPrivate {
15 15 public:
16 16 QMutex m_WorkingMutex;
17 17 /// Data sources registered
18 18 QHash<QUuid, QString> m_DataSources;
19 19 /// Data sources structures
20 20 std::map<QUuid, std::unique_ptr<DataSourceItem> > m_DataSourceItems;
21 21 /// Data providers registered
22 22 /// @remarks Data providers are stored as shared_ptr as they can be sent to a variable and
23 23 /// continue to live without necessarily the data source controller
24 24 std::map<QUuid, std::shared_ptr<IDataProvider> > m_DataProviders;
25 25 };
26 26
27 27 DataSourceController::DataSourceController(QObject *parent)
28 28 : impl{spimpl::make_unique_impl<DataSourceControllerPrivate>()}
29 29 {
30 30 qCDebug(LOG_DataSourceController()) << tr("DataSourceController construction")
31 31 << QThread::currentThread();
32 32 }
33 33
34 34 DataSourceController::~DataSourceController()
35 35 {
36 36 qCDebug(LOG_DataSourceController()) << tr("DataSourceController destruction")
37 37 << QThread::currentThread();
38 38 this->waitForFinish();
39 39 }
40 40
41 41 QUuid DataSourceController::registerDataSource(const QString &dataSourceName) noexcept
42 42 {
43 43 auto dataSourceUid = QUuid::createUuid();
44 44 impl->m_DataSources.insert(dataSourceUid, dataSourceName);
45 45
46 46 return dataSourceUid;
47 47 }
48 48
49 49 void DataSourceController::setDataSourceItem(
50 50 const QUuid &dataSourceUid, std::unique_ptr<DataSourceItem> dataSourceItem) noexcept
51 51 {
52 52 if (!dataSourceItem) {
53 53 qCWarning(LOG_DataSourceController())
54 54 << tr("Data source item can't be registered (null item)");
55 55 return;
56 56 }
57 57
58 58 if (impl->m_DataSources.contains(dataSourceUid)) {
59 59 // The data provider is implicitly converted to a shared_ptr
60 60 impl->m_DataSourceItems.insert(std::make_pair(dataSourceUid, std::move(dataSourceItem)));
61 61
62 62 // Retrieves the data source item to emit the signal with it
63 63 auto it = impl->m_DataSourceItems.find(dataSourceUid);
64 64 if (it != impl->m_DataSourceItems.end()) {
65 65 emit dataSourceItemSet(it->second.get());
66 66 }
67 67 }
68 68 else {
69 69 qCWarning(LOG_DataSourceController()) << tr("Can't set data source item for uid %1 : no "
70 70 "data source has been registered with the uid")
71 71 .arg(dataSourceUid.toString());
72 72 }
73 73 }
74 74
75 75 void DataSourceController::setDataProvider(const QUuid &dataSourceUid,
76 76 std::unique_ptr<IDataProvider> dataProvider) noexcept
77 77 {
78 78 if (impl->m_DataSources.contains(dataSourceUid)) {
79 79 impl->m_DataProviders.insert(std::make_pair(dataSourceUid, std::move(dataProvider)));
80 80 }
81 81 else {
82 82 qCWarning(LOG_DataSourceController()) << tr("Can't set data provider for uid %1 : no data "
83 83 "source has been registered with the uid")
84 84 .arg(dataSourceUid.toString());
85 85 }
86 86 }
87 87
88 88 void DataSourceController::loadProductItem(const QUuid &dataSourceUid,
89 89 const DataSourceItem &productItem) noexcept
90 90 {
91 if (productItem.type() == DataSourceItemType::PRODUCT) {
91 if (productItem.type() == DataSourceItemType::PRODUCT
92 || productItem.type() == DataSourceItemType::COMPONENT) {
92 93 /// Retrieves the data provider of the data source (if any)
93 94 auto it = impl->m_DataProviders.find(dataSourceUid);
94 95 auto dataProvider = (it != impl->m_DataProviders.end()) ? it->second : nullptr;
95 96
96 /// @todo retrieve timerange, and pass it to the signal
97 emit variableCreationRequested(productItem.name(), dataProvider);
97 emit variableCreationRequested(productItem.name(), productItem.data(), dataProvider);
98 98 }
99 99 else {
100 100 qCWarning(LOG_DataSourceController()) << tr("Can't load an item that is not a product");
101 101 }
102 102 }
103 103
104 104 void DataSourceController::initialize()
105 105 {
106 106 qCDebug(LOG_DataSourceController()) << tr("DataSourceController init")
107 107 << QThread::currentThread();
108 108 impl->m_WorkingMutex.lock();
109 109 qCDebug(LOG_DataSourceController()) << tr("DataSourceController init END");
110 110 }
111 111
112 112 void DataSourceController::finalize()
113 113 {
114 114 impl->m_WorkingMutex.unlock();
115 115 }
116 116
117 117 void DataSourceController::waitForFinish()
118 118 {
119 119 QMutexLocker locker{&impl->m_WorkingMutex};
120 120 }
@@ -1,140 +1,140
1 1 #include <DataSource/DataSourceItem.h>
2 2 #include <DataSource/DataSourceItemAction.h>
3 3
4 4 #include <QVector>
5 5
6 6 const QString DataSourceItem::NAME_DATA_KEY = QStringLiteral("name");
7 7
8 8 struct DataSourceItem::DataSourceItemPrivate {
9 explicit DataSourceItemPrivate(DataSourceItemType type, QHash<QString, QVariant> data)
9 explicit DataSourceItemPrivate(DataSourceItemType type, QVariantHash data)
10 10 : m_Parent{nullptr}, m_Children{}, m_Type{type}, m_Data{std::move(data)}, m_Actions{}
11 11 {
12 12 }
13 13
14 14 DataSourceItem *m_Parent;
15 15 std::vector<std::unique_ptr<DataSourceItem> > m_Children;
16 16 DataSourceItemType m_Type;
17 QHash<QString, QVariant> m_Data;
17 QVariantHash m_Data;
18 18 std::vector<std::unique_ptr<DataSourceItemAction> > m_Actions;
19 19 };
20 20
21 21 DataSourceItem::DataSourceItem(DataSourceItemType type, const QString &name)
22 : DataSourceItem{type, QHash<QString, QVariant>{{NAME_DATA_KEY, name}}}
22 : DataSourceItem{type, QVariantHash{{NAME_DATA_KEY, name}}}
23 23 {
24 24 }
25 25
26 DataSourceItem::DataSourceItem(DataSourceItemType type, QHash<QString, QVariant> data)
26 DataSourceItem::DataSourceItem(DataSourceItemType type, QVariantHash data)
27 27 : impl{spimpl::make_unique_impl<DataSourceItemPrivate>(type, std::move(data))}
28 28 {
29 29 }
30 30
31 31 QVector<DataSourceItemAction *> DataSourceItem::actions() const noexcept
32 32 {
33 33 auto result = QVector<DataSourceItemAction *>{};
34 34
35 35 std::transform(std::cbegin(impl->m_Actions), std::cend(impl->m_Actions),
36 36 std::back_inserter(result), [](const auto &action) { return action.get(); });
37 37
38 38 return result;
39 39 }
40 40
41 41 void DataSourceItem::addAction(std::unique_ptr<DataSourceItemAction> action) noexcept
42 42 {
43 43 action->setDataSourceItem(this);
44 44 impl->m_Actions.push_back(std::move(action));
45 45 }
46 46
47 47 void DataSourceItem::appendChild(std::unique_ptr<DataSourceItem> child) noexcept
48 48 {
49 49 child->impl->m_Parent = this;
50 50 impl->m_Children.push_back(std::move(child));
51 51 }
52 52
53 53 DataSourceItem *DataSourceItem::child(int childIndex) const noexcept
54 54 {
55 55 if (childIndex < 0 || childIndex >= childCount()) {
56 56 return nullptr;
57 57 }
58 58 else {
59 59 return impl->m_Children.at(childIndex).get();
60 60 }
61 61 }
62 62
63 63 int DataSourceItem::childCount() const noexcept
64 64 {
65 65 return impl->m_Children.size();
66 66 }
67 67
68 68 QVariant DataSourceItem::data(const QString &key) const noexcept
69 69 {
70 70 return impl->m_Data.value(key);
71 71 }
72 72
73 const QHash<QString, QVariant> &DataSourceItem::data() const noexcept
73 QVariantHash DataSourceItem::data() const noexcept
74 74 {
75 75 return impl->m_Data;
76 76 }
77 77
78 78 bool DataSourceItem::isRoot() const noexcept
79 79 {
80 80 return impl->m_Parent == nullptr;
81 81 }
82 82
83 83 QString DataSourceItem::name() const noexcept
84 84 {
85 85 return data(NAME_DATA_KEY).toString();
86 86 }
87 87
88 88 DataSourceItem *DataSourceItem::parentItem() const noexcept
89 89 {
90 90 return impl->m_Parent;
91 91 }
92 92
93 93 void DataSourceItem::setData(const QString &key, const QVariant &value, bool append) noexcept
94 94 {
95 95 auto it = impl->m_Data.constFind(key);
96 96 if (append && it != impl->m_Data.constEnd()) {
97 97 // Case of an existing value to which we want to add to the new value
98 98 if (it->canConvert<QVariantList>()) {
99 99 auto variantList = it->value<QVariantList>();
100 100 variantList.append(value);
101 101
102 102 impl->m_Data.insert(key, variantList);
103 103 }
104 104 else {
105 105 impl->m_Data.insert(key, QVariantList{*it, value});
106 106 }
107 107 }
108 108 else {
109 109 // Other cases :
110 110 // - new value in map OR
111 111 // - replacement of an existing value (not appending)
112 112 impl->m_Data.insert(key, value);
113 113 }
114 114 }
115 115
116 116 DataSourceItemType DataSourceItem::type() const noexcept
117 117 {
118 118 return impl->m_Type;
119 119 }
120 120
121 121 bool DataSourceItem::operator==(const DataSourceItem &other)
122 122 {
123 123 // Compares items' attributes
124 124 if (std::tie(impl->m_Type, impl->m_Data) == std::tie(other.impl->m_Type, other.impl->m_Data)) {
125 125 // Compares contents of items' children
126 126 return std::equal(std::cbegin(impl->m_Children), std::cend(impl->m_Children),
127 127 std::cbegin(other.impl->m_Children),
128 128 [](const auto &itemChild, const auto &otherChild) {
129 129 return *itemChild == *otherChild;
130 130 });
131 131 }
132 132 else {
133 133 return false;
134 134 }
135 135 }
136 136
137 137 bool DataSourceItem::operator!=(const DataSourceItem &other)
138 138 {
139 139 return !(*this == other);
140 140 }
@@ -1,101 +1,90
1 1 #include "Variable/Variable.h"
2 2
3 3 #include <Data/IDataSeries.h>
4 4 #include <Data/SqpDateTime.h>
5 5
6 6 #include <QReadWriteLock>
7 7 #include <QThread>
8 8
9 9 Q_LOGGING_CATEGORY(LOG_Variable, "Variable")
10 10
11 11 struct Variable::VariablePrivate {
12 explicit VariablePrivate(const QString &name, const QString &unit, const QString &mission,
13 const SqpDateTime &dateTime)
14 : m_Name{name},
15 m_Unit{unit},
16 m_Mission{mission},
17 m_DateTime{dateTime},
18 m_DataSeries{nullptr}
12 explicit VariablePrivate(const QString &name, const SqpDateTime &dateTime,
13 const QVariantHash &metadata)
14 : m_Name{name}, m_DateTime{dateTime}, m_Metadata{metadata}, m_DataSeries{nullptr}
19 15 {
20 16 }
21 17
22 18 QString m_Name;
23 QString m_Unit;
24 QString m_Mission;
25 19
26 20 SqpDateTime m_DateTime; // The dateTime available in the view and loaded. not the cache.
21 QVariantHash m_Metadata;
27 22 std::unique_ptr<IDataSeries> m_DataSeries;
28 23 };
29 24
30 Variable::Variable(const QString &name, const QString &unit, const QString &mission,
31 const SqpDateTime &dateTime)
32 : impl{spimpl::make_unique_impl<VariablePrivate>(name, unit, mission, dateTime)}
25 Variable::Variable(const QString &name, const SqpDateTime &dateTime, const QVariantHash &metadata)
26 : impl{spimpl::make_unique_impl<VariablePrivate>(name, dateTime, metadata)}
33 27 {
34 28 }
35 29
36 30 QString Variable::name() const noexcept
37 31 {
38 32 return impl->m_Name;
39 33 }
40 34
41 QString Variable::mission() const noexcept
42 {
43 return impl->m_Mission;
44 }
45
46 QString Variable::unit() const noexcept
47 {
48 return impl->m_Unit;
49 }
50
51 35 SqpDateTime Variable::dateTime() const noexcept
52 36 {
53 37 return impl->m_DateTime;
54 38 }
55 39
56 40 void Variable::setDateTime(const SqpDateTime &dateTime) noexcept
57 41 {
58 42 impl->m_DateTime = dateTime;
59 43 }
60 44
61 45 void Variable::setDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept
62 46 {
63 47 qCDebug(LOG_Variable()) << "Variable::setDataSeries" << QThread::currentThread()->objectName();
64 48 if (!dataSeries) {
65 49 /// @todo ALX : log
66 50 return;
67 51 }
68 52
69 53 // Inits the data series of the variable
70 54 if (!impl->m_DataSeries) {
71 55 impl->m_DataSeries = dataSeries->clone();
72 56 }
73 57 else {
74 58 dataSeries->lockWrite();
75 59 impl->m_DataSeries->lockWrite();
76 60 impl->m_DataSeries->merge(dataSeries.get());
77 61 impl->m_DataSeries->unlock();
78 62 dataSeries->unlock();
79 63 emit updated();
80 64 }
81 65 }
82 66
83 67 IDataSeries *Variable::dataSeries() const noexcept
84 68 {
85 69 return impl->m_DataSeries.get();
86 70 }
87 71
72 QVariantHash Variable::metadata() const noexcept
73 {
74 return impl->m_Metadata;
75 }
76
88 77 bool Variable::contains(const SqpDateTime &dateTime) const noexcept
89 78 {
90 79 return impl->m_DateTime.contains(dateTime);
91 80 }
92 81
93 82 bool Variable::intersect(const SqpDateTime &dateTime) const noexcept
94 83 {
95 84 return impl->m_DateTime.intersect(dateTime);
96 85 }
97 86
98 87 bool Variable::isInside(const SqpDateTime &dateTime) const noexcept
99 88 {
100 89 return dateTime.contains(SqpDateTime{impl->m_DateTime.m_TStart, impl->m_DateTime.m_TEnd});
101 90 }
@@ -1,216 +1,212
1 1 #include <Variable/Variable.h>
2 2 #include <Variable/VariableCacheController.h>
3 3 #include <Variable/VariableController.h>
4 4 #include <Variable/VariableModel.h>
5 5
6 6 #include <Data/DataProviderParameters.h>
7 7 #include <Data/IDataProvider.h>
8 8 #include <Data/IDataSeries.h>
9 9 #include <Time/TimeController.h>
10 10
11 11 #include <QDateTime>
12 12 #include <QMutex>
13 13 #include <QThread>
14 14 #include <QUuid>
15 15 #include <QtCore/QItemSelectionModel>
16 16
17 17 #include <unordered_map>
18 18
19 19 Q_LOGGING_CATEGORY(LOG_VariableController, "VariableController")
20 20
21 21 struct VariableController::VariableControllerPrivate {
22 22 explicit VariableControllerPrivate(VariableController *parent)
23 23 : m_WorkingMutex{},
24 24 m_VariableModel{new VariableModel{parent}},
25 25 m_VariableSelectionModel{new QItemSelectionModel{m_VariableModel, parent}},
26 26 m_VariableCacheController{std::make_unique<VariableCacheController>()}
27 27 {
28 28 }
29 29
30 30 QMutex m_WorkingMutex;
31 31 /// Variable model. The VariableController has the ownership
32 32 VariableModel *m_VariableModel;
33 33 QItemSelectionModel *m_VariableSelectionModel;
34 34
35 35
36 36 TimeController *m_TimeController{nullptr};
37 37 std::unique_ptr<VariableCacheController> m_VariableCacheController;
38 38
39 39 std::unordered_map<std::shared_ptr<Variable>, std::shared_ptr<IDataProvider> >
40 40 m_VariableToProviderMap;
41 41 std::unordered_map<std::shared_ptr<Variable>, QUuid> m_VariableToIdentifier;
42 42 };
43 43
44 44 VariableController::VariableController(QObject *parent)
45 45 : QObject{parent}, impl{spimpl::make_unique_impl<VariableControllerPrivate>(this)}
46 46 {
47 47 qCDebug(LOG_VariableController()) << tr("VariableController construction")
48 48 << QThread::currentThread();
49 49 }
50 50
51 51 VariableController::~VariableController()
52 52 {
53 53 qCDebug(LOG_VariableController()) << tr("VariableController destruction")
54 54 << QThread::currentThread();
55 55 this->waitForFinish();
56 56 }
57 57
58 58 VariableModel *VariableController::variableModel() noexcept
59 59 {
60 60 return impl->m_VariableModel;
61 61 }
62 62
63 63 QItemSelectionModel *VariableController::variableSelectionModel() noexcept
64 64 {
65 65 return impl->m_VariableSelectionModel;
66 66 }
67 67
68 68 void VariableController::setTimeController(TimeController *timeController) noexcept
69 69 {
70 70 impl->m_TimeController = timeController;
71 71 }
72 72
73 73 void VariableController::deleteVariable(std::shared_ptr<Variable> variable) noexcept
74 74 {
75 75 if (!variable) {
76 76 qCCritical(LOG_VariableController()) << "Can't delete variable: variable is null";
77 77 return;
78 78 }
79 79
80 80 // Spreads in SciQlop that the variable will be deleted, so that potential receivers can
81 81 // make some treatments before the deletion
82 82 emit variableAboutToBeDeleted(variable);
83 83
84 84 // Deletes provider
85 85 auto nbProvidersDeleted = impl->m_VariableToProviderMap.erase(variable);
86 86 qCDebug(LOG_VariableController())
87 87 << tr("Number of providers deleted for variable %1: %2")
88 88 .arg(variable->name(), QString::number(nbProvidersDeleted));
89 89
90 90 // Clears cache
91 91 impl->m_VariableCacheController->clear(variable);
92 92
93 93 // Deletes from model
94 94 impl->m_VariableModel->deleteVariable(variable);
95 95 }
96 96
97 97 void VariableController::deleteVariables(
98 98 const QVector<std::shared_ptr<Variable> > &variables) noexcept
99 99 {
100 100 for (auto variable : qAsConst(variables)) {
101 101 deleteVariable(variable);
102 102 }
103 103 }
104 104
105 void VariableController::createVariable(const QString &name,
105 void VariableController::createVariable(const QString &name, const QVariantHash &metadata,
106 106 std::shared_ptr<IDataProvider> provider) noexcept
107 107 {
108 108
109 109 if (!impl->m_TimeController) {
110 110 qCCritical(LOG_VariableController())
111 111 << tr("Impossible to create variable: The time controller is null");
112 112 return;
113 113 }
114 114
115
116 /// @todo : for the moment :
117 /// - the provider is only used to retrieve data from the variable for its initialization, but
118 /// it will be retained later
119 /// - default data are generated for the variable, without taking into account the timerange set
120 /// in sciqlop
121 115 auto dateTime = impl->m_TimeController->dateTime();
122 if (auto newVariable = impl->m_VariableModel->createVariable(name, dateTime)) {
116
117 if (auto newVariable = impl->m_VariableModel->createVariable(name, dateTime, metadata)) {
123 118 auto identifier = QUuid::createUuid();
124 119
125 120 // store the provider
126 121 impl->m_VariableToProviderMap[newVariable] = provider;
127 122 impl->m_VariableToIdentifier[newVariable] = identifier;
128 123
129 124 auto addDateTimeAcquired = [ this, varW = std::weak_ptr<Variable>{newVariable} ](
130 125 QUuid identifier, auto dataSeriesAcquired, auto dateTimeToPutInCache)
131 126 {
132 127 if (auto variable = varW.lock()) {
133 128 auto varIdentifier = impl->m_VariableToIdentifier.at(variable);
134 129 if (varIdentifier == identifier) {
135 130 impl->m_VariableCacheController->addDateTime(variable, dateTimeToPutInCache);
136 131 variable->setDataSeries(dataSeriesAcquired);
137 132 }
138 133 }
139 134 };
140 135
141 136 connect(provider.get(), &IDataProvider::dataProvided, addDateTimeAcquired);
142 137 this->onRequestDataLoading(newVariable, dateTime);
143 138 }
144 139 }
145 140
146 141 void VariableController::onDateTimeOnSelection(const SqpDateTime &dateTime)
147 142 {
148 143 qCDebug(LOG_VariableController()) << "VariableController::onDateTimeOnSelection"
149 144 << QThread::currentThread()->objectName();
150 145 auto selectedRows = impl->m_VariableSelectionModel->selectedRows();
151 146
152 147 for (const auto &selectedRow : qAsConst(selectedRows)) {
153 148 if (auto selectedVariable = impl->m_VariableModel->variable(selectedRow.row())) {
154 149 selectedVariable->setDateTime(dateTime);
155 150 this->onRequestDataLoading(selectedVariable, dateTime);
156 151 }
157 152 }
158 153 }
159 154
160 155 void VariableController::onVariableRetrieveDataInProgress(QUuid identifier, double progress)
161 156 {
162 157 auto findReply = [identifier](const auto &entry) { return identifier == entry.second; };
163 158
164 159 auto end = impl->m_VariableToIdentifier.cend();
165 160 auto it = std::find_if(impl->m_VariableToIdentifier.cbegin(), end, findReply);
166 161 if (it != end) {
167 162 impl->m_VariableModel->setDataProgress(it->first, progress);
168 163 }
169 164 }
170 165
171 166
172 167 void VariableController::onRequestDataLoading(std::shared_ptr<Variable> variable,
173 168 const SqpDateTime &dateTime)
174 169 {
175 170 qCDebug(LOG_VariableController()) << "VariableController::onRequestDataLoading"
176 171 << QThread::currentThread()->objectName();
177 172 // we want to load data of the variable for the dateTime.
178 173 // First we check if the cache contains some of them.
179 174 // For the other, we ask the provider to give them.
180 175 if (variable) {
181 176
182 177 auto dateTimeListNotInCache
183 178 = impl->m_VariableCacheController->provideNotInCacheDateTimeList(variable, dateTime);
184 179
185 180 if (!dateTimeListNotInCache.empty()) {
186 181 // Ask the provider for each data on the dateTimeListNotInCache
187 182 auto identifier = impl->m_VariableToIdentifier.at(variable);
188 183 impl->m_VariableToProviderMap.at(variable)->requestDataLoading(
189 identifier, std::move(dateTimeListNotInCache));
184 identifier,
185 DataProviderParameters{std::move(dateTimeListNotInCache), variable->metadata()});
190 186 }
191 187 else {
192 188 emit variable->updated();
193 189 }
194 190 }
195 191 else {
196 192 qCCritical(LOG_VariableController()) << tr("Impossible to load data of a variable null");
197 193 }
198 194 }
199 195
200 196
201 197 void VariableController::initialize()
202 198 {
203 199 qCDebug(LOG_VariableController()) << tr("VariableController init") << QThread::currentThread();
204 200 impl->m_WorkingMutex.lock();
205 201 qCDebug(LOG_VariableController()) << tr("VariableController init END");
206 202 }
207 203
208 204 void VariableController::finalize()
209 205 {
210 206 impl->m_WorkingMutex.unlock();
211 207 }
212 208
213 209 void VariableController::waitForFinish()
214 210 {
215 211 QMutexLocker locker{&impl->m_WorkingMutex};
216 212 }
@@ -1,236 +1,235
1 1 #include <Variable/Variable.h>
2 2 #include <Variable/VariableModel.h>
3 3
4 4 #include <Data/IDataSeries.h>
5 5
6 6 #include <QDateTime>
7 7 #include <QSize>
8 8 #include <unordered_map>
9 9
10 10 Q_LOGGING_CATEGORY(LOG_VariableModel, "VariableModel")
11 11
12 12 namespace {
13 13
14 14 // Column indexes
15 15 const auto NAME_COLUMN = 0;
16 16 const auto TSTART_COLUMN = 1;
17 17 const auto TEND_COLUMN = 2;
18 18 const auto NB_COLUMNS = 3;
19 19
20 20 // Column properties
21 21 const auto DEFAULT_HEIGHT = 25;
22 22 const auto DEFAULT_WIDTH = 100;
23 23
24 24 struct ColumnProperties {
25 25 ColumnProperties(const QString &name = {}, int width = DEFAULT_WIDTH,
26 26 int height = DEFAULT_HEIGHT)
27 27 : m_Name{name}, m_Width{width}, m_Height{height}
28 28 {
29 29 }
30 30
31 31 QString m_Name;
32 32 int m_Width;
33 33 int m_Height;
34 34 };
35 35
36 36 const auto COLUMN_PROPERTIES
37 37 = QHash<int, ColumnProperties>{{NAME_COLUMN, {QObject::tr("Name")}},
38 38 {TSTART_COLUMN, {QObject::tr("tStart"), 180}},
39 39 {TEND_COLUMN, {QObject::tr("tEnd"), 180}}};
40 40
41 41 /// Format for datetimes
42 42 const auto DATETIME_FORMAT = QStringLiteral("dd/MM/yyyy \nhh:mm:ss:zzz");
43 43
44 44
45 45 } // namespace
46 46
47 47 struct VariableModel::VariableModelPrivate {
48 48 /// Variables created in SciQlop
49 49 std::vector<std::shared_ptr<Variable> > m_Variables;
50 50 std::unordered_map<std::shared_ptr<Variable>, double> m_VariableToProgress;
51 51
52 52
53 53 /// Return the row index of the variable. -1 if it's not found
54 54 int indexOfVariable(Variable *variable) const noexcept;
55 55 };
56 56
57 57 VariableModel::VariableModel(QObject *parent)
58 58 : QAbstractTableModel{parent}, impl{spimpl::make_unique_impl<VariableModelPrivate>()}
59 59 {
60 60 }
61 61
62 62 std::shared_ptr<Variable> VariableModel::createVariable(const QString &name,
63 const SqpDateTime &dateTime) noexcept
63 const SqpDateTime &dateTime,
64 const QVariantHash &metadata) noexcept
64 65 {
65 66 auto insertIndex = rowCount();
66 67 beginInsertRows({}, insertIndex, insertIndex);
67 68
68 /// @todo For the moment, the other data of the variable is initialized with default values
69 auto variable = std::make_shared<Variable>(name, QStringLiteral("unit"),
70 QStringLiteral("mission"), dateTime);
69 auto variable = std::make_shared<Variable>(name, dateTime, metadata);
71 70
72 71 impl->m_Variables.push_back(variable);
73 72 connect(variable.get(), &Variable::updated, this, &VariableModel::onVariableUpdated);
74 73
75 74 endInsertRows();
76 75
77 76 return variable;
78 77 }
79 78
80 79 void VariableModel::deleteVariable(std::shared_ptr<Variable> variable) noexcept
81 80 {
82 81 if (!variable) {
83 82 qCCritical(LOG_Variable()) << "Can't delete a null variable from the model";
84 83 return;
85 84 }
86 85
87 86 // Finds variable in the model
88 87 auto begin = impl->m_Variables.cbegin();
89 88 auto end = impl->m_Variables.cend();
90 89 auto it = std::find(begin, end, variable);
91 90 if (it != end) {
92 91 auto removeIndex = std::distance(begin, it);
93 92
94 93 // Deletes variable
95 94 beginRemoveRows({}, removeIndex, removeIndex);
96 95 impl->m_Variables.erase(it);
97 96 endRemoveRows();
98 97 }
99 98 else {
100 99 qCritical(LOG_VariableModel())
101 100 << tr("Can't delete variable %1 from the model: the variable is not in the model")
102 101 .arg(variable->name());
103 102 }
104 103 }
105 104
106 105
107 106 std::shared_ptr<Variable> VariableModel::variable(int index) const
108 107 {
109 108 return (index >= 0 && index < impl->m_Variables.size()) ? impl->m_Variables[index] : nullptr;
110 109 }
111 110
112 111 void VariableModel::setDataProgress(std::shared_ptr<Variable> variable, double progress)
113 112 {
114 113
115 114 impl->m_VariableToProgress[variable] = progress;
116 115 auto modelIndex = createIndex(impl->indexOfVariable(variable.get()), NAME_COLUMN);
117 116
118 117 emit dataChanged(modelIndex, modelIndex);
119 118 }
120 119
121 120 int VariableModel::columnCount(const QModelIndex &parent) const
122 121 {
123 122 Q_UNUSED(parent);
124 123
125 124 return NB_COLUMNS;
126 125 }
127 126
128 127 int VariableModel::rowCount(const QModelIndex &parent) const
129 128 {
130 129 Q_UNUSED(parent);
131 130
132 131 return impl->m_Variables.size();
133 132 }
134 133
135 134 QVariant VariableModel::data(const QModelIndex &index, int role) const
136 135 {
137 136 if (!index.isValid()) {
138 137 return QVariant{};
139 138 }
140 139
141 140 if (index.row() < 0 || index.row() >= rowCount()) {
142 141 return QVariant{};
143 142 }
144 143
145 144 if (role == Qt::DisplayRole) {
146 145 if (auto variable = impl->m_Variables.at(index.row()).get()) {
147 146 /// Lambda function that builds the variant to return for a time value
148 147 auto dateTimeVariant = [](double time) {
149 148 auto dateTime = QDateTime::fromMSecsSinceEpoch(time * 1000.);
150 149 return dateTime.toString(DATETIME_FORMAT);
151 150 };
152 151
153 152 switch (index.column()) {
154 153 case NAME_COLUMN:
155 154 return variable->name();
156 155 case TSTART_COLUMN:
157 156 return dateTimeVariant(variable->dateTime().m_TStart);
158 157 case TEND_COLUMN:
159 158 return dateTimeVariant(variable->dateTime().m_TEnd);
160 159 default:
161 160 // No action
162 161 break;
163 162 }
164 163
165 164 qWarning(LOG_VariableModel())
166 165 << tr("Can't get data (unknown column %1)").arg(index.column());
167 166 }
168 167 else {
169 168 qWarning(LOG_VariableModel()) << tr("Can't get data (no variable)");
170 169 }
171 170 }
172 171 else if (role == VariableRoles::ProgressRole) {
173 172 if (auto variable = impl->m_Variables.at(index.row())) {
174 173
175 174 auto it = impl->m_VariableToProgress.find(variable);
176 175 if (it != impl->m_VariableToProgress.cend()) {
177 176 return it->second;
178 177 }
179 178 }
180 179 }
181 180
182 181 return QVariant{};
183 182 }
184 183
185 184 QVariant VariableModel::headerData(int section, Qt::Orientation orientation, int role) const
186 185 {
187 186 if (role != Qt::DisplayRole && role != Qt::SizeHintRole) {
188 187 return QVariant{};
189 188 }
190 189
191 190 if (orientation == Qt::Horizontal) {
192 191 auto propertiesIt = COLUMN_PROPERTIES.find(section);
193 192 if (propertiesIt != COLUMN_PROPERTIES.cend()) {
194 193 // Role is either DisplayRole or SizeHintRole
195 194 return (role == Qt::DisplayRole)
196 195 ? QVariant{propertiesIt->m_Name}
197 196 : QVariant{QSize{propertiesIt->m_Width, propertiesIt->m_Height}};
198 197 }
199 198 else {
200 199 qWarning(LOG_VariableModel())
201 200 << tr("Can't get header data (unknown column %1)").arg(section);
202 201 }
203 202 }
204 203
205 204 return QVariant{};
206 205 }
207 206
208 207 void VariableModel::onVariableUpdated() noexcept
209 208 {
210 209 // Finds variable that has been updated in the model
211 210 if (auto updatedVariable = dynamic_cast<Variable *>(sender())) {
212 211 auto updatedVariableIndex = impl->indexOfVariable(updatedVariable);
213 212
214 213 if (updatedVariableIndex > -1) {
215 214 emit dataChanged(createIndex(updatedVariableIndex, 0),
216 215 createIndex(updatedVariableIndex, columnCount() - 1));
217 216 }
218 217 }
219 218 }
220 219
221 220 int VariableModel::VariableModelPrivate::indexOfVariable(Variable *variable) const noexcept
222 221 {
223 222 auto begin = std::cbegin(m_Variables);
224 223 auto end = std::cend(m_Variables);
225 224 auto it
226 225 = std::find_if(begin, end, [variable](const auto &var) { return var.get() == variable; });
227 226
228 227 if (it != end) {
229 228 // Gets the index of the variable in the model: we assume here that views have the same
230 229 // order as the model
231 230 return std::distance(begin, it);
232 231 }
233 232 else {
234 233 return -1;
235 234 }
236 235 }
@@ -1,353 +1,353
1 1 #include <Variable/Variable.h>
2 2 #include <Variable/VariableCacheController.h>
3 3
4 4 #include <QObject>
5 5 #include <QtTest>
6 6
7 7 #include <memory>
8 8
9 9 class TestVariableCacheController : public QObject {
10 10 Q_OBJECT
11 11
12 12 private slots:
13 13 void testProvideNotInCacheDateTimeList();
14 14
15 15 void testAddDateTime();
16 16 };
17 17
18 18
19 19 void TestVariableCacheController::testProvideNotInCacheDateTimeList()
20 20 {
21 21 VariableCacheController variableCacheController{};
22 22
23 23 auto ts0 = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 0, 0}};
24 24 auto te0 = QDateTime{QDate{2017, 01, 01}, QTime{2, 4, 0, 0}};
25 25 auto sqp0 = SqpDateTime{static_cast<double>(ts0.toMSecsSinceEpoch()),
26 26 static_cast<double>(te0.toMSecsSinceEpoch())};
27 27
28 28 auto ts1 = QDateTime{QDate{2017, 01, 01}, QTime{2, 6, 0, 0}};
29 29 auto te1 = QDateTime{QDate{2017, 01, 01}, QTime{2, 8, 0, 0}};
30 30 auto sqp1 = SqpDateTime{static_cast<double>(ts1.toMSecsSinceEpoch()),
31 31 static_cast<double>(te1.toMSecsSinceEpoch())};
32 32
33 33 auto ts2 = QDateTime{QDate{2017, 01, 01}, QTime{2, 18, 0, 0}};
34 34 auto te2 = QDateTime{QDate{2017, 01, 01}, QTime{2, 20, 0, 0}};
35 35 auto sqp2 = SqpDateTime{static_cast<double>(ts2.toMSecsSinceEpoch()),
36 36 static_cast<double>(te2.toMSecsSinceEpoch())};
37 37
38 auto var0 = std::make_shared<Variable>("", "", "", sqp0);
38 auto var0 = std::make_shared<Variable>("", sqp0);
39 39
40 40 variableCacheController.addDateTime(var0, sqp0);
41 41 variableCacheController.addDateTime(var0, sqp1);
42 42 variableCacheController.addDateTime(var0, sqp2);
43 43
44 44 // first case [ts,te] < ts0
45 45 auto ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 0, 0, 0}};
46 46 auto te = QDateTime{QDate{2017, 01, 01}, QTime{2, 1, 0, 0}};
47 47 auto sqp = SqpDateTime{static_cast<double>(ts.toMSecsSinceEpoch()),
48 48 static_cast<double>(te.toMSecsSinceEpoch())};
49 49
50 50
51 51 auto notInCach = variableCacheController.provideNotInCacheDateTimeList(var0, sqp);
52 52
53 53 QCOMPARE(notInCach.size(), 1);
54 54 auto notInCacheSqp = notInCach.first();
55 55 QCOMPARE(notInCacheSqp.m_TStart, static_cast<double>(ts.toMSecsSinceEpoch()));
56 56 QCOMPARE(notInCacheSqp.m_TEnd, static_cast<double>(te.toMSecsSinceEpoch()));
57 57
58 58
59 59 // second case ts < ts0 && ts0 < te <= te0
60 60 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 0, 0, 0}};
61 61 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 30, 0}};
62 62 sqp = SqpDateTime{static_cast<double>(ts.toMSecsSinceEpoch()),
63 63 static_cast<double>(te.toMSecsSinceEpoch())};
64 64
65 65
66 66 notInCach = variableCacheController.provideNotInCacheDateTimeList(var0, sqp);
67 67
68 68 QCOMPARE(notInCach.size(), 1);
69 69 notInCacheSqp = notInCach.first();
70 70 QCOMPARE(notInCacheSqp.m_TStart, static_cast<double>(ts.toMSecsSinceEpoch()));
71 71 QCOMPARE(notInCacheSqp.m_TEnd, static_cast<double>(ts0.toMSecsSinceEpoch()));
72 72
73 73 // 3th case ts < ts0 && te0 < te <= ts1
74 74 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 0, 0, 0}};
75 75 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 5, 0, 0}};
76 76 sqp = SqpDateTime{static_cast<double>(ts.toMSecsSinceEpoch()),
77 77 static_cast<double>(te.toMSecsSinceEpoch())};
78 78
79 79
80 80 notInCach = variableCacheController.provideNotInCacheDateTimeList(var0, sqp);
81 81
82 82 QCOMPARE(notInCach.size(), 2);
83 83 notInCacheSqp = notInCach.first();
84 84 QCOMPARE(notInCacheSqp.m_TStart, static_cast<double>(ts.toMSecsSinceEpoch()));
85 85 QCOMPARE(notInCacheSqp.m_TEnd, static_cast<double>(ts0.toMSecsSinceEpoch()));
86 86
87 87 notInCacheSqp = notInCach.at(1);
88 88 QCOMPARE(notInCacheSqp.m_TStart, static_cast<double>(te0.toMSecsSinceEpoch()));
89 89 QCOMPARE(notInCacheSqp.m_TEnd, static_cast<double>(te.toMSecsSinceEpoch()));
90 90
91 91 // 4th case ts < ts0 && ts1 < te <= te1
92 92 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 0, 0, 0}};
93 93 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 7, 0, 0}};
94 94 sqp = SqpDateTime{static_cast<double>(ts.toMSecsSinceEpoch()),
95 95 static_cast<double>(te.toMSecsSinceEpoch())};
96 96
97 97
98 98 notInCach = variableCacheController.provideNotInCacheDateTimeList(var0, sqp);
99 99
100 100 QCOMPARE(notInCach.size(), 2);
101 101 notInCacheSqp = notInCach.first();
102 102 QCOMPARE(notInCacheSqp.m_TStart, static_cast<double>(ts.toMSecsSinceEpoch()));
103 103 QCOMPARE(notInCacheSqp.m_TEnd, static_cast<double>(ts0.toMSecsSinceEpoch()));
104 104
105 105 notInCacheSqp = notInCach.at(1);
106 106 QCOMPARE(notInCacheSqp.m_TStart, static_cast<double>(te0.toMSecsSinceEpoch()));
107 107 QCOMPARE(notInCacheSqp.m_TEnd, static_cast<double>(ts1.toMSecsSinceEpoch()));
108 108
109 109 // 5th case ts < ts0 && te3 < te
110 110 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 0, 0, 0}};
111 111 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 22, 0, 0}};
112 112 sqp = SqpDateTime{static_cast<double>(ts.toMSecsSinceEpoch()),
113 113 static_cast<double>(te.toMSecsSinceEpoch())};
114 114
115 115
116 116 notInCach = variableCacheController.provideNotInCacheDateTimeList(var0, sqp);
117 117
118 118 QCOMPARE(notInCach.size(), 4);
119 119 notInCacheSqp = notInCach.first();
120 120 QCOMPARE(notInCacheSqp.m_TStart, static_cast<double>(ts.toMSecsSinceEpoch()));
121 121 QCOMPARE(notInCacheSqp.m_TEnd, static_cast<double>(ts0.toMSecsSinceEpoch()));
122 122
123 123 notInCacheSqp = notInCach.at(1);
124 124 QCOMPARE(notInCacheSqp.m_TStart, static_cast<double>(te0.toMSecsSinceEpoch()));
125 125 QCOMPARE(notInCacheSqp.m_TEnd, static_cast<double>(ts1.toMSecsSinceEpoch()));
126 126
127 127 notInCacheSqp = notInCach.at(2);
128 128 QCOMPARE(notInCacheSqp.m_TStart, static_cast<double>(te1.toMSecsSinceEpoch()));
129 129 QCOMPARE(notInCacheSqp.m_TEnd, static_cast<double>(ts2.toMSecsSinceEpoch()));
130 130
131 131 notInCacheSqp = notInCach.at(3);
132 132 QCOMPARE(notInCacheSqp.m_TStart, static_cast<double>(te2.toMSecsSinceEpoch()));
133 133 QCOMPARE(notInCacheSqp.m_TEnd, static_cast<double>(te.toMSecsSinceEpoch()));
134 134
135 135
136 136 // 6th case ts2 < ts
137 137 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 45, 0, 0}};
138 138 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 47, 0, 0}};
139 139 sqp = SqpDateTime{static_cast<double>(ts.toMSecsSinceEpoch()),
140 140 static_cast<double>(te.toMSecsSinceEpoch())};
141 141
142 142
143 143 notInCach = variableCacheController.provideNotInCacheDateTimeList(var0, sqp);
144 144
145 145 QCOMPARE(notInCach.size(), 1);
146 146 notInCacheSqp = notInCach.first();
147 147 QCOMPARE(notInCacheSqp.m_TStart, static_cast<double>(ts.toMSecsSinceEpoch()));
148 148 QCOMPARE(notInCacheSqp.m_TEnd, static_cast<double>(te.toMSecsSinceEpoch()));
149 149
150 150 // 7th case ts = te0 && te < ts1
151 151 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 4, 0, 0}};
152 152 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 5, 0, 0}};
153 153 sqp = SqpDateTime{static_cast<double>(ts.toMSecsSinceEpoch()),
154 154 static_cast<double>(te.toMSecsSinceEpoch())};
155 155
156 156
157 157 notInCach = variableCacheController.provideNotInCacheDateTimeList(var0, sqp);
158 158
159 159 QCOMPARE(notInCach.size(), 1);
160 160 notInCacheSqp = notInCach.first();
161 161 QCOMPARE(notInCacheSqp.m_TStart, static_cast<double>(te0.toMSecsSinceEpoch()));
162 162 QCOMPARE(notInCacheSqp.m_TEnd, static_cast<double>(te.toMSecsSinceEpoch()));
163 163
164 164 // 8th case ts0 < ts < te0 && te < ts1
165 165 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 30, 0}};
166 166 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 5, 0, 0}};
167 167 sqp = SqpDateTime{static_cast<double>(ts.toMSecsSinceEpoch()),
168 168 static_cast<double>(te.toMSecsSinceEpoch())};
169 169
170 170
171 171 notInCach = variableCacheController.provideNotInCacheDateTimeList(var0, sqp);
172 172
173 173 QCOMPARE(notInCach.size(), 1);
174 174 notInCacheSqp = notInCach.first();
175 175 QCOMPARE(notInCacheSqp.m_TStart, static_cast<double>(te0.toMSecsSinceEpoch()));
176 176 QCOMPARE(notInCacheSqp.m_TEnd, static_cast<double>(te.toMSecsSinceEpoch()));
177 177
178 178 // 9th case ts0 < ts < te0 && ts1 < te < te1
179 179 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 30, 0}};
180 180 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 7, 0, 0}};
181 181 sqp = SqpDateTime{static_cast<double>(ts.toMSecsSinceEpoch()),
182 182 static_cast<double>(te.toMSecsSinceEpoch())};
183 183
184 184
185 185 notInCach = variableCacheController.provideNotInCacheDateTimeList(var0, sqp);
186 186
187 187 QCOMPARE(notInCach.size(), 1);
188 188 notInCacheSqp = notInCach.first();
189 189 QCOMPARE(notInCacheSqp.m_TStart, static_cast<double>(te0.toMSecsSinceEpoch()));
190 190 QCOMPARE(notInCacheSqp.m_TEnd, static_cast<double>(ts1.toMSecsSinceEpoch()));
191 191
192 192 // 10th case te1 < ts < te < ts2
193 193 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 9, 0, 0}};
194 194 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 10, 0, 0}};
195 195 sqp = SqpDateTime{static_cast<double>(ts.toMSecsSinceEpoch()),
196 196 static_cast<double>(te.toMSecsSinceEpoch())};
197 197
198 198
199 199 notInCach = variableCacheController.provideNotInCacheDateTimeList(var0, sqp);
200 200
201 201 QCOMPARE(notInCach.size(), 1);
202 202 notInCacheSqp = notInCach.first();
203 203 QCOMPARE(notInCacheSqp.m_TStart, static_cast<double>(ts.toMSecsSinceEpoch()));
204 204 QCOMPARE(notInCacheSqp.m_TEnd, static_cast<double>(te.toMSecsSinceEpoch()));
205 205
206 206 // 11th case te0 < ts < ts1 && te3 < te
207 207 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 5, 0, 0}};
208 208 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 47, 0, 0}};
209 209 sqp = SqpDateTime{static_cast<double>(ts.toMSecsSinceEpoch()),
210 210 static_cast<double>(te.toMSecsSinceEpoch())};
211 211
212 212
213 213 notInCach = variableCacheController.provideNotInCacheDateTimeList(var0, sqp);
214 214
215 215 QCOMPARE(notInCach.size(), 3);
216 216 notInCacheSqp = notInCach.first();
217 217 QCOMPARE(notInCacheSqp.m_TStart, static_cast<double>(ts.toMSecsSinceEpoch()));
218 218 QCOMPARE(notInCacheSqp.m_TEnd, static_cast<double>(ts1.toMSecsSinceEpoch()));
219 219
220 220 notInCacheSqp = notInCach.at(1);
221 221 QCOMPARE(notInCacheSqp.m_TStart, static_cast<double>(te1.toMSecsSinceEpoch()));
222 222 QCOMPARE(notInCacheSqp.m_TEnd, static_cast<double>(ts2.toMSecsSinceEpoch()));
223 223
224 224 notInCacheSqp = notInCach.at(2);
225 225 QCOMPARE(notInCacheSqp.m_TStart, static_cast<double>(te2.toMSecsSinceEpoch()));
226 226 QCOMPARE(notInCacheSqp.m_TEnd, static_cast<double>(te.toMSecsSinceEpoch()));
227 227
228 228 // 12th case te0 < ts < ts1 && te3 < te
229 229 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 5, 0, 0}};
230 230 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 10, 0, 0}};
231 231 sqp = SqpDateTime{static_cast<double>(ts.toMSecsSinceEpoch()),
232 232 static_cast<double>(te.toMSecsSinceEpoch())};
233 233
234 234 notInCach = variableCacheController.provideNotInCacheDateTimeList(var0, sqp);
235 235
236 236 QCOMPARE(notInCach.size(), 2);
237 237 notInCacheSqp = notInCach.first();
238 238 QCOMPARE(notInCacheSqp.m_TStart, static_cast<double>(ts.toMSecsSinceEpoch()));
239 239 QCOMPARE(notInCacheSqp.m_TEnd, static_cast<double>(ts1.toMSecsSinceEpoch()));
240 240
241 241 notInCacheSqp = notInCach.at(1);
242 242 QCOMPARE(notInCacheSqp.m_TStart, static_cast<double>(te1.toMSecsSinceEpoch()));
243 243 QCOMPARE(notInCacheSqp.m_TEnd, static_cast<double>(te.toMSecsSinceEpoch()));
244 244
245 245
246 246 // 12th case ts0 < ts < te0
247 247 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 10, 0}};
248 248 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 50, 0}};
249 249 sqp = SqpDateTime{static_cast<double>(ts.toMSecsSinceEpoch()),
250 250 static_cast<double>(te.toMSecsSinceEpoch())};
251 251
252 252 notInCach = variableCacheController.provideNotInCacheDateTimeList(var0, sqp);
253 253 QCOMPARE(notInCach.size(), 0);
254 254 }
255 255
256 256
257 257 void TestVariableCacheController::testAddDateTime()
258 258 {
259 259 VariableCacheController variableCacheController{};
260 260
261 261 auto ts0 = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 0, 0}};
262 262 auto te0 = QDateTime{QDate{2017, 01, 01}, QTime{2, 4, 0, 0}};
263 263 auto sqp0 = SqpDateTime{static_cast<double>(ts0.toMSecsSinceEpoch()),
264 264 static_cast<double>(te0.toMSecsSinceEpoch())};
265 265
266 266 auto ts1 = QDateTime{QDate{2017, 01, 01}, QTime{2, 6, 0, 0}};
267 267 auto te1 = QDateTime{QDate{2017, 01, 01}, QTime{2, 8, 0, 0}};
268 268 auto sqp1 = SqpDateTime{static_cast<double>(ts1.toMSecsSinceEpoch()),
269 269 static_cast<double>(te1.toMSecsSinceEpoch())};
270 270
271 271 auto ts2 = QDateTime{QDate{2017, 01, 01}, QTime{2, 18, 0, 0}};
272 272 auto te2 = QDateTime{QDate{2017, 01, 01}, QTime{2, 20, 0, 0}};
273 273 auto sqp2 = SqpDateTime{static_cast<double>(ts2.toMSecsSinceEpoch()),
274 274 static_cast<double>(te2.toMSecsSinceEpoch())};
275 275
276 276 auto ts01 = QDateTime{QDate{2017, 01, 01}, QTime{2, 4, 0, 0}};
277 277 auto te01 = QDateTime{QDate{2017, 01, 01}, QTime{2, 6, 0, 0}};
278 278 auto sqp01 = SqpDateTime{static_cast<double>(ts01.toMSecsSinceEpoch()),
279 279 static_cast<double>(te01.toMSecsSinceEpoch())};
280 280
281 281 auto ts3 = QDateTime{QDate{2017, 01, 01}, QTime{2, 14, 0, 0}};
282 282 auto te3 = QDateTime{QDate{2017, 01, 01}, QTime{2, 16, 0, 0}};
283 283 auto sqp3 = SqpDateTime{static_cast<double>(ts3.toMSecsSinceEpoch()),
284 284 static_cast<double>(te3.toMSecsSinceEpoch())};
285 285
286 286 auto ts03 = QDateTime{QDate{2017, 01, 01}, QTime{2, 4, 0, 0}};
287 287 auto te03 = QDateTime{QDate{2017, 01, 01}, QTime{2, 22, 0, 0}};
288 288 auto sqp03 = SqpDateTime{static_cast<double>(ts03.toMSecsSinceEpoch()),
289 289 static_cast<double>(te03.toMSecsSinceEpoch())};
290 290
291 291
292 auto var0 = std::make_shared<Variable>("", "", "", sqp0);
292 auto var0 = std::make_shared<Variable>("", sqp0);
293 293
294 294
295 295 // First case: add the first interval to the variable :sqp0
296 296 variableCacheController.addDateTime(var0, sqp0);
297 297 auto dateCacheList = variableCacheController.dateCacheList(var0);
298 298 QCOMPARE(dateCacheList.count(), 1);
299 299 auto dateCache = dateCacheList.at(0);
300 300 QCOMPARE(dateCache.m_TStart, static_cast<double>(ts0.toMSecsSinceEpoch()));
301 301 QCOMPARE(dateCache.m_TEnd, static_cast<double>(te0.toMSecsSinceEpoch()));
302 302
303 303 // 2nd case: add a second interval : sqp1 > sqp0
304 304 variableCacheController.addDateTime(var0, sqp1);
305 305 dateCacheList = variableCacheController.dateCacheList(var0);
306 306 QCOMPARE(dateCacheList.count(), 2);
307 307 dateCache = dateCacheList.at(0);
308 308 QCOMPARE(dateCache.m_TStart, static_cast<double>(ts0.toMSecsSinceEpoch()));
309 309 QCOMPARE(dateCache.m_TEnd, static_cast<double>(te0.toMSecsSinceEpoch()));
310 310
311 311 dateCache = dateCacheList.at(1);
312 312 QCOMPARE(dateCache.m_TStart, static_cast<double>(ts1.toMSecsSinceEpoch()));
313 313 QCOMPARE(dateCache.m_TEnd, static_cast<double>(te1.toMSecsSinceEpoch()));
314 314
315 315 // 3th case: merge sqp0 & sqp1 with sqp01
316 316 variableCacheController.addDateTime(var0, sqp01);
317 317 dateCacheList = variableCacheController.dateCacheList(var0);
318 318 QCOMPARE(dateCacheList.count(), 1);
319 319 dateCache = dateCacheList.at(0);
320 320 QCOMPARE(dateCache.m_TStart, static_cast<double>(ts0.toMSecsSinceEpoch()));
321 321 QCOMPARE(dateCache.m_TEnd, static_cast<double>(te1.toMSecsSinceEpoch()));
322 322
323 323
324 324 // 4th case: add a second interval : sqp1 > sqp0
325 325 variableCacheController.addDateTime(var0, sqp2);
326 326 variableCacheController.addDateTime(var0, sqp3);
327 327 dateCacheList = variableCacheController.dateCacheList(var0);
328 328 QCOMPARE(dateCacheList.count(), 3);
329 329 dateCache = dateCacheList.at(0);
330 330 QCOMPARE(dateCache.m_TStart, static_cast<double>(ts0.toMSecsSinceEpoch()));
331 331 QCOMPARE(dateCache.m_TEnd, static_cast<double>(te1.toMSecsSinceEpoch()));
332 332
333 333 dateCache = dateCacheList.at(1);
334 334 QCOMPARE(dateCache.m_TStart, static_cast<double>(ts3.toMSecsSinceEpoch()));
335 335 QCOMPARE(dateCache.m_TEnd, static_cast<double>(te3.toMSecsSinceEpoch()));
336 336
337 337 dateCache = dateCacheList.at(2);
338 338 QCOMPARE(dateCache.m_TStart, static_cast<double>(ts2.toMSecsSinceEpoch()));
339 339 QCOMPARE(dateCache.m_TEnd, static_cast<double>(te2.toMSecsSinceEpoch()));
340 340
341 341
342 342 // 5th case: merge all interval
343 343 variableCacheController.addDateTime(var0, sqp03);
344 344 dateCacheList = variableCacheController.dateCacheList(var0);
345 345 QCOMPARE(dateCacheList.count(), 1);
346 346 dateCache = dateCacheList.at(0);
347 347 QCOMPARE(dateCache.m_TStart, static_cast<double>(ts0.toMSecsSinceEpoch()));
348 348 QCOMPARE(dateCache.m_TEnd, static_cast<double>(te03.toMSecsSinceEpoch()));
349 349 }
350 350
351 351
352 352 QTEST_MAIN(TestVariableCacheController)
353 353 #include "TestVariableCacheController.moc"
@@ -1,60 +1,61
1 1 #ifndef SCIQLOP_MENUBUILDER_H
2 2 #define SCIQLOP_MENUBUILDER_H
3 3
4 4 #include <QLoggingCategory>
5 5 #include <QMenu>
6 6 #include <QStack>
7 7
8 8 Q_DECLARE_LOGGING_CATEGORY(LOG_MenuBuilder)
9 9
10 10 /// Helper assigned to build a hierarchical menu
11 11 class MenuBuilder {
12 12 public:
13 13 /**
14 14 * Ctor
15 15 * @param menu the parent menu
16 16 */
17 17 explicit MenuBuilder(QMenu *menu);
18 18
19 19 /**
20 20 * Adds action to the current menu
21 21 * @param actionName the name of the action
22 22 * @param actionFunction the function that will be executed when the action is triggered
23 23 */
24 24 template <typename ActionFun>
25 25 void addAction(const QString &actionName, ActionFun actionFunction);
26 26
27 27 /**
28 * Adds a new menu to the current menu
28 * Adds a new menu to the current menu and returns it
29 29 * @param name the name of the menu
30 30 * @param icon the icon of the menu (can be null)
31 * @returns the created menu, nullptr if it couldn't be created
31 32 */
32 void addMenu(const QString &name, const QIcon &icon = {});
33 QMenu *addMenu(const QString &name, const QIcon &icon = {});
33 34
34 35 /// Adds a separator to the current menu. The separator is added only if the menu already
35 36 /// contains entries
36 37 void addSeparator();
37 38
38 39 /// Closes the current menu
39 40 void closeMenu();
40 41
41 42 private:
42 43 /// @return the current menu (i.e. the top menu of the stack), nullptr if there is no menu
43 44 QMenu *currentMenu() const;
44 45
45 46 /// Stack of all menus currently opened
46 47 QStack<QMenu *> m_Menus{};
47 48 };
48 49
49 50 template <typename ActionFun>
50 51 void MenuBuilder::addAction(const QString &actionName, ActionFun actionFunction)
51 52 {
52 53 if (auto currMenu = currentMenu()) {
53 54 currMenu->addAction(actionName, actionFunction);
54 55 }
55 56 else {
56 57 qCCritical(LOG_MenuBuilder()) << QObject::tr("No current menu to attach the action");
57 58 }
58 59 }
59 60
60 61 #endif // SCIQLOP_MENUBUILDER_H
@@ -1,145 +1,147
1 1 #include "SqpApplication.h"
2 2
3 3 #include <Data/IDataProvider.h>
4 4 #include <DataSource/DataSourceController.h>
5 5 #include <Network/NetworkController.h>
6 6 #include <QThread>
7 7 #include <Time/TimeController.h>
8 8 #include <Variable/Variable.h>
9 9 #include <Variable/VariableController.h>
10 10 #include <Visualization/VisualizationController.h>
11 11
12 12 Q_LOGGING_CATEGORY(LOG_SqpApplication, "SqpApplication")
13 13
14 14 class SqpApplication::SqpApplicationPrivate {
15 15 public:
16 16 SqpApplicationPrivate()
17 17 : m_DataSourceController{std::make_unique<DataSourceController>()},
18 18 m_NetworkController{std::make_unique<NetworkController>()},
19 19 m_TimeController{std::make_unique<TimeController>()},
20 20 m_VariableController{std::make_unique<VariableController>()},
21 21 m_VisualizationController{std::make_unique<VisualizationController>()}
22 22 {
23 23 // /////////////////////////////// //
24 24 // Connections between controllers //
25 25 // /////////////////////////////// //
26 26
27 27 // VariableController <-> DataSourceController
28 28 connect(m_DataSourceController.get(),
29 SIGNAL(variableCreationRequested(const QString &, std::shared_ptr<IDataProvider>)),
29 SIGNAL(variableCreationRequested(const QString &, const QVariantHash &,
30 std::shared_ptr<IDataProvider>)),
30 31 m_VariableController.get(),
31 SLOT(createVariable(const QString &, std::shared_ptr<IDataProvider>)));
32 SLOT(createVariable(const QString &, const QVariantHash &,
33 std::shared_ptr<IDataProvider>)));
32 34
33 35 // VariableController <-> VisualizationController
34 36 connect(m_VariableController.get(),
35 37 SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)),
36 38 m_VisualizationController.get(),
37 39 SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)), Qt::DirectConnection);
38 40
39 41
40 42 m_DataSourceController->moveToThread(&m_DataSourceControllerThread);
41 43 m_NetworkController->moveToThread(&m_NetworkControllerThread);
42 44 m_VariableController->moveToThread(&m_VariableControllerThread);
43 45 m_VisualizationController->moveToThread(&m_VisualizationControllerThread);
44 46
45 47
46 48 // Additionnal init
47 49 m_VariableController->setTimeController(m_TimeController.get());
48 50 }
49 51
50 52 virtual ~SqpApplicationPrivate()
51 53 {
52 54 qCInfo(LOG_SqpApplication()) << tr("SqpApplicationPrivate destruction");
53 55 m_DataSourceControllerThread.quit();
54 56 m_DataSourceControllerThread.wait();
55 57
56 58 m_NetworkControllerThread.quit();
57 59 m_NetworkControllerThread.wait();
58 60
59 61 m_VariableControllerThread.quit();
60 62 m_VariableControllerThread.wait();
61 63
62 64 m_VisualizationControllerThread.quit();
63 65 m_VisualizationControllerThread.wait();
64 66 }
65 67
66 68 std::unique_ptr<DataSourceController> m_DataSourceController;
67 69 std::unique_ptr<VariableController> m_VariableController;
68 70 std::unique_ptr<TimeController> m_TimeController;
69 71 std::unique_ptr<NetworkController> m_NetworkController;
70 72 std::unique_ptr<VisualizationController> m_VisualizationController;
71 73 QThread m_DataSourceControllerThread;
72 74 QThread m_NetworkControllerThread;
73 75 QThread m_VariableControllerThread;
74 76 QThread m_VisualizationControllerThread;
75 77 };
76 78
77 79
78 80 SqpApplication::SqpApplication(int &argc, char **argv)
79 81 : QApplication{argc, argv}, impl{spimpl::make_unique_impl<SqpApplicationPrivate>()}
80 82 {
81 83 qCDebug(LOG_SqpApplication()) << tr("SqpApplication construction") << QThread::currentThread();
82 84
83 85 connect(&impl->m_DataSourceControllerThread, &QThread::started,
84 86 impl->m_DataSourceController.get(), &DataSourceController::initialize);
85 87 connect(&impl->m_DataSourceControllerThread, &QThread::finished,
86 88 impl->m_DataSourceController.get(), &DataSourceController::finalize);
87 89
88 90 connect(&impl->m_NetworkControllerThread, &QThread::started, impl->m_NetworkController.get(),
89 91 &NetworkController::initialize);
90 92 connect(&impl->m_NetworkControllerThread, &QThread::finished, impl->m_NetworkController.get(),
91 93 &NetworkController::finalize);
92 94
93 95 connect(&impl->m_VariableControllerThread, &QThread::started, impl->m_VariableController.get(),
94 96 &VariableController::initialize);
95 97 connect(&impl->m_VariableControllerThread, &QThread::finished, impl->m_VariableController.get(),
96 98 &VariableController::finalize);
97 99
98 100 connect(&impl->m_VisualizationControllerThread, &QThread::started,
99 101 impl->m_VisualizationController.get(), &VisualizationController::initialize);
100 102 connect(&impl->m_VisualizationControllerThread, &QThread::finished,
101 103 impl->m_VisualizationController.get(), &VisualizationController::finalize);
102 104
103 105 impl->m_DataSourceControllerThread.start();
104 106 impl->m_NetworkControllerThread.start();
105 107 impl->m_VariableControllerThread.start();
106 108 impl->m_VisualizationControllerThread.start();
107 109
108 110 // Core connections:
109 111 // NetworkController <-> VariableController
110 112 connect(&sqpApp->networkController(), &NetworkController::replyDownloadProgress,
111 113 &sqpApp->variableController(), &VariableController::onVariableRetrieveDataInProgress);
112 114 }
113 115
114 116 SqpApplication::~SqpApplication()
115 117 {
116 118 }
117 119
118 120 void SqpApplication::initialize()
119 121 {
120 122 }
121 123
122 124 DataSourceController &SqpApplication::dataSourceController() noexcept
123 125 {
124 126 return *impl->m_DataSourceController;
125 127 }
126 128
127 129 NetworkController &SqpApplication::networkController() noexcept
128 130 {
129 131 return *impl->m_NetworkController;
130 132 }
131 133
132 134 TimeController &SqpApplication::timeController() noexcept
133 135 {
134 136 return *impl->m_TimeController;
135 137 }
136 138
137 139 VariableController &SqpApplication::variableController() noexcept
138 140 {
139 141 return *impl->m_VariableController;
140 142 }
141 143
142 144 VisualizationController &SqpApplication::visualizationController() noexcept
143 145 {
144 146 return *impl->m_VisualizationController;
145 147 }
@@ -1,196 +1,200
1 1 #include "Visualization/operations/GenerateVariableMenuOperation.h"
2 2 #include "Visualization/operations/MenuBuilder.h"
3 3
4 4 #include "Visualization/VisualizationGraphWidget.h"
5 5 #include "Visualization/VisualizationTabWidget.h"
6 6 #include "Visualization/VisualizationZoneWidget.h"
7 7
8 8 #include <Variable/Variable.h>
9 9
10 10 #include <QMenu>
11 11 #include <QStack>
12 12
13 13 Q_LOGGING_CATEGORY(LOG_GenerateVariableMenuOperation, "GenerateVariableMenuOperation")
14 14
15 15 struct GenerateVariableMenuOperation::GenerateVariableMenuOperationPrivate {
16 16 explicit GenerateVariableMenuOperationPrivate(QMenu *menu, std::shared_ptr<Variable> variable)
17 17 : m_Variable{variable}, m_PlotMenuBuilder{menu}, m_UnplotMenuBuilder{menu}
18 18 {
19 19 }
20 20
21 21 void visitRootEnter()
22 22 {
23 23 // Creates the root menu
24 m_PlotMenuBuilder.addMenu(QObject::tr("Plot"), QIcon{":/icones/plot.png"});
24 if (auto plotMenu
25 = m_PlotMenuBuilder.addMenu(QObject::tr("Plot"), QIcon{":/icones/plot.png"})) {
26 plotMenu->setEnabled(m_Variable && m_Variable->dataSeries() != nullptr);
27 }
28
25 29 m_UnplotMenuBuilder.addMenu(QObject::tr("Unplot"), QIcon{":/icones/unplot.png"});
26 30 }
27 31
28 32 void visitRootLeave()
29 33 {
30 34 // Closes the root menu
31 35 m_PlotMenuBuilder.closeMenu();
32 36 m_UnplotMenuBuilder.closeMenu();
33 37 }
34 38
35 39 void visitNodeEnter(const IVisualizationWidget &container)
36 40 {
37 41 // Opens a new menu associated to the node
38 42 m_PlotMenuBuilder.addMenu(container.name());
39 43 m_UnplotMenuBuilder.addMenu(container.name());
40 44 }
41 45
42 46 template <typename ActionFun>
43 47 void visitNodeLeavePlot(const IVisualizationWidget &container, const QString &actionName,
44 48 ActionFun actionFunction)
45 49 {
46 50 if (m_Variable && container.canDrop(*m_Variable)) {
47 51 m_PlotMenuBuilder.addSeparator();
48 52 m_PlotMenuBuilder.addAction(actionName, actionFunction);
49 53 }
50 54
51 55 // Closes the menu associated to the node
52 56 m_PlotMenuBuilder.closeMenu();
53 57 }
54 58
55 59 void visitNodeLeaveUnplot()
56 60 {
57 61 // Closes the menu associated to the node
58 62 m_UnplotMenuBuilder.closeMenu();
59 63 }
60 64
61 65 template <typename ActionFun>
62 66 void visitLeafPlot(const IVisualizationWidget &container, const QString &actionName,
63 67 ActionFun actionFunction)
64 68 {
65 69 if (m_Variable && container.canDrop(*m_Variable)) {
66 70 m_PlotMenuBuilder.addAction(actionName, actionFunction);
67 71 }
68 72 }
69 73
70 74 template <typename ActionFun>
71 75 void visitLeafUnplot(const IVisualizationWidget &container, const QString &actionName,
72 76 ActionFun actionFunction)
73 77 {
74 78 if (m_Variable && container.contains(*m_Variable)) {
75 79 m_UnplotMenuBuilder.addAction(actionName, actionFunction);
76 80 }
77 81 }
78 82
79 83 std::shared_ptr<Variable> m_Variable;
80 84 MenuBuilder m_PlotMenuBuilder; ///< Builder for the 'Plot' menu
81 85 MenuBuilder m_UnplotMenuBuilder; ///< Builder for the 'Unplot' menu
82 86 };
83 87
84 88 GenerateVariableMenuOperation::GenerateVariableMenuOperation(QMenu *menu,
85 89 std::shared_ptr<Variable> variable)
86 90 : impl{spimpl::make_unique_impl<GenerateVariableMenuOperationPrivate>(menu, variable)}
87 91 {
88 92 }
89 93
90 94 void GenerateVariableMenuOperation::visitEnter(VisualizationWidget *widget)
91 95 {
92 96 // VisualizationWidget is not intended to accommodate a variable
93 97 Q_UNUSED(widget)
94 98
95 99 // 'Plot' and 'Unplot' menus
96 100 impl->visitRootEnter();
97 101 }
98 102
99 103 void GenerateVariableMenuOperation::visitLeave(VisualizationWidget *widget)
100 104 {
101 105 // VisualizationWidget is not intended to accommodate a variable
102 106 Q_UNUSED(widget)
103 107
104 108 // 'Plot' and 'Unplot' menus
105 109 impl->visitRootLeave();
106 110 }
107 111
108 112 void GenerateVariableMenuOperation::visitEnter(VisualizationTabWidget *tabWidget)
109 113 {
110 114 if (tabWidget) {
111 115 // 'Plot' and 'Unplot' menus
112 116 impl->visitNodeEnter(*tabWidget);
113 117 }
114 118 else {
115 119 qCCritical(LOG_GenerateVariableMenuOperation(),
116 120 "Can't visit enter VisualizationTabWidget : the widget is null");
117 121 }
118 122 }
119 123
120 124 void GenerateVariableMenuOperation::visitLeave(VisualizationTabWidget *tabWidget)
121 125 {
122 126 if (tabWidget) {
123 127 // 'Plot' menu
124 128 impl->visitNodeLeavePlot(*tabWidget, QObject::tr("Open in a new zone"),
125 129 [ varW = std::weak_ptr<Variable>{impl->m_Variable}, tabWidget ]() {
126 130 if (auto var = varW.lock()) {
127 131 tabWidget->createZone(var);
128 132 }
129 133 });
130 134
131 135 // 'Unplot' menu
132 136 impl->visitNodeLeaveUnplot();
133 137 }
134 138 else {
135 139 qCCritical(LOG_GenerateVariableMenuOperation(),
136 140 "Can't visit leave VisualizationTabWidget : the widget is null");
137 141 }
138 142 }
139 143
140 144 void GenerateVariableMenuOperation::visitEnter(VisualizationZoneWidget *zoneWidget)
141 145 {
142 146 if (zoneWidget) {
143 147 // 'Plot' and 'Unplot' menus
144 148 impl->visitNodeEnter(*zoneWidget);
145 149 }
146 150 else {
147 151 qCCritical(LOG_GenerateVariableMenuOperation(),
148 152 "Can't visit enter VisualizationZoneWidget : the widget is null");
149 153 }
150 154 }
151 155
152 156 void GenerateVariableMenuOperation::visitLeave(VisualizationZoneWidget *zoneWidget)
153 157 {
154 158 if (zoneWidget) {
155 159 // 'Plot' menu
156 160 impl->visitNodeLeavePlot(
157 161 *zoneWidget, QObject::tr("Open in a new graph"),
158 162 [ varW = std::weak_ptr<Variable>{impl->m_Variable}, zoneWidget ]() {
159 163 if (auto var = varW.lock()) {
160 164 zoneWidget->createGraph(var);
161 165 }
162 166 });
163 167
164 168 // 'Unplot' menu
165 169 impl->visitNodeLeaveUnplot();
166 170 }
167 171 else {
168 172 qCCritical(LOG_GenerateVariableMenuOperation(),
169 173 "Can't visit leave VisualizationZoneWidget : the widget is null");
170 174 }
171 175 }
172 176
173 177 void GenerateVariableMenuOperation::visit(VisualizationGraphWidget *graphWidget)
174 178 {
175 179 if (graphWidget) {
176 180 // 'Plot' menu
177 181 impl->visitLeafPlot(*graphWidget, QObject::tr("Open in %1").arg(graphWidget->name()),
178 182 [ varW = std::weak_ptr<Variable>{impl->m_Variable}, graphWidget ]() {
179 183 if (auto var = varW.lock()) {
180 184 graphWidget->addVariableUsingGraph(var);
181 185 }
182 186 });
183 187
184 188 // 'Unplot' menu
185 189 impl->visitLeafUnplot(*graphWidget, QObject::tr("Remove from %1").arg(graphWidget->name()),
186 190 [ varW = std::weak_ptr<Variable>{impl->m_Variable}, graphWidget ]() {
187 191 if (auto var = varW.lock()) {
188 192 graphWidget->removeVariable(var);
189 193 }
190 194 });
191 195 }
192 196 else {
193 197 qCCritical(LOG_GenerateVariableMenuOperation(),
194 198 "Can't visit VisualizationGraphWidget : the widget is null");
195 199 }
196 200 }
@@ -1,55 +1,58
1 1 #include "Visualization/operations/MenuBuilder.h"
2 2
3 3 Q_LOGGING_CATEGORY(LOG_MenuBuilder, "MenuBuilder")
4 4
5 5 MenuBuilder::MenuBuilder(QMenu *menu)
6 6 {
7 7 if (menu) {
8 8 m_Menus.push(menu);
9 9 }
10 10 else {
11 11 qCCritical(LOG_MenuBuilder()) << QObject::tr("No parent menu has been defined");
12 12 }
13 13 }
14 14
15 void MenuBuilder::addMenu(const QString &name, const QIcon &icon)
15 QMenu *MenuBuilder::addMenu(const QString &name, const QIcon &icon)
16 16 {
17 17 if (auto currMenu = currentMenu()) {
18 m_Menus.push(currMenu->addMenu(icon, name));
18 auto menu = currMenu->addMenu(icon, name);
19 m_Menus.push(menu);
20 return menu;
19 21 }
20 22 else {
21 23 qCCritical(LOG_MenuBuilder()) << QObject::tr("No current menu to attach the new menu");
24 return nullptr;
22 25 }
23 26 }
24 27
25 28 void MenuBuilder::addSeparator()
26 29 {
27 30 if (auto currMenu = currentMenu()) {
28 31 if (!currMenu->isEmpty()) {
29 32 currMenu->addSeparator();
30 33 }
31 34 }
32 35 else {
33 36 qCCritical(LOG_MenuBuilder()) << QObject::tr("No current menu to attach the separator");
34 37 }
35 38 }
36 39
37 40 void MenuBuilder::closeMenu()
38 41 {
39 42 if (!m_Menus.isEmpty()) {
40 43 if (auto closedMenu = m_Menus.pop()) {
41 44 // Purge menu : if the closed menu has no entries, we remove it from its parent (the
42 45 // current menu)
43 46 if (auto currMenu = currentMenu()) {
44 47 if (closedMenu->isEmpty()) {
45 48 currMenu->removeAction(closedMenu->menuAction());
46 49 }
47 50 }
48 51 }
49 52 }
50 53 }
51 54
52 55 QMenu *MenuBuilder::currentMenu() const
53 56 {
54 57 return !m_Menus.isEmpty() ? m_Menus.top() : nullptr;
55 58 }
@@ -1,38 +1,28
1 1 #ifndef SCIQLOP_AMDAPROVIDER_H
2 2 #define SCIQLOP_AMDAPROVIDER_H
3 3
4 4 #include "AmdaGlobal.h"
5 5
6 #include <Common/spimpl.h>
7
8 6 #include <Data/IDataProvider.h>
9 7
10 8 #include <QLoggingCategory>
11 9
12 10
13 11 Q_DECLARE_LOGGING_CATEGORY(LOG_AmdaProvider)
14 12
15 13 class QNetworkReply;
16 14
17 15 /**
18 16 * @brief The AmdaProvider class is an example of how a data provider can generate data
19 17 */
20 18 class SCIQLOP_AMDA_EXPORT AmdaProvider : public IDataProvider {
21 19 public:
22 20 explicit AmdaProvider();
23 21
24 void requestDataLoading(QUuid token, const QVector<SqpDateTime> &dateTimeList) override;
22 void requestDataLoading(QUuid token, const DataProviderParameters &parameters) override;
25 23
26 24 private:
27 void retrieveData(QUuid token, const DataProviderParameters &parameters);
28
29 class AmdaProviderPrivate;
30 spimpl::unique_impl_ptr<AmdaProviderPrivate> impl;
31
32 // private slots:
33 // void httpFinished(QNetworkReply *reply, QUuid dataId) noexcept;
34 // void httpDownloadFinished(QNetworkReply *reply, QUuid dataId) noexcept;
35 // void httpDownloadReadyRead(QNetworkReply *reply, QUuid dataId) noexcept;
25 void retrieveData(QUuid token, const SqpDateTime &dateTime, const QVariantHash &data);
36 26 };
37 27
38 28 #endif // SCIQLOP_AMDAPROVIDER_H
@@ -1,129 +1,125
1 1 #include "AmdaParser.h"
2 #include "AmdaDefs.h"
2 3
3 4 #include <DataSource/DataSourceItem.h>
4 5
5 6 #include <QFile>
6 7 #include <QJsonArray>
7 8 #include <QJsonDocument>
8 9 #include <QJsonObject>
9 10
10 11 Q_LOGGING_CATEGORY(LOG_AmdaParser, "AmdaParser")
11 12
12 13 namespace {
13 14
14 // Significant keys of an AMDA's JSON file
15 const auto COMPONENT_KEY = QStringLiteral("component");
16 const auto PRODUCT_KEY = QStringLiteral("parameter");
17 const auto ROOT_KEY = QStringLiteral("dataCenter");
18
19 15 /// Returns the correct item type according to the key passed in parameter
20 16 DataSourceItemType itemType(const QString &key) noexcept
21 17 {
22 if (key == PRODUCT_KEY) {
18 if (key == AMDA_PRODUCT_KEY) {
23 19 return DataSourceItemType::PRODUCT;
24 20 }
25 else if (key == COMPONENT_KEY) {
21 else if (key == AMDA_COMPONENT_KEY) {
26 22 return DataSourceItemType::COMPONENT;
27 23 }
28 24 else {
29 25 return DataSourceItemType::NODE;
30 26 }
31 27 }
32 28
33 29 /**
34 30 * Processes an entry of the JSON file to populate/create data source items
35 31 * @param jsonKey the entry's key
36 32 * @param jsonValue the entry's value
37 33 * @param item the current item for which the entry processing will be applied
38 34 * @param appendData flag indicating that the entry is part of an array. In the case of an array of
39 35 * values, each value will be concatenated to the others (rather than replacing the others)
40 36 */
41 37 void parseEntry(const QString &jsonKey, const QJsonValue &jsonValue, DataSourceItem &item,
42 38 bool isArrayEntry = false)
43 39 {
44 40 if (jsonValue.isObject()) {
45 41 // Case of an object:
46 42 // - a new data source item is created and
47 43 // - parsing is called recursively to process the new item
48 44 // - the new item is then added as a child of the former item
49 45 auto object = jsonValue.toObject();
50 46
51 47 auto newItem = std::make_unique<DataSourceItem>(itemType(jsonKey));
52 48
53 49 for (auto it = object.constBegin(), end = object.constEnd(); it != end; ++it) {
54 50 parseEntry(it.key(), it.value(), *newItem);
55 51 }
56 52
57 53 item.appendChild(std::move(newItem));
58 54 }
59 55 else if (jsonValue.isArray()) {
60 56 // Case of an array: the item is populated with the arrays' content
61 57 auto object = jsonValue.toArray();
62 58
63 59 for (auto it = object.constBegin(), end = object.constEnd(); it != end; ++it) {
64 60 parseEntry(jsonKey, *it, item, true);
65 61 }
66 62 }
67 63 else {
68 64 // Case of a simple value: we add a data to the item. If the simple value is a part of an
69 65 // array, it is concatenated to the values already existing for this key
70 66 item.setData(jsonKey, jsonValue.toVariant(), isArrayEntry);
71 67 }
72 68 }
73 69
74 70 } // namespace
75 71
76 72 std::unique_ptr<DataSourceItem> AmdaParser::readJson(const QString &filePath) noexcept
77 73 {
78 74 QFile jsonFile{filePath};
79 75
80 76 if (!jsonFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
81 77 qCCritical(LOG_AmdaParser())
82 78 << QObject::tr("Can't retrieve data source tree from file %1: %2")
83 79 .arg(filePath, jsonFile.errorString());
84 80 return nullptr;
85 81 }
86 82
87 83 auto json = jsonFile.readAll();
88 84 auto jsonDocument = QJsonDocument::fromJson(json);
89 85
90 86 // Check preconditions for parsing
91 87 if (!jsonDocument.isObject()) {
92 88 qCCritical(LOG_AmdaParser())
93 89 << QObject::tr(
94 90 "Can't retrieve data source tree from file %1: the file is malformed (there is "
95 91 "not one and only one root object)")
96 92 .arg(filePath);
97 93 return nullptr;
98 94 }
99 95
100 96 auto jsonDocumentObject = jsonDocument.object();
101 if (!jsonDocumentObject.contains(ROOT_KEY)) {
97 if (!jsonDocumentObject.contains(AMDA_ROOT_KEY)) {
102 98 qCCritical(LOG_AmdaParser())
103 99 << QObject::tr(
104 100 "Can't retrieve data source tree from file %1: the file is malformed (the key "
105 101 "for the root element was not found (%2))")
106 .arg(filePath, ROOT_KEY);
102 .arg(filePath, AMDA_ROOT_KEY);
107 103 return nullptr;
108 104 }
109 105
110 auto rootValue = jsonDocumentObject.value(ROOT_KEY);
106 auto rootValue = jsonDocumentObject.value(AMDA_ROOT_KEY);
111 107 if (!rootValue.isObject()) {
112 108 qCCritical(LOG_AmdaParser())
113 109 << QObject::tr(
114 110 "Can't retrieve data source tree from file %1: the file is malformed (the root "
115 111 "element is of the wrong type)")
116 112 .arg(filePath);
117 113 return nullptr;
118 114 }
119 115
120 116 // Makes the parsing
121 117 auto rootObject = rootValue.toObject();
122 118 auto rootItem = std::make_unique<DataSourceItem>(DataSourceItemType::NODE);
123 119
124 120 for (auto it = rootObject.constBegin(), end = rootObject.constEnd(); it != end; ++it) {
125 121 parseEntry(it.key(), it.value(), *rootItem);
126 122 }
127 123
128 124 return rootItem;
129 125 }
@@ -1,68 +1,83
1 1 #include "AmdaPlugin.h"
2 #include "AmdaDefs.h"
2 3 #include "AmdaParser.h"
3 4 #include "AmdaProvider.h"
4 5
5 6 #include <DataSource/DataSourceController.h>
6 7 #include <DataSource/DataSourceItem.h>
7 8 #include <DataSource/DataSourceItemAction.h>
8 9
9 10 #include <SqpApplication.h>
10 11
11 12 Q_LOGGING_CATEGORY(LOG_AmdaPlugin, "AmdaPlugin")
12 13
13 14 namespace {
14 15
15 16 /// Name of the data source
16 17 const auto DATA_SOURCE_NAME = QStringLiteral("AMDA");
17 18
18 19 /// Path of the file used to generate the data source item for AMDA
19 20 const auto JSON_FILE_PATH = QStringLiteral(":/samples/AmdaSample.json");
20 21
21 22 void associateActions(DataSourceItem &item, const QUuid &dataSourceUid)
22 23 {
23 if (item.type() == DataSourceItemType::PRODUCT) {
24 auto itemName = item.name();
25
26 item.addAction(std::make_unique<DataSourceItemAction>(
27 QObject::tr("Load %1 product").arg(itemName),
28 [itemName, dataSourceUid](DataSourceItem &item) {
24 auto addLoadAction = [&item, dataSourceUid](const QString &label) {
25 item.addAction(
26 std::make_unique<DataSourceItemAction>(label, [dataSourceUid](DataSourceItem &item) {
29 27 if (auto app = sqpApp) {
30 28 app->dataSourceController().loadProductItem(dataSourceUid, item);
31 29 }
32 30 }));
31 };
32
33 const auto itemType = item.type();
34 if (itemType == DataSourceItemType::PRODUCT) {
35 /// @todo : As for the moment we do not manage the loading of vectors, in the case of a
36 /// parameter, we update the identifier of download of the data:
37 /// - if the parameter has no component, the identifier remains the same
38 /// - if the parameter has at least one component, the identifier is that of the first
39 /// component (for example, "imf" becomes "imf (0)")
40 if (item.childCount() != 0) {
41 item.setData(AMDA_XML_ID_KEY, item.child(0)->data(AMDA_XML_ID_KEY));
42 }
43
44 addLoadAction(QObject::tr("Load %1 product").arg(item.name()));
45 }
46 else if (itemType == DataSourceItemType::COMPONENT) {
47 addLoadAction(QObject::tr("Load %1 component").arg(item.name()));
33 48 }
34 49
35 50 auto count = item.childCount();
36 51 for (auto i = 0; i < count; ++i) {
37 52 if (auto child = item.child(i)) {
38 53 associateActions(*child, dataSourceUid);
39 54 }
40 55 }
41 56 }
42 57
43 58 } // namespace
44 59
45 60 void AmdaPlugin::initialize()
46 61 {
47 62 if (auto app = sqpApp) {
48 63 // Registers to the data source controller
49 64 auto &dataSourceController = app->dataSourceController();
50 65 auto dataSourceUid = dataSourceController.registerDataSource(DATA_SOURCE_NAME);
51 66
52 67 // Sets data source tree
53 68 if (auto dataSourceItem = AmdaParser::readJson(JSON_FILE_PATH)) {
54 69 associateActions(*dataSourceItem, dataSourceUid);
55 70
56 71 dataSourceController.setDataSourceItem(dataSourceUid, std::move(dataSourceItem));
57 72 }
58 73 else {
59 74 qCCritical(LOG_AmdaPlugin()) << tr("No data source item could be generated for AMDA");
60 75 }
61 76
62 77 // Sets data provider
63 78 dataSourceController.setDataProvider(dataSourceUid, std::make_unique<AmdaProvider>());
64 79 }
65 80 else {
66 81 qCWarning(LOG_AmdaPlugin()) << tr("Can't access to SciQlop application");
67 82 }
68 83 }
@@ -1,128 +1,129
1 1 #include "AmdaProvider.h"
2 #include "AmdaDefs.h"
2 3 #include "AmdaResultParser.h"
3 4
4 5 #include <Data/DataProviderParameters.h>
5 6 #include <Network/NetworkController.h>
6 7 #include <SqpApplication.h>
7 8 #include <Variable/Variable.h>
8 9
9 10 #include <QNetworkAccessManager>
10 11 #include <QNetworkReply>
11 12 #include <QTemporaryFile>
12 13 #include <QThread>
13 14
14 15 Q_LOGGING_CATEGORY(LOG_AmdaProvider, "AmdaProvider")
15 16
16 17 namespace {
17 18
18 19 /// URL format for a request on AMDA server. The parameters are as follows:
19 20 /// - %1: start date
20 21 /// - %2: end date
21 22 /// - %3: parameter id
22 23 const auto AMDA_URL_FORMAT = QStringLiteral(
23 24 "http://amda.irap.omp.eu/php/rest/"
24 25 "getParameter.php?startTime=%1&stopTime=%2&parameterID=%3&sampling=60&outputFormat=ASCII&"
25 26 "timeFormat=ISO8601&gzip=0");
26 27
27 28 /// Dates format passed in the URL (e.g 2013-09-23T09:00)
28 29 const auto AMDA_TIME_FORMAT = QStringLiteral("yyyy-MM-ddThh:ss");
29 30
30 31 /// Formats a time to a date that can be passed in URL
31 32 QString dateFormat(double sqpDateTime) noexcept
32 33 {
33 34 auto dateTime = QDateTime::fromMSecsSinceEpoch(sqpDateTime * 1000.);
34 35 return dateTime.toString(AMDA_TIME_FORMAT);
35 36 }
36 37
37
38 38 } // namespace
39 39
40 struct AmdaProvider::AmdaProviderPrivate {
41 DataProviderParameters m_Params{};
42 std::unique_ptr<QNetworkAccessManager> m_AccessManager{nullptr};
43 QNetworkReply *m_Reply{nullptr};
44 // std::unique_ptr<QTemporaryFile> m_File{nullptr};
45 QUuid m_Token;
46 };
47
48 AmdaProvider::AmdaProvider() : impl{spimpl::make_unique_impl<AmdaProviderPrivate>()}
40 AmdaProvider::AmdaProvider()
49 41 {
50 42 qCDebug(LOG_NetworkController()) << tr("AmdaProvider::AmdaProvider")
51 43 << QThread::currentThread();
52 44 if (auto app = sqpApp) {
53 45 auto &networkController = app->networkController();
54 connect(this, &AmdaProvider::requestConstructed, &networkController,
55 &NetworkController::onProcessRequested);
46 connect(this, SIGNAL(requestConstructed(QNetworkRequest, QUuid,
47 std::function<void(QNetworkReply *, QUuid)>)),
48 &networkController,
49 SLOT(onProcessRequested(QNetworkRequest, QUuid,
50 std::function<void(QNetworkReply *, QUuid)>)));
56 51 }
57 52 }
58 53
59 void AmdaProvider::requestDataLoading(QUuid token, const QVector<SqpDateTime> &dateTimeList)
54 void AmdaProvider::requestDataLoading(QUuid token, const DataProviderParameters &parameters)
60 55 {
61 56 // NOTE: Try to use multithread if possible
62 for (const auto &dateTime : dateTimeList) {
63 retrieveData(token, DataProviderParameters{dateTime});
57 const auto times = parameters.m_Times;
58 const auto data = parameters.m_Data;
59 for (const auto &dateTime : qAsConst(times)) {
60 retrieveData(token, dateTime, data);
64 61 }
65 62 }
66 63
67 void AmdaProvider::retrieveData(QUuid token, const DataProviderParameters &parameters)
64 void AmdaProvider::retrieveData(QUuid token, const SqpDateTime &dateTime, const QVariantHash &data)
68 65 {
66 // Retrieves product ID from data: if the value is invalid, no request is made
67 auto productId = data.value(AMDA_XML_ID_KEY).toString();
68 if (productId.isNull()) {
69 qCCritical(LOG_AmdaProvider()) << tr("Can't retrieve data: unknown product id");
70 return;
71 }
72
69 73 // /////////// //
70 74 // Creates URL //
71 75 // /////////// //
72 76
73 auto startDate = dateFormat(parameters.m_Time.m_TStart);
74 auto endDate = dateFormat(parameters.m_Time.m_TEnd);
75 auto productId = QStringLiteral("imf(0)");
77 auto startDate = dateFormat(dateTime.m_TStart);
78 auto endDate = dateFormat(dateTime.m_TEnd);
76 79
77 80 auto url = QUrl{QString{AMDA_URL_FORMAT}.arg(startDate, endDate, productId)};
78 81
79 82 auto tempFile = std::make_shared<QTemporaryFile>();
80 83
81
82 84 // LAMBDA
83 auto httpDownloadFinished = [this, tempFile](QNetworkReply *reply, QUuid dataId) noexcept {
85 auto httpDownloadFinished
86 = [this, dateTime, tempFile, token](QNetworkReply *reply, QUuid dataId) noexcept {
87 Q_UNUSED(dataId);
84 88
85 89 if (tempFile) {
86 90 auto replyReadAll = reply->readAll();
87 91 if (!replyReadAll.isEmpty()) {
88 92 tempFile->write(replyReadAll);
89 93 }
90 94 tempFile->close();
91 95
92 96 // Parse results file
93 97 if (auto dataSeries = AmdaResultParser::readTxt(tempFile->fileName())) {
94 emit dataProvided(impl->m_Token, dataSeries, impl->m_Params.m_Time);
98 emit dataProvided(token, dataSeries, dateTime);
95 99 }
96 100 else {
97 101 /// @todo ALX : debug
98 102 }
99 103 }
100 104
101 105 // Deletes reply
102 106 reply->deleteLater();
103 107 reply = nullptr;
104 108 };
105 109 auto httpFinishedLambda = [this, httpDownloadFinished, tempFile](QNetworkReply *reply,
106 110 QUuid dataId) noexcept {
107 111
108 112 auto downloadFileUrl = QUrl{QString{reply->readAll()}};
109 113 // Deletes old reply
110 114 reply->deleteLater();
111 115
112 116 // Executes request for downloading file //
113 117
114 118 // Creates destination file
115 119 if (tempFile->open()) {
116 120 // Executes request
117 121 emit requestConstructed(QNetworkRequest{downloadFileUrl}, dataId, httpDownloadFinished);
118 122 }
119 123 };
120 124
121 125 // //////////////// //
122 126 // Executes request //
123 127 // //////////////// //
124
125 impl->m_Token = token;
126 impl->m_Params = parameters;
127 128 emit requestConstructed(QNetworkRequest{url}, token, httpFinishedLambda);
128 129 }
@@ -1,26 +1,25
1 1 #ifndef SCIQLOP_COSINUSPROVIDER_H
2 2 #define SCIQLOP_COSINUSPROVIDER_H
3 3
4 4 #include "MockPluginGlobal.h"
5 5
6 6 #include <Data/IDataProvider.h>
7 7
8 8 #include <QLoggingCategory>
9 9
10 10 Q_DECLARE_LOGGING_CATEGORY(LOG_CosinusProvider)
11 11
12 12 /**
13 13 * @brief The CosinusProvider class is an example of how a data provider can generate data
14 14 */
15 15 class SCIQLOP_MOCKPLUGIN_EXPORT CosinusProvider : public IDataProvider {
16 16 public:
17 void requestDataLoading(QUuid token, const QVector<SqpDateTime> &dateTimeList) override;
17 void requestDataLoading(QUuid token, const DataProviderParameters &parameters) override;
18 18
19 19
20 20 private:
21 21 /// @sa IDataProvider::retrieveData()
22 std::shared_ptr<IDataSeries> retrieveData(const DataProviderParameters &parameters) const;
23 std::shared_ptr<IDataSeries> retrieveDataSeries(const SqpDateTime &dateTime);
22 std::shared_ptr<IDataSeries> retrieveData(const SqpDateTime &dateTime) const;
24 23 };
25 24
26 25 #endif // SCIQLOP_COSINUSPROVIDER_H
@@ -1,50 +1,48
1 1 #include "CosinusProvider.h"
2 2
3 3 #include <Data/DataProviderParameters.h>
4 4 #include <Data/ScalarSeries.h>
5 5
6 6 #include <cmath>
7 7
8 8 #include <QDateTime>
9 9 #include <QThread>
10 10
11 11 Q_LOGGING_CATEGORY(LOG_CosinusProvider, "CosinusProvider")
12 12
13 std::shared_ptr<IDataSeries>
14 CosinusProvider::retrieveData(const DataProviderParameters &parameters) const
13 std::shared_ptr<IDataSeries> CosinusProvider::retrieveData(const SqpDateTime &dateTime) const
15 14 {
16 auto dateTime = parameters.m_Time;
17
18 15 auto dataIndex = 0;
19 16
20 17 // Gets the timerange from the parameters
21 18 double freq = 100.0;
22 19 double start = dateTime.m_TStart * freq; // 100 htz
23 20 double end = dateTime.m_TEnd * freq; // 100 htz
24 21
25 22 // We assure that timerange is valid
26 23 if (end < start) {
27 24 std::swap(start, end);
28 25 }
29 26
30 27 // Generates scalar series containing cosinus values (one value per second)
31 28 auto scalarSeries
32 29 = std::make_shared<ScalarSeries>(end - start, Unit{QStringLiteral("t"), true}, Unit{});
33 30
34 31 for (auto time = start; time < end; ++time, ++dataIndex) {
35 32 const auto timeOnFreq = time / freq;
36 33 scalarSeries->setData(dataIndex, timeOnFreq, std::cos(timeOnFreq));
37 34 }
38 35 return scalarSeries;
39 36 }
40 37
41 void CosinusProvider::requestDataLoading(QUuid token, const QVector<SqpDateTime> &dateTimeList)
38 void CosinusProvider::requestDataLoading(QUuid token, const DataProviderParameters &parameters)
42 39 {
43 40 qCDebug(LOG_CosinusProvider()) << "CosinusProvider::requestDataLoading"
44 41 << QThread::currentThread()->objectName();
45 42 // NOTE: Try to use multithread if possible
46 for (const auto &dateTime : dateTimeList) {
47 auto scalarSeries = this->retrieveData(DataProviderParameters{dateTime});
43 const auto times = parameters.m_Times;
44 for (const auto &dateTime : qAsConst(times)) {
45 auto scalarSeries = this->retrieveData(dateTime);
48 46 emit dataProvided(token, scalarSeries, dateTime);
49 47 }
50 48 }
General Comments 0
You need to be logged in to leave comments. Login now