##// END OF EJS Templates
Merge branch 'feature/DisplayDataBeforeAcquisition' into develop
perrinel -
r574:23422057e407 merge
parent child
Show More
@@ -1,65 +1,66
1 #ifndef SCIQLOP_VARIABLE_H
1 #ifndef SCIQLOP_VARIABLE_H
2 #define SCIQLOP_VARIABLE_H
2 #define SCIQLOP_VARIABLE_H
3
3
4 #include "CoreGlobal.h"
4 #include "CoreGlobal.h"
5
5
6 #include <Data/SqpRange.h>
6 #include <Data/SqpRange.h>
7
7
8 #include <QLoggingCategory>
8 #include <QLoggingCategory>
9 #include <QObject>
9 #include <QObject>
10
10
11 #include <Common/MetaTypes.h>
11 #include <Common/MetaTypes.h>
12 #include <Common/spimpl.h>
12 #include <Common/spimpl.h>
13
13
14 Q_DECLARE_LOGGING_CATEGORY(LOG_Variable)
14 Q_DECLARE_LOGGING_CATEGORY(LOG_Variable)
15
15
16 class IDataSeries;
16 class IDataSeries;
17 class QString;
17 class QString;
18
18
19 /**
19 /**
20 * @brief The Variable class represents a variable in SciQlop.
20 * @brief The Variable class represents a variable in SciQlop.
21 */
21 */
22 class SCIQLOP_CORE_EXPORT Variable : public QObject {
22 class SCIQLOP_CORE_EXPORT Variable : public QObject {
23
23
24 Q_OBJECT
24 Q_OBJECT
25
25
26 public:
26 public:
27 explicit Variable(const QString &name, const SqpRange &dateTime,
27 explicit Variable(const QString &name, const SqpRange &dateTime,
28 const QVariantHash &metadata = {});
28 const QVariantHash &metadata = {});
29
29
30 QString name() const noexcept;
30 QString name() const noexcept;
31 SqpRange range() const noexcept;
31 SqpRange range() const noexcept;
32 void setRange(const SqpRange &range) noexcept;
32 void setRange(const SqpRange &range) noexcept;
33 SqpRange cacheRange() const noexcept;
33 SqpRange cacheRange() const noexcept;
34 void setCacheRange(const SqpRange &cacheRange) noexcept;
34 void setCacheRange(const SqpRange &cacheRange) noexcept;
35
35
36 /// @return the data of the variable, nullptr if there is no data
36 /// @return the data of the variable, nullptr if there is no data
37 std::shared_ptr<IDataSeries> dataSeries() const noexcept;
37 std::shared_ptr<IDataSeries> dataSeries() const noexcept;
38
38
39 QVariantHash metadata() const noexcept;
39 QVariantHash metadata() const noexcept;
40
40
41 bool contains(const SqpRange &range) const noexcept;
41 bool contains(const SqpRange &range) const noexcept;
42 bool intersect(const SqpRange &range) const noexcept;
42 bool intersect(const SqpRange &range) const noexcept;
43 bool isInside(const SqpRange &range) const noexcept;
43 bool isInside(const SqpRange &range) const noexcept;
44
44
45 bool cacheContains(const SqpRange &range) const noexcept;
45 bool cacheContains(const SqpRange &range) const noexcept;
46 bool cacheIntersect(const SqpRange &range) const noexcept;
46 bool cacheIntersect(const SqpRange &range) const noexcept;
47 bool cacheIsInside(const SqpRange &range) const noexcept;
47 bool cacheIsInside(const SqpRange &range) const noexcept;
48
48
49 QVector<SqpRange> provideNotInCacheRangeList(const SqpRange &range) const noexcept;
49 QVector<SqpRange> provideNotInCacheRangeList(const SqpRange &range) const noexcept;
50 QVector<SqpRange> provideInCacheRangeList(const SqpRange &range) const noexcept;
50 void setDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept;
51 void setDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept;
51 void mergeDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept;
52 void mergeDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept;
52
53
53 signals:
54 signals:
54 void updated();
55 void updated();
55
56
56 private:
57 private:
57 class VariablePrivate;
58 class VariablePrivate;
58 spimpl::unique_impl_ptr<VariablePrivate> impl;
59 spimpl::unique_impl_ptr<VariablePrivate> impl;
59 };
60 };
60
61
61 // Required for using shared_ptr in signals/slots
62 // Required for using shared_ptr in signals/slots
62 SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_REGISTRY, std::shared_ptr<Variable>)
63 SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_REGISTRY, std::shared_ptr<Variable>)
63 SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_VECTOR_REGISTRY, QVector<std::shared_ptr<Variable> >)
64 SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_VECTOR_REGISTRY, QVector<std::shared_ptr<Variable> >)
64
65
65 #endif // SCIQLOP_VARIABLE_H
66 #endif // SCIQLOP_VARIABLE_H
@@ -1,117 +1,120
1 #ifndef SCIQLOP_VARIABLECONTROLLER_H
1 #ifndef SCIQLOP_VARIABLECONTROLLER_H
2 #define SCIQLOP_VARIABLECONTROLLER_H
2 #define SCIQLOP_VARIABLECONTROLLER_H
3
3
4 #include "CoreGlobal.h"
4 #include "CoreGlobal.h"
5
5
6 #include <Data/AcquisitionDataPacket.h>
6 #include <Data/AcquisitionDataPacket.h>
7 #include <Data/SqpRange.h>
7 #include <Data/SqpRange.h>
8
8
9 #include <QLoggingCategory>
9 #include <QLoggingCategory>
10 #include <QObject>
10 #include <QObject>
11
11
12 #include <Common/spimpl.h>
12 #include <Common/spimpl.h>
13
13
14 class IDataProvider;
14 class IDataProvider;
15 class QItemSelectionModel;
15 class QItemSelectionModel;
16 class TimeController;
16 class TimeController;
17 class Variable;
17 class Variable;
18 class VariableModel;
18 class VariableModel;
19
19
20 Q_DECLARE_LOGGING_CATEGORY(LOG_VariableController)
20 Q_DECLARE_LOGGING_CATEGORY(LOG_VariableController)
21
21
22
22
23 /**
23 /**
24 * Possible types of zoom operation
24 * Possible types of zoom operation
25 */
25 */
26 enum class AcquisitionZoomType { ZoomOut, ZoomIn, PanRight, PanLeft, Unknown };
26 enum class AcquisitionZoomType { ZoomOut, ZoomIn, PanRight, PanLeft, Unknown };
27
27
28
28
29 /**
29 /**
30 * @brief The VariableController class aims to handle the variables in SciQlop.
30 * @brief The VariableController class aims to handle the variables in SciQlop.
31 */
31 */
32 class SCIQLOP_CORE_EXPORT VariableController : public QObject {
32 class SCIQLOP_CORE_EXPORT VariableController : public QObject {
33 Q_OBJECT
33 Q_OBJECT
34 public:
34 public:
35 explicit VariableController(QObject *parent = 0);
35 explicit VariableController(QObject *parent = 0);
36 virtual ~VariableController();
36 virtual ~VariableController();
37
37
38 VariableModel *variableModel() noexcept;
38 VariableModel *variableModel() noexcept;
39 QItemSelectionModel *variableSelectionModel() noexcept;
39 QItemSelectionModel *variableSelectionModel() noexcept;
40
40
41 void setTimeController(TimeController *timeController) noexcept;
41 void setTimeController(TimeController *timeController) noexcept;
42
42
43 /**
43 /**
44 * Deletes from the controller the variable passed in parameter.
44 * Deletes from the controller the variable passed in parameter.
45 *
45 *
46 * Delete a variable includes:
46 * Delete a variable includes:
47 * - the deletion of the various references to the variable in SciQlop
47 * - the deletion of the various references to the variable in SciQlop
48 * - the deletion of the model variable
48 * - the deletion of the model variable
49 * - the deletion of the provider associated with the variable
49 * - the deletion of the provider associated with the variable
50 * - removing the cache associated with the variable
50 * - removing the cache associated with the variable
51 *
51 *
52 * @param variable the variable to delete from the controller.
52 * @param variable the variable to delete from the controller.
53 */
53 */
54 void deleteVariable(std::shared_ptr<Variable> variable) noexcept;
54 void deleteVariable(std::shared_ptr<Variable> variable) noexcept;
55
55
56 /**
56 /**
57 * Deletes from the controller the variables passed in parameter.
57 * Deletes from the controller the variables passed in parameter.
58 * @param variables the variables to delete from the controller.
58 * @param variables the variables to delete from the controller.
59 * @sa deleteVariable()
59 * @sa deleteVariable()
60 */
60 */
61 void deleteVariables(const QVector<std::shared_ptr<Variable> > &variables) noexcept;
61 void deleteVariables(const QVector<std::shared_ptr<Variable> > &variables) noexcept;
62
62
63 /**
63 /**
64 * @brief abort the variable retrieve data progression
64 * @brief abort the variable retrieve data progression
65 */
65 */
66 void abortProgress(std::shared_ptr<Variable> variable);
66 void abortProgress(std::shared_ptr<Variable> variable);
67
67
68 static AcquisitionZoomType getZoomType(const SqpRange &range, const SqpRange &oldRange);
68 static AcquisitionZoomType getZoomType(const SqpRange &range, const SqpRange &oldRange);
69 signals:
69 signals:
70 /// Signal emitted when a variable is about to be deleted from the controller
70 /// Signal emitted when a variable is about to be deleted from the controller
71 void variableAboutToBeDeleted(std::shared_ptr<Variable> variable);
71 void variableAboutToBeDeleted(std::shared_ptr<Variable> variable);
72
72
73 /// Signal emitted when a data acquisition is requested on a range for a variable
73 /// Signal emitted when a data acquisition is requested on a range for a variable
74 void rangeChanged(std::shared_ptr<Variable> variable, const SqpRange &range);
74 void rangeChanged(std::shared_ptr<Variable> variable, const SqpRange &range);
75
75
76 /// Signal emitted when a sub range of the cacheRange of the variable can be displayed
77 void updateVarDisplaying(std::shared_ptr<Variable> variable, const SqpRange &range);
78
76 public slots:
79 public slots:
77 /// Request the data loading of the variable whithin range
80 /// Request the data loading of the variable whithin range
78 void onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables, const SqpRange &range,
81 void onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables, const SqpRange &range,
79 const SqpRange &oldRange, bool synchronise);
82 const SqpRange &oldRange, bool synchronise);
80 /**
83 /**
81 * Creates a new variable and adds it to the model
84 * Creates a new variable and adds it to the model
82 * @param name the name of the new variable
85 * @param name the name of the new variable
83 * @param metadata the metadata of the new variable
86 * @param metadata the metadata of the new variable
84 * @param provider the data provider for the new variable
87 * @param provider the data provider for the new variable
85 */
88 */
86 void createVariable(const QString &name, const QVariantHash &metadata,
89 void createVariable(const QString &name, const QVariantHash &metadata,
87 std::shared_ptr<IDataProvider> provider) noexcept;
90 std::shared_ptr<IDataProvider> provider) noexcept;
88
91
89 /// Update the temporal parameters of every selected variable to dateTime
92 /// Update the temporal parameters of every selected variable to dateTime
90 void onDateTimeOnSelection(const SqpRange &dateTime);
93 void onDateTimeOnSelection(const SqpRange &dateTime);
91
94
92
95
93 void onDataProvided(QUuid vIdentifier, const SqpRange &rangeRequested,
96 void onDataProvided(QUuid vIdentifier, const SqpRange &rangeRequested,
94 const SqpRange &cacheRangeRequested,
97 const SqpRange &cacheRangeRequested,
95 QVector<AcquisitionDataPacket> dataAcquired);
98 QVector<AcquisitionDataPacket> dataAcquired);
96
99
97 void onVariableRetrieveDataInProgress(QUuid identifier, double progress);
100 void onVariableRetrieveDataInProgress(QUuid identifier, double progress);
98
101
99 /// Cancel the current request for the variable
102 /// Cancel the current request for the variable
100 void onAbortProgressRequested(std::shared_ptr<Variable> variable);
103 void onAbortProgressRequested(std::shared_ptr<Variable> variable);
101
104
102 /// synchronization group methods
105 /// synchronization group methods
103 void onAddSynchronizationGroupId(QUuid synchronizationGroupId);
106 void onAddSynchronizationGroupId(QUuid synchronizationGroupId);
104 void onRemoveSynchronizationGroupId(QUuid synchronizationGroupId);
107 void onRemoveSynchronizationGroupId(QUuid synchronizationGroupId);
105 void onAddSynchronized(std::shared_ptr<Variable> variable, QUuid synchronizationGroupId);
108 void onAddSynchronized(std::shared_ptr<Variable> variable, QUuid synchronizationGroupId);
106
109
107 void initialize();
110 void initialize();
108 void finalize();
111 void finalize();
109
112
110 private:
113 private:
111 void waitForFinish();
114 void waitForFinish();
112
115
113 class VariableControllerPrivate;
116 class VariableControllerPrivate;
114 spimpl::unique_impl_ptr<VariableControllerPrivate> impl;
117 spimpl::unique_impl_ptr<VariableControllerPrivate> impl;
115 };
118 };
116
119
117 #endif // SCIQLOP_VARIABLECONTROLLER_H
120 #endif // SCIQLOP_VARIABLECONTROLLER_H
@@ -1,211 +1,243
1 #include "Variable/Variable.h"
1 #include "Variable/Variable.h"
2
2
3 #include <Data/IDataSeries.h>
3 #include <Data/IDataSeries.h>
4 #include <Data/SqpRange.h>
4 #include <Data/SqpRange.h>
5
5
6 #include <QMutex>
6 #include <QMutex>
7 #include <QReadWriteLock>
7 #include <QReadWriteLock>
8 #include <QThread>
8 #include <QThread>
9
9
10 Q_LOGGING_CATEGORY(LOG_Variable, "Variable")
10 Q_LOGGING_CATEGORY(LOG_Variable, "Variable")
11
11
12 struct Variable::VariablePrivate {
12 struct Variable::VariablePrivate {
13 explicit VariablePrivate(const QString &name, const SqpRange &dateTime,
13 explicit VariablePrivate(const QString &name, const SqpRange &dateTime,
14 const QVariantHash &metadata)
14 const QVariantHash &metadata)
15 : m_Name{name}, m_Range{dateTime}, m_Metadata{metadata}, m_DataSeries{nullptr}
15 : m_Name{name}, m_Range{dateTime}, m_Metadata{metadata}, m_DataSeries{nullptr}
16 {
16 {
17 }
17 }
18
18
19 void lockRead() { m_Lock.lockForRead(); }
19 void lockRead() { m_Lock.lockForRead(); }
20 void lockWrite() { m_Lock.lockForWrite(); }
20 void lockWrite() { m_Lock.lockForWrite(); }
21 void unlock() { m_Lock.unlock(); }
21 void unlock() { m_Lock.unlock(); }
22
22
23 QString m_Name;
23 QString m_Name;
24
24
25 SqpRange m_Range;
25 SqpRange m_Range;
26 SqpRange m_CacheRange;
26 SqpRange m_CacheRange;
27 QVariantHash m_Metadata;
27 QVariantHash m_Metadata;
28 std::shared_ptr<IDataSeries> m_DataSeries;
28 std::shared_ptr<IDataSeries> m_DataSeries;
29
29
30 QReadWriteLock m_Lock;
30 QReadWriteLock m_Lock;
31 };
31 };
32
32
33 Variable::Variable(const QString &name, const SqpRange &dateTime, const QVariantHash &metadata)
33 Variable::Variable(const QString &name, const SqpRange &dateTime, const QVariantHash &metadata)
34 : impl{spimpl::make_unique_impl<VariablePrivate>(name, dateTime, metadata)}
34 : impl{spimpl::make_unique_impl<VariablePrivate>(name, dateTime, metadata)}
35 {
35 {
36 }
36 }
37
37
38 QString Variable::name() const noexcept
38 QString Variable::name() const noexcept
39 {
39 {
40 impl->lockRead();
40 impl->lockRead();
41 auto name = impl->m_Name;
41 auto name = impl->m_Name;
42 impl->unlock();
42 impl->unlock();
43 return name;
43 return name;
44 }
44 }
45
45
46 SqpRange Variable::range() const noexcept
46 SqpRange Variable::range() const noexcept
47 {
47 {
48 impl->lockRead();
48 impl->lockRead();
49 auto range = impl->m_Range;
49 auto range = impl->m_Range;
50 impl->unlock();
50 impl->unlock();
51 return range;
51 return range;
52 }
52 }
53
53
54 void Variable::setRange(const SqpRange &range) noexcept
54 void Variable::setRange(const SqpRange &range) noexcept
55 {
55 {
56 impl->lockWrite();
56 impl->lockWrite();
57 impl->m_Range = range;
57 impl->m_Range = range;
58 impl->unlock();
58 impl->unlock();
59 }
59 }
60
60
61 SqpRange Variable::cacheRange() const noexcept
61 SqpRange Variable::cacheRange() const noexcept
62 {
62 {
63 impl->lockRead();
63 impl->lockRead();
64 auto cacheRange = impl->m_CacheRange;
64 auto cacheRange = impl->m_CacheRange;
65 impl->unlock();
65 impl->unlock();
66 return cacheRange;
66 return cacheRange;
67 }
67 }
68
68
69 void Variable::setCacheRange(const SqpRange &cacheRange) noexcept
69 void Variable::setCacheRange(const SqpRange &cacheRange) noexcept
70 {
70 {
71 impl->lockWrite();
71 impl->lockWrite();
72 impl->m_CacheRange = cacheRange;
72 impl->m_CacheRange = cacheRange;
73 impl->unlock();
73 impl->unlock();
74 }
74 }
75
75
76 void Variable::setDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept
76 void Variable::setDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept
77 {
77 {
78 qCDebug(LOG_Variable()) << "TORM Variable::setDataSeries"
78 qCDebug(LOG_Variable()) << "TORM Variable::setDataSeries"
79 << QThread::currentThread()->objectName();
79 << QThread::currentThread()->objectName();
80 if (!dataSeries) {
80 if (!dataSeries) {
81 /// @todo ALX : log
81 /// @todo ALX : log
82 return;
82 return;
83 }
83 }
84 impl->lockWrite();
84 impl->lockWrite();
85 impl->m_DataSeries = dataSeries->clone();
85 impl->m_DataSeries = dataSeries->clone();
86 impl->unlock();
86 impl->unlock();
87 }
87 }
88
88
89 void Variable::mergeDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept
89 void Variable::mergeDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept
90 {
90 {
91 qCDebug(LOG_Variable()) << "TORM Variable::mergeDataSeries"
91 qCDebug(LOG_Variable()) << "TORM Variable::mergeDataSeries"
92 << QThread::currentThread()->objectName();
92 << QThread::currentThread()->objectName();
93 if (!dataSeries) {
93 if (!dataSeries) {
94 /// @todo ALX : log
94 /// @todo ALX : log
95 return;
95 return;
96 }
96 }
97
97
98 // Add or merge the data
98 // Add or merge the data
99 // Inits the data series of the variable
99 // Inits the data series of the variable
100 impl->lockWrite();
100 impl->lockWrite();
101 if (!impl->m_DataSeries) {
101 if (!impl->m_DataSeries) {
102 impl->m_DataSeries = dataSeries->clone();
102 impl->m_DataSeries = dataSeries->clone();
103 }
103 }
104 else {
104 else {
105 impl->m_DataSeries->merge(dataSeries.get());
105 impl->m_DataSeries->merge(dataSeries.get());
106 }
106 }
107 impl->unlock();
107 impl->unlock();
108
108
109 // sub the data
109 // sub the data
110 auto subData = this->dataSeries()->subDataSeries(this->cacheRange());
110 auto subData = this->dataSeries()->subDataSeries(this->cacheRange());
111 qCDebug(LOG_Variable()) << "TORM: Variable::mergeDataSeries sub" << subData->range();
111 qCDebug(LOG_Variable()) << "TORM: Variable::mergeDataSeries sub" << subData->range();
112 this->setDataSeries(subData);
112 this->setDataSeries(subData);
113 qCDebug(LOG_Variable()) << "TORM: Variable::mergeDataSeries set" << this->dataSeries()->range();
113 qCDebug(LOG_Variable()) << "TORM: Variable::mergeDataSeries set" << this->dataSeries()->range();
114 }
114 }
115
115
116 std::shared_ptr<IDataSeries> Variable::dataSeries() const noexcept
116 std::shared_ptr<IDataSeries> Variable::dataSeries() const noexcept
117 {
117 {
118 impl->lockRead();
118 impl->lockRead();
119 auto dataSeries = impl->m_DataSeries;
119 auto dataSeries = impl->m_DataSeries;
120 impl->unlock();
120 impl->unlock();
121
121
122 return dataSeries;
122 return dataSeries;
123 }
123 }
124
124
125 QVariantHash Variable::metadata() const noexcept
125 QVariantHash Variable::metadata() const noexcept
126 {
126 {
127 impl->lockRead();
127 impl->lockRead();
128 auto metadata = impl->m_Metadata;
128 auto metadata = impl->m_Metadata;
129 impl->unlock();
129 impl->unlock();
130 return metadata;
130 return metadata;
131 }
131 }
132
132
133 bool Variable::contains(const SqpRange &range) const noexcept
133 bool Variable::contains(const SqpRange &range) const noexcept
134 {
134 {
135 impl->lockRead();
135 impl->lockRead();
136 auto res = impl->m_Range.contains(range);
136 auto res = impl->m_Range.contains(range);
137 impl->unlock();
137 impl->unlock();
138 return res;
138 return res;
139 }
139 }
140
140
141 bool Variable::intersect(const SqpRange &range) const noexcept
141 bool Variable::intersect(const SqpRange &range) const noexcept
142 {
142 {
143
143
144 impl->lockRead();
144 impl->lockRead();
145 auto res = impl->m_Range.intersect(range);
145 auto res = impl->m_Range.intersect(range);
146 impl->unlock();
146 impl->unlock();
147 return res;
147 return res;
148 }
148 }
149
149
150 bool Variable::isInside(const SqpRange &range) const noexcept
150 bool Variable::isInside(const SqpRange &range) const noexcept
151 {
151 {
152 impl->lockRead();
152 impl->lockRead();
153 auto res = range.contains(SqpRange{impl->m_Range.m_TStart, impl->m_Range.m_TEnd});
153 auto res = range.contains(SqpRange{impl->m_Range.m_TStart, impl->m_Range.m_TEnd});
154 impl->unlock();
154 impl->unlock();
155 return res;
155 return res;
156 }
156 }
157
157
158 bool Variable::cacheContains(const SqpRange &range) const noexcept
158 bool Variable::cacheContains(const SqpRange &range) const noexcept
159 {
159 {
160 impl->lockRead();
160 impl->lockRead();
161 auto res = impl->m_CacheRange.contains(range);
161 auto res = impl->m_CacheRange.contains(range);
162 impl->unlock();
162 impl->unlock();
163 return res;
163 return res;
164 }
164 }
165
165
166 bool Variable::cacheIntersect(const SqpRange &range) const noexcept
166 bool Variable::cacheIntersect(const SqpRange &range) const noexcept
167 {
167 {
168 impl->lockRead();
168 impl->lockRead();
169 auto res = impl->m_CacheRange.intersect(range);
169 auto res = impl->m_CacheRange.intersect(range);
170 impl->unlock();
170 impl->unlock();
171 return res;
171 return res;
172 }
172 }
173
173
174 bool Variable::cacheIsInside(const SqpRange &range) const noexcept
174 bool Variable::cacheIsInside(const SqpRange &range) const noexcept
175 {
175 {
176 impl->lockRead();
176 impl->lockRead();
177 auto res = range.contains(SqpRange{impl->m_CacheRange.m_TStart, impl->m_CacheRange.m_TEnd});
177 auto res = range.contains(SqpRange{impl->m_CacheRange.m_TStart, impl->m_CacheRange.m_TEnd});
178 impl->unlock();
178 impl->unlock();
179 return res;
179 return res;
180 }
180 }
181
181
182
182
183 QVector<SqpRange> Variable::provideNotInCacheRangeList(const SqpRange &range) const noexcept
183 QVector<SqpRange> Variable::provideNotInCacheRangeList(const SqpRange &range) const noexcept
184 {
184 {
185 // This code assume that cach in contigue. Can return 0, 1 or 2 SqpRange
186
185 auto notInCache = QVector<SqpRange>{};
187 auto notInCache = QVector<SqpRange>{};
186
188
187 if (!this->cacheContains(range)) {
189 if (!this->cacheContains(range)) {
188 if (range.m_TEnd <= impl->m_CacheRange.m_TStart
190 if (range.m_TEnd <= impl->m_CacheRange.m_TStart
189 || range.m_TStart >= impl->m_CacheRange.m_TEnd) {
191 || range.m_TStart >= impl->m_CacheRange.m_TEnd) {
190 notInCache << range;
192 notInCache << range;
191 }
193 }
192 else if (range.m_TStart < impl->m_CacheRange.m_TStart
194 else if (range.m_TStart < impl->m_CacheRange.m_TStart
193 && range.m_TEnd <= impl->m_CacheRange.m_TEnd) {
195 && range.m_TEnd <= impl->m_CacheRange.m_TEnd) {
194 notInCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TStart};
196 notInCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TStart};
195 }
197 }
196 else if (range.m_TStart < impl->m_CacheRange.m_TStart
198 else if (range.m_TStart < impl->m_CacheRange.m_TStart
197 && range.m_TEnd > impl->m_CacheRange.m_TEnd) {
199 && range.m_TEnd > impl->m_CacheRange.m_TEnd) {
198 notInCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TStart}
200 notInCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TStart}
199 << SqpRange{impl->m_CacheRange.m_TEnd, range.m_TEnd};
201 << SqpRange{impl->m_CacheRange.m_TEnd, range.m_TEnd};
200 }
202 }
201 else if (range.m_TStart < impl->m_CacheRange.m_TEnd) {
203 else if (range.m_TStart < impl->m_CacheRange.m_TEnd) {
202 notInCache << SqpRange{impl->m_CacheRange.m_TEnd, range.m_TEnd};
204 notInCache << SqpRange{impl->m_CacheRange.m_TEnd, range.m_TEnd};
203 }
205 }
204 else {
206 else {
205 qCCritical(LOG_Variable()) << tr("Detection of unknown case.")
207 qCCritical(LOG_Variable()) << tr("Detection of unknown case.")
206 << QThread::currentThread();
208 << QThread::currentThread();
207 }
209 }
208 }
210 }
209
211
210 return notInCache;
212 return notInCache;
211 }
213 }
214
215 QVector<SqpRange> Variable::provideInCacheRangeList(const SqpRange &range) const noexcept
216 {
217 // This code assume that cach in contigue. Can return 0 or 1 SqpRange
218
219 auto inCache = QVector<SqpRange>{};
220
221
222 if (this->cacheContains(range)) {
223 if (range.m_TStart <= impl->m_CacheRange.m_TEnd
224 && range.m_TEnd >= impl->m_CacheRange.m_TEnd) {
225 inCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TEnd};
226 }
227
228 else if (range.m_TStart >= impl->m_CacheRange.m_TStart
229 && range.m_TEnd < impl->m_CacheRange.m_TEnd) {
230 inCache << range;
231 }
232 else if (range.m_TStart < impl->m_CacheRange.m_TStart
233 && range.m_TEnd >= impl->m_CacheRange.m_TStart) {
234 inCache << SqpRange{impl->m_CacheRange.m_TStart, range.m_TEnd};
235 }
236 else {
237 qCCritical(LOG_Variable()) << tr("Detection of unknown case.")
238 << QThread::currentThread();
239 }
240 }
241
242 return inCache;
243 }
@@ -1,541 +1,550
1 #include <Variable/Variable.h>
1 #include <Variable/Variable.h>
2 #include <Variable/VariableAcquisitionWorker.h>
2 #include <Variable/VariableAcquisitionWorker.h>
3 #include <Variable/VariableCacheController.h>
3 #include <Variable/VariableCacheController.h>
4 #include <Variable/VariableCacheStrategy.h>
4 #include <Variable/VariableCacheStrategy.h>
5 #include <Variable/VariableController.h>
5 #include <Variable/VariableController.h>
6 #include <Variable/VariableModel.h>
6 #include <Variable/VariableModel.h>
7 #include <Variable/VariableSynchronizationGroup.h>
7 #include <Variable/VariableSynchronizationGroup.h>
8
8
9 #include <Data/DataProviderParameters.h>
9 #include <Data/DataProviderParameters.h>
10 #include <Data/IDataProvider.h>
10 #include <Data/IDataProvider.h>
11 #include <Data/IDataSeries.h>
11 #include <Data/IDataSeries.h>
12 #include <Time/TimeController.h>
12 #include <Time/TimeController.h>
13
13
14 #include <QMutex>
14 #include <QMutex>
15 #include <QThread>
15 #include <QThread>
16 #include <QUuid>
16 #include <QUuid>
17 #include <QtCore/QItemSelectionModel>
17 #include <QtCore/QItemSelectionModel>
18
18
19 #include <set>
19 #include <set>
20 #include <unordered_map>
20 #include <unordered_map>
21
21
22 Q_LOGGING_CATEGORY(LOG_VariableController, "VariableController")
22 Q_LOGGING_CATEGORY(LOG_VariableController, "VariableController")
23
23
24 namespace {
24 namespace {
25
25
26 SqpRange computeSynchroRangeRequested(const SqpRange &varRange, const SqpRange &graphRange,
26 SqpRange computeSynchroRangeRequested(const SqpRange &varRange, const SqpRange &graphRange,
27 const SqpRange &oldGraphRange)
27 const SqpRange &oldGraphRange)
28 {
28 {
29 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
29 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
30
30
31 auto varRangeRequested = varRange;
31 auto varRangeRequested = varRange;
32 switch (zoomType) {
32 switch (zoomType) {
33 case AcquisitionZoomType::ZoomIn: {
33 case AcquisitionZoomType::ZoomIn: {
34 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
34 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
35 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
35 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
36 varRangeRequested.m_TStart += deltaLeft;
36 varRangeRequested.m_TStart += deltaLeft;
37 varRangeRequested.m_TEnd -= deltaRight;
37 varRangeRequested.m_TEnd -= deltaRight;
38 break;
38 break;
39 }
39 }
40
40
41 case AcquisitionZoomType::ZoomOut: {
41 case AcquisitionZoomType::ZoomOut: {
42 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
42 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
43 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
43 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
44 varRangeRequested.m_TStart -= deltaLeft;
44 varRangeRequested.m_TStart -= deltaLeft;
45 varRangeRequested.m_TEnd += deltaRight;
45 varRangeRequested.m_TEnd += deltaRight;
46 break;
46 break;
47 }
47 }
48 case AcquisitionZoomType::PanRight: {
48 case AcquisitionZoomType::PanRight: {
49 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
49 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
50 varRangeRequested.m_TStart += deltaRight;
50 varRangeRequested.m_TStart += deltaRight;
51 varRangeRequested.m_TEnd += deltaRight;
51 varRangeRequested.m_TEnd += deltaRight;
52 break;
52 break;
53 }
53 }
54 case AcquisitionZoomType::PanLeft: {
54 case AcquisitionZoomType::PanLeft: {
55 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
55 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
56 varRangeRequested.m_TStart -= deltaLeft;
56 varRangeRequested.m_TStart -= deltaLeft;
57 varRangeRequested.m_TEnd -= deltaLeft;
57 varRangeRequested.m_TEnd -= deltaLeft;
58 break;
58 break;
59 }
59 }
60 case AcquisitionZoomType::Unknown: {
60 case AcquisitionZoomType::Unknown: {
61 qCCritical(LOG_VariableController())
61 qCCritical(LOG_VariableController())
62 << VariableController::tr("Impossible to synchronize: zoom type unknown");
62 << VariableController::tr("Impossible to synchronize: zoom type unknown");
63 break;
63 break;
64 }
64 }
65 default:
65 default:
66 qCCritical(LOG_VariableController()) << VariableController::tr(
66 qCCritical(LOG_VariableController()) << VariableController::tr(
67 "Impossible to synchronize: zoom type not take into account");
67 "Impossible to synchronize: zoom type not take into account");
68 // No action
68 // No action
69 break;
69 break;
70 }
70 }
71
71
72 return varRangeRequested;
72 return varRangeRequested;
73 }
73 }
74 }
74 }
75
75
76 struct VariableController::VariableControllerPrivate {
76 struct VariableController::VariableControllerPrivate {
77 explicit VariableControllerPrivate(VariableController *parent)
77 explicit VariableControllerPrivate(VariableController *parent)
78 : m_WorkingMutex{},
78 : m_WorkingMutex{},
79 m_VariableModel{new VariableModel{parent}},
79 m_VariableModel{new VariableModel{parent}},
80 m_VariableSelectionModel{new QItemSelectionModel{m_VariableModel, parent}},
80 m_VariableSelectionModel{new QItemSelectionModel{m_VariableModel, parent}},
81 m_VariableCacheController{std::make_unique<VariableCacheController>()},
81 m_VariableCacheController{std::make_unique<VariableCacheController>()},
82 m_VariableCacheStrategy{std::make_unique<VariableCacheStrategy>()},
82 m_VariableCacheStrategy{std::make_unique<VariableCacheStrategy>()},
83 m_VariableAcquisitionWorker{std::make_unique<VariableAcquisitionWorker>()}
83 m_VariableAcquisitionWorker{std::make_unique<VariableAcquisitionWorker>()},
84 q{parent}
84 {
85 {
85
86
86 m_VariableAcquisitionWorker->moveToThread(&m_VariableAcquisitionWorkerThread);
87 m_VariableAcquisitionWorker->moveToThread(&m_VariableAcquisitionWorkerThread);
87 m_VariableAcquisitionWorkerThread.setObjectName("VariableAcquisitionWorkerThread");
88 m_VariableAcquisitionWorkerThread.setObjectName("VariableAcquisitionWorkerThread");
88 }
89 }
89
90
90
91
91 virtual ~VariableControllerPrivate()
92 virtual ~VariableControllerPrivate()
92 {
93 {
93 qCDebug(LOG_VariableController()) << tr("VariableControllerPrivate destruction");
94 qCDebug(LOG_VariableController()) << tr("VariableControllerPrivate destruction");
94 m_VariableAcquisitionWorkerThread.quit();
95 m_VariableAcquisitionWorkerThread.quit();
95 m_VariableAcquisitionWorkerThread.wait();
96 m_VariableAcquisitionWorkerThread.wait();
96 }
97 }
97
98
98
99
99 void processRequest(std::shared_ptr<Variable> var, const SqpRange &rangeRequested);
100 void processRequest(std::shared_ptr<Variable> var, const SqpRange &rangeRequested);
100
101
101 QVector<SqpRange> provideNotInCacheDateTimeList(std::shared_ptr<Variable> variable,
102 QVector<SqpRange> provideNotInCacheDateTimeList(std::shared_ptr<Variable> variable,
102 const SqpRange &dateTime);
103 const SqpRange &dateTime);
103
104
104 std::shared_ptr<Variable> findVariable(QUuid vIdentifier);
105 std::shared_ptr<Variable> findVariable(QUuid vIdentifier);
105 std::shared_ptr<IDataSeries>
106 std::shared_ptr<IDataSeries>
106 retrieveDataSeries(const QVector<AcquisitionDataPacket> acqDataPacketVector);
107 retrieveDataSeries(const QVector<AcquisitionDataPacket> acqDataPacketVector);
107
108
108 void registerProvider(std::shared_ptr<IDataProvider> provider);
109 void registerProvider(std::shared_ptr<IDataProvider> provider);
109
110
110 QMutex m_WorkingMutex;
111 QMutex m_WorkingMutex;
111 /// Variable model. The VariableController has the ownership
112 /// Variable model. The VariableController has the ownership
112 VariableModel *m_VariableModel;
113 VariableModel *m_VariableModel;
113 QItemSelectionModel *m_VariableSelectionModel;
114 QItemSelectionModel *m_VariableSelectionModel;
114
115
115
116
116 TimeController *m_TimeController{nullptr};
117 TimeController *m_TimeController{nullptr};
117 std::unique_ptr<VariableCacheController> m_VariableCacheController;
118 std::unique_ptr<VariableCacheController> m_VariableCacheController;
118 std::unique_ptr<VariableCacheStrategy> m_VariableCacheStrategy;
119 std::unique_ptr<VariableCacheStrategy> m_VariableCacheStrategy;
119 std::unique_ptr<VariableAcquisitionWorker> m_VariableAcquisitionWorker;
120 std::unique_ptr<VariableAcquisitionWorker> m_VariableAcquisitionWorker;
120 QThread m_VariableAcquisitionWorkerThread;
121 QThread m_VariableAcquisitionWorkerThread;
121
122
122 std::unordered_map<std::shared_ptr<Variable>, std::shared_ptr<IDataProvider> >
123 std::unordered_map<std::shared_ptr<Variable>, std::shared_ptr<IDataProvider> >
123 m_VariableToProviderMap;
124 m_VariableToProviderMap;
124 std::unordered_map<std::shared_ptr<Variable>, QUuid> m_VariableToIdentifierMap;
125 std::unordered_map<std::shared_ptr<Variable>, QUuid> m_VariableToIdentifierMap;
125 std::map<QUuid, std::shared_ptr<VariableSynchronizationGroup> >
126 std::map<QUuid, std::shared_ptr<VariableSynchronizationGroup> >
126 m_GroupIdToVariableSynchronizationGroupMap;
127 m_GroupIdToVariableSynchronizationGroupMap;
127 std::map<QUuid, QUuid> m_VariableIdGroupIdMap;
128 std::map<QUuid, QUuid> m_VariableIdGroupIdMap;
128 std::set<std::shared_ptr<IDataProvider> > m_ProviderSet;
129 std::set<std::shared_ptr<IDataProvider> > m_ProviderSet;
130
131
132 VariableController *q;
129 };
133 };
130
134
131
135
132 VariableController::VariableController(QObject *parent)
136 VariableController::VariableController(QObject *parent)
133 : QObject{parent}, impl{spimpl::make_unique_impl<VariableControllerPrivate>(this)}
137 : QObject{parent}, impl{spimpl::make_unique_impl<VariableControllerPrivate>(this)}
134 {
138 {
135 qCDebug(LOG_VariableController()) << tr("VariableController construction")
139 qCDebug(LOG_VariableController()) << tr("VariableController construction")
136 << QThread::currentThread();
140 << QThread::currentThread();
137
141
138 connect(impl->m_VariableModel, &VariableModel::abortProgessRequested, this,
142 connect(impl->m_VariableModel, &VariableModel::abortProgessRequested, this,
139 &VariableController::onAbortProgressRequested);
143 &VariableController::onAbortProgressRequested);
140
144
141 connect(impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::dataProvided, this,
145 connect(impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::dataProvided, this,
142 &VariableController::onDataProvided);
146 &VariableController::onDataProvided);
143 connect(impl->m_VariableAcquisitionWorker.get(),
147 connect(impl->m_VariableAcquisitionWorker.get(),
144 &VariableAcquisitionWorker::variableRequestInProgress, this,
148 &VariableAcquisitionWorker::variableRequestInProgress, this,
145 &VariableController::onVariableRetrieveDataInProgress);
149 &VariableController::onVariableRetrieveDataInProgress);
146
150
147 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::started,
151 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::started,
148 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::initialize);
152 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::initialize);
149 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::finished,
153 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::finished,
150 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::finalize);
154 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::finalize);
151
155
152
156
153 impl->m_VariableAcquisitionWorkerThread.start();
157 impl->m_VariableAcquisitionWorkerThread.start();
154 }
158 }
155
159
156 VariableController::~VariableController()
160 VariableController::~VariableController()
157 {
161 {
158 qCDebug(LOG_VariableController()) << tr("VariableController destruction")
162 qCDebug(LOG_VariableController()) << tr("VariableController destruction")
159 << QThread::currentThread();
163 << QThread::currentThread();
160 this->waitForFinish();
164 this->waitForFinish();
161 }
165 }
162
166
163 VariableModel *VariableController::variableModel() noexcept
167 VariableModel *VariableController::variableModel() noexcept
164 {
168 {
165 return impl->m_VariableModel;
169 return impl->m_VariableModel;
166 }
170 }
167
171
168 QItemSelectionModel *VariableController::variableSelectionModel() noexcept
172 QItemSelectionModel *VariableController::variableSelectionModel() noexcept
169 {
173 {
170 return impl->m_VariableSelectionModel;
174 return impl->m_VariableSelectionModel;
171 }
175 }
172
176
173 void VariableController::setTimeController(TimeController *timeController) noexcept
177 void VariableController::setTimeController(TimeController *timeController) noexcept
174 {
178 {
175 impl->m_TimeController = timeController;
179 impl->m_TimeController = timeController;
176 }
180 }
177
181
178 void VariableController::deleteVariable(std::shared_ptr<Variable> variable) noexcept
182 void VariableController::deleteVariable(std::shared_ptr<Variable> variable) noexcept
179 {
183 {
180 if (!variable) {
184 if (!variable) {
181 qCCritical(LOG_VariableController()) << "Can't delete variable: variable is null";
185 qCCritical(LOG_VariableController()) << "Can't delete variable: variable is null";
182 return;
186 return;
183 }
187 }
184
188
185 // Spreads in SciQlop that the variable will be deleted, so that potential receivers can
189 // Spreads in SciQlop that the variable will be deleted, so that potential receivers can
186 // make some treatments before the deletion
190 // make some treatments before the deletion
187 emit variableAboutToBeDeleted(variable);
191 emit variableAboutToBeDeleted(variable);
188
192
189 // Deletes identifier
193 // Deletes identifier
190 impl->m_VariableToIdentifierMap.erase(variable);
194 impl->m_VariableToIdentifierMap.erase(variable);
191
195
192 // Deletes provider
196 // Deletes provider
193 auto nbProvidersDeleted = impl->m_VariableToProviderMap.erase(variable);
197 auto nbProvidersDeleted = impl->m_VariableToProviderMap.erase(variable);
194 qCDebug(LOG_VariableController())
198 qCDebug(LOG_VariableController())
195 << tr("Number of providers deleted for variable %1: %2")
199 << tr("Number of providers deleted for variable %1: %2")
196 .arg(variable->name(), QString::number(nbProvidersDeleted));
200 .arg(variable->name(), QString::number(nbProvidersDeleted));
197
201
198 // Clears cache
202 // Clears cache
199 impl->m_VariableCacheController->clear(variable);
203 impl->m_VariableCacheController->clear(variable);
200
204
201 // Deletes from model
205 // Deletes from model
202 impl->m_VariableModel->deleteVariable(variable);
206 impl->m_VariableModel->deleteVariable(variable);
203 }
207 }
204
208
205 void VariableController::deleteVariables(
209 void VariableController::deleteVariables(
206 const QVector<std::shared_ptr<Variable> > &variables) noexcept
210 const QVector<std::shared_ptr<Variable> > &variables) noexcept
207 {
211 {
208 for (auto variable : qAsConst(variables)) {
212 for (auto variable : qAsConst(variables)) {
209 deleteVariable(variable);
213 deleteVariable(variable);
210 }
214 }
211 }
215 }
212
216
213 void VariableController::abortProgress(std::shared_ptr<Variable> variable)
217 void VariableController::abortProgress(std::shared_ptr<Variable> variable)
214 {
218 {
215 }
219 }
216
220
217 void VariableController::createVariable(const QString &name, const QVariantHash &metadata,
221 void VariableController::createVariable(const QString &name, const QVariantHash &metadata,
218 std::shared_ptr<IDataProvider> provider) noexcept
222 std::shared_ptr<IDataProvider> provider) noexcept
219 {
223 {
220
224
221 if (!impl->m_TimeController) {
225 if (!impl->m_TimeController) {
222 qCCritical(LOG_VariableController())
226 qCCritical(LOG_VariableController())
223 << tr("Impossible to create variable: The time controller is null");
227 << tr("Impossible to create variable: The time controller is null");
224 return;
228 return;
225 }
229 }
226
230
227 auto range = impl->m_TimeController->dateTime();
231 auto range = impl->m_TimeController->dateTime();
228
232
229 if (auto newVariable = impl->m_VariableModel->createVariable(name, range, metadata)) {
233 if (auto newVariable = impl->m_VariableModel->createVariable(name, range, metadata)) {
230 auto identifier = QUuid::createUuid();
234 auto identifier = QUuid::createUuid();
231
235
232 // store the provider
236 // store the provider
233 impl->registerProvider(provider);
237 impl->registerProvider(provider);
234
238
235 // Associate the provider
239 // Associate the provider
236 impl->m_VariableToProviderMap[newVariable] = provider;
240 impl->m_VariableToProviderMap[newVariable] = provider;
237 impl->m_VariableToIdentifierMap[newVariable] = identifier;
241 impl->m_VariableToIdentifierMap[newVariable] = identifier;
238
242
239
243
240 impl->processRequest(newVariable, range);
244 impl->processRequest(newVariable, range);
241 }
245 }
242 }
246 }
243
247
244 void VariableController::onDateTimeOnSelection(const SqpRange &dateTime)
248 void VariableController::onDateTimeOnSelection(const SqpRange &dateTime)
245 {
249 {
246 // TODO check synchronisation
250 // TODO check synchronisation
247 qCDebug(LOG_VariableController()) << "VariableController::onDateTimeOnSelection"
251 qCDebug(LOG_VariableController()) << "VariableController::onDateTimeOnSelection"
248 << QThread::currentThread()->objectName();
252 << QThread::currentThread()->objectName();
249 auto selectedRows = impl->m_VariableSelectionModel->selectedRows();
253 auto selectedRows = impl->m_VariableSelectionModel->selectedRows();
250
254
251 for (const auto &selectedRow : qAsConst(selectedRows)) {
255 for (const auto &selectedRow : qAsConst(selectedRows)) {
252 if (auto selectedVariable = impl->m_VariableModel->variable(selectedRow.row())) {
256 if (auto selectedVariable = impl->m_VariableModel->variable(selectedRow.row())) {
253 selectedVariable->setRange(dateTime);
257 selectedVariable->setRange(dateTime);
254 impl->processRequest(selectedVariable, dateTime);
258 impl->processRequest(selectedVariable, dateTime);
255
259
256 // notify that rescale operation has to be done
260 // notify that rescale operation has to be done
257 emit rangeChanged(selectedVariable, dateTime);
261 emit rangeChanged(selectedVariable, dateTime);
258 }
262 }
259 }
263 }
260 }
264 }
261
265
262 void VariableController::onDataProvided(QUuid vIdentifier, const SqpRange &rangeRequested,
266 void VariableController::onDataProvided(QUuid vIdentifier, const SqpRange &rangeRequested,
263 const SqpRange &cacheRangeRequested,
267 const SqpRange &cacheRangeRequested,
264 QVector<AcquisitionDataPacket> dataAcquired)
268 QVector<AcquisitionDataPacket> dataAcquired)
265 {
269 {
266 if (auto var = impl->findVariable(vIdentifier)) {
270 if (auto var = impl->findVariable(vIdentifier)) {
267 var->setRange(rangeRequested);
271 var->setRange(rangeRequested);
268 var->setCacheRange(cacheRangeRequested);
272 var->setCacheRange(cacheRangeRequested);
269 qCDebug(LOG_VariableController()) << tr("1: onDataProvided") << rangeRequested;
273 qCDebug(LOG_VariableController()) << tr("1: onDataProvided") << rangeRequested;
270 qCDebug(LOG_VariableController()) << tr("2: onDataProvided") << cacheRangeRequested;
274 qCDebug(LOG_VariableController()) << tr("2: onDataProvided") << cacheRangeRequested;
271
275
272 auto retrievedDataSeries = impl->retrieveDataSeries(dataAcquired);
276 auto retrievedDataSeries = impl->retrieveDataSeries(dataAcquired);
273 qCDebug(LOG_VariableController()) << tr("3: onDataProvided")
277 qCDebug(LOG_VariableController()) << tr("3: onDataProvided")
274 << retrievedDataSeries->range();
278 << retrievedDataSeries->range();
275 var->mergeDataSeries(retrievedDataSeries);
279 var->mergeDataSeries(retrievedDataSeries);
276 qCDebug(LOG_VariableController()) << tr("4: onDataProvided");
280 qCDebug(LOG_VariableController()) << tr("4: onDataProvided");
277 emit var->updated();
281 emit var->updated();
278 }
282 }
279 else {
283 else {
280 qCCritical(LOG_VariableController()) << tr("Impossible to provide data to a null variable");
284 qCCritical(LOG_VariableController()) << tr("Impossible to provide data to a null variable");
281 }
285 }
282 }
286 }
283
287
284 void VariableController::onVariableRetrieveDataInProgress(QUuid identifier, double progress)
288 void VariableController::onVariableRetrieveDataInProgress(QUuid identifier, double progress)
285 {
289 {
286 if (auto var = impl->findVariable(identifier)) {
290 if (auto var = impl->findVariable(identifier)) {
287 impl->m_VariableModel->setDataProgress(var, progress);
291 impl->m_VariableModel->setDataProgress(var, progress);
288 }
292 }
289 else {
293 else {
290 qCCritical(LOG_VariableController())
294 qCCritical(LOG_VariableController())
291 << tr("Impossible to notify progression of a null variable");
295 << tr("Impossible to notify progression of a null variable");
292 }
296 }
293 }
297 }
294
298
295 void VariableController::onAbortProgressRequested(std::shared_ptr<Variable> variable)
299 void VariableController::onAbortProgressRequested(std::shared_ptr<Variable> variable)
296 {
300 {
297 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAbortProgressRequested"
301 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAbortProgressRequested"
298 << QThread::currentThread()->objectName();
302 << QThread::currentThread()->objectName();
299
303
300 auto it = impl->m_VariableToIdentifierMap.find(variable);
304 auto it = impl->m_VariableToIdentifierMap.find(variable);
301 if (it != impl->m_VariableToIdentifierMap.cend()) {
305 if (it != impl->m_VariableToIdentifierMap.cend()) {
302 impl->m_VariableToProviderMap.at(variable)->requestDataAborting(it->second);
306 impl->m_VariableToProviderMap.at(variable)->requestDataAborting(it->second);
303 }
307 }
304 else {
308 else {
305 qCWarning(LOG_VariableController())
309 qCWarning(LOG_VariableController())
306 << tr("Aborting progression of inexistant variable detected !!!")
310 << tr("Aborting progression of inexistant variable detected !!!")
307 << QThread::currentThread()->objectName();
311 << QThread::currentThread()->objectName();
308 }
312 }
309 }
313 }
310
314
311 void VariableController::onAddSynchronizationGroupId(QUuid synchronizationGroupId)
315 void VariableController::onAddSynchronizationGroupId(QUuid synchronizationGroupId)
312 {
316 {
313 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronizationGroupId"
317 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronizationGroupId"
314 << QThread::currentThread()->objectName()
318 << QThread::currentThread()->objectName()
315 << synchronizationGroupId;
319 << synchronizationGroupId;
316 auto vSynchroGroup = std::make_shared<VariableSynchronizationGroup>();
320 auto vSynchroGroup = std::make_shared<VariableSynchronizationGroup>();
317 impl->m_GroupIdToVariableSynchronizationGroupMap.insert(
321 impl->m_GroupIdToVariableSynchronizationGroupMap.insert(
318 std::make_pair(synchronizationGroupId, vSynchroGroup));
322 std::make_pair(synchronizationGroupId, vSynchroGroup));
319 }
323 }
320
324
321 void VariableController::onRemoveSynchronizationGroupId(QUuid synchronizationGroupId)
325 void VariableController::onRemoveSynchronizationGroupId(QUuid synchronizationGroupId)
322 {
326 {
323 impl->m_GroupIdToVariableSynchronizationGroupMap.erase(synchronizationGroupId);
327 impl->m_GroupIdToVariableSynchronizationGroupMap.erase(synchronizationGroupId);
324 }
328 }
325
329
326 void VariableController::onAddSynchronized(std::shared_ptr<Variable> variable,
330 void VariableController::onAddSynchronized(std::shared_ptr<Variable> variable,
327 QUuid synchronizationGroupId)
331 QUuid synchronizationGroupId)
328
332
329 {
333 {
330 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronized"
334 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronized"
331 << synchronizationGroupId;
335 << synchronizationGroupId;
332 auto varToVarIdIt = impl->m_VariableToIdentifierMap.find(variable);
336 auto varToVarIdIt = impl->m_VariableToIdentifierMap.find(variable);
333 if (varToVarIdIt != impl->m_VariableToIdentifierMap.cend()) {
337 if (varToVarIdIt != impl->m_VariableToIdentifierMap.cend()) {
334 auto groupIdToVSGIt
338 auto groupIdToVSGIt
335 = impl->m_GroupIdToVariableSynchronizationGroupMap.find(synchronizationGroupId);
339 = impl->m_GroupIdToVariableSynchronizationGroupMap.find(synchronizationGroupId);
336 if (groupIdToVSGIt != impl->m_GroupIdToVariableSynchronizationGroupMap.cend()) {
340 if (groupIdToVSGIt != impl->m_GroupIdToVariableSynchronizationGroupMap.cend()) {
337 impl->m_VariableIdGroupIdMap.insert(
341 impl->m_VariableIdGroupIdMap.insert(
338 std::make_pair(varToVarIdIt->second, synchronizationGroupId));
342 std::make_pair(varToVarIdIt->second, synchronizationGroupId));
339 groupIdToVSGIt->second->addVariableId(varToVarIdIt->second);
343 groupIdToVSGIt->second->addVariableId(varToVarIdIt->second);
340 }
344 }
341 else {
345 else {
342 qCCritical(LOG_VariableController())
346 qCCritical(LOG_VariableController())
343 << tr("Impossible to synchronize a variable with an unknown sycnhronization group")
347 << tr("Impossible to synchronize a variable with an unknown sycnhronization group")
344 << variable->name();
348 << variable->name();
345 }
349 }
346 }
350 }
347 else {
351 else {
348 qCCritical(LOG_VariableController())
352 qCCritical(LOG_VariableController())
349 << tr("Impossible to synchronize a variable with no identifier") << variable->name();
353 << tr("Impossible to synchronize a variable with no identifier") << variable->name();
350 }
354 }
351 }
355 }
352
356
353
357
354 void VariableController::onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables,
358 void VariableController::onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables,
355 const SqpRange &range, const SqpRange &oldRange,
359 const SqpRange &range, const SqpRange &oldRange,
356 bool synchronise)
360 bool synchronise)
357 {
361 {
358 // NOTE: oldRange isn't really necessary since oldRange == variable->range().
362 // NOTE: oldRange isn't really necessary since oldRange == variable->range().
359
363
360 qCDebug(LOG_VariableController()) << "VariableController::onRequestDataLoading"
364 qCDebug(LOG_VariableController()) << "VariableController::onRequestDataLoading"
361 << QThread::currentThread()->objectName();
365 << QThread::currentThread()->objectName();
362 // we want to load data of the variable for the dateTime.
366 // we want to load data of the variable for the dateTime.
363 // First we check if the cache contains some of them.
367 // First we check if the cache contains some of them.
364 // For the other, we ask the provider to give them.
368 // For the other, we ask the provider to give them.
365
369
366 for (const auto &var : variables) {
370 for (const auto &var : variables) {
367 qCDebug(LOG_VariableController()) << "processRequest for" << var->name();
371 qCDebug(LOG_VariableController()) << "processRequest for" << var->name();
368 impl->processRequest(var, range);
372 impl->processRequest(var, range);
369 }
373 }
370
374
371 if (synchronise) {
375 if (synchronise) {
372 // Get the group ids
376 // Get the group ids
373 qCDebug(LOG_VariableController())
377 qCDebug(LOG_VariableController())
374 << "TORM VariableController::onRequestDataLoading for synchro var ENABLE";
378 << "TORM VariableController::onRequestDataLoading for synchro var ENABLE";
375 auto groupIds = std::set<QUuid>();
379 auto groupIds = std::set<QUuid>();
376 for (const auto &var : variables) {
380 for (const auto &var : variables) {
377 auto varToVarIdIt = impl->m_VariableToIdentifierMap.find(var);
381 auto varToVarIdIt = impl->m_VariableToIdentifierMap.find(var);
378 if (varToVarIdIt != impl->m_VariableToIdentifierMap.cend()) {
382 if (varToVarIdIt != impl->m_VariableToIdentifierMap.cend()) {
379 auto vId = varToVarIdIt->second;
383 auto vId = varToVarIdIt->second;
380 auto varIdToGroupIdIt = impl->m_VariableIdGroupIdMap.find(vId);
384 auto varIdToGroupIdIt = impl->m_VariableIdGroupIdMap.find(vId);
381 if (varIdToGroupIdIt != impl->m_VariableIdGroupIdMap.cend()) {
385 if (varIdToGroupIdIt != impl->m_VariableIdGroupIdMap.cend()) {
382 auto gId = varIdToGroupIdIt->second;
386 auto gId = varIdToGroupIdIt->second;
383 if (groupIds.find(gId) == groupIds.cend()) {
387 if (groupIds.find(gId) == groupIds.cend()) {
384 qCDebug(LOG_VariableController()) << "Synchro detect group " << gId;
388 qCDebug(LOG_VariableController()) << "Synchro detect group " << gId;
385 groupIds.insert(gId);
389 groupIds.insert(gId);
386 }
390 }
387 }
391 }
388 }
392 }
389 }
393 }
390
394
391 // We assume here all group ids exist
395 // We assume here all group ids exist
392 for (const auto &gId : groupIds) {
396 for (const auto &gId : groupIds) {
393 auto vSynchronizationGroup = impl->m_GroupIdToVariableSynchronizationGroupMap.at(gId);
397 auto vSynchronizationGroup = impl->m_GroupIdToVariableSynchronizationGroupMap.at(gId);
394 auto vSyncIds = vSynchronizationGroup->getIds();
398 auto vSyncIds = vSynchronizationGroup->getIds();
395 qCDebug(LOG_VariableController()) << "Var in synchro group ";
399 qCDebug(LOG_VariableController()) << "Var in synchro group ";
396 for (auto vId : vSyncIds) {
400 for (auto vId : vSyncIds) {
397 auto var = impl->findVariable(vId);
401 auto var = impl->findVariable(vId);
398
402
399 // Don't process already processed var
403 // Don't process already processed var
400 if (!variables.contains(var)) {
404 if (!variables.contains(var)) {
401 if (var != nullptr) {
405 if (var != nullptr) {
402 qCDebug(LOG_VariableController()) << "processRequest synchro for"
406 qCDebug(LOG_VariableController()) << "processRequest synchro for"
403 << var->name();
407 << var->name();
404 auto vSyncRangeRequested
408 auto vSyncRangeRequested
405 = computeSynchroRangeRequested(var->range(), range, oldRange);
409 = computeSynchroRangeRequested(var->range(), range, oldRange);
406 impl->processRequest(var, vSyncRangeRequested);
410 impl->processRequest(var, vSyncRangeRequested);
407 }
411 }
408 else {
412 else {
409 qCCritical(LOG_VariableController())
413 qCCritical(LOG_VariableController())
410
414
411 << tr("Impossible to synchronize a null variable");
415 << tr("Impossible to synchronize a null variable");
412 }
416 }
413 }
417 }
414 }
418 }
415 }
419 }
416 }
420 }
417 }
421 }
418
422
419
423
420 void VariableController::initialize()
424 void VariableController::initialize()
421 {
425 {
422 qCDebug(LOG_VariableController()) << tr("VariableController init") << QThread::currentThread();
426 qCDebug(LOG_VariableController()) << tr("VariableController init") << QThread::currentThread();
423 impl->m_WorkingMutex.lock();
427 impl->m_WorkingMutex.lock();
424 qCDebug(LOG_VariableController()) << tr("VariableController init END");
428 qCDebug(LOG_VariableController()) << tr("VariableController init END");
425 }
429 }
426
430
427 void VariableController::finalize()
431 void VariableController::finalize()
428 {
432 {
429 impl->m_WorkingMutex.unlock();
433 impl->m_WorkingMutex.unlock();
430 }
434 }
431
435
432 void VariableController::waitForFinish()
436 void VariableController::waitForFinish()
433 {
437 {
434 QMutexLocker locker{&impl->m_WorkingMutex};
438 QMutexLocker locker{&impl->m_WorkingMutex};
435 }
439 }
436
440
437 AcquisitionZoomType VariableController::getZoomType(const SqpRange &range, const SqpRange &oldRange)
441 AcquisitionZoomType VariableController::getZoomType(const SqpRange &range, const SqpRange &oldRange)
438 {
442 {
439 // t1.m_TStart <= t2.m_TStart && t2.m_TEnd <= t1.m_TEnd
443 // t1.m_TStart <= t2.m_TStart && t2.m_TEnd <= t1.m_TEnd
440 auto zoomType = AcquisitionZoomType::Unknown;
444 auto zoomType = AcquisitionZoomType::Unknown;
441 if (range.m_TStart <= oldRange.m_TStart && oldRange.m_TEnd <= range.m_TEnd) {
445 if (range.m_TStart <= oldRange.m_TStart && oldRange.m_TEnd <= range.m_TEnd) {
442 zoomType = AcquisitionZoomType::ZoomOut;
446 zoomType = AcquisitionZoomType::ZoomOut;
443 }
447 }
444 else if (range.m_TStart > oldRange.m_TStart && range.m_TEnd > oldRange.m_TEnd) {
448 else if (range.m_TStart > oldRange.m_TStart && range.m_TEnd > oldRange.m_TEnd) {
445 zoomType = AcquisitionZoomType::PanRight;
449 zoomType = AcquisitionZoomType::PanRight;
446 }
450 }
447 else if (range.m_TStart < oldRange.m_TStart && range.m_TEnd < oldRange.m_TEnd) {
451 else if (range.m_TStart < oldRange.m_TStart && range.m_TEnd < oldRange.m_TEnd) {
448 zoomType = AcquisitionZoomType::PanLeft;
452 zoomType = AcquisitionZoomType::PanLeft;
449 }
453 }
450 else if (range.m_TStart > oldRange.m_TStart && oldRange.m_TEnd > range.m_TEnd) {
454 else if (range.m_TStart > oldRange.m_TStart && oldRange.m_TEnd > range.m_TEnd) {
451 zoomType = AcquisitionZoomType::ZoomIn;
455 zoomType = AcquisitionZoomType::ZoomIn;
452 }
456 }
453 else {
457 else {
454 qCCritical(LOG_VariableController()) << "getZoomType: Unknown type detected";
458 qCCritical(LOG_VariableController()) << "getZoomType: Unknown type detected";
455 }
459 }
456 return zoomType;
460 return zoomType;
457 }
461 }
458
462
459 void VariableController::VariableControllerPrivate::processRequest(std::shared_ptr<Variable> var,
463 void VariableController::VariableControllerPrivate::processRequest(std::shared_ptr<Variable> var,
460 const SqpRange &rangeRequested)
464 const SqpRange &rangeRequested)
461 {
465 {
462
466
463 auto varRangesRequested
467 auto varRangesRequested
464 = m_VariableCacheStrategy->computeCacheRange(var->range(), rangeRequested);
468 = m_VariableCacheStrategy->computeCacheRange(var->range(), rangeRequested);
465 auto notInCacheRangeList = var->provideNotInCacheRangeList(varRangesRequested.second);
469 auto notInCacheRangeList = var->provideNotInCacheRangeList(varRangesRequested.second);
470 auto inCacheRangeList = var->provideInCacheRangeList(varRangesRequested.second);
466
471
467 if (!notInCacheRangeList.empty()) {
472 if (!notInCacheRangeList.empty()) {
468 auto identifier = m_VariableToIdentifierMap.at(var);
473 auto identifier = m_VariableToIdentifierMap.at(var);
469 auto varProvider = m_VariableToProviderMap.at(var);
474 auto varProvider = m_VariableToProviderMap.at(var);
470 if (varProvider != nullptr) {
475 if (varProvider != nullptr) {
471 m_VariableAcquisitionWorker->pushVariableRequest(
476 m_VariableAcquisitionWorker->pushVariableRequest(
472 identifier, varRangesRequested.first, varRangesRequested.second,
477 identifier, varRangesRequested.first, varRangesRequested.second,
473 DataProviderParameters{std::move(notInCacheRangeList), var->metadata()},
478 DataProviderParameters{std::move(notInCacheRangeList), var->metadata()},
474 varProvider);
479 varProvider);
475 }
480 }
476 else {
481 else {
477 qCCritical(LOG_VariableController())
482 qCCritical(LOG_VariableController())
478 << "Impossible to provide data with a null provider";
483 << "Impossible to provide data with a null provider";
479 }
484 }
485
486 if (!inCacheRangeList.empty()) {
487 emit q->updateVarDisplaying(var, inCacheRangeList.first());
488 }
480 }
489 }
481 else {
490 else {
482 var->setRange(rangeRequested);
491 var->setRange(rangeRequested);
483 var->setCacheRange(varRangesRequested.second);
492 var->setCacheRange(varRangesRequested.second);
484 var->setDataSeries(var->dataSeries()->subDataSeries(varRangesRequested.second));
493 var->setDataSeries(var->dataSeries()->subDataSeries(varRangesRequested.second));
485 emit var->updated();
494 emit var->updated();
486 }
495 }
487 }
496 }
488
497
489 std::shared_ptr<Variable>
498 std::shared_ptr<Variable>
490 VariableController::VariableControllerPrivate::findVariable(QUuid vIdentifier)
499 VariableController::VariableControllerPrivate::findVariable(QUuid vIdentifier)
491 {
500 {
492 std::shared_ptr<Variable> var;
501 std::shared_ptr<Variable> var;
493 auto findReply = [vIdentifier](const auto &entry) { return vIdentifier == entry.second; };
502 auto findReply = [vIdentifier](const auto &entry) { return vIdentifier == entry.second; };
494
503
495 auto end = m_VariableToIdentifierMap.cend();
504 auto end = m_VariableToIdentifierMap.cend();
496 auto it = std::find_if(m_VariableToIdentifierMap.cbegin(), end, findReply);
505 auto it = std::find_if(m_VariableToIdentifierMap.cbegin(), end, findReply);
497 if (it != end) {
506 if (it != end) {
498 var = it->first;
507 var = it->first;
499 }
508 }
500 else {
509 else {
501 qCCritical(LOG_VariableController())
510 qCCritical(LOG_VariableController())
502 << tr("Impossible to find the variable with the identifier: ") << vIdentifier;
511 << tr("Impossible to find the variable with the identifier: ") << vIdentifier;
503 }
512 }
504
513
505 return var;
514 return var;
506 }
515 }
507
516
508 std::shared_ptr<IDataSeries> VariableController::VariableControllerPrivate::retrieveDataSeries(
517 std::shared_ptr<IDataSeries> VariableController::VariableControllerPrivate::retrieveDataSeries(
509 const QVector<AcquisitionDataPacket> acqDataPacketVector)
518 const QVector<AcquisitionDataPacket> acqDataPacketVector)
510 {
519 {
511 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size")
520 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size")
512 << acqDataPacketVector.size();
521 << acqDataPacketVector.size();
513 std::shared_ptr<IDataSeries> dataSeries;
522 std::shared_ptr<IDataSeries> dataSeries;
514 if (!acqDataPacketVector.isEmpty()) {
523 if (!acqDataPacketVector.isEmpty()) {
515 dataSeries = acqDataPacketVector[0].m_DateSeries;
524 dataSeries = acqDataPacketVector[0].m_DateSeries;
516 for (int i = 1; i < acqDataPacketVector.size(); ++i) {
525 for (int i = 1; i < acqDataPacketVector.size(); ++i) {
517 dataSeries->merge(acqDataPacketVector[i].m_DateSeries.get());
526 dataSeries->merge(acqDataPacketVector[i].m_DateSeries.get());
518 }
527 }
519 }
528 }
520 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size END")
529 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size END")
521 << acqDataPacketVector.size();
530 << acqDataPacketVector.size();
522 return dataSeries;
531 return dataSeries;
523 }
532 }
524
533
525 void VariableController::VariableControllerPrivate::registerProvider(
534 void VariableController::VariableControllerPrivate::registerProvider(
526 std::shared_ptr<IDataProvider> provider)
535 std::shared_ptr<IDataProvider> provider)
527 {
536 {
528 if (m_ProviderSet.find(provider) == m_ProviderSet.end()) {
537 if (m_ProviderSet.find(provider) == m_ProviderSet.end()) {
529 qCDebug(LOG_VariableController()) << tr("Registering of a new provider")
538 qCDebug(LOG_VariableController()) << tr("Registering of a new provider")
530 << provider->objectName();
539 << provider->objectName();
531 m_ProviderSet.insert(provider);
540 m_ProviderSet.insert(provider);
532 connect(provider.get(), &IDataProvider::dataProvided, m_VariableAcquisitionWorker.get(),
541 connect(provider.get(), &IDataProvider::dataProvided, m_VariableAcquisitionWorker.get(),
533 &VariableAcquisitionWorker::onVariableDataAcquired);
542 &VariableAcquisitionWorker::onVariableDataAcquired);
534 connect(provider.get(), &IDataProvider::dataProvidedProgress,
543 connect(provider.get(), &IDataProvider::dataProvidedProgress,
535 m_VariableAcquisitionWorker.get(),
544 m_VariableAcquisitionWorker.get(),
536 &VariableAcquisitionWorker::onVariableRetrieveDataInProgress);
545 &VariableAcquisitionWorker::onVariableRetrieveDataInProgress);
537 }
546 }
538 else {
547 else {
539 qCDebug(LOG_VariableController()) << tr("Cannot register provider, it already exists ");
548 qCDebug(LOG_VariableController()) << tr("Cannot register provider, it already exists ");
540 }
549 }
541 }
550 }
@@ -1,84 +1,86
1 #ifndef SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
1 #ifndef SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
2 #define SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
2 #define SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
3
3
4 #include "Visualization/IVisualizationWidget.h"
4 #include "Visualization/IVisualizationWidget.h"
5
5
6 #include <QLoggingCategory>
6 #include <QLoggingCategory>
7 #include <QWidget>
7 #include <QWidget>
8
8
9 #include <memory>
9 #include <memory>
10
10
11 #include <Common/spimpl.h>
11 #include <Common/spimpl.h>
12
12
13 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationGraphWidget)
13 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationGraphWidget)
14
14
15 class QCPRange;
15 class QCPRange;
16 class SqpRange;
16 class SqpRange;
17 class Variable;
17 class Variable;
18
18
19 namespace Ui {
19 namespace Ui {
20 class VisualizationGraphWidget;
20 class VisualizationGraphWidget;
21 } // namespace Ui
21 } // namespace Ui
22
22
23 class VisualizationGraphWidget : public QWidget, public IVisualizationWidget {
23 class VisualizationGraphWidget : public QWidget, public IVisualizationWidget {
24 Q_OBJECT
24 Q_OBJECT
25
25
26 public:
26 public:
27 explicit VisualizationGraphWidget(const QString &name = {}, QWidget *parent = 0);
27 explicit VisualizationGraphWidget(const QString &name = {}, QWidget *parent = 0);
28 virtual ~VisualizationGraphWidget();
28 virtual ~VisualizationGraphWidget();
29
29
30 /// If acquisition isn't enable, requestDataLoading signal cannot be emit
30 /// If acquisition isn't enable, requestDataLoading signal cannot be emit
31 void enableAcquisition(bool enable);
31 void enableAcquisition(bool enable);
32
32
33 void addVariable(std::shared_ptr<Variable> variable, SqpRange range);
33 void addVariable(std::shared_ptr<Variable> variable, SqpRange range);
34
34
35 /// Removes a variable from the graph
35 /// Removes a variable from the graph
36 void removeVariable(std::shared_ptr<Variable> variable) noexcept;
36 void removeVariable(std::shared_ptr<Variable> variable) noexcept;
37
37
38 void setRange(std::shared_ptr<Variable> variable, const SqpRange &range);
38 void setRange(std::shared_ptr<Variable> variable, const SqpRange &range);
39 void setYRange(const SqpRange &range);
39 void setYRange(const SqpRange &range);
40 SqpRange graphRange() const noexcept;
40 SqpRange graphRange() const noexcept;
41 void setGraphRange(const SqpRange &range);
41 void setGraphRange(const SqpRange &range);
42
42
43 // IVisualizationWidget interface
43 // IVisualizationWidget interface
44 void accept(IVisualizationWidgetVisitor *visitor) override;
44 void accept(IVisualizationWidgetVisitor *visitor) override;
45 bool canDrop(const Variable &variable) const override;
45 bool canDrop(const Variable &variable) const override;
46 bool contains(const Variable &variable) const override;
46 bool contains(const Variable &variable) const override;
47 QString name() const override;
47 QString name() const override;
48
48
49
49
50 signals:
50 signals:
51 void synchronize(const SqpRange &range, const SqpRange &oldRange);
51 void synchronize(const SqpRange &range, const SqpRange &oldRange);
52 void requestDataLoading(QVector<std::shared_ptr<Variable> > variable, const SqpRange &range,
52 void requestDataLoading(QVector<std::shared_ptr<Variable> > variable, const SqpRange &range,
53 const SqpRange &oldRange, bool synchronise);
53 const SqpRange &oldRange, bool synchronise);
54
54
55
55
56 void variableAdded(std::shared_ptr<Variable> var);
56 void variableAdded(std::shared_ptr<Variable> var);
57
57
58
58
59 private:
59 private:
60 Ui::VisualizationGraphWidget *ui;
60 Ui::VisualizationGraphWidget *ui;
61
61
62 class VisualizationGraphWidgetPrivate;
62 class VisualizationGraphWidgetPrivate;
63 spimpl::unique_impl_ptr<VisualizationGraphWidgetPrivate> impl;
63 spimpl::unique_impl_ptr<VisualizationGraphWidgetPrivate> impl;
64
64
65 private slots:
65 private slots:
66 /// Slot called when right clicking on the graph (displays a menu)
66 /// Slot called when right clicking on the graph (displays a menu)
67 void onGraphMenuRequested(const QPoint &pos) noexcept;
67 void onGraphMenuRequested(const QPoint &pos) noexcept;
68
68
69 /// Rescale the X axe to range parameter
69 /// Rescale the X axe to range parameter
70 void onRangeChanged(const QCPRange &t1, const QCPRange &t2);
70 void onRangeChanged(const QCPRange &t1, const QCPRange &t2);
71
71
72 /// Slot called when a mouse move was made
72 /// Slot called when a mouse move was made
73 void onMouseMove(QMouseEvent *event) noexcept;
73 void onMouseMove(QMouseEvent *event) noexcept;
74 /// Slot called when a mouse wheel was made, to perform some processing before the zoom is done
74 /// Slot called when a mouse wheel was made, to perform some processing before the zoom is done
75 void onMouseWheel(QWheelEvent *event) noexcept;
75 void onMouseWheel(QWheelEvent *event) noexcept;
76 /// Slot called when a mouse press was made, to activate the calibration of a graph
76 /// Slot called when a mouse press was made, to activate the calibration of a graph
77 void onMousePress(QMouseEvent *event) noexcept;
77 void onMousePress(QMouseEvent *event) noexcept;
78 /// Slot called when a mouse release was made, to deactivate the calibration of a graph
78 /// Slot called when a mouse release was made, to deactivate the calibration of a graph
79 void onMouseRelease(QMouseEvent *event) noexcept;
79 void onMouseRelease(QMouseEvent *event) noexcept;
80
80
81 void onDataCacheVariableUpdated();
81 void onDataCacheVariableUpdated();
82
83 void onUpdateVarDisplaying(std::shared_ptr<Variable> variable, const SqpRange &range);
82 };
84 };
83
85
84 #endif // SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
86 #endif // SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
@@ -1,210 +1,195
1 #include "Visualization/VisualizationGraphHelper.h"
1 #include "Visualization/VisualizationGraphHelper.h"
2 #include "Visualization/qcustomplot.h"
2 #include "Visualization/qcustomplot.h"
3
3
4 #include <Data/ScalarSeries.h>
4 #include <Data/ScalarSeries.h>
5
5
6 #include <Variable/Variable.h>
6 #include <Variable/Variable.h>
7
7
8 Q_LOGGING_CATEGORY(LOG_VisualizationGraphHelper, "VisualizationGraphHelper")
8 Q_LOGGING_CATEGORY(LOG_VisualizationGraphHelper, "VisualizationGraphHelper")
9
9
10 namespace {
10 namespace {
11
11
12 class SqpDataContainer : public QCPGraphDataContainer {
12 class SqpDataContainer : public QCPGraphDataContainer {
13 public:
13 public:
14 void appendGraphData(const QCPGraphData &data) { mData.append(data); }
14 void appendGraphData(const QCPGraphData &data) { mData.append(data); }
15 };
15 };
16
16
17
17
18 /// Format for datetimes on a axis
18 /// Format for datetimes on a axis
19 const auto DATETIME_TICKER_FORMAT = QStringLiteral("yyyy/MM/dd \nhh:mm:ss");
19 const auto DATETIME_TICKER_FORMAT = QStringLiteral("yyyy/MM/dd \nhh:mm:ss");
20
20
21 /// Generates the appropriate ticker for an axis, depending on whether the axis displays time or
21 /// Generates the appropriate ticker for an axis, depending on whether the axis displays time or
22 /// non-time data
22 /// non-time data
23 QSharedPointer<QCPAxisTicker> axisTicker(bool isTimeAxis)
23 QSharedPointer<QCPAxisTicker> axisTicker(bool isTimeAxis)
24 {
24 {
25 if (isTimeAxis) {
25 if (isTimeAxis) {
26 auto dateTicker = QSharedPointer<QCPAxisTickerDateTime>::create();
26 auto dateTicker = QSharedPointer<QCPAxisTickerDateTime>::create();
27 dateTicker->setDateTimeFormat(DATETIME_TICKER_FORMAT);
27 dateTicker->setDateTimeFormat(DATETIME_TICKER_FORMAT);
28 dateTicker->setDateTimeSpec(Qt::UTC);
28 dateTicker->setDateTimeSpec(Qt::UTC);
29
29
30 return dateTicker;
30 return dateTicker;
31 }
31 }
32 else {
32 else {
33 // default ticker
33 // default ticker
34 return QSharedPointer<QCPAxisTicker>::create();
34 return QSharedPointer<QCPAxisTicker>::create();
35 }
35 }
36 }
36 }
37
37
38 void updateScalarData(QCPAbstractPlottable *component, std::shared_ptr<ScalarSeries> scalarSeries,
38 void updateScalarData(QCPAbstractPlottable *component, std::shared_ptr<ScalarSeries> scalarSeries,
39 const SqpRange &dateTime)
39 const SqpRange &range)
40 {
40 {
41 qCDebug(LOG_VisualizationGraphHelper()) << "TORM: updateScalarData"
41 qCDebug(LOG_VisualizationGraphHelper()) << "TORM: updateScalarData"
42 << QThread::currentThread()->objectName();
42 << QThread::currentThread()->objectName();
43 if (auto qcpGraph = dynamic_cast<QCPGraph *>(component)) {
43 if (auto qcpGraph = dynamic_cast<QCPGraph *>(component)) {
44 scalarSeries->lockRead();
44 scalarSeries->lockRead();
45 {
45 {
46 const auto &xData = scalarSeries->xAxisData()->cdata();
47 const auto &valuesData = scalarSeries->valuesData()->cdata();
48
49 auto xDataBegin = xData.cbegin();
50 auto xDataEnd = xData.cend();
51
52 qCInfo(LOG_VisualizationGraphHelper()) << "TODEBUG: Current points in cache"
53 << xData.count();
54
55 auto sqpDataContainer = QSharedPointer<SqpDataContainer>::create();
46 auto sqpDataContainer = QSharedPointer<SqpDataContainer>::create();
56 qcpGraph->setData(sqpDataContainer);
47 qcpGraph->setData(sqpDataContainer);
57
48 auto bounds = scalarSeries->subData(range.m_TStart, range.m_TEnd);
58 auto lowerIt = std::lower_bound(xDataBegin, xDataEnd, dateTime.m_TStart);
49 for (auto it = bounds.first; it != bounds.second; ++it) {
59 auto upperIt = std::upper_bound(xDataBegin, xDataEnd, dateTime.m_TEnd);
50 sqpDataContainer->appendGraphData(QCPGraphData(it->x(), it->value()));
60 auto distance = std::distance(xDataBegin, lowerIt);
61
62 auto valuesDataIt = valuesData.cbegin() + distance;
63 for (auto xAxisDataIt = lowerIt; xAxisDataIt != upperIt;
64 ++xAxisDataIt, ++valuesDataIt) {
65 sqpDataContainer->appendGraphData(QCPGraphData(*xAxisDataIt, *valuesDataIt));
66 }
51 }
67
52
68 qCInfo(LOG_VisualizationGraphHelper()) << "TODEBUG: Current points displayed"
53 qCInfo(LOG_VisualizationGraphHelper()) << "TODEBUG: Current points displayed"
69 << sqpDataContainer->size();
54 << sqpDataContainer->size();
70 }
55 }
71 scalarSeries->unlock();
56 scalarSeries->unlock();
72
57
73
58
74 // Display all data
59 // Display all data
75 component->parentPlot()->replot();
60 component->parentPlot()->replot();
76 }
61 }
77 else {
62 else {
78 /// @todo DEBUG
63 /// @todo DEBUG
79 }
64 }
80 }
65 }
81
66
82 QCPAbstractPlottable *createScalarSeriesComponentV2(std::shared_ptr<ScalarSeries> scalarSeries,
67 QCPAbstractPlottable *createScalarSeriesComponentV2(std::shared_ptr<ScalarSeries> scalarSeries,
83 QCustomPlot &plot)
68 QCustomPlot &plot)
84 {
69 {
85 auto component = plot.addGraph();
70 auto component = plot.addGraph();
86
71
87 if (component) {
72 if (component) {
88 // Axes properties
73 // Axes properties
89 /// @todo : for the moment, no control is performed on the axes: the units and the tickers
74 /// @todo : for the moment, no control is performed on the axes: the units and the tickers
90 /// are fixed for the default x-axis and y-axis of the plot, and according to the new graph
75 /// are fixed for the default x-axis and y-axis of the plot, and according to the new graph
91
76
92 auto setAxisProperties = [](auto axis, const auto &unit) {
77 auto setAxisProperties = [](auto axis, const auto &unit) {
93 // label (unit name)
78 // label (unit name)
94 axis->setLabel(unit.m_Name);
79 axis->setLabel(unit.m_Name);
95
80
96 // ticker (depending on the type of unit)
81 // ticker (depending on the type of unit)
97 axis->setTicker(axisTicker(unit.m_TimeUnit));
82 axis->setTicker(axisTicker(unit.m_TimeUnit));
98 };
83 };
99 setAxisProperties(plot.xAxis, scalarSeries->xAxisUnit());
84 setAxisProperties(plot.xAxis, scalarSeries->xAxisUnit());
100 setAxisProperties(plot.yAxis, scalarSeries->valuesUnit());
85 setAxisProperties(plot.yAxis, scalarSeries->valuesUnit());
101 }
86 }
102 return component;
87 return component;
103 }
88 }
104
89
105 QCPAbstractPlottable *createScalarSeriesComponent(std::shared_ptr<ScalarSeries> scalarSeries,
90 QCPAbstractPlottable *createScalarSeriesComponent(std::shared_ptr<ScalarSeries> scalarSeries,
106 QCustomPlot &plot, const SqpRange &dateTime)
91 QCustomPlot &plot, const SqpRange &dateTime)
107 {
92 {
108 auto component = plot.addGraph();
93 auto component = plot.addGraph();
109
94
110 if (component) {
95 if (component) {
111 // // Graph data
96 // // Graph data
112 component->setData(scalarSeries->xAxisData()->data(), scalarSeries->valuesData()->data(),
97 component->setData(scalarSeries->xAxisData()->data(), scalarSeries->valuesData()->data(),
113 true);
98 true);
114
99
115 updateScalarData(component, scalarSeries, dateTime);
100 updateScalarData(component, scalarSeries, dateTime);
116
101
117 // Axes properties
102 // Axes properties
118 /// @todo : for the moment, no control is performed on the axes: the units and the tickers
103 /// @todo : for the moment, no control is performed on the axes: the units and the tickers
119 /// are fixed for the default x-axis and y-axis of the plot, and according to the new graph
104 /// are fixed for the default x-axis and y-axis of the plot, and according to the new graph
120
105
121 auto setAxisProperties = [](auto axis, const auto &unit) {
106 auto setAxisProperties = [](auto axis, const auto &unit) {
122 // label (unit name)
107 // label (unit name)
123 axis->setLabel(unit.m_Name);
108 axis->setLabel(unit.m_Name);
124
109
125 // ticker (depending on the type of unit)
110 // ticker (depending on the type of unit)
126 axis->setTicker(axisTicker(unit.m_TimeUnit));
111 axis->setTicker(axisTicker(unit.m_TimeUnit));
127 };
112 };
128 setAxisProperties(plot.xAxis, scalarSeries->xAxisUnit());
113 setAxisProperties(plot.xAxis, scalarSeries->xAxisUnit());
129 setAxisProperties(plot.yAxis, scalarSeries->valuesUnit());
114 setAxisProperties(plot.yAxis, scalarSeries->valuesUnit());
130
115
131 // Display all data
116 // Display all data
132 component->rescaleAxes();
117 component->rescaleAxes();
133 plot.replot();
118 plot.replot();
134 }
119 }
135 else {
120 else {
136 qCDebug(LOG_VisualizationGraphHelper())
121 qCDebug(LOG_VisualizationGraphHelper())
137 << QObject::tr("Can't create graph for the scalar series");
122 << QObject::tr("Can't create graph for the scalar series");
138 }
123 }
139
124
140 return component;
125 return component;
141 }
126 }
142
127
143 } // namespace
128 } // namespace
144
129
145 QVector<QCPAbstractPlottable *>
130 QVector<QCPAbstractPlottable *>
146 VisualizationGraphHelper::createV2(std::shared_ptr<Variable> variable, QCustomPlot &plot) noexcept
131 VisualizationGraphHelper::createV2(std::shared_ptr<Variable> variable, QCustomPlot &plot) noexcept
147 {
132 {
148 auto result = QVector<QCPAbstractPlottable *>{};
133 auto result = QVector<QCPAbstractPlottable *>{};
149
134
150 if (variable) {
135 if (variable) {
151 // Gets the data series of the variable to call the creation of the right components
136 // Gets the data series of the variable to call the creation of the right components
152 // according to its type
137 // according to its type
153 if (auto scalarSeries = std::dynamic_pointer_cast<ScalarSeries>(variable->dataSeries())) {
138 if (auto scalarSeries = std::dynamic_pointer_cast<ScalarSeries>(variable->dataSeries())) {
154 result.append(createScalarSeriesComponentV2(scalarSeries, plot));
139 result.append(createScalarSeriesComponentV2(scalarSeries, plot));
155 }
140 }
156 else {
141 else {
157 qCDebug(LOG_VisualizationGraphHelper())
142 qCDebug(LOG_VisualizationGraphHelper())
158 << QObject::tr("Can't create graph plottables : unmanaged data series type");
143 << QObject::tr("Can't create graph plottables : unmanaged data series type");
159 }
144 }
160 }
145 }
161 else {
146 else {
162 qCDebug(LOG_VisualizationGraphHelper())
147 qCDebug(LOG_VisualizationGraphHelper())
163 << QObject::tr("Can't create graph plottables : the variable is null");
148 << QObject::tr("Can't create graph plottables : the variable is null");
164 }
149 }
165
150
166 return result;
151 return result;
167 }
152 }
168
153
169 QVector<QCPAbstractPlottable *> VisualizationGraphHelper::create(std::shared_ptr<Variable> variable,
154 QVector<QCPAbstractPlottable *> VisualizationGraphHelper::create(std::shared_ptr<Variable> variable,
170 QCustomPlot &plot) noexcept
155 QCustomPlot &plot) noexcept
171 {
156 {
172 auto result = QVector<QCPAbstractPlottable *>{};
157 auto result = QVector<QCPAbstractPlottable *>{};
173
158
174 if (variable) {
159 if (variable) {
175 // Gets the data series of the variable to call the creation of the right components
160 // Gets the data series of the variable to call the creation of the right components
176 // according to its type
161 // according to its type
177 if (auto scalarSeries = std::dynamic_pointer_cast<ScalarSeries>(variable->dataSeries())) {
162 if (auto scalarSeries = std::dynamic_pointer_cast<ScalarSeries>(variable->dataSeries())) {
178 result.append(createScalarSeriesComponent(scalarSeries, plot, variable->range()));
163 result.append(createScalarSeriesComponent(scalarSeries, plot, variable->range()));
179 }
164 }
180 else {
165 else {
181 qCDebug(LOG_VisualizationGraphHelper())
166 qCDebug(LOG_VisualizationGraphHelper())
182 << QObject::tr("Can't create graph plottables : unmanaged data series type");
167 << QObject::tr("Can't create graph plottables : unmanaged data series type");
183 }
168 }
184 }
169 }
185 else {
170 else {
186 qCDebug(LOG_VisualizationGraphHelper())
171 qCDebug(LOG_VisualizationGraphHelper())
187 << QObject::tr("Can't create graph plottables : the variable is null");
172 << QObject::tr("Can't create graph plottables : the variable is null");
188 }
173 }
189
174
190 return result;
175 return result;
191 }
176 }
192
177
193 void VisualizationGraphHelper::updateData(QVector<QCPAbstractPlottable *> plotableVect,
178 void VisualizationGraphHelper::updateData(QVector<QCPAbstractPlottable *> plotableVect,
194 std::shared_ptr<IDataSeries> dataSeries,
179 std::shared_ptr<IDataSeries> dataSeries,
195 const SqpRange &dateTime)
180 const SqpRange &dateTime)
196 {
181 {
197 if (auto scalarSeries = std::dynamic_pointer_cast<ScalarSeries>(dataSeries)) {
182 if (auto scalarSeries = std::dynamic_pointer_cast<ScalarSeries>(dataSeries)) {
198 if (plotableVect.size() == 1) {
183 if (plotableVect.size() == 1) {
199 updateScalarData(plotableVect.at(0), scalarSeries, dateTime);
184 updateScalarData(plotableVect.at(0), scalarSeries, dateTime);
200 }
185 }
201 else {
186 else {
202 qCCritical(LOG_VisualizationGraphHelper()) << QObject::tr(
187 qCCritical(LOG_VisualizationGraphHelper()) << QObject::tr(
203 "Can't update Data of a scalarSeries because there is not only one component "
188 "Can't update Data of a scalarSeries because there is not only one component "
204 "associated");
189 "associated");
205 }
190 }
206 }
191 }
207 else {
192 else {
208 /// @todo DEBUG
193 /// @todo DEBUG
209 }
194 }
210 }
195 }
@@ -1,307 +1,320
1 #include "Visualization/VisualizationGraphWidget.h"
1 #include "Visualization/VisualizationGraphWidget.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 #include "Visualization/VisualizationGraphHelper.h"
3 #include "Visualization/VisualizationGraphHelper.h"
4 #include "Visualization/VisualizationGraphRenderingDelegate.h"
4 #include "Visualization/VisualizationGraphRenderingDelegate.h"
5 #include "ui_VisualizationGraphWidget.h"
5 #include "ui_VisualizationGraphWidget.h"
6
6
7 #include <Data/ArrayData.h>
7 #include <Data/ArrayData.h>
8 #include <Data/IDataSeries.h>
8 #include <Data/IDataSeries.h>
9 #include <Settings/SqpSettingsDefs.h>
9 #include <Settings/SqpSettingsDefs.h>
10 #include <SqpApplication.h>
10 #include <SqpApplication.h>
11 #include <Variable/Variable.h>
11 #include <Variable/Variable.h>
12 #include <Variable/VariableController.h>
12 #include <Variable/VariableController.h>
13
13
14 #include <unordered_map>
14 #include <unordered_map>
15
15
16 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
16 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
17
17
18 namespace {
18 namespace {
19
19
20 /// Key pressed to enable zoom on horizontal axis
20 /// Key pressed to enable zoom on horizontal axis
21 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::NoModifier;
21 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::NoModifier;
22
22
23 /// Key pressed to enable zoom on vertical axis
23 /// Key pressed to enable zoom on vertical axis
24 const auto VERTICAL_ZOOM_MODIFIER = Qt::ControlModifier;
24 const auto VERTICAL_ZOOM_MODIFIER = Qt::ControlModifier;
25
25
26 } // namespace
26 } // namespace
27
27
28 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
28 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
29
29
30 explicit VisualizationGraphWidgetPrivate()
30 explicit VisualizationGraphWidgetPrivate()
31 : m_DoAcquisition{true}, m_IsCalibration{false}, m_RenderingDelegate{nullptr}
31 : m_DoAcquisition{true}, m_IsCalibration{false}, m_RenderingDelegate{nullptr}
32 {
32 {
33 }
33 }
34
34
35 // 1 variable -> n qcpplot
35 // 1 variable -> n qcpplot
36 std::multimap<std::shared_ptr<Variable>, QCPAbstractPlottable *> m_VariableToPlotMultiMap;
36 std::multimap<std::shared_ptr<Variable>, QCPAbstractPlottable *> m_VariableToPlotMultiMap;
37 bool m_DoAcquisition;
37 bool m_DoAcquisition;
38 bool m_IsCalibration;
38 bool m_IsCalibration;
39 QCPItemTracer *m_TextTracer;
39 QCPItemTracer *m_TextTracer;
40 /// Delegate used to attach rendering features to the plot
40 /// Delegate used to attach rendering features to the plot
41 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
41 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
42 };
42 };
43
43
44 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
44 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
45 : QWidget{parent},
45 : QWidget{parent},
46 ui{new Ui::VisualizationGraphWidget},
46 ui{new Ui::VisualizationGraphWidget},
47 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>()}
47 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>()}
48 {
48 {
49 ui->setupUi(this);
49 ui->setupUi(this);
50
50
51 // The delegate must be initialized after the ui as it uses the plot
51 // The delegate must be initialized after the ui as it uses the plot
52 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*ui->widget);
52 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*ui->widget);
53
53
54 ui->graphNameLabel->setText(name);
54 ui->graphNameLabel->setText(name);
55
55
56 // 'Close' options : widget is deleted when closed
56 // 'Close' options : widget is deleted when closed
57 setAttribute(Qt::WA_DeleteOnClose);
57 setAttribute(Qt::WA_DeleteOnClose);
58 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationGraphWidget::close);
58 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationGraphWidget::close);
59 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
59 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
60
60
61 // Set qcpplot properties :
61 // Set qcpplot properties :
62 // - Drag (on x-axis) and zoom are enabled
62 // - Drag (on x-axis) and zoom are enabled
63 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
63 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
64 ui->widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);
64 ui->widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);
65 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal);
65 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal);
66
66
67 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
67 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
68 connect(ui->widget, &QCustomPlot::mouseRelease, this,
68 connect(ui->widget, &QCustomPlot::mouseRelease, this,
69 &VisualizationGraphWidget::onMouseRelease);
69 &VisualizationGraphWidget::onMouseRelease);
70 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
70 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
71 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
71 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
72 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
72 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
73 &QCPAxis::rangeChanged),
73 &QCPAxis::rangeChanged),
74 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
74 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
75
75
76 // Activates menu when right clicking on the graph
76 // Activates menu when right clicking on the graph
77 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
77 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
78 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
78 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
79 &VisualizationGraphWidget::onGraphMenuRequested);
79 &VisualizationGraphWidget::onGraphMenuRequested);
80
80
81 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
81 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
82 &VariableController::onRequestDataLoading);
82 &VariableController::onRequestDataLoading);
83
84 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
85 &VisualizationGraphWidget::onUpdateVarDisplaying);
83 }
86 }
84
87
85
88
86 VisualizationGraphWidget::~VisualizationGraphWidget()
89 VisualizationGraphWidget::~VisualizationGraphWidget()
87 {
90 {
88 delete ui;
91 delete ui;
89 }
92 }
90
93
91 void VisualizationGraphWidget::enableAcquisition(bool enable)
94 void VisualizationGraphWidget::enableAcquisition(bool enable)
92 {
95 {
93 impl->m_DoAcquisition = enable;
96 impl->m_DoAcquisition = enable;
94 }
97 }
95
98
96 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
99 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
97 {
100 {
98 // Uses delegate to create the qcpplot components according to the variable
101 // Uses delegate to create the qcpplot components according to the variable
99 auto createdPlottables = VisualizationGraphHelper::createV2(variable, *ui->widget);
102 auto createdPlottables = VisualizationGraphHelper::createV2(variable, *ui->widget);
100
103
101 for (auto createdPlottable : qAsConst(createdPlottables)) {
104 for (auto createdPlottable : qAsConst(createdPlottables)) {
102 impl->m_VariableToPlotMultiMap.insert({variable, createdPlottable});
105 impl->m_VariableToPlotMultiMap.insert({variable, createdPlottable});
103 }
106 }
104
107
105 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
108 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
106
109
107 auto varRange = variable->range();
110 auto varRange = variable->range();
108
111
109 this->enableAcquisition(false);
112 this->enableAcquisition(false);
110 this->setGraphRange(range);
113 this->setGraphRange(range);
111 this->enableAcquisition(true);
114 this->enableAcquisition(true);
112
115
113 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable, range, varRange,
116 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable, range, varRange,
114 false);
117 false);
115
118
116 emit variableAdded(variable);
119 emit variableAdded(variable);
117 }
120 }
118
121
119 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
122 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
120 {
123 {
121 // Each component associated to the variable :
124 // Each component associated to the variable :
122 // - is removed from qcpplot (which deletes it)
125 // - is removed from qcpplot (which deletes it)
123 // - is no longer referenced in the map
126 // - is no longer referenced in the map
124 auto componentsIt = impl->m_VariableToPlotMultiMap.equal_range(variable);
127 auto componentsIt = impl->m_VariableToPlotMultiMap.equal_range(variable);
125 for (auto it = componentsIt.first; it != componentsIt.second;) {
128 for (auto it = componentsIt.first; it != componentsIt.second;) {
126 ui->widget->removePlottable(it->second);
129 ui->widget->removePlottable(it->second);
127 it = impl->m_VariableToPlotMultiMap.erase(it);
130 it = impl->m_VariableToPlotMultiMap.erase(it);
128 }
131 }
129
132
130 // Updates graph
133 // Updates graph
131 ui->widget->replot();
134 ui->widget->replot();
132 }
135 }
133
136
134 void VisualizationGraphWidget::setRange(std::shared_ptr<Variable> variable, const SqpRange &range)
137 void VisualizationGraphWidget::setRange(std::shared_ptr<Variable> variable, const SqpRange &range)
135 {
138 {
136 // Note: in case of different axes that depends on variable, we could start with a code like
139 // Note: in case of different axes that depends on variable, we could start with a code like
137 // that:
140 // that:
138 // auto componentsIt = impl->m_VariableToPlotMultiMap.equal_range(variable);
141 // auto componentsIt = impl->m_VariableToPlotMultiMap.equal_range(variable);
139 // for (auto it = componentsIt.first; it != componentsIt.second;) {
142 // for (auto it = componentsIt.first; it != componentsIt.second;) {
140 // }
143 // }
141 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
144 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
142 ui->widget->replot();
145 ui->widget->replot();
143 }
146 }
144
147
145 void VisualizationGraphWidget::setYRange(const SqpRange &range)
148 void VisualizationGraphWidget::setYRange(const SqpRange &range)
146 {
149 {
147 ui->widget->yAxis->setRange(range.m_TStart, range.m_TEnd);
150 ui->widget->yAxis->setRange(range.m_TStart, range.m_TEnd);
148 }
151 }
149
152
150 SqpRange VisualizationGraphWidget::graphRange() const noexcept
153 SqpRange VisualizationGraphWidget::graphRange() const noexcept
151 {
154 {
152 auto graphRange = ui->widget->xAxis->range();
155 auto graphRange = ui->widget->xAxis->range();
153 return SqpRange{graphRange.lower, graphRange.upper};
156 return SqpRange{graphRange.lower, graphRange.upper};
154 }
157 }
155
158
156 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
159 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
157 {
160 {
158 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
161 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
159 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
162 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
160 ui->widget->replot();
163 ui->widget->replot();
161 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
164 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
162 }
165 }
163
166
164 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
167 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
165 {
168 {
166 if (visitor) {
169 if (visitor) {
167 visitor->visit(this);
170 visitor->visit(this);
168 }
171 }
169 else {
172 else {
170 qCCritical(LOG_VisualizationGraphWidget())
173 qCCritical(LOG_VisualizationGraphWidget())
171 << tr("Can't visit widget : the visitor is null");
174 << tr("Can't visit widget : the visitor is null");
172 }
175 }
173 }
176 }
174
177
175 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
178 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
176 {
179 {
177 /// @todo : for the moment, a graph can always accomodate a variable
180 /// @todo : for the moment, a graph can always accomodate a variable
178 Q_UNUSED(variable);
181 Q_UNUSED(variable);
179 return true;
182 return true;
180 }
183 }
181
184
182 bool VisualizationGraphWidget::contains(const Variable &variable) const
185 bool VisualizationGraphWidget::contains(const Variable &variable) const
183 {
186 {
184 // Finds the variable among the keys of the map
187 // Finds the variable among the keys of the map
185 auto variablePtr = &variable;
188 auto variablePtr = &variable;
186 auto findVariable
189 auto findVariable
187 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
190 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
188
191
189 auto end = impl->m_VariableToPlotMultiMap.cend();
192 auto end = impl->m_VariableToPlotMultiMap.cend();
190 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
193 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
191 return it != end;
194 return it != end;
192 }
195 }
193
196
194 QString VisualizationGraphWidget::name() const
197 QString VisualizationGraphWidget::name() const
195 {
198 {
196 return ui->graphNameLabel->text();
199 return ui->graphNameLabel->text();
197 }
200 }
198
201
199 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
202 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
200 {
203 {
201 QMenu graphMenu{};
204 QMenu graphMenu{};
202
205
203 // Iterates on variables (unique keys)
206 // Iterates on variables (unique keys)
204 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
207 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
205 end = impl->m_VariableToPlotMultiMap.cend();
208 end = impl->m_VariableToPlotMultiMap.cend();
206 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
209 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
207 // 'Remove variable' action
210 // 'Remove variable' action
208 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
211 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
209 [ this, var = it->first ]() { removeVariable(var); });
212 [ this, var = it->first ]() { removeVariable(var); });
210 }
213 }
211
214
212 if (!graphMenu.isEmpty()) {
215 if (!graphMenu.isEmpty()) {
213 graphMenu.exec(mapToGlobal(pos));
216 graphMenu.exec(mapToGlobal(pos));
214 }
217 }
215 }
218 }
216
219
217 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
220 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
218 {
221 {
219 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
222 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
220 << QThread::currentThread()->objectName() << "DoAcqui"
223 << QThread::currentThread()->objectName() << "DoAcqui"
221 << impl->m_DoAcquisition;
224 << impl->m_DoAcquisition;
222
225
223 auto graphRange = SqpRange{t1.lower, t1.upper};
226 auto graphRange = SqpRange{t1.lower, t1.upper};
224 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
227 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
225
228
226 if (impl->m_DoAcquisition) {
229 if (impl->m_DoAcquisition) {
227 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
230 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
228
231
229 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
232 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
230 end = impl->m_VariableToPlotMultiMap.end();
233 end = impl->m_VariableToPlotMultiMap.end();
231 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
234 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
232 variableUnderGraphVector.push_back(it->first);
235 variableUnderGraphVector.push_back(it->first);
233 }
236 }
234 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange, oldGraphRange,
237 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange, oldGraphRange,
235 !impl->m_IsCalibration);
238 !impl->m_IsCalibration);
236
239
237 if (!impl->m_IsCalibration) {
240 if (!impl->m_IsCalibration) {
238 qCDebug(LOG_VisualizationGraphWidget())
241 qCDebug(LOG_VisualizationGraphWidget())
239 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
242 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
240 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
243 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
241 emit synchronize(graphRange, oldGraphRange);
244 emit synchronize(graphRange, oldGraphRange);
242 }
245 }
243 }
246 }
244 }
247 }
245
248
246 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
249 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
247 {
250 {
248 // Handles plot rendering when mouse is moving
251 // Handles plot rendering when mouse is moving
249 impl->m_RenderingDelegate->onMouseMove(event);
252 impl->m_RenderingDelegate->onMouseMove(event);
250 }
253 }
251
254
252 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
255 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
253 {
256 {
254 auto zoomOrientations = QFlags<Qt::Orientation>{};
257 auto zoomOrientations = QFlags<Qt::Orientation>{};
255
258
256 // Lambda that enables a zoom orientation if the key modifier related to this orientation
259 // Lambda that enables a zoom orientation if the key modifier related to this orientation
257 // has
260 // has
258 // been pressed
261 // been pressed
259 auto enableOrientation
262 auto enableOrientation
260 = [&zoomOrientations, event](const auto &orientation, const auto &modifier) {
263 = [&zoomOrientations, event](const auto &orientation, const auto &modifier) {
261 auto orientationEnabled = event->modifiers().testFlag(modifier);
264 auto orientationEnabled = event->modifiers().testFlag(modifier);
262 zoomOrientations.setFlag(orientation, orientationEnabled);
265 zoomOrientations.setFlag(orientation, orientationEnabled);
263 };
266 };
264 enableOrientation(Qt::Vertical, VERTICAL_ZOOM_MODIFIER);
267 enableOrientation(Qt::Vertical, VERTICAL_ZOOM_MODIFIER);
265 enableOrientation(Qt::Horizontal, HORIZONTAL_ZOOM_MODIFIER);
268 enableOrientation(Qt::Horizontal, HORIZONTAL_ZOOM_MODIFIER);
266
269
267 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
270 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
268 }
271 }
269
272
270 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
273 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
271 {
274 {
272 impl->m_IsCalibration = event->modifiers().testFlag(Qt::ControlModifier);
275 impl->m_IsCalibration = event->modifiers().testFlag(Qt::ControlModifier);
273 }
276 }
274
277
275 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
278 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
276 {
279 {
277 impl->m_IsCalibration = false;
280 impl->m_IsCalibration = false;
278 }
281 }
279
282
280 void VisualizationGraphWidget::onDataCacheVariableUpdated()
283 void VisualizationGraphWidget::onDataCacheVariableUpdated()
281 {
284 {
282 // NOTE:
285 // NOTE:
283 // We don't want to call the method for each component of a variable unitarily, but for
286 // We don't want to call the method for each component of a variable unitarily, but for
284 // all
287 // all
285 // its components at once (eg its three components in the case of a vector).
288 // its components at once (eg its three components in the case of a vector).
286
289
287 // The unordered_multimap does not do this easily, so the question is whether to:
290 // The unordered_multimap does not do this easily, so the question is whether to:
288 // - use an ordered_multimap and the algos of std to group the values by key
291 // - use an ordered_multimap and the algos of std to group the values by key
289 // - use a map (unique keys) and store as values directly the list of components
292 // - use a map (unique keys) and store as values directly the list of components
290
293
291 auto graphRange = ui->widget->xAxis->range();
294 auto graphRange = ui->widget->xAxis->range();
292 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
295 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
293
296
294 for (auto it = impl->m_VariableToPlotMultiMap.cbegin();
297 for (auto it = impl->m_VariableToPlotMultiMap.cbegin();
295 it != impl->m_VariableToPlotMultiMap.cend(); ++it) {
298 it != impl->m_VariableToPlotMultiMap.cend(); ++it) {
296 auto variable = it->first;
299 auto variable = it->first;
297 qCDebug(LOG_VisualizationGraphWidget())
300 qCDebug(LOG_VisualizationGraphWidget())
298 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
301 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
299 qCDebug(LOG_VisualizationGraphWidget())
302 qCDebug(LOG_VisualizationGraphWidget())
300 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
303 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
301 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
304 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
302
305
303 VisualizationGraphHelper::updateData(QVector<QCPAbstractPlottable *>{} << it->second,
306 VisualizationGraphHelper::updateData(QVector<QCPAbstractPlottable *>{} << it->second,
304 variable->dataSeries(), variable->range());
307 variable->dataSeries(), variable->range());
305 }
308 }
306 }
309 }
307 }
310 }
311
312 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
313 const SqpRange &range)
314 {
315 auto componentsIt = impl->m_VariableToPlotMultiMap.equal_range(variable);
316 for (auto it = componentsIt.first; it != componentsIt.second;) {
317 VisualizationGraphHelper::updateData(QVector<QCPAbstractPlottable *>{} << it->second,
318 variable->dataSeries(), range);
319 }
320 }
@@ -1,310 +1,310
1 #include "AmdaResultParser.h"
1 #include "AmdaResultParser.h"
2
2
3 #include <Data/ScalarSeries.h>
3 #include <Data/ScalarSeries.h>
4 #include <Data/VectorSeries.h>
4 #include <Data/VectorSeries.h>
5
5
6 #include <QObject>
6 #include <QObject>
7 #include <QtTest>
7 #include <QtTest>
8
8
9 namespace {
9 namespace {
10
10
11 /// Path for the tests
11 /// Path for the tests
12 const auto TESTS_RESOURCES_PATH
12 const auto TESTS_RESOURCES_PATH
13 = QFileInfo{QString{AMDA_TESTS_RESOURCES_DIR}, "TestAmdaResultParser"}.absoluteFilePath();
13 = QFileInfo{QString{AMDA_TESTS_RESOURCES_DIR}, "TestAmdaResultParser"}.absoluteFilePath();
14
14
15 QDateTime dateTime(int year, int month, int day, int hours, int minutes, int seconds)
15 QDateTime dateTime(int year, int month, int day, int hours, int minutes, int seconds)
16 {
16 {
17 return QDateTime{{year, month, day}, {hours, minutes, seconds}, Qt::UTC};
17 return QDateTime{{year, month, day}, {hours, minutes, seconds}, Qt::UTC};
18 }
18 }
19
19
20 /// Compares two vectors that can potentially contain NaN values
20 /// Compares two vectors that can potentially contain NaN values
21 bool compareVectors(const QVector<double> &v1, const QVector<double> &v2)
21 bool compareVectors(const QVector<double> &v1, const QVector<double> &v2)
22 {
22 {
23 if (v1.size() != v2.size()) {
23 if (v1.size() != v2.size()) {
24 return false;
24 return false;
25 }
25 }
26
26
27 auto result = true;
27 auto result = true;
28 auto v2It = v2.cbegin();
28 auto v2It = v2.cbegin();
29 for (auto v1It = v1.cbegin(), v1End = v1.cend(); v1It != v1End && result; ++v1It, ++v2It) {
29 for (auto v1It = v1.cbegin(), v1End = v1.cend(); v1It != v1End && result; ++v1It, ++v2It) {
30 auto v1Value = *v1It;
30 auto v1Value = *v1It;
31 auto v2Value = *v2It;
31 auto v2Value = *v2It;
32
32
33 // If v1 is NaN, v2 has to be NaN too
33 // If v1 is NaN, v2 has to be NaN too
34 result = std::isnan(v1Value) ? std::isnan(v2Value) : (v1Value == v2Value);
34 result = std::isnan(v1Value) ? std::isnan(v2Value) : (v1Value == v2Value);
35 }
35 }
36
36
37 return result;
37 return result;
38 }
38 }
39
39
40 bool compareVectors(const QVector<QVector<double> > &v1, const QVector<QVector<double> > &v2)
40 bool compareVectors(const QVector<QVector<double> > &v1, const QVector<QVector<double> > &v2)
41 {
41 {
42 if (v1.size() != v2.size()) {
42 if (v1.size() != v2.size()) {
43 return false;
43 return false;
44 }
44 }
45
45
46 auto result = true;
46 auto result = true;
47 for (auto i = 0; i < v1.size() && result; ++i) {
47 for (auto i = 0; i < v1.size() && result; ++i) {
48 result &= compareVectors(v1.at(i), v2.at(i));
48 result &= compareVectors(v1.at(i), v2.at(i));
49 }
49 }
50
50
51 return result;
51 return result;
52 }
52 }
53
53
54 QVector<QVector<double> > valuesData(const ArrayData<1> &arrayData)
54 QVector<QVector<double> > valuesData(const ArrayData<1> &arrayData)
55 {
55 {
56 return QVector<QVector<double> >{arrayData.data()};
56 return QVector<QVector<double> >{arrayData.data()};
57 }
57 }
58
58
59 QVector<QVector<double> > valuesData(const ArrayData<2> &arrayData)
59 QVector<QVector<double> > valuesData(const ArrayData<2> &arrayData)
60 {
60 {
61 return arrayData.data();
61 return arrayData.data();
62 }
62 }
63
63
64
64
65 QString inputFilePath(const QString &inputFileName)
65 QString inputFilePath(const QString &inputFileName)
66 {
66 {
67 return QFileInfo{TESTS_RESOURCES_PATH, inputFileName}.absoluteFilePath();
67 return QFileInfo{TESTS_RESOURCES_PATH, inputFileName}.absoluteFilePath();
68 }
68 }
69
69
70 template <typename T>
70 template <typename T>
71 struct ExpectedResults {
71 struct ExpectedResults {
72 explicit ExpectedResults() = default;
72 explicit ExpectedResults() = default;
73
73
74 explicit ExpectedResults(Unit xAxisUnit, Unit valuesUnit, const QVector<QDateTime> &xAxisData,
74 explicit ExpectedResults(Unit xAxisUnit, Unit valuesUnit, const QVector<QDateTime> &xAxisData,
75 QVector<double> valuesData)
75 QVector<double> valuesData)
76 : ExpectedResults(xAxisUnit, valuesUnit, xAxisData,
76 : ExpectedResults(xAxisUnit, valuesUnit, xAxisData,
77 QVector<QVector<double> >{std::move(valuesData)})
77 QVector<QVector<double> >{std::move(valuesData)})
78 {
78 {
79 }
79 }
80
80
81 /// Ctor with QVector<QDateTime> as x-axis data. Datetimes are converted to doubles
81 /// Ctor with QVector<QDateTime> as x-axis data. Datetimes are converted to doubles
82 explicit ExpectedResults(Unit xAxisUnit, Unit valuesUnit, const QVector<QDateTime> &xAxisData,
82 explicit ExpectedResults(Unit xAxisUnit, Unit valuesUnit, const QVector<QDateTime> &xAxisData,
83 QVector<QVector<double> > valuesData)
83 QVector<QVector<double> > valuesData)
84 : m_ParsingOK{true},
84 : m_ParsingOK{true},
85 m_XAxisUnit{xAxisUnit},
85 m_XAxisUnit{xAxisUnit},
86 m_ValuesUnit{valuesUnit},
86 m_ValuesUnit{valuesUnit},
87 m_XAxisData{},
87 m_XAxisData{},
88 m_ValuesData{std::move(valuesData)}
88 m_ValuesData{std::move(valuesData)}
89 {
89 {
90 // Converts QVector<QDateTime> to QVector<double>
90 // Converts QVector<QDateTime> to QVector<double>
91 std::transform(xAxisData.cbegin(), xAxisData.cend(), std::back_inserter(m_XAxisData),
91 std::transform(xAxisData.cbegin(), xAxisData.cend(), std::back_inserter(m_XAxisData),
92 [](const auto &dateTime) { return dateTime.toMSecsSinceEpoch() / 1000.; });
92 [](const auto &dateTime) { return dateTime.toMSecsSinceEpoch() / 1000.; });
93 }
93 }
94
94
95 /**
95 /**
96 * Validates a DataSeries compared to the expected results
96 * Validates a DataSeries compared to the expected results
97 * @param results the DataSeries to validate
97 * @param results the DataSeries to validate
98 */
98 */
99 void validate(std::shared_ptr<IDataSeries> results)
99 void validate(std::shared_ptr<IDataSeries> results)
100 {
100 {
101 if (m_ParsingOK) {
101 if (m_ParsingOK) {
102 auto dataSeries = dynamic_cast<T *>(results.get());
102 auto dataSeries = dynamic_cast<T *>(results.get());
103 QVERIFY(dataSeries != nullptr);
103 QVERIFY(dataSeries != nullptr);
104
104
105 // Checks units
105 // Checks units
106 QVERIFY(dataSeries->xAxisUnit() == m_XAxisUnit);
106 QVERIFY(dataSeries->xAxisUnit() == m_XAxisUnit);
107 QVERIFY(dataSeries->valuesUnit() == m_ValuesUnit);
107 QVERIFY(dataSeries->valuesUnit() == m_ValuesUnit);
108
108
109 // Checks values : as the vectors can potentially contain NaN values, we must use a
109 // Checks values : as the vectors can potentially contain NaN values, we must use a
110 // custom vector comparison method
110 // custom vector comparison method
111 QVERIFY(compareVectors(dataSeries->xAxisData()->data(), m_XAxisData));
111 QVERIFY(compareVectors(dataSeries->xAxisData()->data(), m_XAxisData));
112 QVERIFY(compareVectors(valuesData(*dataSeries->valuesData()), m_ValuesData));
112 QVERIFY(compareVectors(valuesData(*dataSeries->valuesData()), m_ValuesData));
113 }
113 }
114 else {
114 else {
115 QVERIFY(results == nullptr);
115 QVERIFY(results == nullptr);
116 }
116 }
117 }
117 }
118
118
119 // Parsing was successfully completed
119 // Parsing was successfully completed
120 bool m_ParsingOK{false};
120 bool m_ParsingOK{false};
121 // Expected x-axis unit
121 // Expected x-axis unit
122 Unit m_XAxisUnit{};
122 Unit m_XAxisUnit{};
123 // Expected values unit
123 // Expected values unit
124 Unit m_ValuesUnit{};
124 Unit m_ValuesUnit{};
125 // Expected x-axis data
125 // Expected x-axis data
126 QVector<double> m_XAxisData{};
126 QVector<double> m_XAxisData{};
127 // Expected values data
127 // Expected values data
128 QVector<QVector<double> > m_ValuesData{};
128 QVector<QVector<double> > m_ValuesData{};
129 };
129 };
130
130
131 } // namespace
131 } // namespace
132
132
133 Q_DECLARE_METATYPE(ExpectedResults<ScalarSeries>)
133 Q_DECLARE_METATYPE(ExpectedResults<ScalarSeries>)
134 Q_DECLARE_METATYPE(ExpectedResults<VectorSeries>)
134 Q_DECLARE_METATYPE(ExpectedResults<VectorSeries>)
135
135
136 class TestAmdaResultParser : public QObject {
136 class TestAmdaResultParser : public QObject {
137 Q_OBJECT
137 Q_OBJECT
138 private:
138 private:
139 template <typename T>
139 template <typename T>
140 void testReadDataStructure()
140 void testReadDataStructure()
141 {
141 {
142 // ////////////// //
142 // ////////////// //
143 // Test structure //
143 // Test structure //
144 // ////////////// //
144 // ////////////// //
145
145
146 // Name of TXT file to read
146 // Name of TXT file to read
147 QTest::addColumn<QString>("inputFileName");
147 QTest::addColumn<QString>("inputFileName");
148 // Expected results
148 // Expected results
149 QTest::addColumn<ExpectedResults<T> >("expectedResults");
149 QTest::addColumn<ExpectedResults<T> >("expectedResults");
150 }
150 }
151
151
152 template <typename T>
152 template <typename T>
153 void testRead(AmdaResultParser::ValueType valueType)
153 void testRead(AmdaResultParser::ValueType valueType)
154 {
154 {
155 QFETCH(QString, inputFileName);
155 QFETCH(QString, inputFileName);
156 QFETCH(ExpectedResults<T>, expectedResults);
156 QFETCH(ExpectedResults<T>, expectedResults);
157
157
158 // Parses file
158 // Parses file
159 auto filePath = inputFilePath(inputFileName);
159 auto filePath = inputFilePath(inputFileName);
160 auto results = AmdaResultParser::readTxt(filePath, valueType);
160 auto results = AmdaResultParser::readTxt(filePath, valueType);
161
161
162 // ///////////////// //
162 // ///////////////// //
163 // Validates results //
163 // Validates results //
164 // ///////////////// //
164 // ///////////////// //
165 expectedResults.validate(results);
165 expectedResults.validate(results);
166 }
166 }
167
167
168 private slots:
168 private slots:
169 /// Input test data
169 /// Input test data
170 /// @sa testReadScalarTxt()
170 /// @sa testReadScalarTxt()
171 void testReadScalarTxt_data();
171 void testReadScalarTxt_data();
172
172
173 /// Tests parsing scalar series of a TXT file
173 /// Tests parsing scalar series of a TXT file
174 void testReadScalarTxt();
174 void testReadScalarTxt();
175
175
176 /// Input test data
176 /// Input test data
177 /// @sa testReadVectorTxt()
177 /// @sa testReadVectorTxt()
178 void testReadVectorTxt_data();
178 void testReadVectorTxt_data();
179
179
180 /// Tests parsing vector series of a TXT file
180 /// Tests parsing vector series of a TXT file
181 void testReadVectorTxt();
181 void testReadVectorTxt();
182 };
182 };
183
183
184 void TestAmdaResultParser::testReadScalarTxt_data()
184 void TestAmdaResultParser::testReadScalarTxt_data()
185 {
185 {
186 testReadDataStructure<ScalarSeries>();
186 testReadDataStructure<ScalarSeries>();
187
187
188 // ////////// //
188 // ////////// //
189 // Test cases //
189 // Test cases //
190 // ////////// //
190 // ////////// //
191
191
192 // Valid files
192 // Valid files
193 QTest::newRow("Valid file")
193 QTest::newRow("Valid file")
194 << QStringLiteral("ValidScalar1.txt")
194 << QStringLiteral("ValidScalar1.txt")
195 << ExpectedResults<ScalarSeries>{
195 << ExpectedResults<ScalarSeries>{
196 Unit{QStringLiteral("nT"), true}, Unit{},
196 Unit{QStringLiteral("nT"), true}, Unit{},
197 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 0, 30), dateTime(2013, 9, 23, 9, 1, 30),
197 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 0, 30), dateTime(2013, 9, 23, 9, 1, 30),
198 dateTime(2013, 9, 23, 9, 2, 30), dateTime(2013, 9, 23, 9, 3, 30),
198 dateTime(2013, 9, 23, 9, 2, 30), dateTime(2013, 9, 23, 9, 3, 30),
199 dateTime(2013, 9, 23, 9, 4, 30), dateTime(2013, 9, 23, 9, 5, 30),
199 dateTime(2013, 9, 23, 9, 4, 30), dateTime(2013, 9, 23, 9, 5, 30),
200 dateTime(2013, 9, 23, 9, 6, 30), dateTime(2013, 9, 23, 9, 7, 30),
200 dateTime(2013, 9, 23, 9, 6, 30), dateTime(2013, 9, 23, 9, 7, 30),
201 dateTime(2013, 9, 23, 9, 8, 30), dateTime(2013, 9, 23, 9, 9, 30)},
201 dateTime(2013, 9, 23, 9, 8, 30), dateTime(2013, 9, 23, 9, 9, 30)},
202 QVector<double>{-2.83950, -2.71850, -2.52150, -2.57633, -2.58050, -2.48325, -2.63025,
202 QVector<double>{-2.83950, -2.71850, -2.52150, -2.57633, -2.58050, -2.48325, -2.63025,
203 -2.55800, -2.43250, -2.42200}};
203 -2.55800, -2.43250, -2.42200}};
204
204
205 QTest::newRow("Valid file (value of first line is invalid but it is converted to NaN")
205 QTest::newRow("Valid file (value of first line is invalid but it is converted to NaN")
206 << QStringLiteral("WrongValue.txt")
206 << QStringLiteral("WrongValue.txt")
207 << ExpectedResults<ScalarSeries>{
207 << ExpectedResults<ScalarSeries>{
208 Unit{QStringLiteral("nT"), true}, Unit{},
208 Unit{QStringLiteral("nT"), true}, Unit{},
209 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 0, 30), dateTime(2013, 9, 23, 9, 1, 30),
209 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 0, 30), dateTime(2013, 9, 23, 9, 1, 30),
210 dateTime(2013, 9, 23, 9, 2, 30)},
210 dateTime(2013, 9, 23, 9, 2, 30)},
211 QVector<double>{std::numeric_limits<double>::quiet_NaN(), -2.71850, -2.52150}};
211 QVector<double>{std::numeric_limits<double>::quiet_NaN(), -2.71850, -2.52150}};
212
212
213 QTest::newRow("Valid file that contains NaN values")
213 QTest::newRow("Valid file that contains NaN values")
214 << QStringLiteral("NaNValue.txt")
214 << QStringLiteral("NaNValue.txt")
215 << ExpectedResults<ScalarSeries>{
215 << ExpectedResults<ScalarSeries>{
216 Unit{QStringLiteral("nT"), true}, Unit{},
216 Unit{QStringLiteral("nT"), true}, Unit{},
217 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 0, 30), dateTime(2013, 9, 23, 9, 1, 30),
217 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 0, 30), dateTime(2013, 9, 23, 9, 1, 30),
218 dateTime(2013, 9, 23, 9, 2, 30)},
218 dateTime(2013, 9, 23, 9, 2, 30)},
219 QVector<double>{std::numeric_limits<double>::quiet_NaN(), -2.71850, -2.52150}};
219 QVector<double>{std::numeric_limits<double>::quiet_NaN(), -2.71850, -2.52150}};
220
220
221 // Valid files but with some invalid lines (wrong unit, wrong values, etc.)
221 // Valid files but with some invalid lines (wrong unit, wrong values, etc.)
222 QTest::newRow("No unit file") << QStringLiteral("NoUnit.txt")
222 QTest::newRow("No unit file") << QStringLiteral("NoUnit.txt")
223 << ExpectedResults<ScalarSeries>{Unit{QStringLiteral(""), true},
223 << ExpectedResults<ScalarSeries>{Unit{QStringLiteral(""), true},
224 Unit{}, QVector<QDateTime>{},
224 Unit{}, QVector<QDateTime>{},
225 QVector<double>{}};
225 QVector<double>{}};
226 QTest::newRow("Wrong unit file")
226 QTest::newRow("Wrong unit file")
227 << QStringLiteral("WrongUnit.txt")
227 << QStringLiteral("WrongUnit.txt")
228 << ExpectedResults<ScalarSeries>{Unit{QStringLiteral(""), true}, Unit{},
228 << ExpectedResults<ScalarSeries>{Unit{QStringLiteral(""), true}, Unit{},
229 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 0, 30),
229 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 0, 30),
230 dateTime(2013, 9, 23, 9, 1, 30),
230 dateTime(2013, 9, 23, 9, 1, 30),
231 dateTime(2013, 9, 23, 9, 2, 30)},
231 dateTime(2013, 9, 23, 9, 2, 30)},
232 QVector<double>{-2.83950, -2.71850, -2.52150}};
232 QVector<double>{-2.83950, -2.71850, -2.52150}};
233
233
234 QTest::newRow("Wrong results file (date of first line is invalid")
234 QTest::newRow("Wrong results file (date of first line is invalid")
235 << QStringLiteral("WrongDate.txt")
235 << QStringLiteral("WrongDate.txt")
236 << ExpectedResults<ScalarSeries>{
236 << ExpectedResults<ScalarSeries>{
237 Unit{QStringLiteral("nT"), true}, Unit{},
237 Unit{QStringLiteral("nT"), true}, Unit{},
238 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)},
238 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)},
239 QVector<double>{-2.71850, -2.52150}};
239 QVector<double>{-2.71850, -2.52150}};
240
240
241 QTest::newRow("Wrong results file (too many values for first line")
241 QTest::newRow("Wrong results file (too many values for first line")
242 << QStringLiteral("TooManyValues.txt")
242 << QStringLiteral("TooManyValues.txt")
243 << ExpectedResults<ScalarSeries>{
243 << ExpectedResults<ScalarSeries>{
244 Unit{QStringLiteral("nT"), true}, Unit{},
244 Unit{QStringLiteral("nT"), true}, Unit{},
245 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)},
245 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)},
246 QVector<double>{-2.71850, -2.52150}};
246 QVector<double>{-2.71850, -2.52150}};
247
247
248 QTest::newRow("Wrong results file (x of first line is NaN")
248 QTest::newRow("Wrong results file (x of first line is NaN")
249 << QStringLiteral("NaNX.txt")
249 << QStringLiteral("NaNX.txt")
250 << ExpectedResults<ScalarSeries>{
250 << ExpectedResults<ScalarSeries>{
251 Unit{QStringLiteral("nT"), true}, Unit{},
251 Unit{QStringLiteral("nT"), true}, Unit{},
252 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)},
252 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)},
253 QVector<double>{-2.71850, -2.52150}};
253 QVector<double>{-2.71850, -2.52150}};
254
254
255 QTest::newRow("Invalid file type (vector)")
255 QTest::newRow("Invalid file type (vector)")
256 << QStringLiteral("ValidVector1.txt")
256 << QStringLiteral("ValidVector1.txt")
257 << ExpectedResults<ScalarSeries>{Unit{QStringLiteral("nT"), true}, Unit{},
257 << ExpectedResults<ScalarSeries>{Unit{QStringLiteral("nT"), true}, Unit{},
258 QVector<QDateTime>{}, QVector<double>{}};
258 QVector<QDateTime>{}, QVector<double>{}};
259
259
260 // Invalid files
260 // Invalid files
261 QTest::newRow("Invalid file (unexisting file)")
261 QTest::newRow("Invalid file (unexisting file)") << QStringLiteral("UnexistingFile.txt")
262 << QStringLiteral("UnexistingFile.txt") << ExpectedResults<ScalarSeries>{};
262 << ExpectedResults<ScalarSeries>{};
263
263
264 QTest::newRow("Invalid file (file not found on server)")
264 QTest::newRow("Invalid file (file not found on server)") << QStringLiteral("FileNotFound.txt")
265 << QStringLiteral("FileNotFound.txt") << ExpectedResults<ScalarSeries>{};
265 << ExpectedResults<ScalarSeries>{};
266 }
266 }
267
267
268 void TestAmdaResultParser::testReadScalarTxt()
268 void TestAmdaResultParser::testReadScalarTxt()
269 {
269 {
270 testRead<ScalarSeries>(AmdaResultParser::ValueType::SCALAR);
270 testRead<ScalarSeries>(AmdaResultParser::ValueType::SCALAR);
271 }
271 }
272
272
273 void TestAmdaResultParser::testReadVectorTxt_data()
273 void TestAmdaResultParser::testReadVectorTxt_data()
274 {
274 {
275 testReadDataStructure<VectorSeries>();
275 testReadDataStructure<VectorSeries>();
276
276
277 // ////////// //
277 // ////////// //
278 // Test cases //
278 // Test cases //
279 // ////////// //
279 // ////////// //
280
280
281 // Valid files
281 // Valid files
282 QTest::newRow("Valid file")
282 QTest::newRow("Valid file")
283 << QStringLiteral("ValidVector1.txt")
283 << QStringLiteral("ValidVector1.txt")
284 << ExpectedResults<VectorSeries>{
284 << ExpectedResults<VectorSeries>{
285 Unit{QStringLiteral("nT"), true}, Unit{},
285 Unit{QStringLiteral("nT"), true}, Unit{},
286 QVector<QDateTime>{dateTime(2013, 7, 2, 9, 13, 50), dateTime(2013, 7, 2, 9, 14, 6),
286 QVector<QDateTime>{dateTime(2013, 7, 2, 9, 13, 50), dateTime(2013, 7, 2, 9, 14, 6),
287 dateTime(2013, 7, 2, 9, 14, 22), dateTime(2013, 7, 2, 9, 14, 38),
287 dateTime(2013, 7, 2, 9, 14, 22), dateTime(2013, 7, 2, 9, 14, 38),
288 dateTime(2013, 7, 2, 9, 14, 54), dateTime(2013, 7, 2, 9, 15, 10),
288 dateTime(2013, 7, 2, 9, 14, 54), dateTime(2013, 7, 2, 9, 15, 10),
289 dateTime(2013, 7, 2, 9, 15, 26), dateTime(2013, 7, 2, 9, 15, 42),
289 dateTime(2013, 7, 2, 9, 15, 26), dateTime(2013, 7, 2, 9, 15, 42),
290 dateTime(2013, 7, 2, 9, 15, 58), dateTime(2013, 7, 2, 9, 16, 14)},
290 dateTime(2013, 7, 2, 9, 15, 58), dateTime(2013, 7, 2, 9, 16, 14)},
291 QVector<QVector<double> >{
291 QVector<QVector<double> >{
292 {-0.332, -1.011, -1.457, -1.293, -1.217, -1.443, -1.278, -1.202, -1.22, -1.259},
292 {-0.332, -1.011, -1.457, -1.293, -1.217, -1.443, -1.278, -1.202, -1.22, -1.259},
293 {3.206, 2.999, 2.785, 2.736, 2.612, 2.564, 2.892, 2.862, 2.859, 2.764},
293 {3.206, 2.999, 2.785, 2.736, 2.612, 2.564, 2.892, 2.862, 2.859, 2.764},
294 {0.058, 0.496, 1.018, 1.485, 1.662, 1.505, 1.168, 1.244, 1.15, 1.358}}};
294 {0.058, 0.496, 1.018, 1.485, 1.662, 1.505, 1.168, 1.244, 1.15, 1.358}}};
295
295
296 // Valid files but with some invalid lines (wrong unit, wrong values, etc.)
296 // Valid files but with some invalid lines (wrong unit, wrong values, etc.)
297 QTest::newRow("Invalid file type (scalar)")
297 QTest::newRow("Invalid file type (scalar)")
298 << QStringLiteral("ValidScalar1.txt")
298 << QStringLiteral("ValidScalar1.txt")
299 << ExpectedResults<VectorSeries>{Unit{QStringLiteral("nT"), true}, Unit{},
299 << ExpectedResults<VectorSeries>{Unit{QStringLiteral("nT"), true}, Unit{},
300 QVector<QDateTime>{},
300 QVector<QDateTime>{},
301 QVector<QVector<double> >{{}, {}, {}}};
301 QVector<QVector<double> >{{}, {}, {}}};
302 }
302 }
303
303
304 void TestAmdaResultParser::testReadVectorTxt()
304 void TestAmdaResultParser::testReadVectorTxt()
305 {
305 {
306 testRead<VectorSeries>(AmdaResultParser::ValueType::VECTOR);
306 testRead<VectorSeries>(AmdaResultParser::ValueType::VECTOR);
307 }
307 }
308
308
309 QTEST_MAIN(TestAmdaResultParser)
309 QTEST_MAIN(TestAmdaResultParser)
310 #include "TestAmdaResultParser.moc"
310 #include "TestAmdaResultParser.moc"
General Comments 0
You need to be logged in to leave comments. Login now