##// END OF EJS Templates
Implementation of V5 acquisition
perrinel -
r539:7c107b5923b0
parent child
Show More
@@ -1,180 +1,190
1 1 #ifndef SCIQLOP_DATASERIES_H
2 2 #define SCIQLOP_DATASERIES_H
3 3
4 4 #include <Common/SortUtils.h>
5 5
6 6 #include <Data/ArrayData.h>
7 7 #include <Data/IDataSeries.h>
8 8
9 9 #include <QLoggingCategory>
10 10
11 11 #include <QReadLocker>
12 12 #include <QReadWriteLock>
13 13 #include <memory>
14 14
15 15 Q_DECLARE_LOGGING_CATEGORY(LOG_DataSeries)
16 16 Q_LOGGING_CATEGORY(LOG_DataSeries, "DataSeries")
17 17
18 18
19 19 /**
20 20 * @brief The DataSeries class is the base (abstract) implementation of IDataSeries.
21 21 *
22 22 * It proposes to set a dimension for the values ​​data.
23 23 *
24 24 * A DataSeries is always sorted on its x-axis data.
25 25 *
26 26 * @tparam Dim The dimension of the values data
27 27 *
28 28 */
29 29 template <int Dim>
30 30 class DataSeries : public IDataSeries {
31 31 public:
32 32 /// @sa IDataSeries::xAxisData()
33 33 std::shared_ptr<ArrayData<1> > xAxisData() override { return m_XAxisData; }
34 34 const std::shared_ptr<ArrayData<1> > xAxisData() const { return m_XAxisData; }
35 35
36 36 /// @sa IDataSeries::xAxisUnit()
37 37 Unit xAxisUnit() const override { return m_XAxisUnit; }
38 38
39 39 /// @return the values dataset
40 40 std::shared_ptr<ArrayData<Dim> > valuesData() { return m_ValuesData; }
41 41 const std::shared_ptr<ArrayData<Dim> > valuesData() const { return m_ValuesData; }
42 42
43 43 /// @sa IDataSeries::valuesUnit()
44 44 Unit valuesUnit() const override { return m_ValuesUnit; }
45 45
46
47 SqpRange range() const override
48 {
49 if (!m_XAxisData->cdata().isEmpty()) {
50 return SqpRange{m_XAxisData->cdata().first(), m_XAxisData->cdata().last()};
51 }
52
53 return SqpRange{};
54 }
55
46 56 void clear()
47 57 {
48 58 m_XAxisData->clear();
49 59 m_ValuesData->clear();
50 60 }
51 61
52 62 /// Merges into the data series an other data series
53 63 /// @remarks the data series to merge with is cleared after the operation
54 64 void merge(IDataSeries *dataSeries) override
55 65 {
56 66 dataSeries->lockWrite();
57 67 lockWrite();
58 68
59 69 if (auto other = dynamic_cast<DataSeries<Dim> *>(dataSeries)) {
60 70 const auto &otherXAxisData = other->xAxisData()->cdata();
61 71 const auto &xAxisData = m_XAxisData->cdata();
62 72
63 73 // As data series are sorted, we can improve performances of merge, by call the sort
64 74 // method only if the two data series overlap.
65 75 if (!otherXAxisData.empty()) {
66 76 auto firstValue = otherXAxisData.front();
67 77 auto lastValue = otherXAxisData.back();
68 78
69 79 auto xAxisDataBegin = xAxisData.cbegin();
70 80 auto xAxisDataEnd = xAxisData.cend();
71 81
72 82 bool prepend;
73 83 bool sortNeeded;
74 84
75 85 if (std::lower_bound(xAxisDataBegin, xAxisDataEnd, firstValue) == xAxisDataEnd) {
76 86 // Other data series if after data series
77 87 prepend = false;
78 88 sortNeeded = false;
79 89 }
80 90 else if (std::upper_bound(xAxisDataBegin, xAxisDataEnd, lastValue)
81 91 == xAxisDataBegin) {
82 92 // Other data series if before data series
83 93 prepend = true;
84 94 sortNeeded = false;
85 95 }
86 96 else {
87 97 // The two data series overlap
88 98 prepend = false;
89 99 sortNeeded = true;
90 100 }
91 101
92 102 // Makes the merge
93 103 m_XAxisData->add(*other->xAxisData(), prepend);
94 104 m_ValuesData->add(*other->valuesData(), prepend);
95 105
96 106 if (sortNeeded) {
97 107 sort();
98 108 }
99 109 }
100 110
101 111 // Clears the other data series
102 112 other->clear();
103 113 }
104 114 else {
105 115 qCWarning(LOG_DataSeries())
106 116 << QObject::tr("Detection of a type of IDataSeries we cannot merge with !");
107 117 }
108 118 unlock();
109 119 dataSeries->unlock();
110 120 }
111 121
112 122 virtual void lockRead() { m_Lock.lockForRead(); }
113 123 virtual void lockWrite() { m_Lock.lockForWrite(); }
114 124 virtual void unlock() { m_Lock.unlock(); }
115 125
116 126 protected:
117 127 /// Protected ctor (DataSeries is abstract). The vectors must have the same size, otherwise a
118 128 /// DataSeries with no values will be created.
119 129 /// @remarks data series is automatically sorted on its x-axis data
120 130 explicit DataSeries(std::shared_ptr<ArrayData<1> > xAxisData, const Unit &xAxisUnit,
121 131 std::shared_ptr<ArrayData<Dim> > valuesData, const Unit &valuesUnit)
122 132 : m_XAxisData{xAxisData},
123 133 m_XAxisUnit{xAxisUnit},
124 134 m_ValuesData{valuesData},
125 135 m_ValuesUnit{valuesUnit}
126 136 {
127 137 if (m_XAxisData->size() != m_ValuesData->size()) {
128 138 clear();
129 139 }
130 140
131 141 // Sorts data if it's not the case
132 142 const auto &xAxisCData = m_XAxisData->cdata();
133 143 if (!std::is_sorted(xAxisCData.cbegin(), xAxisCData.cend())) {
134 144 sort();
135 145 }
136 146 }
137 147
138 148 /// Copy ctor
139 149 explicit DataSeries(const DataSeries<Dim> &other)
140 150 : m_XAxisData{std::make_shared<ArrayData<1> >(*other.m_XAxisData)},
141 151 m_XAxisUnit{other.m_XAxisUnit},
142 152 m_ValuesData{std::make_shared<ArrayData<Dim> >(*other.m_ValuesData)},
143 153 m_ValuesUnit{other.m_ValuesUnit}
144 154 {
145 155 // Since a series is ordered from its construction and is always ordered, it is not
146 156 // necessary to call the sort method here ('other' is sorted)
147 157 }
148 158
149 159 /// Assignment operator
150 160 template <int D>
151 161 DataSeries &operator=(DataSeries<D> other)
152 162 {
153 163 std::swap(m_XAxisData, other.m_XAxisData);
154 164 std::swap(m_XAxisUnit, other.m_XAxisUnit);
155 165 std::swap(m_ValuesData, other.m_ValuesData);
156 166 std::swap(m_ValuesUnit, other.m_ValuesUnit);
157 167
158 168 return *this;
159 169 }
160 170
161 171 private:
162 172 /**
163 173 * Sorts data series on its x-axis data
164 174 */
165 175 void sort() noexcept
166 176 {
167 177 auto permutation = SortUtils::sortPermutation(*m_XAxisData, std::less<double>());
168 178 m_XAxisData = m_XAxisData->sort(permutation);
169 179 m_ValuesData = m_ValuesData->sort(permutation);
170 180 }
171 181
172 182 std::shared_ptr<ArrayData<1> > m_XAxisData;
173 183 Unit m_XAxisUnit;
174 184 std::shared_ptr<ArrayData<Dim> > m_ValuesData;
175 185 Unit m_ValuesUnit;
176 186
177 187 QReadWriteLock m_Lock;
178 188 };
179 189
180 190 #endif // SCIQLOP_DATASERIES_H
@@ -1,74 +1,76
1 1 #ifndef SCIQLOP_IDATAPROVIDER_H
2 2 #define SCIQLOP_IDATAPROVIDER_H
3 3
4 4 #include "CoreGlobal.h"
5 5
6 6 #include <memory>
7 7
8 8 #include <QObject>
9 9 #include <QUuid>
10 10
11 11 #include <Common/MetaTypes.h>
12 12
13 13 #include <Data/SqpRange.h>
14 14
15 15 #include <functional>
16 16
17 17 class DataProviderParameters;
18 18 class IDataSeries;
19 19 class QNetworkReply;
20 20 class QNetworkRequest;
21 21
22 22 /**
23 23 * @brief The IDataProvider interface aims to declare a data provider.
24 24 *
25 25 * A data provider is an entity that generates data and returns it according to various parameters
26 26 * (time interval, product to retrieve the data, etc.)
27 27 *
28 28 * @sa IDataSeries
29 29 */
30 30 class SCIQLOP_CORE_EXPORT IDataProvider : public QObject {
31 31
32 32 Q_OBJECT
33 33 public:
34 34 virtual ~IDataProvider() noexcept = default;
35 35
36 36 /**
37 * @brief requestDataLoading provide datas for the data identified by identifier and parameters
37 * @brief requestDataLoading provide datas for the data identified by acqIdentifier and
38 * parameters
38 39 */
39 virtual void requestDataLoading(QUuid identifier, const DataProviderParameters &parameters) = 0;
40 virtual void requestDataLoading(QUuid acqIdentifier, const DataProviderParameters &parameters)
41 = 0;
40 42
41 43 /**
42 * @brief requestDataAborting stop data loading of the data identified by identifier
44 * @brief requestDataAborting stop data loading of the data identified by acqIdentifier
43 45 */
44 virtual void requestDataAborting(QUuid identifier) = 0;
46 virtual void requestDataAborting(QUuid acqIdentifier) = 0;
45 47
46 48 signals:
47 49 /**
48 50 * @brief dataProvided send dataSeries under dateTime and that corresponds of the data
49 * identified by identifier
51 * identified by acqIdentifier
50 52 */
51 void dataProvided(QUuid identifier, std::shared_ptr<IDataSeries> dateSerie,
52 const SqpRange &dateTime);
53 void dataProvided(QUuid acqIdentifier, std::shared_ptr<IDataSeries> dateSeriesAcquired,
54 const SqpRange &dataRangeAcquired);
53 55
54 56 /**
55 57 * @brief dataProvided send dataSeries under dateTime and that corresponds of the data
56 58 * identified by identifier
57 59 */
58 void dataProvidedProgress(QUuid identifier, double progress);
60 void dataProvidedProgress(QUuid acqIdentifier, double progress);
59 61
60 62
61 63 /**
62 * @brief requestConstructed send a request for the data identified by identifier
64 * @brief requestConstructed send a request for the data identified by acqIdentifier
63 65 * @callback is the methode call by the reply of the request when it is finished.
64 66 */
65 void requestConstructed(const QNetworkRequest &request, QUuid identifier,
67 void requestConstructed(const QNetworkRequest &request, QUuid acqIdentifier,
66 68 std::function<void(QNetworkReply *, QUuid)> callback);
67 69 };
68 70
69 71 // Required for using shared_ptr in signals/slots
70 72 SCIQLOP_REGISTER_META_TYPE(IDATAPROVIDER_PTR_REGISTRY, std::shared_ptr<IDataProvider>)
71 73 SCIQLOP_REGISTER_META_TYPE(IDATAPROVIDER_FUNCTION_REGISTRY,
72 74 std::function<void(QNetworkReply *, QUuid)>)
73 75
74 76 #endif // SCIQLOP_IDATAPROVIDER_H
@@ -1,69 +1,72
1 1 #ifndef SCIQLOP_IDATASERIES_H
2 2 #define SCIQLOP_IDATASERIES_H
3 3
4 4 #include <Common/MetaTypes.h>
5 #include <Data/SqpRange.h>
5 6
6 7 #include <memory>
7 8
8 9 #include <QString>
9 10
10 11 template <int Dim>
11 12 class ArrayData;
12 13
13 14 struct Unit {
14 15 explicit Unit(const QString &name = {}, bool timeUnit = false)
15 16 : m_Name{name}, m_TimeUnit{timeUnit}
16 17 {
17 18 }
18 19
19 20 inline bool operator==(const Unit &other) const
20 21 {
21 22 return std::tie(m_Name, m_TimeUnit) == std::tie(other.m_Name, other.m_TimeUnit);
22 23 }
23 24 inline bool operator!=(const Unit &other) const { return !(*this == other); }
24 25
25 26 QString m_Name; ///< Unit name
26 27 bool m_TimeUnit; ///< The unit is a unit of time (UTC)
27 28 };
28 29
29 30 /**
30 31 * @brief The IDataSeries aims to declare a data series.
31 32 *
32 33 * A data series is an entity that contains at least :
33 34 * - one dataset representing the x-axis
34 35 * - one dataset representing the values
35 36 *
36 37 * Each dataset is represented by an ArrayData, and is associated with a unit.
37 38 *
38 39 * An ArrayData can be unidimensional or two-dimensional, depending on the implementation of the
39 40 * IDataSeries. The x-axis dataset is always unidimensional.
40 41 *
41 42 * @sa ArrayData
42 43 */
43 44 class IDataSeries {
44 45 public:
45 46 virtual ~IDataSeries() noexcept = default;
46 47
47 48 /// Returns the x-axis dataset
48 49 virtual std::shared_ptr<ArrayData<1> > xAxisData() = 0;
49 50
50 51 /// Returns the x-axis dataset (as const)
51 52 virtual const std::shared_ptr<ArrayData<1> > xAxisData() const = 0;
52 53
53 54 virtual Unit xAxisUnit() const = 0;
54 55
55 56 virtual Unit valuesUnit() const = 0;
56 57
57 58 virtual void merge(IDataSeries *dataSeries) = 0;
59 virtual std::shared_ptr<IDataSeries> subData(const SqpRange &range) = 0;
58 60
59 61 virtual std::unique_ptr<IDataSeries> clone() const = 0;
62 virtual SqpRange range() const = 0;
60 63
61 64 virtual void lockRead() = 0;
62 65 virtual void lockWrite() = 0;
63 66 virtual void unlock() = 0;
64 67 };
65 68
66 69 // Required for using shared_ptr in signals/slots
67 70 SCIQLOP_REGISTER_META_TYPE(IDATASERIES_PTR_REGISTRY, std::shared_ptr<IDataSeries>)
68 71
69 72 #endif // SCIQLOP_IDATASERIES_H
@@ -1,25 +1,27
1 1 #ifndef SCIQLOP_SCALARSERIES_H
2 2 #define SCIQLOP_SCALARSERIES_H
3 3
4 4 #include "CoreGlobal.h"
5 5
6 6 #include <Data/DataSeries.h>
7 7
8 8 /**
9 9 * @brief The ScalarSeries class is the implementation for a data series representing a scalar.
10 10 */
11 11 class SCIQLOP_CORE_EXPORT ScalarSeries : public DataSeries<1> {
12 12 public:
13 13 /**
14 14 * Ctor with two vectors. The vectors must have the same size, otherwise a ScalarSeries with no
15 15 * values will be created.
16 16 * @param xAxisData x-axis data
17 17 * @param valuesData values data
18 18 */
19 19 explicit ScalarSeries(QVector<double> xAxisData, QVector<double> valuesData,
20 20 const Unit &xAxisUnit, const Unit &valuesUnit);
21 21
22 std::unique_ptr<IDataSeries> clone() const;
22 std::unique_ptr<IDataSeries> clone() const override;
23
24 std::shared_ptr<IDataSeries> subData(const SqpRange &range) override;
23 25 };
24 26
25 27 #endif // SCIQLOP_SCALARSERIES_H
@@ -1,36 +1,61
1 1 #ifndef SCIQLOP_VARIABLEACQUISITIONWORKER_H
2 2 #define SCIQLOP_VARIABLEACQUISITIONWORKER_H
3 3
4 4 #include "CoreGlobal.h"
5 5
6 6 #include <Data/DataProviderParameters.h>
7 7 #include <QLoggingCategory>
8 8 #include <QObject>
9 9 #include <QUuid>
10 10
11 #include <Data/AcquisitionDataPacket.h>
12 #include <Data/IDataSeries.h>
11 13 #include <Data/SqpRange.h>
12 14
13 15 #include <QLoggingCategory>
14 16
15 17 #include <Common/spimpl.h>
16 18
17 19 Q_DECLARE_LOGGING_CATEGORY(LOG_VariableAcquisitionWorker)
18 20
19 21 class Variable;
20 22 class IDataProvider;
21 23
22 24 /// This class aims to handle all acquisition request
23 25 class SCIQLOP_CORE_EXPORT VariableAcquisitionWorker : public QObject {
24 26 Q_OBJECT
25 27 public:
26 28 explicit VariableAcquisitionWorker(QObject *parent = 0);
29 virtual ~VariableAcquisitionWorker();
27 30
28 void pushVariableRequest(QUuid vIdentifier, SqpRange rangeRequest, SqpRange cacheRangeRequested,
29 DataProviderParameters parameters, IDataProvider *provider);
31 void pushVariableRequest(QUuid vIdentifier, SqpRange rangeRequested,
32 SqpRange cacheRangeRequested, DataProviderParameters parameters,
33 std::shared_ptr<IDataProvider> provider);
34
35 void abortProgressRequested(QUuid vIdentifier);
36
37 void initialize();
38 void finalize();
39 signals:
40 void dataProvided(QUuid vIdentifier, const SqpRange &rangeRequested,
41 const SqpRange &cacheRangeRequested,
42 QVector<AcquisitionDataPacket> dataAcquired);
43
44 void variableRequestInProgress(QUuid vIdentifier, double progress);
45
46 public slots:
47 void onVariableDataAcquired(QUuid acqIdentifier, std::shared_ptr<IDataSeries> dataSeries,
48 SqpRange dataRangeAcquired);
49 void onVariableRetrieveDataInProgress(QUuid acqIdentifier, double progress);
50
51 private slots:
52 void onExecuteRequest(QUuid acqIdentifier);
30 53
31 54 private:
55 void waitForFinish();
56
32 57 class VariableAcquisitionWorkerPrivate;
33 58 spimpl::unique_impl_ptr<VariableAcquisitionWorkerPrivate> impl;
34 59 };
35 60
36 61 #endif // SCIQLOP_VARIABLEACQUISITIONWORKER_H
@@ -1,97 +1,116
1 1 #ifndef SCIQLOP_VARIABLECONTROLLER_H
2 2 #define SCIQLOP_VARIABLECONTROLLER_H
3 3
4 4 #include "CoreGlobal.h"
5 5
6 #include <Data/AcquisitionDataPacket.h>
6 7 #include <Data/SqpRange.h>
7 8
8 9 #include <QLoggingCategory>
9 10 #include <QObject>
10 11
11 12 #include <Common/spimpl.h>
12 13
13 14 class IDataProvider;
14 15 class QItemSelectionModel;
15 16 class TimeController;
16 17 class Variable;
17 18 class VariableModel;
18 19
19 20 Q_DECLARE_LOGGING_CATEGORY(LOG_VariableController)
20 21
22
23 /**
24 * Possible types of zoom operation
25 */
26 enum class AcquisitionZoomType { ZoomOut, ZoomIn, PanRight, PanLeft, Unknown };
27
28
21 29 /**
22 30 * @brief The VariableController class aims to handle the variables in SciQlop.
23 31 */
24 32 class SCIQLOP_CORE_EXPORT VariableController : public QObject {
25 33 Q_OBJECT
26 34 public:
27 35 explicit VariableController(QObject *parent = 0);
28 36 virtual ~VariableController();
29 37
30 38 VariableModel *variableModel() noexcept;
31 39 QItemSelectionModel *variableSelectionModel() noexcept;
32 40
33 41 void setTimeController(TimeController *timeController) noexcept;
34 42
35 43 /**
36 44 * Deletes from the controller the variable passed in parameter.
37 45 *
38 46 * Delete a variable includes:
39 47 * - the deletion of the various references to the variable in SciQlop
40 48 * - the deletion of the model variable
41 49 * - the deletion of the provider associated with the variable
42 50 * - removing the cache associated with the variable
43 51 *
44 52 * @param variable the variable to delete from the controller.
45 53 */
46 54 void deleteVariable(std::shared_ptr<Variable> variable) noexcept;
47 55
48 56 /**
49 57 * Deletes from the controller the variables passed in parameter.
50 58 * @param variables the variables to delete from the controller.
51 59 * @sa deleteVariable()
52 60 */
53 61 void deleteVariables(const QVector<std::shared_ptr<Variable> > &variables) noexcept;
54 62
55 63 /**
56 64 * @brief abort the variable retrieve data progression
57 65 */
58 66 void abortProgress(std::shared_ptr<Variable> variable);
59 67
68 static AcquisitionZoomType getZoomType(const SqpRange &range, const SqpRange &oldRange);
60 69 signals:
61 70 /// Signal emitted when a variable is about to be deleted from the controller
62 71 void variableAboutToBeDeleted(std::shared_ptr<Variable> variable);
63 72
64 73 /// Signal emitted when a data acquisition is requested on a range for a variable
65 74 void rangeChanged(std::shared_ptr<Variable> variable, const SqpRange &range);
66 75
67 76 public slots:
68 /// Request the data loading of the variable whithin dateTime
69 void onRequestDataLoading(std::shared_ptr<Variable> variable, const SqpRange &dateTime);
77 /// Request the data loading of the variable whithin range
78 void onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables, const SqpRange &range,
79 const SqpRange &oldRange, bool synchronise);
70 80 /**
71 81 * Creates a new variable and adds it to the model
72 82 * @param name the name of the new variable
73 83 * @param metadata the metadata of the new variable
74 84 * @param provider the data provider for the new variable
75 85 */
76 86 void createVariable(const QString &name, const QVariantHash &metadata,
77 87 std::shared_ptr<IDataProvider> provider) noexcept;
78 88
79 89 /// Update the temporal parameters of every selected variable to dateTime
80 90 void onDateTimeOnSelection(const SqpRange &dateTime);
81 91
82 92
93 void onDataProvided(QUuid vIdentifier, const SqpRange &rangeRequested,
94 const SqpRange &cacheRangeRequested,
95 QVector<AcquisitionDataPacket> dataAcquired);
96
83 97 void onVariableRetrieveDataInProgress(QUuid identifier, double progress);
84 98
99 /// Cancel the current request for the variable
85 100 void onAbortProgressRequested(std::shared_ptr<Variable> variable);
86 101
102 /// synchronization group methods
103 void onAddSynchronizationGroupId(QUuid synchronizationGroupId);
104 void onRemoveSynchronizationGroupId(QUuid synchronizationGroupId);
105
87 106 void initialize();
88 107 void finalize();
89 108
90 109 private:
91 110 void waitForFinish();
92 111
93 112 class VariableControllerPrivate;
94 113 spimpl::unique_impl_ptr<VariableControllerPrivate> impl;
95 114 };
96 115
97 116 #endif // SCIQLOP_VARIABLECONTROLLER_H
@@ -1,13 +1,41
1 1 #include <Data/ScalarSeries.h>
2 2
3 3 ScalarSeries::ScalarSeries(QVector<double> xAxisData, QVector<double> valuesData,
4 4 const Unit &xAxisUnit, const Unit &valuesUnit)
5 5 : DataSeries{std::make_shared<ArrayData<1> >(std::move(xAxisData)), xAxisUnit,
6 6 std::make_shared<ArrayData<1> >(std::move(valuesData)), valuesUnit}
7 7 {
8 8 }
9 9
10 10 std::unique_ptr<IDataSeries> ScalarSeries::clone() const
11 11 {
12 12 return std::make_unique<ScalarSeries>(*this);
13 13 }
14
15 std::shared_ptr<IDataSeries> ScalarSeries::subData(const SqpRange &range)
16 {
17 auto subXAxisData = QVector<double>();
18 auto subValuesData = QVector<double>();
19 this->lockRead();
20 {
21 const auto &currentXData = this->xAxisData()->cdata();
22 const auto &currentValuesData = this->valuesData()->cdata();
23
24 auto xDataBegin = currentXData.cbegin();
25 auto xDataEnd = currentXData.cend();
26
27 auto lowerIt = std::lower_bound(xDataBegin, xDataEnd, range.m_TStart);
28 auto upperIt = std::upper_bound(xDataBegin, xDataEnd, range.m_TEnd);
29 auto distance = std::distance(xDataBegin, lowerIt);
30
31 auto valuesDataIt = currentValuesData.cbegin() + distance;
32 for (auto xAxisDataIt = lowerIt; xAxisDataIt != upperIt; ++xAxisDataIt, ++valuesDataIt) {
33 subXAxisData.append(*xAxisDataIt);
34 subValuesData.append(*valuesDataIt);
35 }
36 }
37 this->unlock();
38
39 return std::make_shared<ScalarSeries>(subXAxisData, subValuesData, this->xAxisUnit(),
40 this->valuesUnit());
41 }
@@ -1,133 +1,134
1 1 #include "Network/NetworkController.h"
2 2
3 3 #include <QMutex>
4 4 #include <QNetworkAccessManager>
5 5 #include <QNetworkReply>
6 6 #include <QNetworkRequest>
7 7 #include <QReadWriteLock>
8 8 #include <QThread>
9 9
10 10 #include <unordered_map>
11 11
12 12 Q_LOGGING_CATEGORY(LOG_NetworkController, "NetworkController")
13 13
14 14 struct NetworkController::NetworkControllerPrivate {
15 15 explicit NetworkControllerPrivate(NetworkController *parent) : m_WorkingMutex{} {}
16
17 void lockRead() { m_Lock.lockForRead(); }
18 void lockWrite() { m_Lock.lockForWrite(); }
19 void unlock() { m_Lock.unlock(); }
20
16 21 QMutex m_WorkingMutex;
17 22
18 23 QReadWriteLock m_Lock;
19 24 std::unordered_map<QNetworkReply *, QUuid> m_NetworkReplyToVariableId;
20 25 std::unique_ptr<QNetworkAccessManager> m_AccessManager{nullptr};
21
22 void lockRead() { m_Lock.lockForRead(); }
23 void lockWrite() { m_Lock.lockForWrite(); }
24 void unlock() { m_Lock.unlock(); }
25 26 };
26 27
27 28 NetworkController::NetworkController(QObject *parent)
28 29 : QObject(parent), impl{spimpl::make_unique_impl<NetworkControllerPrivate>(this)}
29 30 {
30 31 }
31 32
32 33 void NetworkController::onProcessRequested(const QNetworkRequest &request, QUuid identifier,
33 34 std::function<void(QNetworkReply *, QUuid)> callback)
34 35 {
35 36 qCDebug(LOG_NetworkController()) << tr("NetworkController registered")
36 37 << QThread::currentThread()->objectName();
37 38 auto reply = impl->m_AccessManager->get(request);
38 39
39 40 // Store the couple reply id
40 41 impl->lockWrite();
41 42 impl->m_NetworkReplyToVariableId[reply] = identifier;
42 43 impl->unlock();
43 44
44 45 auto onReplyFinished = [reply, this, identifier, callback]() {
45 46
46 47 qCDebug(LOG_NetworkController()) << tr("NetworkController onReplyFinished")
47 48 << QThread::currentThread() << reply;
48 49 impl->lockRead();
49 50 auto it = impl->m_NetworkReplyToVariableId.find(reply);
50 51 impl->unlock();
51 52 if (it != impl->m_NetworkReplyToVariableId.cend()) {
52 53 impl->lockWrite();
53 54 impl->m_NetworkReplyToVariableId.erase(reply);
54 55 impl->unlock();
55 56 // Deletes reply
56 57 callback(reply, identifier);
57 58 reply->deleteLater();
58 59
59 60 emit this->replyDownloadProgress(identifier, 0);
60 61 }
61 62
62 63 qCDebug(LOG_NetworkController()) << tr("NetworkController onReplyFinished END")
63 64 << QThread::currentThread() << reply;
64 65 };
65 66
66 67 auto onReplyProgress = [reply, this](qint64 bytesRead, qint64 totalBytes) {
67 68
68 69 double progress = (bytesRead * 100.0) / totalBytes;
69 70 qCDebug(LOG_NetworkController()) << tr("NetworkController onReplyProgress") << progress
70 71 << QThread::currentThread() << reply;
71 72 impl->lockRead();
72 73 auto it = impl->m_NetworkReplyToVariableId.find(reply);
73 74 impl->unlock();
74 75 if (it != impl->m_NetworkReplyToVariableId.cend()) {
75 76 emit this->replyDownloadProgress(it->second, progress);
76 77 }
77 78 qCDebug(LOG_NetworkController()) << tr("NetworkController onReplyProgress END")
78 79 << QThread::currentThread() << reply;
79 80 };
80 81
81 82
82 83 connect(reply, &QNetworkReply::finished, this, onReplyFinished);
83 84 connect(reply, &QNetworkReply::downloadProgress, this, onReplyProgress);
84 85 qCDebug(LOG_NetworkController()) << tr("NetworkController registered END")
85 86 << QThread::currentThread()->objectName() << reply;
86 87 }
87 88
88 89 void NetworkController::initialize()
89 90 {
90 91 qCDebug(LOG_NetworkController()) << tr("NetworkController init") << QThread::currentThread();
91 92 impl->m_WorkingMutex.lock();
92 93 impl->m_AccessManager = std::make_unique<QNetworkAccessManager>();
93 94
94 95
95 96 auto onReplyErrors = [this](QNetworkReply *reply, const QList<QSslError> &errors) {
96 97
97 98 qCCritical(LOG_NetworkController()) << tr("NetworkAcessManager errors: ") << errors;
98 99
99 100 };
100 101
101 102
102 103 connect(impl->m_AccessManager.get(), &QNetworkAccessManager::sslErrors, this, onReplyErrors);
103 104
104 105 qCDebug(LOG_NetworkController()) << tr("NetworkController init END");
105 106 }
106 107
107 108 void NetworkController::finalize()
108 109 {
109 110 impl->m_WorkingMutex.unlock();
110 111 }
111 112
112 113 void NetworkController::onReplyCanceled(QUuid identifier)
113 114 {
114 115 auto findReply = [identifier](const auto &entry) { return identifier == entry.second; };
115 116 qCDebug(LOG_NetworkController()) << tr("NetworkController onReplyCanceled")
116 117 << QThread::currentThread();
117 118
118 119
119 120 impl->lockRead();
120 121 auto end = impl->m_NetworkReplyToVariableId.cend();
121 122 auto it = std::find_if(impl->m_NetworkReplyToVariableId.cbegin(), end, findReply);
122 123 impl->unlock();
123 124 if (it != end) {
124 125 it->first->abort();
125 126 }
126 127 qCDebug(LOG_NetworkController()) << tr("NetworkController onReplyCanceled END")
127 128 << QThread::currentThread();
128 129 }
129 130
130 131 void NetworkController::waitForFinish()
131 132 {
132 133 QMutexLocker locker{&impl->m_WorkingMutex};
133 134 }
@@ -1,26 +1,225
1 1 #include "Variable/VariableAcquisitionWorker.h"
2 2
3 3 #include "Variable/Variable.h"
4
5 #include <Data/AcquisitionRequest.h>
6 #include <Data/SqpRange.h>
7
4 8 #include <unordered_map>
9 #include <utility>
5 10
11 #include <QMutex>
12 #include <QReadWriteLock>
6 13 #include <QThread>
14
7 15 Q_LOGGING_CATEGORY(LOG_VariableAcquisitionWorker, "VariableAcquisitionWorker")
8 16
9 17 struct VariableAcquisitionWorker::VariableAcquisitionWorkerPrivate {
10 18
11 std::unordered_map<std::shared_ptr<Variable>, QVector<SqpRange> >
12 m_VariableToSqpDateTimeListMap;
19 explicit VariableAcquisitionWorkerPrivate() : m_Lock{QReadWriteLock::Recursive} {}
20
21 void lockRead() { m_Lock.lockForRead(); }
22 void lockWrite() { m_Lock.lockForWrite(); }
23 void unlock() { m_Lock.unlock(); }
24
25 void removeVariableRequest(QUuid vIdentifier);
26
27 QMutex m_WorkingMutex;
28 QReadWriteLock m_Lock;
29
30 std::map<QUuid, QVector<AcquisitionDataPacket> > m_AcqIdentifierToAcqDataPacketVectorMap;
31 std::map<QUuid, AcquisitionRequest> m_AcqIdentifierToAcqRequestMap;
32 std::map<QUuid, std::pair<QUuid, QUuid> > m_VIdentifierToCurrrentAcqIdNextIdPairMap;
13 33 };
14 34
15 35
16 36 VariableAcquisitionWorker::VariableAcquisitionWorker(QObject *parent)
17 37 : QObject{parent}, impl{spimpl::make_unique_impl<VariableAcquisitionWorkerPrivate>()}
18 38 {
19 39 }
20 40
21 void VariableAcquisitionWorker::pushVariableRequest(QUuid vIdentifier, SqpRange rangeRequest,
41 VariableAcquisitionWorker::~VariableAcquisitionWorker()
42 {
43 qCInfo(LOG_VariableAcquisitionWorker()) << tr("VariableAcquisitionWorker destruction")
44 << QThread::currentThread();
45 this->waitForFinish();
46 }
47
48
49 void VariableAcquisitionWorker::pushVariableRequest(QUuid vIdentifier, SqpRange rangeRequested,
22 50 SqpRange cacheRangeRequested,
23 51 DataProviderParameters parameters,
24 IDataProvider *provider)
52 std::shared_ptr<IDataProvider> provider)
53 {
54 qCDebug(LOG_VariableAcquisitionWorker())
55 << tr("TORM VariableAcquisitionWorker::pushVariableRequest ") << cacheRangeRequested;
56
57 // Request creation
58 auto acqRequest = AcquisitionRequest{};
59 acqRequest.m_vIdentifier = vIdentifier;
60 acqRequest.m_DataProviderParameters = parameters;
61 acqRequest.m_RangeRequested = rangeRequested;
62 acqRequest.m_CacheRangeRequested = cacheRangeRequested;
63 acqRequest.m_Size = parameters.m_Times.size();
64 acqRequest.m_Provider = provider;
65
66 // Register request
67 impl->lockWrite();
68 impl->m_AcqIdentifierToAcqRequestMap.insert(
69 std::make_pair(acqRequest.m_AcqIdentifier, acqRequest));
70
71 auto it = impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.find(vIdentifier);
72 if (it != impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.cend()) {
73 // A current request already exists, we can replace the next one
74 it->second.second = acqRequest.m_AcqIdentifier;
75 impl->unlock();
76 }
77 else {
78 // First request for the variable, it must be stored and executed
79 impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.insert(
80 std::make_pair(vIdentifier, std::make_pair(acqRequest.m_AcqIdentifier, QUuid())));
81 impl->unlock();
82
83 QMetaObject::invokeMethod(this, "onExecuteRequest", Qt::QueuedConnection,
84 Q_ARG(QUuid, acqRequest.m_AcqIdentifier));
85 }
86 }
87
88 void VariableAcquisitionWorker::abortProgressRequested(QUuid vIdentifier)
89 {
90 // TODO
91 }
92
93 void VariableAcquisitionWorker::onVariableRetrieveDataInProgress(QUuid acqIdentifier,
94 double progress)
95 {
96 // TODO
97 }
98
99 void VariableAcquisitionWorker::onVariableDataAcquired(QUuid acqIdentifier,
100 std::shared_ptr<IDataSeries> dataSeries,
101 SqpRange dataRangeAcquired)
25 102 {
103 qCDebug(LOG_VariableAcquisitionWorker()) << tr("onVariableDataAcquired on range ")
104 << acqIdentifier << dataRangeAcquired;
105 impl->lockWrite();
106 auto aIdToARit = impl->m_AcqIdentifierToAcqRequestMap.find(acqIdentifier);
107 if (aIdToARit != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
108 // Store the result
109 auto dataPacket = AcquisitionDataPacket{};
110 dataPacket.m_Range = dataRangeAcquired;
111 dataPacket.m_DateSeries = dataSeries;
112
113 auto aIdToADPVit = impl->m_AcqIdentifierToAcqDataPacketVectorMap.find(acqIdentifier);
114 if (aIdToADPVit != impl->m_AcqIdentifierToAcqDataPacketVectorMap.cend()) {
115 // A current request result already exists, we can update it
116 aIdToADPVit->second.push_back(dataPacket);
117 }
118 else {
119 // First request result for the variable, it must be stored
120 impl->m_AcqIdentifierToAcqDataPacketVectorMap.insert(
121 std::make_pair(acqIdentifier, QVector<AcquisitionDataPacket>() << dataPacket));
122 }
123
124
125 // Decrement the counter of the request
126 auto &acqRequest = aIdToARit->second;
127 acqRequest.m_Size = acqRequest.m_Size - 1;
128
129 // if the counter is 0, we can return data then run the next request if it exists and
130 // removed the finished request
131 if (acqRequest.m_Size == 0) {
132 // Return the data
133 aIdToADPVit = impl->m_AcqIdentifierToAcqDataPacketVectorMap.find(acqIdentifier);
134 if (aIdToADPVit != impl->m_AcqIdentifierToAcqDataPacketVectorMap.cend()) {
135 emit dataProvided(acqRequest.m_vIdentifier, acqRequest.m_RangeRequested,
136 acqRequest.m_CacheRangeRequested, aIdToADPVit->second);
137 }
138
139 // Execute the next one
140 auto it
141 = impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.find(acqRequest.m_vIdentifier);
142
143 if (it != impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.cend()) {
144 if (it->second.second.isNull()) {
145 // There is no next request, we can remove the varibale request
146 impl->removeVariableRequest(acqRequest.m_vIdentifier);
147 }
148 else {
149 auto acqIdentifierToRemove = it->second.first;
150 // Move the next request to the current request
151 it->second.first = it->second.second;
152 it->second.second = QUuid();
153 // Remove AcquisitionRequest and results;
154 impl->m_AcqIdentifierToAcqRequestMap.erase(acqIdentifierToRemove);
155 impl->m_AcqIdentifierToAcqDataPacketVectorMap.erase(acqIdentifierToRemove);
156 // Execute the current request
157 QMetaObject::invokeMethod(this, "onExecuteRequest", Qt::QueuedConnection,
158 Q_ARG(QUuid, it->second.first));
159 }
160 }
161 else {
162 qCCritical(LOG_VariableAcquisitionWorker())
163 << tr("Impossible to execute the acquisition on an unfound variable ");
164 }
165 }
166 }
167 else {
168 qCCritical(LOG_VariableAcquisitionWorker())
169 << tr("Impossible to retrieve AcquisitionRequest for the incoming data");
170 }
171 impl->unlock();
172 }
173
174 void VariableAcquisitionWorker::onExecuteRequest(QUuid acqIdentifier)
175 {
176 qCDebug(LOG_VariableAcquisitionWorker()) << tr("onExecuteRequest") << QThread::currentThread();
177 impl->lockRead();
178 auto it = impl->m_AcqIdentifierToAcqRequestMap.find(acqIdentifier);
179 if (it != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
180 auto request = it->second;
181 impl->unlock();
182 request.m_Provider->requestDataLoading(acqIdentifier, request.m_DataProviderParameters);
183 }
184 else {
185 impl->unlock();
186 // TODO log no acqIdentifier recognized
187 }
188 }
189
190 void VariableAcquisitionWorker::initialize()
191 {
192 qCDebug(LOG_VariableAcquisitionWorker()) << tr("VariableAcquisitionWorker init")
193 << QThread::currentThread();
194 impl->m_WorkingMutex.lock();
195 qCDebug(LOG_VariableAcquisitionWorker()) << tr("VariableAcquisitionWorker init END");
196 }
197
198 void VariableAcquisitionWorker::finalize()
199 {
200 impl->m_WorkingMutex.unlock();
201 }
202
203 void VariableAcquisitionWorker::waitForFinish()
204 {
205 QMutexLocker locker{&impl->m_WorkingMutex};
206 }
207
208 void VariableAcquisitionWorker::VariableAcquisitionWorkerPrivate::removeVariableRequest(
209 QUuid vIdentifier)
210 {
211 lockWrite();
212 auto it = m_VIdentifierToCurrrentAcqIdNextIdPairMap.find(vIdentifier);
213
214 if (it != m_VIdentifierToCurrrentAcqIdNextIdPairMap.cend()) {
215 // A current request already exists, we can replace the next one
216
217 m_AcqIdentifierToAcqRequestMap.erase(it->second.first);
218 m_AcqIdentifierToAcqDataPacketVectorMap.erase(it->second.first);
219
220 m_AcqIdentifierToAcqRequestMap.erase(it->second.second);
221 m_AcqIdentifierToAcqDataPacketVectorMap.erase(it->second.second);
222 }
223 m_VIdentifierToCurrrentAcqIdNextIdPairMap.erase(vIdentifier);
224 unlock();
26 225 }
@@ -1,276 +1,508
1 1 #include <Variable/Variable.h>
2 #include <Variable/VariableAcquisitionWorker.h>
2 3 #include <Variable/VariableCacheController.h>
4 #include <Variable/VariableCacheStrategy.h>
3 5 #include <Variable/VariableController.h>
4 6 #include <Variable/VariableModel.h>
7 #include <Variable/VariableSynchronizationGroup.h>
5 8
6 9 #include <Data/DataProviderParameters.h>
7 10 #include <Data/IDataProvider.h>
8 11 #include <Data/IDataSeries.h>
9 12 #include <Time/TimeController.h>
10 13
11 14 #include <QMutex>
12 15 #include <QThread>
13 16 #include <QUuid>
14 17 #include <QtCore/QItemSelectionModel>
15 18
19 #include <set>
16 20 #include <unordered_map>
17 21
18 22 Q_LOGGING_CATEGORY(LOG_VariableController, "VariableController")
19 23
24 namespace {
25
26 SqpRange computeSynchroRangeRequested(const SqpRange &varRange, const SqpRange &grapheRange,
27 const SqpRange &oldGraphRange)
28 {
29 auto zoomType = VariableController::getZoomType(grapheRange, oldGraphRange);
30
31 auto varRangeRequested = varRange;
32 switch (zoomType) {
33 case AcquisitionZoomType::ZoomIn: {
34 auto deltaLeft = grapheRange.m_TStart - oldGraphRange.m_TStart;
35 auto deltaRight = oldGraphRange.m_TEnd - grapheRange.m_TEnd;
36 varRangeRequested.m_TStart += deltaLeft;
37 varRangeRequested.m_TEnd -= deltaRight;
38 break;
39 }
40
41 case AcquisitionZoomType::ZoomOut: {
42 auto deltaLeft = oldGraphRange.m_TStart - grapheRange.m_TStart;
43 auto deltaRight = grapheRange.m_TEnd - oldGraphRange.m_TEnd;
44 varRangeRequested.m_TStart -= deltaLeft;
45 varRangeRequested.m_TEnd += deltaRight;
46 break;
47 }
48 case AcquisitionZoomType::PanRight: {
49 auto deltaRight = grapheRange.m_TEnd - oldGraphRange.m_TEnd;
50 varRangeRequested.m_TStart += deltaRight;
51 varRangeRequested.m_TEnd += deltaRight;
52 break;
53 }
54 case AcquisitionZoomType::PanLeft: {
55 auto deltaLeft = oldGraphRange.m_TStart - grapheRange.m_TStart;
56 varRangeRequested.m_TStart -= deltaLeft;
57 varRangeRequested.m_TEnd -= deltaLeft;
58 break;
59 }
60 case AcquisitionZoomType::Unknown: {
61 qCCritical(LOG_VariableController())
62 << VariableController::tr("Impossible to synchronize: zoom type unknown");
63 break;
64 }
65 default:
66 qCCritical(LOG_VariableController()) << VariableController::tr(
67 "Impossible to synchronize: zoom type not take into account");
68 // No action
69 break;
70 }
71
72 return varRangeRequested;
73 }
74 }
75
20 76 struct VariableController::VariableControllerPrivate {
21 77 explicit VariableControllerPrivate(VariableController *parent)
22 78 : m_WorkingMutex{},
23 79 m_VariableModel{new VariableModel{parent}},
24 80 m_VariableSelectionModel{new QItemSelectionModel{m_VariableModel, parent}},
25 m_VariableCacheController{std::make_unique<VariableCacheController>()}
81 m_VariableCacheController{std::make_unique<VariableCacheController>()},
82 m_VariableCacheStrategy{std::make_unique<VariableCacheStrategy>()},
83 m_VariableAcquisitionWorker{std::make_unique<VariableAcquisitionWorker>()}
84 {
85
86 m_VariableAcquisitionWorker->moveToThread(&m_VariableAcquisitionWorkerThread);
87 m_VariableAcquisitionWorkerThread.setObjectName("VariableAcquisitionWorkerThread");
88 }
89
90
91 virtual ~VariableControllerPrivate()
26 92 {
93 qCDebug(LOG_VariableController()) << tr("VariableControllerPrivate destruction");
94 m_VariableAcquisitionWorkerThread.quit();
95 m_VariableAcquisitionWorkerThread.wait();
27 96 }
28 97
98
99 void processRequest(std::shared_ptr<Variable> var, const SqpRange &rangeRequested);
100
29 101 QVector<SqpRange> provideNotInCacheDateTimeList(std::shared_ptr<Variable> variable,
30 102 const SqpRange &dateTime);
31 103
104 std::shared_ptr<Variable> findVariable(QUuid vIdentifier);
105 std::shared_ptr<IDataSeries>
106 retrieveDataSeries(const QVector<AcquisitionDataPacket> acqDataPacketVector);
107
108 void registerProvider(std::shared_ptr<IDataProvider> provider);
109
32 110 QMutex m_WorkingMutex;
33 111 /// Variable model. The VariableController has the ownership
34 112 VariableModel *m_VariableModel;
35 113 QItemSelectionModel *m_VariableSelectionModel;
36 114
37 115
38 116 TimeController *m_TimeController{nullptr};
39 117 std::unique_ptr<VariableCacheController> m_VariableCacheController;
118 std::unique_ptr<VariableCacheStrategy> m_VariableCacheStrategy;
119 std::unique_ptr<VariableAcquisitionWorker> m_VariableAcquisitionWorker;
120 QThread m_VariableAcquisitionWorkerThread;
40 121
41 122 std::unordered_map<std::shared_ptr<Variable>, std::shared_ptr<IDataProvider> >
42 123 m_VariableToProviderMap;
43 124 std::unordered_map<std::shared_ptr<Variable>, QUuid> m_VariableToIdentifierMap;
125 std::map<QUuid, std::shared_ptr<VariableSynchronizationGroup> >
126 m_GroupIdToVariableSynchronizationGroupMap;
127 std::map<QUuid, QUuid> m_VariableIdGroupIdMap;
128 std::set<std::shared_ptr<IDataProvider> > m_ProviderSet;
44 129 };
45 130
131
46 132 VariableController::VariableController(QObject *parent)
47 133 : QObject{parent}, impl{spimpl::make_unique_impl<VariableControllerPrivate>(this)}
48 134 {
49 135 qCDebug(LOG_VariableController()) << tr("VariableController construction")
50 136 << QThread::currentThread();
51 137
52 138 connect(impl->m_VariableModel, &VariableModel::abortProgessRequested, this,
53 139 &VariableController::onAbortProgressRequested);
140
141 connect(impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::dataProvided, this,
142 &VariableController::onDataProvided);
143 connect(impl->m_VariableAcquisitionWorker.get(),
144 &VariableAcquisitionWorker::variableRequestInProgress, this,
145 &VariableController::onVariableRetrieveDataInProgress);
146
147 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::started,
148 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::initialize);
149 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::finished,
150 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::finalize);
151
152
153 impl->m_VariableAcquisitionWorkerThread.start();
54 154 }
55 155
56 156 VariableController::~VariableController()
57 157 {
58 158 qCDebug(LOG_VariableController()) << tr("VariableController destruction")
59 159 << QThread::currentThread();
60 160 this->waitForFinish();
61 161 }
62 162
63 163 VariableModel *VariableController::variableModel() noexcept
64 164 {
65 165 return impl->m_VariableModel;
66 166 }
67 167
68 168 QItemSelectionModel *VariableController::variableSelectionModel() noexcept
69 169 {
70 170 return impl->m_VariableSelectionModel;
71 171 }
72 172
73 173 void VariableController::setTimeController(TimeController *timeController) noexcept
74 174 {
75 175 impl->m_TimeController = timeController;
76 176 }
77 177
78 178 void VariableController::deleteVariable(std::shared_ptr<Variable> variable) noexcept
79 179 {
80 180 if (!variable) {
81 181 qCCritical(LOG_VariableController()) << "Can't delete variable: variable is null";
82 182 return;
83 183 }
84 184
85 185 // Spreads in SciQlop that the variable will be deleted, so that potential receivers can
86 186 // make some treatments before the deletion
87 187 emit variableAboutToBeDeleted(variable);
88 188
89 189 // Deletes identifier
90 190 impl->m_VariableToIdentifierMap.erase(variable);
91 191
92 192 // Deletes provider
93 193 auto nbProvidersDeleted = impl->m_VariableToProviderMap.erase(variable);
94 194 qCDebug(LOG_VariableController())
95 195 << tr("Number of providers deleted for variable %1: %2")
96 196 .arg(variable->name(), QString::number(nbProvidersDeleted));
97 197
98 198 // Clears cache
99 199 impl->m_VariableCacheController->clear(variable);
100 200
101 201 // Deletes from model
102 202 impl->m_VariableModel->deleteVariable(variable);
103 203 }
104 204
105 205 void VariableController::deleteVariables(
106 206 const QVector<std::shared_ptr<Variable> > &variables) noexcept
107 207 {
108 208 for (auto variable : qAsConst(variables)) {
109 209 deleteVariable(variable);
110 210 }
111 211 }
112 212
113 213 void VariableController::abortProgress(std::shared_ptr<Variable> variable)
114 214 {
115 215 }
116 216
117 217 void VariableController::createVariable(const QString &name, const QVariantHash &metadata,
118 218 std::shared_ptr<IDataProvider> provider) noexcept
119 219 {
120 220
121 221 if (!impl->m_TimeController) {
122 222 qCCritical(LOG_VariableController())
123 223 << tr("Impossible to create variable: The time controller is null");
124 224 return;
125 225 }
126 226
127 auto dateTime = impl->m_TimeController->dateTime();
227 auto range = impl->m_TimeController->dateTime();
128 228
129 if (auto newVariable = impl->m_VariableModel->createVariable(name, dateTime, metadata)) {
229 if (auto newVariable = impl->m_VariableModel->createVariable(name, range, metadata)) {
130 230 auto identifier = QUuid::createUuid();
131 231
132 232 // store the provider
233 impl->registerProvider(provider);
234
235 // Associate the provider
133 236 impl->m_VariableToProviderMap[newVariable] = provider;
134 237 impl->m_VariableToIdentifierMap[newVariable] = identifier;
135 238
136 auto addDateTimeAcquired = [ this, varW = std::weak_ptr<Variable>{newVariable} ](
137 QUuid identifier, auto dataSeriesAcquired, auto dateTimeToPutInCache)
138 {
139 if (auto variable = varW.lock()) {
140 auto varIdentifier = impl->m_VariableToIdentifierMap.at(variable);
141 if (varIdentifier == identifier) {
142 impl->m_VariableCacheController->addDateTime(variable, dateTimeToPutInCache);
143 variable->setDataSeries(dataSeriesAcquired);
144 emit variable->updated();
145 }
146 }
147 };
148 239
149 connect(provider.get(), &IDataProvider::dataProvided, addDateTimeAcquired);
150 connect(provider.get(), &IDataProvider::dataProvidedProgress, this,
151 &VariableController::onVariableRetrieveDataInProgress);
152 this->onRequestDataLoading(newVariable, dateTime);
240 impl->processRequest(newVariable, range);
153 241 }
154 242 }
155 243
156 244 void VariableController::onDateTimeOnSelection(const SqpRange &dateTime)
157 245 {
246 // TODO check synchronisation
158 247 qCDebug(LOG_VariableController()) << "VariableController::onDateTimeOnSelection"
159 248 << QThread::currentThread()->objectName();
160 249 auto selectedRows = impl->m_VariableSelectionModel->selectedRows();
161 250
162 251 for (const auto &selectedRow : qAsConst(selectedRows)) {
163 252 if (auto selectedVariable = impl->m_VariableModel->variable(selectedRow.row())) {
164 selectedVariable->setDateTime(dateTime);
165 this->onRequestDataLoading(selectedVariable, dateTime);
253 selectedVariable->setRange(dateTime);
254 impl->processRequest(selectedVariable, dateTime);
166 255
167 256 // notify that rescale operation has to be done
168 257 emit rangeChanged(selectedVariable, dateTime);
169 258 }
170 259 }
171 260 }
172 261
173 void VariableController::onVariableRetrieveDataInProgress(QUuid identifier, double progress)
262 void VariableController::onDataProvided(QUuid vIdentifier, const SqpRange &rangeRequested,
263 const SqpRange &cacheRangeRequested,
264 QVector<AcquisitionDataPacket> dataAcquired)
174 265 {
175 auto findReply = [identifier](const auto &entry) { return identifier == entry.second; };
266 qCCritical(LOG_VariableController()) << tr("onDataProvided") << dataAcquired.isEmpty();
267
268 auto var = impl->findVariable(vIdentifier);
269 if (var != nullptr) {
270 var->setRange(rangeRequested);
271 var->setCacheRange(cacheRangeRequested);
272 qCCritical(LOG_VariableController()) << tr("1: onDataProvided") << rangeRequested;
273 qCCritical(LOG_VariableController()) << tr("2: onDataProvided") << cacheRangeRequested;
274
275 auto retrievedDataSeries = impl->retrieveDataSeries(dataAcquired);
276 qCCritical(LOG_VariableController()) << tr("3: onDataProvided")
277 << retrievedDataSeries->range();
278 var->mergeDataSeries(retrievedDataSeries);
279 emit var->updated();
280 }
281 else {
282 qCCritical(LOG_VariableController()) << tr("Impossible to provide data to a null variable");
283 }
284 }
176 285
177 auto end = impl->m_VariableToIdentifierMap.cend();
178 auto it = std::find_if(impl->m_VariableToIdentifierMap.cbegin(), end, findReply);
179 if (it != end) {
180 impl->m_VariableModel->setDataProgress(it->first, progress);
286 void VariableController::onVariableRetrieveDataInProgress(QUuid identifier, double progress)
287 {
288 auto var = impl->findVariable(identifier);
289 if (var != nullptr) {
290 impl->m_VariableModel->setDataProgress(var, progress);
291 }
292 else {
293 qCCritical(LOG_VariableController())
294 << tr("Impossible to notify progression of a null variable");
181 295 }
182 296 }
183 297
184 298 void VariableController::onAbortProgressRequested(std::shared_ptr<Variable> variable)
185 299 {
186 300 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAbortProgressRequested"
187 301 << QThread::currentThread()->objectName();
188 302
189 303 auto it = impl->m_VariableToIdentifierMap.find(variable);
190 304 if (it != impl->m_VariableToIdentifierMap.cend()) {
191 305 impl->m_VariableToProviderMap.at(variable)->requestDataAborting(it->second);
192 306 }
193 307 else {
194 308 qCWarning(LOG_VariableController())
195 309 << tr("Aborting progression of inexistant variable detected !!!")
196 310 << QThread::currentThread()->objectName();
197 311 }
198 312 }
199 313
314 void VariableController::onAddSynchronizationGroupId(QUuid synchronizationGroupId)
315 {
316 auto vSynchroGroup = std::make_shared<VariableSynchronizationGroup>();
317 impl->m_GroupIdToVariableSynchronizationGroupMap.insert(
318 std::make_pair(synchronizationGroupId, vSynchroGroup));
319 }
320
321 void VariableController::onRemoveSynchronizationGroupId(QUuid synchronizationGroupId)
322 {
323 impl->m_GroupIdToVariableSynchronizationGroupMap.erase(synchronizationGroupId);
324 }
325
200 326
201 void VariableController::onRequestDataLoading(std::shared_ptr<Variable> variable,
202 const SqpRange &dateTime)
327 void VariableController::onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables,
328 const SqpRange &range, const SqpRange &oldRange,
329 bool synchronise)
203 330 {
331 // NOTE: oldRange isn't really necessary since oldRange == variable->range().
332
204 333 qCDebug(LOG_VariableController()) << "VariableController::onRequestDataLoading"
205 334 << QThread::currentThread()->objectName();
206 335 // we want to load data of the variable for the dateTime.
207 336 // First we check if the cache contains some of them.
208 337 // For the other, we ask the provider to give them.
209 if (variable) {
210 338
211 auto dateTimeListNotInCache
212 = impl->m_VariableCacheController->provideNotInCacheDateTimeList(variable, dateTime);
339 foreach (auto var, variables) {
340 qCInfo(LOG_VariableController()) << "processRequest for" << var->name();
341 impl->processRequest(var, range);
342 }
213 343
214 if (!dateTimeListNotInCache.empty()) {
215 // Ask the provider for each data on the dateTimeListNotInCache
216 auto identifier = impl->m_VariableToIdentifierMap.at(variable);
217 impl->m_VariableToProviderMap.at(variable)->requestDataLoading(
218 identifier,
219 DataProviderParameters{std::move(dateTimeListNotInCache), variable->metadata()});
344 if (synchronise) {
345 // Get the group ids
346 qCInfo(LOG_VariableController())
347 << "VariableController::onRequestDataLoading for synchro var ENABLE";
348 auto groupIds = std::set<QUuid>();
349 foreach (auto var, variables) {
350 auto vToVIdit = impl->m_VariableToIdentifierMap.find(var);
351 if (vToVIdit != impl->m_VariableToIdentifierMap.cend()) {
352 auto vId = vToVIdit->second;
353
354 auto vIdToGIdit = impl->m_VariableIdGroupIdMap.find(vId);
355 if (vIdToGIdit != impl->m_VariableIdGroupIdMap.cend()) {
356 auto gId = vToVIdit->second;
357 if (groupIds.find(gId) == groupIds.cend()) {
358 groupIds.insert(gId);
359 }
360 }
361 }
220 362 }
221 else {
222 emit variable->updated();
363
364 // We assume here all group ids exist
365 foreach (auto gId, groupIds) {
366 auto vSynchronizationGroup = impl->m_GroupIdToVariableSynchronizationGroupMap.at(gId);
367 auto vSyncIds = vSynchronizationGroup->getIds();
368 for (auto vId : vSyncIds) {
369 auto var = impl->findVariable(vId);
370 if (var != nullptr) {
371 qCInfo(LOG_VariableController()) << "processRequest synchro for" << var->name();
372 auto vSyncRangeRequested
373 = computeSynchroRangeRequested(var->range(), range, oldRange);
374 impl->processRequest(var, vSyncRangeRequested);
375 }
376 else {
377 qCCritical(LOG_VariableController())
378 << tr("Impossible to synchronize a null variable");
379 }
380 }
223 381 }
224 382 }
225 else {
226 qCCritical(LOG_VariableController()) << tr("Impossible to load data of a variable null");
227 }
228 383 }
229 384
230 385
231 386 void VariableController::initialize()
232 387 {
233 388 qCDebug(LOG_VariableController()) << tr("VariableController init") << QThread::currentThread();
234 389 impl->m_WorkingMutex.lock();
235 390 qCDebug(LOG_VariableController()) << tr("VariableController init END");
236 391 }
237 392
238 393 void VariableController::finalize()
239 394 {
240 395 impl->m_WorkingMutex.unlock();
241 396 }
242 397
243 398 void VariableController::waitForFinish()
244 399 {
245 400 QMutexLocker locker{&impl->m_WorkingMutex};
246 401 }
247 402
403 AcquisitionZoomType VariableController::getZoomType(const SqpRange &range, const SqpRange &oldRange)
404 {
405 // t1.m_TStart <= t2.m_TStart && t2.m_TEnd <= t1.m_TEnd
406 auto zoomType = AcquisitionZoomType::Unknown;
407 if (range.m_TStart <= oldRange.m_TStart && oldRange.m_TEnd <= range.m_TEnd) {
408 zoomType = AcquisitionZoomType::ZoomOut;
409 }
410 else if (range.m_TStart > oldRange.m_TStart && range.m_TEnd > oldRange.m_TEnd) {
411 zoomType = AcquisitionZoomType::PanRight;
412 }
413 else if (range.m_TStart < oldRange.m_TStart && range.m_TEnd < oldRange.m_TEnd) {
414 zoomType = AcquisitionZoomType::PanLeft;
415 }
416 else if (range.m_TStart > oldRange.m_TStart && oldRange.m_TEnd > range.m_TEnd) {
417 zoomType = AcquisitionZoomType::ZoomIn;
418 }
419 else {
420 qCCritical(LOG_VariableController()) << "getZoomType: Unknown type detected";
421 }
422 return zoomType;
423 }
248 424
249 QVector<SqpRange> VariableController::VariableControllerPrivate::provideNotInCacheDateTimeList(
250 std::shared_ptr<Variable> variable, const SqpRange &dateTime)
425 void VariableController::VariableControllerPrivate::processRequest(std::shared_ptr<Variable> var,
426 const SqpRange &rangeRequested)
251 427 {
252 auto notInCache = QVector<SqpRange>{};
253 428
254 if (!variable->contains(dateTime)) {
255 auto vDateTime = variable->dateTime();
256 if (dateTime.m_TEnd <= vDateTime.m_TStart || dateTime.m_TStart >= vDateTime.m_TEnd) {
257 notInCache << dateTime;
258 }
259 else if (dateTime.m_TStart < vDateTime.m_TStart && dateTime.m_TEnd <= vDateTime.m_TEnd) {
260 notInCache << SqpRange{dateTime.m_TStart, vDateTime.m_TStart};
261 }
262 else if (dateTime.m_TStart < vDateTime.m_TStart && dateTime.m_TEnd > vDateTime.m_TEnd) {
263 notInCache << SqpRange{dateTime.m_TStart, vDateTime.m_TStart}
264 << SqpRange{vDateTime.m_TEnd, dateTime.m_TStart};
265 }
266 else if (dateTime.m_TStart < vDateTime.m_TEnd) {
267 notInCache << SqpRange{vDateTime.m_TEnd, dateTime.m_TStart};
429 auto varRangesRequested
430 = m_VariableCacheStrategy->computeCacheRange(var->range(), rangeRequested);
431 auto notInCacheRangeList = var->provideNotInCacheRangeList(varRangesRequested.second);
432
433 if (!notInCacheRangeList.empty()) {
434 // Display part of data which are already there
435 // Ask the provider for each data on the dateTimeListNotInCache
436 auto identifier = m_VariableToIdentifierMap.at(var);
437 auto varProvider = m_VariableToProviderMap.at(var);
438 if (varProvider != nullptr) {
439 m_VariableAcquisitionWorker->pushVariableRequest(
440 identifier, varRangesRequested.first, varRangesRequested.second,
441 DataProviderParameters{std::move(notInCacheRangeList), var->metadata()},
442 varProvider);
268 443 }
269 444 else {
270 qCCritical(LOG_VariableController()) << tr("Detection of unknown case.")
271 << QThread::currentThread();
445 qCCritical(LOG_VariableController())
446 << "Impossible to provide data with a null provider";
272 447 }
273 448 }
449 else {
450 var->setRange(rangeRequested);
451 var->setCacheRange(varRangesRequested.second);
452 var->setDataSeries(var->dataSeries()->subData(varRangesRequested.second));
453 emit var->updated();
454 }
455 }
456
457 std::shared_ptr<Variable>
458 VariableController::VariableControllerPrivate::findVariable(QUuid vIdentifier)
459 {
460 std::shared_ptr<Variable> var;
461 auto findReply = [vIdentifier](const auto &entry) { return vIdentifier == entry.second; };
462
463 auto end = m_VariableToIdentifierMap.cend();
464 auto it = std::find_if(m_VariableToIdentifierMap.cbegin(), end, findReply);
465 if (it != end) {
466 var = it->first;
467 }
468 else {
469 qCCritical(LOG_VariableController())
470 << tr("Impossible to find the variable with the identifier: ") << vIdentifier;
471 }
274 472
275 return notInCache;
473 return var;
474 }
475
476 std::shared_ptr<IDataSeries> VariableController::VariableControllerPrivate::retrieveDataSeries(
477 const QVector<AcquisitionDataPacket> acqDataPacketVector)
478 {
479 qCInfo(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size")
480 << acqDataPacketVector.size();
481 std::shared_ptr<IDataSeries> dataSeries;
482 if (!acqDataPacketVector.isEmpty()) {
483 dataSeries = acqDataPacketVector[0].m_DateSeries;
484 for (int i = 1; i < acqDataPacketVector.size(); ++i) {
485 dataSeries->merge(acqDataPacketVector[i].m_DateSeries.get());
486 }
487 }
488
489 return dataSeries;
490 }
491
492 void VariableController::VariableControllerPrivate::registerProvider(
493 std::shared_ptr<IDataProvider> provider)
494 {
495 if (m_ProviderSet.find(provider) == m_ProviderSet.end()) {
496 qCInfo(LOG_VariableController()) << tr("Registering of a new provider")
497 << provider->objectName();
498 m_ProviderSet.insert(provider);
499 connect(provider.get(), &IDataProvider::dataProvided, m_VariableAcquisitionWorker.get(),
500 &VariableAcquisitionWorker::onVariableDataAcquired);
501 connect(provider.get(), &IDataProvider::dataProvidedProgress,
502 m_VariableAcquisitionWorker.get(),
503 &VariableAcquisitionWorker::onVariableRetrieveDataInProgress);
504 }
505 else {
506 qCInfo(LOG_VariableController()) << tr("Cannot register provider, it already exists ");
507 }
276 508 }
@@ -1,84 +1,80
1 1 #ifndef SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
2 2 #define SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
3 3
4 4 #include "Visualization/IVisualizationWidget.h"
5 5
6 6 #include <QLoggingCategory>
7 7 #include <QWidget>
8 8
9 9 #include <memory>
10 10
11 11 #include <Common/spimpl.h>
12 12
13 13 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationGraphWidget)
14 14
15 15 class QCPRange;
16 16 class SqpRange;
17 17 class Variable;
18 18
19 /**
20 * Possible types of zoom operation
21 */
22 enum class VisualizationGraphWidgetZoomType { ZoomOut, ZoomIn, PanRight, PanLeft, Unknown };
23
24 19 namespace Ui {
25 20 class VisualizationGraphWidget;
26 21 } // namespace Ui
27 22
28 23 class VisualizationGraphWidget : public QWidget, public IVisualizationWidget {
29 24 Q_OBJECT
30 25
31 26 public:
32 27 explicit VisualizationGraphWidget(const QString &name = {}, QWidget *parent = 0);
33 28 virtual ~VisualizationGraphWidget();
34 29
35 void enableSynchronize(bool enable);
30 /// If acquisition isn't enable, requestDataLoading signal cannot be emit
31 void enableAcquisition(bool enable);
36 32
37 33 void addVariable(std::shared_ptr<Variable> variable);
38 34 void addVariableUsingGraph(std::shared_ptr<Variable> variable);
39 35 /// Removes a variable from the graph
40 36 void removeVariable(std::shared_ptr<Variable> variable) noexcept;
41 37
42 38 void setRange(std::shared_ptr<Variable> variable, const SqpRange &range);
43 39 SqpRange graphRange() const noexcept;
44 40 void setGraphRange(const SqpRange &range);
45 41
46 42 // IVisualizationWidget interface
47 43 void accept(IVisualizationWidgetVisitor *visitor) override;
48 44 bool canDrop(const Variable &variable) const override;
49 45 bool contains(const Variable &variable) const override;
50 46 QString name() const override;
51 47
52 48
53 49 signals:
54 void requestDataLoading(std::shared_ptr<Variable> variable, const SqpRange &dateTime);
55 void synchronize(const SqpRange &dateTime, const SqpRange &oldDateTime,
56 VisualizationGraphWidgetZoomType zoomType);
50 void synchronize(const SqpRange &range, const SqpRange &oldRange);
51 void requestDataLoading(QVector<std::shared_ptr<Variable> > variable, const SqpRange &range,
52 const SqpRange &oldRange, bool synchronise);
57 53
58 54
59 55 private:
60 56 Ui::VisualizationGraphWidget *ui;
61 57
62 58 class VisualizationGraphWidgetPrivate;
63 59 spimpl::unique_impl_ptr<VisualizationGraphWidgetPrivate> impl;
64 60
65 61 private slots:
66 62 /// Slot called when right clicking on the graph (displays a menu)
67 63 void onGraphMenuRequested(const QPoint &pos) noexcept;
68 64
69 65 /// Rescale the X axe to range parameter
70 66 void onRangeChanged(const QCPRange &t1, const QCPRange &t2);
71 67
72 68 /// Slot called when a mouse move was made
73 69 void onMouseMove(QMouseEvent *event) noexcept;
74 70 /// Slot called when a mouse wheel was made, to perform some processing before the zoom is done
75 71 void onMouseWheel(QWheelEvent *event) noexcept;
76 72 /// Slot called when a mouse press was made, to activate the calibration of a graph
77 73 void onMousePress(QMouseEvent *event) noexcept;
78 74 /// Slot called when a mouse release was made, to deactivate the calibration of a graph
79 75 void onMouseRelease(QMouseEvent *event) noexcept;
80 76
81 77 void onDataCacheVariableUpdated();
82 78 };
83 79
84 80 #endif // SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
@@ -1,45 +1,52
1 1 #ifndef SCIQLOP_VISUALIZATIONZONEWIDGET_H
2 2 #define SCIQLOP_VISUALIZATIONZONEWIDGET_H
3 3
4 4 #include "Visualization/IVisualizationWidget.h"
5 5
6 6 #include <QLoggingCategory>
7 7 #include <QWidget>
8 8
9 #include <memory>
10
11 #include <Common/spimpl.h>
12
9 13 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationZoneWidget)
10 14
11 15 namespace Ui {
12 16 class VisualizationZoneWidget;
13 17 } // Ui
14 18
15 19 class Variable;
16 20 class VisualizationGraphWidget;
17 21
18 22 class VisualizationZoneWidget : public QWidget, public IVisualizationWidget {
19 23 Q_OBJECT
20 24
21 25 public:
22 26 explicit VisualizationZoneWidget(const QString &name = {}, QWidget *parent = 0);
23 27 virtual ~VisualizationZoneWidget();
24 28
25 29 /// Add a graph widget
26 30 void addGraph(VisualizationGraphWidget *graphWidget);
27 31
28 32 /**
29 33 * Creates a graph using a variable. The variable will be displayed in the new graph.
30 34 * @param variable the variable for which to create the graph
31 35 * @return the pointer to the created graph
32 36 */
33 37 VisualizationGraphWidget *createGraph(std::shared_ptr<Variable> variable);
34 38
35 39 // IVisualizationWidget interface
36 40 void accept(IVisualizationWidgetVisitor *visitor) override;
37 41 bool canDrop(const Variable &variable) const override;
38 42 bool contains(const Variable &variable) const override;
39 43 QString name() const override;
40 44
41 45 private:
42 46 Ui::VisualizationZoneWidget *ui;
47
48 class VisualizationZoneWidgetPrivate;
49 spimpl::unique_impl_ptr<VisualizationZoneWidgetPrivate> impl;
43 50 };
44 51
45 52 #endif // SCIQLOP_VISUALIZATIONZONEWIDGET_H
@@ -1,151 +1,151
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 29 SIGNAL(variableCreationRequested(const QString &, const QVariantHash &,
30 30 std::shared_ptr<IDataProvider>)),
31 31 m_VariableController.get(),
32 32 SLOT(createVariable(const QString &, const QVariantHash &,
33 33 std::shared_ptr<IDataProvider>)));
34 34
35 35 // VariableController <-> VisualizationController
36 36 connect(m_VariableController.get(),
37 37 SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)),
38 38 m_VisualizationController.get(),
39 39 SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)), Qt::DirectConnection);
40 40
41 41 connect(m_VariableController.get(),
42 42 SIGNAL(rangeChanged(std::shared_ptr<Variable>, const SqpRange &)),
43 43 m_VisualizationController.get(),
44 44 SIGNAL(rangeChanged(std::shared_ptr<Variable>, const SqpRange &)));
45 45
46 46
47 47 m_DataSourceController->moveToThread(&m_DataSourceControllerThread);
48 48 m_DataSourceControllerThread.setObjectName("DataSourceControllerThread");
49 49 m_NetworkController->moveToThread(&m_NetworkControllerThread);
50 50 m_NetworkControllerThread.setObjectName("NetworkControllerThread");
51 51 m_VariableController->moveToThread(&m_VariableControllerThread);
52 52 m_VariableControllerThread.setObjectName("VariableControllerThread");
53 53 m_VisualizationController->moveToThread(&m_VisualizationControllerThread);
54 54 m_VisualizationControllerThread.setObjectName("VsualizationControllerThread");
55 55
56 56
57 57 // Additionnal init
58 58 m_VariableController->setTimeController(m_TimeController.get());
59 59 }
60 60
61 61 virtual ~SqpApplicationPrivate()
62 62 {
63 qCInfo(LOG_SqpApplication()) << tr("SqpApplicationPrivate destruction");
63 qCDebug(LOG_SqpApplication()) << tr("SqpApplicationPrivate destruction");
64 64 m_DataSourceControllerThread.quit();
65 65 m_DataSourceControllerThread.wait();
66 66
67 67 m_NetworkControllerThread.quit();
68 68 m_NetworkControllerThread.wait();
69 69
70 70 m_VariableControllerThread.quit();
71 71 m_VariableControllerThread.wait();
72 72
73 73 m_VisualizationControllerThread.quit();
74 74 m_VisualizationControllerThread.wait();
75 75 }
76 76
77 77 std::unique_ptr<DataSourceController> m_DataSourceController;
78 78 std::unique_ptr<VariableController> m_VariableController;
79 79 std::unique_ptr<TimeController> m_TimeController;
80 80 std::unique_ptr<NetworkController> m_NetworkController;
81 81 std::unique_ptr<VisualizationController> m_VisualizationController;
82 82 QThread m_DataSourceControllerThread;
83 83 QThread m_NetworkControllerThread;
84 84 QThread m_VariableControllerThread;
85 85 QThread m_VisualizationControllerThread;
86 86 };
87 87
88 88
89 89 SqpApplication::SqpApplication(int &argc, char **argv)
90 90 : QApplication{argc, argv}, impl{spimpl::make_unique_impl<SqpApplicationPrivate>()}
91 91 {
92 92 qCDebug(LOG_SqpApplication()) << tr("SqpApplication construction") << QThread::currentThread();
93 93
94 94 connect(&impl->m_DataSourceControllerThread, &QThread::started,
95 95 impl->m_DataSourceController.get(), &DataSourceController::initialize);
96 96 connect(&impl->m_DataSourceControllerThread, &QThread::finished,
97 97 impl->m_DataSourceController.get(), &DataSourceController::finalize);
98 98
99 99 connect(&impl->m_NetworkControllerThread, &QThread::started, impl->m_NetworkController.get(),
100 100 &NetworkController::initialize);
101 101 connect(&impl->m_NetworkControllerThread, &QThread::finished, impl->m_NetworkController.get(),
102 102 &NetworkController::finalize);
103 103
104 104 connect(&impl->m_VariableControllerThread, &QThread::started, impl->m_VariableController.get(),
105 105 &VariableController::initialize);
106 106 connect(&impl->m_VariableControllerThread, &QThread::finished, impl->m_VariableController.get(),
107 107 &VariableController::finalize);
108 108
109 109 connect(&impl->m_VisualizationControllerThread, &QThread::started,
110 110 impl->m_VisualizationController.get(), &VisualizationController::initialize);
111 111 connect(&impl->m_VisualizationControllerThread, &QThread::finished,
112 112 impl->m_VisualizationController.get(), &VisualizationController::finalize);
113 113
114 114 impl->m_DataSourceControllerThread.start();
115 115 impl->m_NetworkControllerThread.start();
116 116 impl->m_VariableControllerThread.start();
117 117 impl->m_VisualizationControllerThread.start();
118 118 }
119 119
120 120 SqpApplication::~SqpApplication()
121 121 {
122 122 }
123 123
124 124 void SqpApplication::initialize()
125 125 {
126 126 }
127 127
128 128 DataSourceController &SqpApplication::dataSourceController() noexcept
129 129 {
130 130 return *impl->m_DataSourceController;
131 131 }
132 132
133 133 NetworkController &SqpApplication::networkController() noexcept
134 134 {
135 135 return *impl->m_NetworkController;
136 136 }
137 137
138 138 TimeController &SqpApplication::timeController() noexcept
139 139 {
140 140 return *impl->m_TimeController;
141 141 }
142 142
143 143 VariableController &SqpApplication::variableController() noexcept
144 144 {
145 145 return *impl->m_VariableController;
146 146 }
147 147
148 148 VisualizationController &SqpApplication::visualizationController() noexcept
149 149 {
150 150 return *impl->m_VisualizationController;
151 151 }
@@ -1,427 +1,321
1 1 #include "Visualization/VisualizationGraphWidget.h"
2 2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 3 #include "Visualization/VisualizationGraphHelper.h"
4 4 #include "Visualization/VisualizationGraphRenderingDelegate.h"
5 5 #include "ui_VisualizationGraphWidget.h"
6 6
7 7 #include <Data/ArrayData.h>
8 8 #include <Data/IDataSeries.h>
9 9 #include <Settings/SqpSettingsDefs.h>
10 10 #include <SqpApplication.h>
11 11 #include <Variable/Variable.h>
12 12 #include <Variable/VariableController.h>
13 13
14 14 #include <unordered_map>
15 15
16 16 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
17 17
18 18 namespace {
19 19
20 20 /// Key pressed to enable zoom on horizontal axis
21 21 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::NoModifier;
22 22
23 23 /// Key pressed to enable zoom on vertical axis
24 24 const auto VERTICAL_ZOOM_MODIFIER = Qt::ControlModifier;
25 25
26 /// Gets a tolerance value from application settings. If the setting can't be found, the default
27 /// value passed in parameter is returned
28 double toleranceValue(const QString &key, double defaultValue) noexcept
29 {
30 return QSettings{}.value(key, defaultValue).toDouble();
31 }
32
33 26 } // namespace
34 27
35 28 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
36 29
37 30 explicit VisualizationGraphWidgetPrivate()
38 : m_DoSynchronize{true}, m_IsCalibration{false}, m_RenderingDelegate{nullptr}
31 : m_DoAcquisition{true}, m_IsCalibration{false}, m_RenderingDelegate{nullptr}
39 32 {
40 33 }
41 34
42 // Return the operation when range changed
43 VisualizationGraphWidgetZoomType getZoomType(const QCPRange &t1, const QCPRange &t2);
44
45 35 // 1 variable -> n qcpplot
46 36 std::multimap<std::shared_ptr<Variable>, QCPAbstractPlottable *> m_VariableToPlotMultiMap;
47 bool m_DoSynchronize;
37 bool m_DoAcquisition;
48 38 bool m_IsCalibration;
49 39 QCPItemTracer *m_TextTracer;
50 40 /// Delegate used to attach rendering features to the plot
51 41 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
52 42 };
53 43
54 44 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
55 45 : QWidget{parent},
56 46 ui{new Ui::VisualizationGraphWidget},
57 47 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>()}
58 48 {
59 49 ui->setupUi(this);
60 50
61 51 // The delegate must be initialized after the ui as it uses the plot
62 52 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*ui->widget);
63 53
64 54 ui->graphNameLabel->setText(name);
65 55
66 56 // 'Close' options : widget is deleted when closed
67 57 setAttribute(Qt::WA_DeleteOnClose);
68 58 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationGraphWidget::close);
69 59 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
70 60
71 61 // Set qcpplot properties :
72 62 // - Drag (on x-axis) and zoom are enabled
73 63 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
74 64 ui->widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);
75 65 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal);
76 66
77 67 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
78 68 connect(ui->widget, &QCustomPlot::mouseRelease, this,
79 69 &VisualizationGraphWidget::onMouseRelease);
80 70 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
81 71 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
82 72 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
83 73 &QCPAxis::rangeChanged),
84 74 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
85 75
86 76 // Activates menu when right clicking on the graph
87 77 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
88 78 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
89 79 &VisualizationGraphWidget::onGraphMenuRequested);
90 80
91 81 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
92 82 &VariableController::onRequestDataLoading);
93 83 }
94 84
95 85
96 86 VisualizationGraphWidget::~VisualizationGraphWidget()
97 87 {
98 88 delete ui;
99 89 }
100 90
101 void VisualizationGraphWidget::enableSynchronize(bool enable)
91 void VisualizationGraphWidget::enableAcquisition(bool enable)
102 92 {
103 impl->m_DoSynchronize = enable;
93 impl->m_DoAcquisition = enable;
104 94 }
105 95
106 96 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable)
107 97 {
108 98 // Uses delegate to create the qcpplot components according to the variable
109 99 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
110 100
111 101 for (auto createdPlottable : qAsConst(createdPlottables)) {
112 102 impl->m_VariableToPlotMultiMap.insert({variable, createdPlottable});
113 103 }
114 104
115 105 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
116 106 }
117 107 void VisualizationGraphWidget::addVariableUsingGraph(std::shared_ptr<Variable> variable)
118 108 {
109 // TODO
110 // // when adding a variable, we need to set its time range to the current graph range
111 // auto grapheRange = ui->widget->xAxis->range();
112 // auto dateTime = SqpRange{grapheRange.lower, grapheRange.upper};
113 // variable->setDateTime(dateTime);
114
115 // auto variableDateTimeWithTolerance = dateTime;
116
117 // // add tolerance for each side
118 // auto toleranceFactor
119 // = toleranceValue(GENERAL_TOLERANCE_AT_INIT_KEY,
120 // GENERAL_TOLERANCE_AT_INIT_DEFAULT_VALUE);
121 // auto tolerance = toleranceFactor * (dateTime.m_TEnd - dateTime.m_TStart);
122 // variableDateTimeWithTolerance.m_TStart -= tolerance;
123 // variableDateTimeWithTolerance.m_TEnd += tolerance;
124
125 // // Uses delegate to create the qcpplot components according to the variable
126 // auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
127
128 // for (auto createdPlottable : qAsConst(createdPlottables)) {
129 // impl->m_VariableToPlotMultiMap.insert({variable, createdPlottable});
130 // }
119 131
120 // when adding a variable, we need to set its time range to the current graph range
121 auto grapheRange = ui->widget->xAxis->range();
122 auto dateTime = SqpRange{grapheRange.lower, grapheRange.upper};
123 variable->setDateTime(dateTime);
124
125 auto variableDateTimeWithTolerance = dateTime;
126
127 // add tolerance for each side
128 auto toleranceFactor
129 = toleranceValue(GENERAL_TOLERANCE_AT_INIT_KEY, GENERAL_TOLERANCE_AT_INIT_DEFAULT_VALUE);
130 auto tolerance = toleranceFactor * (dateTime.m_TEnd - dateTime.m_TStart);
131 variableDateTimeWithTolerance.m_TStart -= tolerance;
132 variableDateTimeWithTolerance.m_TEnd += tolerance;
133
134 // Uses delegate to create the qcpplot components according to the variable
135 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
136
137 for (auto createdPlottable : qAsConst(createdPlottables)) {
138 impl->m_VariableToPlotMultiMap.insert({variable, createdPlottable});
139 }
132 // connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
140 133
141 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
142
143 // CHangement detected, we need to ask controller to request data loading
144 emit requestDataLoading(variable, variableDateTimeWithTolerance);
134 // // CHangement detected, we need to ask controller to request data loading
135 // emit requestDataLoading(variable, variableDateTimeWithTolerance);
145 136 }
146 137
147 138 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
148 139 {
149 140 // Each component associated to the variable :
150 141 // - is removed from qcpplot (which deletes it)
151 142 // - is no longer referenced in the map
152 143 auto componentsIt = impl->m_VariableToPlotMultiMap.equal_range(variable);
153 144 for (auto it = componentsIt.first; it != componentsIt.second;) {
154 145 ui->widget->removePlottable(it->second);
155 146 it = impl->m_VariableToPlotMultiMap.erase(it);
156 147 }
157 148
158 149 // Updates graph
159 150 ui->widget->replot();
160 151 }
161 152
162 153 void VisualizationGraphWidget::setRange(std::shared_ptr<Variable> variable, const SqpRange &range)
163 154 {
164 155 // Note: in case of different axes that depends on variable, we could start with a code like
165 156 // that:
166 157 // auto componentsIt = impl->m_VariableToPlotMultiMap.equal_range(variable);
167 158 // for (auto it = componentsIt.first; it != componentsIt.second;) {
168 159 // }
169 160 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
170 161 ui->widget->replot();
171 162 }
172 163
173 164 SqpRange VisualizationGraphWidget::graphRange() const noexcept
174 165 {
175 166 auto grapheRange = ui->widget->xAxis->range();
176 167 return SqpRange{grapheRange.lower, grapheRange.upper};
177 168 }
178 169
179 170 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
180 171 {
181 172 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
182 173 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
183 174 ui->widget->replot();
184 175 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
185 176 }
186 177
187 178 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
188 179 {
189 180 if (visitor) {
190 181 visitor->visit(this);
191 182 }
192 183 else {
193 184 qCCritical(LOG_VisualizationGraphWidget())
194 185 << tr("Can't visit widget : the visitor is null");
195 186 }
196 187 }
197 188
198 189 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
199 190 {
200 191 /// @todo : for the moment, a graph can always accomodate a variable
201 192 Q_UNUSED(variable);
202 193 return true;
203 194 }
204 195
205 196 bool VisualizationGraphWidget::contains(const Variable &variable) const
206 197 {
207 198 // Finds the variable among the keys of the map
208 199 auto variablePtr = &variable;
209 200 auto findVariable
210 201 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
211 202
212 203 auto end = impl->m_VariableToPlotMultiMap.cend();
213 204 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
214 205 return it != end;
215 206 }
216 207
217 208 QString VisualizationGraphWidget::name() const
218 209 {
219 210 return ui->graphNameLabel->text();
220 211 }
221 212
222 213 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
223 214 {
224 215 QMenu graphMenu{};
225 216
226 217 // Iterates on variables (unique keys)
227 218 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
228 219 end = impl->m_VariableToPlotMultiMap.cend();
229 220 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
230 221 // 'Remove variable' action
231 222 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
232 223 [ this, var = it->first ]() { removeVariable(var); });
233 224 }
234 225
235 226 if (!graphMenu.isEmpty()) {
236 227 graphMenu.exec(mapToGlobal(pos));
237 228 }
238 229 }
239 230
240 231 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
241 232 {
242 qCInfo(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::onRangeChanged")
243 << QThread::currentThread()->objectName();
233 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
234 << QThread::currentThread()->objectName() << "DoAcqui"
235 << impl->m_DoAcquisition;
244 236
245 auto dateTimeRange = SqpRange{t1.lower, t1.upper};
237 auto graphRange = SqpRange{t1.lower, t1.upper};
238 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
246 239
247 auto zoomType = impl->getZoomType(t1, t2);
248 for (auto it = impl->m_VariableToPlotMultiMap.cbegin();
249 it != impl->m_VariableToPlotMultiMap.cend(); ++it) {
240 if (impl->m_DoAcquisition) {
241 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
250 242
251 auto variable = it->first;
252 auto currentDateTime = dateTimeRange;
253
254 auto toleranceFactor = toleranceValue(GENERAL_TOLERANCE_AT_UPDATE_KEY,
255 GENERAL_TOLERANCE_AT_UPDATE_DEFAULT_VALUE);
256 auto tolerance = toleranceFactor * (currentDateTime.m_TEnd - currentDateTime.m_TStart);
257 auto variableDateTimeWithTolerance = currentDateTime;
258 variableDateTimeWithTolerance.m_TStart -= tolerance;
259 variableDateTimeWithTolerance.m_TEnd += tolerance;
260
261 qCDebug(LOG_VisualizationGraphWidget()) << "r" << currentDateTime;
262 qCDebug(LOG_VisualizationGraphWidget()) << "t" << variableDateTimeWithTolerance;
263 qCDebug(LOG_VisualizationGraphWidget()) << "v" << variable->dateTime();
264 // If new range with tol is upper than variable datetime parameters. we need to request new
265 // data
266 if (!variable->contains(variableDateTimeWithTolerance)) {
267
268 auto variableDateTimeWithTolerance = currentDateTime;
269 if (!variable->isInside(currentDateTime)) {
270 auto variableDateTime = variable->dateTime();
271 if (variable->contains(variableDateTimeWithTolerance)) {
272 qCDebug(LOG_VisualizationGraphWidget())
273 << tr("TORM: Detection zoom in that need request:");
274 // add tolerance for each side
275 tolerance
276 = toleranceFactor * (currentDateTime.m_TEnd - currentDateTime.m_TStart);
277 variableDateTimeWithTolerance.m_TStart -= tolerance;
278 variableDateTimeWithTolerance.m_TEnd += tolerance;
279 }
280 else if (variableDateTime.m_TStart < currentDateTime.m_TStart) {
281 qCInfo(LOG_VisualizationGraphWidget()) << tr("TORM: Detection pan to right:");
282
283 auto diffEndToKeepDelta = currentDateTime.m_TEnd - variableDateTime.m_TEnd;
284 currentDateTime.m_TStart = variableDateTime.m_TStart + diffEndToKeepDelta;
285 // Tolerance have to be added to the right
286 // add tolerance for right (end) side
287 tolerance
288 = toleranceFactor * (currentDateTime.m_TEnd - currentDateTime.m_TStart);
289 variableDateTimeWithTolerance.m_TEnd += tolerance;
290 }
291 else if (variableDateTime.m_TEnd > currentDateTime.m_TEnd) {
292 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: Detection pan to left: ");
293 auto diffStartToKeepDelta
294 = variableDateTime.m_TStart - currentDateTime.m_TStart;
295 currentDateTime.m_TEnd = variableDateTime.m_TEnd - diffStartToKeepDelta;
296 // Tolerance have to be added to the left
297 // add tolerance for left (start) side
298 tolerance
299 = toleranceFactor * (currentDateTime.m_TEnd - currentDateTime.m_TStart);
300 variableDateTimeWithTolerance.m_TStart -= tolerance;
301 }
302 else {
303 qCCritical(LOG_VisualizationGraphWidget())
304 << tr("Detection anormal zoom detection: ");
305 }
306 }
307 else {
308 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: Detection zoom out: ");
309 // add tolerance for each side
310 tolerance = toleranceFactor * (currentDateTime.m_TEnd - currentDateTime.m_TStart);
311 variableDateTimeWithTolerance.m_TStart -= tolerance;
312 variableDateTimeWithTolerance.m_TEnd += tolerance;
313 zoomType = VisualizationGraphWidgetZoomType::ZoomOut;
314 }
315 if (!variable->contains(dateTimeRange)) {
316 qCDebug(LOG_VisualizationGraphWidget())
317 << "TORM: Modif on variable datetime detected" << currentDateTime;
318 variable->setDateTime(currentDateTime);
319 }
320
321 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: Request data detection: ");
322 // CHangement detected, we need to ask controller to request data loading
323 emit requestDataLoading(variable, variableDateTimeWithTolerance);
243 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
244 end = impl->m_VariableToPlotMultiMap.end();
245 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
246 variableUnderGraphVector.push_back(it->first);
324 247 }
325 else {
326 qCInfo(LOG_VisualizationGraphWidget())
327 << tr("TORM: Detection zoom in that doesn't need request: ");
328 zoomType = VisualizationGraphWidgetZoomType::ZoomIn;
248 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange, oldGraphRange,
249 !impl->m_IsCalibration);
250
251 if (!impl->m_IsCalibration) {
252 qCDebug(LOG_VisualizationGraphWidget())
253 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
254 << QThread::currentThread()->objectName();
255 emit synchronize(graphRange, oldGraphRange);
329 256 }
330 257 }
331
332 if (impl->m_DoSynchronize && !impl->m_IsCalibration) {
333 auto oldDateTime = SqpRange{t2.lower, t2.upper};
334 qCDebug(LOG_VisualizationGraphWidget())
335 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
336 << QThread::currentThread()->objectName();
337 emit synchronize(dateTimeRange, oldDateTime, zoomType);
338 }
339 258 }
340 259
341 260 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
342 261 {
343 262 // Handles plot rendering when mouse is moving
344 263 impl->m_RenderingDelegate->onMouseMove(event);
345 264 }
346 265
347 266 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
348 267 {
349 268 auto zoomOrientations = QFlags<Qt::Orientation>{};
350 269
351 270 // Lambda that enables a zoom orientation if the key modifier related to this orientation
352 271 // has
353 272 // been pressed
354 273 auto enableOrientation
355 274 = [&zoomOrientations, event](const auto &orientation, const auto &modifier) {
356 275 auto orientationEnabled = event->modifiers().testFlag(modifier);
357 276 zoomOrientations.setFlag(orientation, orientationEnabled);
358 277 };
359 278 enableOrientation(Qt::Vertical, VERTICAL_ZOOM_MODIFIER);
360 279 enableOrientation(Qt::Horizontal, HORIZONTAL_ZOOM_MODIFIER);
361 280
362 281 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
363 282 }
364 283
365 284 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
366 285 {
367 286 impl->m_IsCalibration = event->modifiers().testFlag(Qt::ControlModifier);
368 287 }
369 288
370 289 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
371 290 {
372 291 impl->m_IsCalibration = false;
373 292 }
374 293
375 294 void VisualizationGraphWidget::onDataCacheVariableUpdated()
376 295 {
377 296 // NOTE:
378 297 // We don't want to call the method for each component of a variable unitarily, but for
379 298 // all
380 299 // its components at once (eg its three components in the case of a vector).
381 300
382 301 // The unordered_multimap does not do this easily, so the question is whether to:
383 302 // - use an ordered_multimap and the algos of std to group the values by key
384 303 // - use a map (unique keys) and store as values directly the list of components
385 304
386 305 auto grapheRange = ui->widget->xAxis->range();
387 306 auto dateTime = SqpRange{grapheRange.lower, grapheRange.upper};
388 307
389 308 for (auto it = impl->m_VariableToPlotMultiMap.cbegin();
390 309 it != impl->m_VariableToPlotMultiMap.cend(); ++it) {
391 310 auto variable = it->first;
392 311 qCDebug(LOG_VisualizationGraphWidget())
393 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S"
394 << variable->dateTime();
312 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
395 313 qCDebug(LOG_VisualizationGraphWidget())
396 314 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
397 if (dateTime.contains(variable->dateTime()) || dateTime.intersect(variable->dateTime())) {
315 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
398 316
399 317 VisualizationGraphHelper::updateData(QVector<QCPAbstractPlottable *>{} << it->second,
400 variable->dataSeries(), variable->dateTime());
318 variable->dataSeries(), variable->range());
401 319 }
402 320 }
403 321 }
404
405 VisualizationGraphWidgetZoomType
406 VisualizationGraphWidget::VisualizationGraphWidgetPrivate::getZoomType(const QCPRange &t1,
407 const QCPRange &t2)
408 {
409 // t1.lower <= t2.lower && t2.upper <= t1.upper
410 auto zoomType = VisualizationGraphWidgetZoomType::Unknown;
411 if (t1.lower <= t2.lower && t2.upper <= t1.upper) {
412 zoomType = VisualizationGraphWidgetZoomType::ZoomOut;
413 }
414 else if (t1.lower > t2.lower && t1.upper > t2.upper) {
415 zoomType = VisualizationGraphWidgetZoomType::PanRight;
416 }
417 else if (t1.lower < t2.lower && t1.upper < t2.upper) {
418 zoomType = VisualizationGraphWidgetZoomType::PanLeft;
419 }
420 else if (t1.lower > t2.lower && t2.upper > t1.upper) {
421 zoomType = VisualizationGraphWidgetZoomType::ZoomIn;
422 }
423 else {
424 qCCritical(LOG_VisualizationGraphWidget()) << "getZoomType: Unknown type detected";
425 }
426 return zoomType;
427 }
@@ -1,200 +1,215
1 1 #include "Visualization/VisualizationZoneWidget.h"
2 2
3 #include "Data/SqpRange.h"
4 3
5 4 #include "Visualization/IVisualizationWidgetVisitor.h"
6 5 #include "Visualization/VisualizationGraphWidget.h"
7 6 #include "ui_VisualizationZoneWidget.h"
8 7
8 #include <Data/SqpRange.h>
9 #include <Variable/VariableController.h>
9 10
11 #include <QUuid>
10 12 #include <SqpApplication.h>
11 13
12 14 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
13 15
14 16 namespace {
15 17
16 18 /// Minimum height for graph added in zones (in pixels)
17 19 const auto GRAPH_MINIMUM_HEIGHT = 300;
18 20
19 21 /// Generates a default name for a new graph, according to the number of graphs already displayed in
20 22 /// the zone
21 23 QString defaultGraphName(const QLayout &layout)
22 24 {
23 25 auto count = 0;
24 26 for (auto i = 0; i < layout.count(); ++i) {
25 27 if (dynamic_cast<VisualizationGraphWidget *>(layout.itemAt(i)->widget())) {
26 28 count++;
27 29 }
28 30 }
29 31
30 32 return QObject::tr("Graph %1").arg(count + 1);
31 33 }
32 34
33 35 } // namespace
34 36
37 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate {
38
39 explicit VisualizationZoneWidgetPrivate() : m_SynchronisationGroupId{QUuid::createUuid()} {}
40 QUuid m_SynchronisationGroupId;
41 };
42
35 43 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
36 : QWidget{parent}, ui{new Ui::VisualizationZoneWidget}
44 : QWidget{parent},
45 ui{new Ui::VisualizationZoneWidget},
46 impl{spimpl::make_unique_impl<VisualizationZoneWidgetPrivate>()}
37 47 {
38 48 ui->setupUi(this);
39 49
40 50 ui->zoneNameLabel->setText(name);
41 51
42 52 // 'Close' options : widget is deleted when closed
43 53 setAttribute(Qt::WA_DeleteOnClose);
44 54 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
45 55 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
56
57 // Synchronisation id
58 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronizationGroupId",
59 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
46 60 }
47 61
48 62 VisualizationZoneWidget::~VisualizationZoneWidget()
49 63 {
50 64 delete ui;
51 65 }
52 66
53 67 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
54 68 {
55 69 ui->visualizationZoneFrame->layout()->addWidget(graphWidget);
56 70 }
57 71
58 72 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
59 73 {
60 74 auto graphWidget = new VisualizationGraphWidget{
61 75 defaultGraphName(*ui->visualizationZoneFrame->layout()), this};
62 76
63 77
64 78 // Set graph properties
65 79 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
66 80 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
67 81
68 82 this->addGraph(graphWidget);
69 83
70 84 graphWidget->addVariable(variable);
71 85
72 86 // Lambda to synchronize zone widget
73 auto synchronizeZoneWidget = [this, graphWidget](const SqpRange &dateTime,
74 const SqpRange &oldDateTime,
75 VisualizationGraphWidgetZoomType zoomType) {
87 auto synchronizeZoneWidget = [this, graphWidget](const SqpRange &grapheRange,
88 const SqpRange &oldGraphRange) {
89
90 auto zoomType = VariableController::getZoomType(grapheRange, oldGraphRange);
76 91 auto frameLayout = ui->visualizationZoneFrame->layout();
77 92 for (auto i = 0; i < frameLayout->count(); ++i) {
78 93 auto graphChild
79 94 = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
80 95 if (graphChild && (graphChild != graphWidget)) {
81 96
82 97 auto graphChildRange = graphChild->graphRange();
83 98 switch (zoomType) {
84 case VisualizationGraphWidgetZoomType::ZoomIn: {
85 auto deltaLeft = dateTime.m_TStart - oldDateTime.m_TStart;
86 auto deltaRight = oldDateTime.m_TEnd - dateTime.m_TEnd;
99 case AcquisitionZoomType::ZoomIn: {
100 auto deltaLeft = grapheRange.m_TStart - oldGraphRange.m_TStart;
101 auto deltaRight = oldGraphRange.m_TEnd - grapheRange.m_TEnd;
87 102 graphChildRange.m_TStart += deltaLeft;
88 103 graphChildRange.m_TEnd -= deltaRight;
89 104 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomIn");
90 105 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
91 106 << deltaLeft;
92 107 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
93 108 << deltaRight;
94 109 qCCritical(LOG_VisualizationZoneWidget())
95 << tr("TORM: dt") << dateTime.m_TEnd - dateTime.m_TStart;
110 << tr("TORM: dt") << grapheRange.m_TEnd - grapheRange.m_TStart;
96 111
97 112 break;
98 113 }
99 114
100 case VisualizationGraphWidgetZoomType::ZoomOut: {
115 case AcquisitionZoomType::ZoomOut: {
101 116 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomOut");
102 auto deltaLeft = oldDateTime.m_TStart - dateTime.m_TStart;
103 auto deltaRight = dateTime.m_TEnd - oldDateTime.m_TEnd;
117 auto deltaLeft = oldGraphRange.m_TStart - grapheRange.m_TStart;
118 auto deltaRight = grapheRange.m_TEnd - oldGraphRange.m_TEnd;
104 119 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
105 120 << deltaLeft;
106 121 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
107 122 << deltaRight;
108 123 qCCritical(LOG_VisualizationZoneWidget())
109 << tr("TORM: dt") << dateTime.m_TEnd - dateTime.m_TStart;
124 << tr("TORM: dt") << grapheRange.m_TEnd - grapheRange.m_TStart;
110 125 graphChildRange.m_TStart -= deltaLeft;
111 126 graphChildRange.m_TEnd += deltaRight;
112 127 break;
113 128 }
114 case VisualizationGraphWidgetZoomType::PanRight: {
129 case AcquisitionZoomType::PanRight: {
115 130 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: PanRight");
116 auto deltaRight = dateTime.m_TEnd - oldDateTime.m_TEnd;
131 auto deltaRight = grapheRange.m_TEnd - oldGraphRange.m_TEnd;
117 132 graphChildRange.m_TStart += deltaRight;
118 133 graphChildRange.m_TEnd += deltaRight;
119 134 qCCritical(LOG_VisualizationZoneWidget())
120 << tr("TORM: dt") << dateTime.m_TEnd - dateTime.m_TStart;
135 << tr("TORM: dt") << grapheRange.m_TEnd - grapheRange.m_TStart;
121 136 break;
122 137 }
123 case VisualizationGraphWidgetZoomType::PanLeft: {
138 case AcquisitionZoomType::PanLeft: {
124 139 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: PanLeft");
125 auto deltaLeft = oldDateTime.m_TStart - dateTime.m_TStart;
140 auto deltaLeft = oldGraphRange.m_TStart - grapheRange.m_TStart;
126 141 graphChildRange.m_TStart -= deltaLeft;
127 142 graphChildRange.m_TEnd -= deltaLeft;
128 143 break;
129 144 }
130 case VisualizationGraphWidgetZoomType::Unknown: {
145 case AcquisitionZoomType::Unknown: {
131 146 qCCritical(LOG_VisualizationZoneWidget())
132 147 << tr("Impossible to synchronize: zoom type unknown");
133 148 break;
134 149 }
135 150 default:
136 151 qCCritical(LOG_VisualizationZoneWidget())
137 152 << tr("Impossible to synchronize: zoom type not take into account");
138 153 // No action
139 154 break;
140 155 }
141 graphChild->enableSynchronize(false);
156 graphChild->enableAcquisition(false);
142 157 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: Range before: ")
143 158 << graphChild->graphRange();
144 159 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: Range after : ")
145 160 << graphChildRange;
146 161 qCCritical(LOG_VisualizationZoneWidget())
147 162 << tr("TORM: child dt") << graphChildRange.m_TEnd - graphChildRange.m_TStart;
148 163 graphChild->setGraphRange(graphChildRange);
149 graphChild->enableSynchronize(true);
164 graphChild->enableAcquisition(true);
150 165 }
151 166 }
152 167 };
153 168
154 169 // connection for synchronization
155 170 connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
156 171
157 172 return graphWidget;
158 173 }
159 174
160 175 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
161 176 {
162 177 if (visitor) {
163 178 visitor->visitEnter(this);
164 179
165 180 // Apply visitor to graph children
166 181 auto layout = ui->visualizationZoneFrame->layout();
167 182 for (auto i = 0; i < layout->count(); ++i) {
168 183 if (auto item = layout->itemAt(i)) {
169 184 // Widgets different from graphs are not visited (no action)
170 185 if (auto visualizationGraphWidget
171 186 = dynamic_cast<VisualizationGraphWidget *>(item->widget())) {
172 187 visualizationGraphWidget->accept(visitor);
173 188 }
174 189 }
175 190 }
176 191
177 192 visitor->visitLeave(this);
178 193 }
179 194 else {
180 195 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
181 196 }
182 197 }
183 198
184 199 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
185 200 {
186 201 // A tab can always accomodate a variable
187 202 Q_UNUSED(variable);
188 203 return true;
189 204 }
190 205
191 206 bool VisualizationZoneWidget::contains(const Variable &variable) const
192 207 {
193 208 Q_UNUSED(variable);
194 209 return false;
195 210 }
196 211
197 212 QString VisualizationZoneWidget::name() const
198 213 {
199 214 return ui->zoneNameLabel->text();
200 215 }
@@ -1,30 +1,30
1 1 #ifndef SCIQLOP_AMDAPROVIDER_H
2 2 #define SCIQLOP_AMDAPROVIDER_H
3 3
4 4 #include "AmdaGlobal.h"
5 5
6 6 #include <Data/IDataProvider.h>
7 7
8 8 #include <QLoggingCategory>
9 9
10 10
11 11 Q_DECLARE_LOGGING_CATEGORY(LOG_AmdaProvider)
12 12
13 13 class QNetworkReply;
14 14
15 15 /**
16 16 * @brief The AmdaProvider class is an example of how a data provider can generate data
17 17 */
18 18 class SCIQLOP_AMDA_EXPORT AmdaProvider : public IDataProvider {
19 19 public:
20 20 explicit AmdaProvider();
21 21
22 void requestDataLoading(QUuid token, const DataProviderParameters &parameters) override;
22 void requestDataLoading(QUuid acqIdentifier, const DataProviderParameters &parameters) override;
23 23
24 void requestDataAborting(QUuid identifier) override;
24 void requestDataAborting(QUuid acqIdentifier) override;
25 25
26 26 private:
27 27 void retrieveData(QUuid token, const SqpRange &dateTime, const QVariantHash &data);
28 28 };
29 29
30 30 #endif // SCIQLOP_AMDAPROVIDER_H
@@ -1,147 +1,147
1 1 #include "AmdaProvider.h"
2 2 #include "AmdaDefs.h"
3 3 #include "AmdaResultParser.h"
4 4
5 5 #include <Common/DateUtils.h>
6 6 #include <Data/DataProviderParameters.h>
7 7 #include <Network/NetworkController.h>
8 8 #include <SqpApplication.h>
9 9 #include <Variable/Variable.h>
10 10
11 11 #include <QNetworkAccessManager>
12 12 #include <QNetworkReply>
13 13 #include <QTemporaryFile>
14 14 #include <QThread>
15 15
16 16 Q_LOGGING_CATEGORY(LOG_AmdaProvider, "AmdaProvider")
17 17
18 18 namespace {
19 19
20 20 /// URL format for a request on AMDA server. The parameters are as follows:
21 21 /// - %1: start date
22 22 /// - %2: end date
23 23 /// - %3: parameter id
24 24 const auto AMDA_URL_FORMAT = QStringLiteral(
25 25 "http://amda.irap.omp.eu/php/rest/"
26 26 "getParameter.php?startTime=%1&stopTime=%2&parameterID=%3&outputFormat=ASCII&"
27 27 "timeFormat=ISO8601&gzip=0");
28 28
29 29 /// Dates format passed in the URL (e.g 2013-09-23T09:00)
30 30 const auto AMDA_TIME_FORMAT = QStringLiteral("yyyy-MM-ddThh:mm:ss");
31 31
32 32 /// Formats a time to a date that can be passed in URL
33 33 QString dateFormat(double sqpRange) noexcept
34 34 {
35 35 auto dateTime = DateUtils::dateTime(sqpRange);
36 36 return dateTime.toString(AMDA_TIME_FORMAT);
37 37 }
38 38
39 39 } // namespace
40 40
41 41 AmdaProvider::AmdaProvider()
42 42 {
43 43 qCDebug(LOG_AmdaProvider()) << tr("AmdaProvider::AmdaProvider") << QThread::currentThread();
44 44 if (auto app = sqpApp) {
45 45 auto &networkController = app->networkController();
46 46 connect(this, SIGNAL(requestConstructed(QNetworkRequest, QUuid,
47 47 std::function<void(QNetworkReply *, QUuid)>)),
48 48 &networkController,
49 49 SLOT(onProcessRequested(QNetworkRequest, QUuid,
50 50 std::function<void(QNetworkReply *, QUuid)>)));
51 51
52 52
53 53 connect(&sqpApp->networkController(), SIGNAL(replyDownloadProgress(QUuid, double)), this,
54 54 SIGNAL(dataProvidedProgress(QUuid, double)));
55 55 }
56 56 }
57 57
58 void AmdaProvider::requestDataLoading(QUuid token, const DataProviderParameters &parameters)
58 void AmdaProvider::requestDataLoading(QUuid acqIdentifier, const DataProviderParameters &parameters)
59 59 {
60 60 // NOTE: Try to use multithread if possible
61 61 const auto times = parameters.m_Times;
62 62 const auto data = parameters.m_Data;
63 63 for (const auto &dateTime : qAsConst(times)) {
64 retrieveData(token, dateTime, data);
64 retrieveData(acqIdentifier, dateTime, data);
65 65 }
66 66 }
67 67
68 void AmdaProvider::requestDataAborting(QUuid identifier)
68 void AmdaProvider::requestDataAborting(QUuid acqIdentifier)
69 69 {
70 70 if (auto app = sqpApp) {
71 71 auto &networkController = app->networkController();
72 networkController.onReplyCanceled(identifier);
72 networkController.onReplyCanceled(acqIdentifier);
73 73 }
74 74 }
75 75
76 76 void AmdaProvider::retrieveData(QUuid token, const SqpRange &dateTime, const QVariantHash &data)
77 77 {
78 78 // Retrieves product ID from data: if the value is invalid, no request is made
79 79 auto productId = data.value(AMDA_XML_ID_KEY).toString();
80 80 if (productId.isNull()) {
81 81 qCCritical(LOG_AmdaProvider()) << tr("Can't retrieve data: unknown product id");
82 82 return;
83 83 }
84 qCInfo(LOG_AmdaProvider()) << tr("AmdaProvider::retrieveData") << dateTime;
84 qCDebug(LOG_AmdaProvider()) << tr("AmdaProvider::retrieveData") << dateTime;
85 85
86 86 // /////////// //
87 87 // Creates URL //
88 88 // /////////// //
89 89
90 90 auto startDate = dateFormat(dateTime.m_TStart);
91 91 auto endDate = dateFormat(dateTime.m_TEnd);
92 92
93 93 auto url = QUrl{QString{AMDA_URL_FORMAT}.arg(startDate, endDate, productId)};
94 94 qCInfo(LOG_AmdaProvider()) << tr("AmdaProvider::retrieveData url:") << url;
95 95 auto tempFile = std::make_shared<QTemporaryFile>();
96 96
97 97 // LAMBDA
98 98 auto httpDownloadFinished
99 99 = [this, dateTime, tempFile](QNetworkReply *reply, QUuid dataId) noexcept {
100 100
101 101 // Don't do anything if the reply was abort
102 102 if (reply->error() != QNetworkReply::OperationCanceledError) {
103 103
104 104 if (tempFile) {
105 105 auto replyReadAll = reply->readAll();
106 106 if (!replyReadAll.isEmpty()) {
107 107 tempFile->write(replyReadAll);
108 108 }
109 109 tempFile->close();
110 110
111 111 // Parse results file
112 112 if (auto dataSeries = AmdaResultParser::readTxt(tempFile->fileName())) {
113 113 emit dataProvided(dataId, dataSeries, dateTime);
114 114 }
115 115 else {
116 116 /// @todo ALX : debug
117 117 }
118 118 }
119 119 }
120 120
121 121 };
122 122 auto httpFinishedLambda
123 123 = [this, httpDownloadFinished, tempFile](QNetworkReply *reply, QUuid dataId) noexcept {
124 124
125 125 // Don't do anything if the reply was abort
126 126 if (reply->error() != QNetworkReply::OperationCanceledError) {
127 127 auto downloadFileUrl = QUrl{QString{reply->readAll()}};
128 128
129 129
130 130 qCInfo(LOG_AmdaProvider()) << tr("AmdaProvider::retrieveData downloadFileUrl:")
131 131 << downloadFileUrl;
132 132 // Executes request for downloading file //
133 133
134 134 // Creates destination file
135 135 if (tempFile->open()) {
136 136 // Executes request
137 137 emit requestConstructed(QNetworkRequest{downloadFileUrl}, dataId,
138 138 httpDownloadFinished);
139 139 }
140 140 }
141 141 };
142 142
143 143 // //////////////// //
144 144 // Executes request //
145 145 // //////////////// //
146 146 emit requestConstructed(QNetworkRequest{url}, token, httpFinishedLambda);
147 147 }
@@ -1,33 +1,34
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 #include <QUuid>
10 10
11 11 #include <QHash>
12 12 Q_DECLARE_LOGGING_CATEGORY(LOG_CosinusProvider)
13 13
14 14 /**
15 15 * @brief The CosinusProvider class is an example of how a data provider can generate data
16 16 */
17 17 class SCIQLOP_MOCKPLUGIN_EXPORT CosinusProvider : public IDataProvider {
18 18 public:
19 19 /// @sa IDataProvider::requestDataLoading(). The current impl isn't thread safe.
20 void requestDataLoading(QUuid token, const DataProviderParameters &parameters) override;
20 void requestDataLoading(QUuid acqIdentifier, const DataProviderParameters &parameters) override;
21 21
22 22
23 23 /// @sa IDataProvider::requestDataAborting(). The current impl isn't thread safe.
24 void requestDataAborting(QUuid identifier) override;
24 void requestDataAborting(QUuid acqIdentifier) override;
25 25
26 26
27 27 private:
28 std::shared_ptr<IDataSeries> retrieveData(QUuid token, const SqpRange &dateTime);
28 std::shared_ptr<IDataSeries> retrieveData(QUuid acqIdentifier,
29 const SqpRange &dataRangeRequested);
29 30
30 31 QHash<QUuid, bool> m_VariableToEnableProvider;
31 32 };
32 33
33 34 #endif // SCIQLOP_COSINUSPROVIDER_H
@@ -1,100 +1,102
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 <QFuture>
9 9 #include <QThread>
10 10 #include <QtConcurrent/QtConcurrent>
11 11
12 12 Q_LOGGING_CATEGORY(LOG_CosinusProvider, "CosinusProvider")
13 13
14 std::shared_ptr<IDataSeries> CosinusProvider::retrieveData(QUuid token, const SqpRange &dateTime)
14 std::shared_ptr<IDataSeries> CosinusProvider::retrieveData(QUuid acqIdentifier,
15 const SqpRange &dataRangeRequested)
15 16 {
16 17 // TODO: Add Mutex
17 18 auto dataIndex = 0;
18 19
19 20 // Gets the timerange from the parameters
20 21 double freq = 100.0;
21 double start = std::ceil(dateTime.m_TStart * freq); // 100 htz
22 double end = std::floor(dateTime.m_TEnd * freq); // 100 htz
22 double start = std::ceil(dataRangeRequested.m_TStart * freq); // 100 htz
23 double end = std::floor(dataRangeRequested.m_TEnd * freq); // 100 htz
23 24
24 25 // We assure that timerange is valid
25 26 if (end < start) {
26 27 std::swap(start, end);
27 28 }
28 29
29 30 // Generates scalar series containing cosinus values (one value per second)
30 31 auto dataCount = end - start;
31 32
32 33 auto xAxisData = QVector<double>{};
33 34 xAxisData.resize(dataCount);
34 35
35 36 auto valuesData = QVector<double>{};
36 37 valuesData.resize(dataCount);
37 38
38 39 int progress = 0;
39 40 auto progressEnd = dataCount;
40 41 for (auto time = start; time < end; ++time, ++dataIndex) {
41 auto it = m_VariableToEnableProvider.find(token);
42 auto it = m_VariableToEnableProvider.find(acqIdentifier);
42 43 if (it != m_VariableToEnableProvider.end() && it.value()) {
43 44 const auto timeOnFreq = time / freq;
44 45
45 46 xAxisData.replace(dataIndex, timeOnFreq);
46 47 valuesData.replace(dataIndex, std::cos(timeOnFreq));
47 48
48 49 // progression
49 50 int currentProgress = (time - start) * 100.0 / progressEnd;
50 51 if (currentProgress != progress) {
51 52 progress = currentProgress;
52 53
53 emit dataProvidedProgress(token, progress);
54 emit dataProvidedProgress(acqIdentifier, progress);
54 55 }
55 56 }
56 57 else {
57 58 if (!it.value()) {
58 59 qCDebug(LOG_CosinusProvider())
59 60 << "CosinusProvider::retrieveData: ARRET De l'acquisition detectΓ©"
60 61 << end - time;
61 62 }
62 63 }
63 64 }
64 emit dataProvidedProgress(token, 0.0);
65 emit dataProvidedProgress(acqIdentifier, 0.0);
65 66
66 67 return std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData),
67 68 Unit{QStringLiteral("t"), true}, Unit{});
68 69 }
69 70
70 void CosinusProvider::requestDataLoading(QUuid token, const DataProviderParameters &parameters)
71 void CosinusProvider::requestDataLoading(QUuid acqIdentifier,
72 const DataProviderParameters &parameters)
71 73 {
72 74 // TODO: Add Mutex
73 m_VariableToEnableProvider[token] = true;
75 m_VariableToEnableProvider[acqIdentifier] = true;
74 76 qCDebug(LOG_CosinusProvider()) << "CosinusProvider::requestDataLoading"
75 77 << QThread::currentThread()->objectName();
76 78 // NOTE: Try to use multithread if possible
77 79 const auto times = parameters.m_Times;
78 80
79 81 for (const auto &dateTime : qAsConst(times)) {
80 if (m_VariableToEnableProvider[token]) {
81 auto scalarSeries = this->retrieveData(token, dateTime);
82 emit dataProvided(token, scalarSeries, dateTime);
82 if (m_VariableToEnableProvider[acqIdentifier]) {
83 auto scalarSeries = this->retrieveData(acqIdentifier, dateTime);
84 emit dataProvided(acqIdentifier, scalarSeries, dateTime);
83 85 }
84 86 }
85 87 }
86 88
87 void CosinusProvider::requestDataAborting(QUuid identifier)
89 void CosinusProvider::requestDataAborting(QUuid acqIdentifier)
88 90 {
89 91 // TODO: Add Mutex
90 qCDebug(LOG_CosinusProvider()) << "CosinusProvider::requestDataAborting" << identifier
92 qCDebug(LOG_CosinusProvider()) << "CosinusProvider::requestDataAborting" << acqIdentifier
91 93 << QThread::currentThread()->objectName();
92 auto it = m_VariableToEnableProvider.find(identifier);
94 auto it = m_VariableToEnableProvider.find(acqIdentifier);
93 95 if (it != m_VariableToEnableProvider.end()) {
94 96 it.value() = false;
95 97 }
96 98 else {
97 99 qCWarning(LOG_CosinusProvider())
98 100 << tr("Aborting progression of inexistant identifier detected !!!");
99 101 }
100 102 }
General Comments 0
You need to be logged in to leave comments. Login now