##// END OF EJS Templates
Merge pull request 306 from SciQLop-fork develop...
perrinel -
r820:0b4649618604 merge
parent child
Show More
@@ -1,83 +1,89
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/DataSeriesIterator.h>
6 #include <Data/DataSeriesIterator.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/MetaTypes.h>
12 #include <Common/MetaTypes.h>
13 #include <Common/spimpl.h>
13 #include <Common/spimpl.h>
14
14
15 Q_DECLARE_LOGGING_CATEGORY(LOG_Variable)
15 Q_DECLARE_LOGGING_CATEGORY(LOG_Variable)
16
16
17 class IDataSeries;
17 class IDataSeries;
18 class QString;
18 class QString;
19
19
20 /**
20 /**
21 * @brief The Variable class represents a variable in SciQlop.
21 * @brief The Variable class represents a variable in SciQlop.
22 */
22 */
23 class SCIQLOP_CORE_EXPORT Variable : public QObject {
23 class SCIQLOP_CORE_EXPORT Variable : public QObject {
24
24
25 Q_OBJECT
25 Q_OBJECT
26
26
27 public:
27 public:
28 explicit Variable(const QString &name, const QVariantHash &metadata = {});
28 explicit Variable(const QString &name, const QVariantHash &metadata = {});
29
29
30 /// Copy ctor
30 /// Copy ctor
31 explicit Variable(const Variable &other);
31 explicit Variable(const Variable &other);
32
32
33 std::shared_ptr<Variable> clone() const;
33 std::shared_ptr<Variable> clone() const;
34
34
35 QString name() const noexcept;
35 QString name() const noexcept;
36 void setName(const QString &name) noexcept;
36 void setName(const QString &name) noexcept;
37 SqpRange range() const noexcept;
37 SqpRange range() const noexcept;
38 void setRange(const SqpRange &range) noexcept;
38 void setRange(const SqpRange &range) noexcept;
39 SqpRange cacheRange() const noexcept;
39 SqpRange cacheRange() const noexcept;
40 void setCacheRange(const SqpRange &cacheRange) noexcept;
40 void setCacheRange(const SqpRange &cacheRange) noexcept;
41
41
42 /// @return the number of points hold by the variable. The number of points is updated each time
42 /// @return the number of points hold by the variable. The number of points is updated each time
43 /// the data series changes
43 /// the data series changes
44 int nbPoints() const noexcept;
44 int nbPoints() const noexcept;
45
45
46 /// Returns the real range of the variable, i.e. the min and max x-axis values of the data
46 /// Returns the real range of the variable, i.e. the min and max x-axis values of the data
47 /// series between the range of the variable. The real range is updated each time the variable
47 /// series between the range of the variable. The real range is updated each time the variable
48 /// range or the data series changed
48 /// range or the data series changed
49 /// @return the real range, invalid range if the data series is null or empty
49 /// @return the real range, invalid range if the data series is null or empty
50 /// @sa setDataSeries()
50 /// @sa setDataSeries()
51 /// @sa setRange()
51 /// @sa setRange()
52 SqpRange realRange() const noexcept;
52 SqpRange realRange() const noexcept;
53
53
54 /// @return the data of the variable, nullptr if there is no data
54 /// @return the data of the variable, nullptr if there is no data
55 std::shared_ptr<IDataSeries> dataSeries() const noexcept;
55 std::shared_ptr<IDataSeries> dataSeries() const noexcept;
56
56
57 QVariantHash metadata() const noexcept;
57 QVariantHash metadata() const noexcept;
58
58
59 bool contains(const SqpRange &range) const noexcept;
59 bool contains(const SqpRange &range) const noexcept;
60 bool intersect(const SqpRange &range) const noexcept;
60 bool intersect(const SqpRange &range) const noexcept;
61 bool isInside(const SqpRange &range) const noexcept;
61 bool isInside(const SqpRange &range) const noexcept;
62
62
63 bool cacheContains(const SqpRange &range) const noexcept;
63 bool cacheContains(const SqpRange &range) const noexcept;
64 bool cacheIntersect(const SqpRange &range) const noexcept;
64 bool cacheIntersect(const SqpRange &range) const noexcept;
65 bool cacheIsInside(const SqpRange &range) const noexcept;
65 bool cacheIsInside(const SqpRange &range) const noexcept;
66
66
67 QVector<SqpRange> provideNotInCacheRangeList(const SqpRange &range) const noexcept;
67 QVector<SqpRange> provideNotInCacheRangeList(const SqpRange &range) const noexcept;
68 QVector<SqpRange> provideInCacheRangeList(const SqpRange &range) const noexcept;
68 QVector<SqpRange> provideInCacheRangeList(const SqpRange &range) const noexcept;
69 void mergeDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept;
69 void mergeDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept;
70
70
71 static QVector<SqpRange> provideNotInCacheRangeList(const SqpRange &oldRange,
72 const SqpRange &nextRange);
73
74 static QVector<SqpRange> provideInCacheRangeList(const SqpRange &oldRange,
75 const SqpRange &nextRange);
76
71 signals:
77 signals:
72 void updated();
78 void updated();
73
79
74 private:
80 private:
75 class VariablePrivate;
81 class VariablePrivate;
76 spimpl::unique_impl_ptr<VariablePrivate> impl;
82 spimpl::unique_impl_ptr<VariablePrivate> impl;
77 };
83 };
78
84
79 // Required for using shared_ptr in signals/slots
85 // Required for using shared_ptr in signals/slots
80 SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_REGISTRY, std::shared_ptr<Variable>)
86 SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_REGISTRY, std::shared_ptr<Variable>)
81 SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_VECTOR_REGISTRY, QVector<std::shared_ptr<Variable> >)
87 SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_VECTOR_REGISTRY, QVector<std::shared_ptr<Variable> >)
82
88
83 #endif // SCIQLOP_VARIABLE_H
89 #endif // SCIQLOP_VARIABLE_H
@@ -1,130 +1,130
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 #include <QUuid>
11 #include <QUuid>
12
12
13 #include <Common/spimpl.h>
13 #include <Common/spimpl.h>
14
14
15 class IDataProvider;
15 class IDataProvider;
16 class QItemSelectionModel;
16 class QItemSelectionModel;
17 class TimeController;
17 class TimeController;
18 class Variable;
18 class Variable;
19 class VariableModel;
19 class VariableModel;
20
20
21 Q_DECLARE_LOGGING_CATEGORY(LOG_VariableController)
21 Q_DECLARE_LOGGING_CATEGORY(LOG_VariableController)
22
22
23
23
24 /**
24 /**
25 * Possible types of zoom operation
25 * Possible types of zoom operation
26 */
26 */
27 enum class AcquisitionZoomType { ZoomOut, ZoomIn, PanRight, PanLeft, Unknown };
27 enum class AcquisitionZoomType { ZoomOut, ZoomIn, PanRight, PanLeft, Unknown };
28
28
29
29
30 /**
30 /**
31 * @brief The VariableController class aims to handle the variables in SciQlop.
31 * @brief The VariableController class aims to handle the variables in SciQlop.
32 */
32 */
33 class SCIQLOP_CORE_EXPORT VariableController : public QObject {
33 class SCIQLOP_CORE_EXPORT VariableController : public QObject {
34 Q_OBJECT
34 Q_OBJECT
35 public:
35 public:
36 explicit VariableController(QObject *parent = 0);
36 explicit VariableController(QObject *parent = 0);
37 virtual ~VariableController();
37 virtual ~VariableController();
38
38
39 VariableModel *variableModel() noexcept;
39 VariableModel *variableModel() noexcept;
40 QItemSelectionModel *variableSelectionModel() noexcept;
40 QItemSelectionModel *variableSelectionModel() noexcept;
41
41
42 void setTimeController(TimeController *timeController) noexcept;
42 void setTimeController(TimeController *timeController) noexcept;
43
43
44 /**
44 /**
45 * Clones the variable passed in parameter and adds the duplicate to the controller
45 * Clones the variable passed in parameter and adds the duplicate to the controller
46 * @param variable the variable to duplicate
46 * @param variable the variable to duplicate
47 * @return the duplicate created, nullptr if the variable couldn't be created
47 * @return the duplicate created, nullptr if the variable couldn't be created
48 */
48 */
49 std::shared_ptr<Variable> cloneVariable(std::shared_ptr<Variable> variable) noexcept;
49 std::shared_ptr<Variable> cloneVariable(std::shared_ptr<Variable> variable) noexcept;
50
50
51 /**
51 /**
52 * Deletes from the controller the variable passed in parameter.
52 * Deletes from the controller the variable passed in parameter.
53 *
53 *
54 * Delete a variable includes:
54 * Delete a variable includes:
55 * - the deletion of the various references to the variable in SciQlop
55 * - the deletion of the various references to the variable in SciQlop
56 * - the deletion of the model variable
56 * - the deletion of the model variable
57 * - the deletion of the provider associated with the variable
57 * - the deletion of the provider associated with the variable
58 * - removing the cache associated with the variable
58 * - removing the cache associated with the variable
59 *
59 *
60 * @param variable the variable to delete from the controller.
60 * @param variable the variable to delete from the controller.
61 */
61 */
62 void deleteVariable(std::shared_ptr<Variable> variable) noexcept;
62 void deleteVariable(std::shared_ptr<Variable> variable) noexcept;
63
63
64 /**
64 /**
65 * Deletes from the controller the variables passed in parameter.
65 * Deletes from the controller the variables passed in parameter.
66 * @param variables the variables to delete from the controller.
66 * @param variables the variables to delete from the controller.
67 * @sa deleteVariable()
67 * @sa deleteVariable()
68 */
68 */
69 void deleteVariables(const QVector<std::shared_ptr<Variable> > &variables) noexcept;
69 void deleteVariables(const QVector<std::shared_ptr<Variable> > &variables) noexcept;
70
70
71
71
72 static AcquisitionZoomType getZoomType(const SqpRange &range, const SqpRange &oldRange);
72 static AcquisitionZoomType getZoomType(const SqpRange &range, const SqpRange &oldRange);
73 signals:
73 signals:
74 /// Signal emitted when a variable is about to be deleted from the controller
74 /// Signal emitted when a variable is about to be deleted from the controller
75 void variableAboutToBeDeleted(std::shared_ptr<Variable> variable);
75 void variableAboutToBeDeleted(std::shared_ptr<Variable> variable);
76
76
77 /// Signal emitted when a data acquisition is requested on a range for a variable
77 /// Signal emitted when a data acquisition is requested on a range for a variable
78 void rangeChanged(std::shared_ptr<Variable> variable, const SqpRange &range);
78 void rangeChanged(std::shared_ptr<Variable> variable, const SqpRange &range);
79
79
80 /// Signal emitted when a sub range of the cacheRange of the variable can be displayed
80 /// Signal emitted when a sub range of the cacheRange of the variable can be displayed
81 void updateVarDisplaying(std::shared_ptr<Variable> variable, const SqpRange &range);
81 void updateVarDisplaying(std::shared_ptr<Variable> variable, const SqpRange &range);
82
82
83 public slots:
83 public slots:
84 /// Request the data loading of the variable whithin range
84 /// Request the data loading of the variable whithin range
85 void onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables, const SqpRange &range,
85 void onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables, const SqpRange &range,
86 const SqpRange &oldRange, bool synchronise);
86 bool synchronise);
87 /**
87 /**
88 * Creates a new variable and adds it to the model
88 * Creates a new variable and adds it to the model
89 * @param name the name of the new variable
89 * @param name the name of the new variable
90 * @param metadata the metadata of the new variable
90 * @param metadata the metadata of the new variable
91 * @param provider the data provider for the new variable
91 * @param provider the data provider for the new variable
92 * @return the pointer to the new variable or nullptr if the creation failed
92 * @return the pointer to the new variable or nullptr if the creation failed
93 */
93 */
94 std::shared_ptr<Variable> createVariable(const QString &name, const QVariantHash &metadata,
94 std::shared_ptr<Variable> createVariable(const QString &name, const QVariantHash &metadata,
95 std::shared_ptr<IDataProvider> provider) noexcept;
95 std::shared_ptr<IDataProvider> provider) noexcept;
96
96
97 /// Update the temporal parameters of every selected variable to dateTime
97 /// Update the temporal parameters of every selected variable to dateTime
98 void onDateTimeOnSelection(const SqpRange &dateTime);
98 void onDateTimeOnSelection(const SqpRange &dateTime);
99
99
100
100
101 void onDataProvided(QUuid vIdentifier, const SqpRange &rangeRequested,
101 void onDataProvided(QUuid vIdentifier, const SqpRange &rangeRequested,
102 const SqpRange &cacheRangeRequested,
102 const SqpRange &cacheRangeRequested,
103 QVector<AcquisitionDataPacket> dataAcquired);
103 QVector<AcquisitionDataPacket> dataAcquired);
104
104
105 void onVariableRetrieveDataInProgress(QUuid identifier, double progress);
105 void onVariableRetrieveDataInProgress(QUuid identifier, double progress);
106
106
107 /// Cancel the current request for the variable
107 /// Cancel the current request for the variable
108 void onAbortProgressRequested(std::shared_ptr<Variable> variable);
108 void onAbortProgressRequested(std::shared_ptr<Variable> variable);
109 void onAbortAcquisitionRequested(QUuid vIdentifier);
109 void onAbortAcquisitionRequested(QUuid vIdentifier);
110
110
111 // synchronization group methods
111 // synchronization group methods
112 void onAddSynchronizationGroupId(QUuid synchronizationGroupId);
112 void onAddSynchronizationGroupId(QUuid synchronizationGroupId);
113 void onRemoveSynchronizationGroupId(QUuid synchronizationGroupId);
113 void onRemoveSynchronizationGroupId(QUuid synchronizationGroupId);
114 void onAddSynchronized(std::shared_ptr<Variable> variable, QUuid synchronizationGroupId);
114 void onAddSynchronized(std::shared_ptr<Variable> variable, QUuid synchronizationGroupId);
115
115
116 /// Desynchronizes the variable of the group whose identifier is passed in parameter
116 /// Desynchronizes the variable of the group whose identifier is passed in parameter
117 /// @remarks the method does nothing if the variable is not part of the group
117 /// @remarks the method does nothing if the variable is not part of the group
118 void desynchronize(std::shared_ptr<Variable> variable, QUuid synchronizationGroupId);
118 void desynchronize(std::shared_ptr<Variable> variable, QUuid synchronizationGroupId);
119
119
120 void initialize();
120 void initialize();
121 void finalize();
121 void finalize();
122
122
123 private:
123 private:
124 void waitForFinish();
124 void waitForFinish();
125
125
126 class VariableControllerPrivate;
126 class VariableControllerPrivate;
127 spimpl::unique_impl_ptr<VariableControllerPrivate> impl;
127 spimpl::unique_impl_ptr<VariableControllerPrivate> impl;
128 };
128 };
129
129
130 #endif // SCIQLOP_VARIABLECONTROLLER_H
130 #endif // SCIQLOP_VARIABLECONTROLLER_H
@@ -1,315 +1,388
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 QVariantHash &metadata)
13 explicit VariablePrivate(const QString &name, const QVariantHash &metadata)
14 : m_Name{name},
14 : m_Name{name},
15 m_Range{INVALID_RANGE},
15 m_Range{INVALID_RANGE},
16 m_CacheRange{INVALID_RANGE},
16 m_CacheRange{INVALID_RANGE},
17 m_Metadata{metadata},
17 m_Metadata{metadata},
18 m_DataSeries{nullptr},
18 m_DataSeries{nullptr},
19 m_RealRange{INVALID_RANGE},
19 m_RealRange{INVALID_RANGE},
20 m_NbPoints{0}
20 m_NbPoints{0}
21 {
21 {
22 }
22 }
23
23
24 VariablePrivate(const VariablePrivate &other)
24 VariablePrivate(const VariablePrivate &other)
25 : m_Name{other.m_Name},
25 : m_Name{other.m_Name},
26 m_Range{other.m_Range},
26 m_Range{other.m_Range},
27 m_CacheRange{other.m_CacheRange},
27 m_CacheRange{other.m_CacheRange},
28 m_Metadata{other.m_Metadata},
28 m_Metadata{other.m_Metadata},
29 m_DataSeries{other.m_DataSeries != nullptr ? other.m_DataSeries->clone() : nullptr},
29 m_DataSeries{other.m_DataSeries != nullptr ? other.m_DataSeries->clone() : nullptr},
30 m_RealRange{other.m_RealRange},
30 m_RealRange{other.m_RealRange},
31 m_NbPoints{other.m_NbPoints}
31 m_NbPoints{other.m_NbPoints}
32 {
32 {
33 }
33 }
34
34
35 void lockRead() { m_Lock.lockForRead(); }
35 void lockRead() { m_Lock.lockForRead(); }
36 void lockWrite() { m_Lock.lockForWrite(); }
36 void lockWrite() { m_Lock.lockForWrite(); }
37 void unlock() { m_Lock.unlock(); }
37 void unlock() { m_Lock.unlock(); }
38
38
39 void purgeDataSeries()
39 void purgeDataSeries()
40 {
40 {
41 if (m_DataSeries) {
41 if (m_DataSeries) {
42 m_DataSeries->purge(m_CacheRange.m_TStart, m_CacheRange.m_TEnd);
42 m_DataSeries->purge(m_CacheRange.m_TStart, m_CacheRange.m_TEnd);
43 }
43 }
44 updateRealRange();
44 updateRealRange();
45 updateNbPoints();
45 updateNbPoints();
46 }
46 }
47
47
48 void updateNbPoints() { m_NbPoints = m_DataSeries ? m_DataSeries->nbPoints() : 0; }
48 void updateNbPoints() { m_NbPoints = m_DataSeries ? m_DataSeries->nbPoints() : 0; }
49
49
50 /// Updates real range according to current variable range and data series
50 /// Updates real range according to current variable range and data series
51 void updateRealRange()
51 void updateRealRange()
52 {
52 {
53 if (m_DataSeries) {
53 if (m_DataSeries) {
54 m_DataSeries->lockRead();
54 m_DataSeries->lockRead();
55 auto end = m_DataSeries->cend();
55 auto end = m_DataSeries->cend();
56 auto minXAxisIt = m_DataSeries->minXAxisData(m_Range.m_TStart);
56 auto minXAxisIt = m_DataSeries->minXAxisData(m_Range.m_TStart);
57 auto maxXAxisIt = m_DataSeries->maxXAxisData(m_Range.m_TEnd);
57 auto maxXAxisIt = m_DataSeries->maxXAxisData(m_Range.m_TEnd);
58
58
59 m_RealRange
59 m_RealRange
60 = (minXAxisIt != end && maxXAxisIt != end && minXAxisIt->x() <= maxXAxisIt->x())
60 = (minXAxisIt != end && maxXAxisIt != end && minXAxisIt->x() <= maxXAxisIt->x())
61 ? SqpRange{minXAxisIt->x(), maxXAxisIt->x()}
61 ? SqpRange{minXAxisIt->x(), maxXAxisIt->x()}
62 : INVALID_RANGE;
62 : INVALID_RANGE;
63 m_DataSeries->unlock();
63 m_DataSeries->unlock();
64 }
64 }
65 else {
65 else {
66 m_RealRange = INVALID_RANGE;
66 m_RealRange = INVALID_RANGE;
67 }
67 }
68 }
68 }
69
69
70 QString m_Name;
70 QString m_Name;
71
71
72 SqpRange m_Range;
72 SqpRange m_Range;
73 SqpRange m_CacheRange;
73 SqpRange m_CacheRange;
74 QVariantHash m_Metadata;
74 QVariantHash m_Metadata;
75 std::shared_ptr<IDataSeries> m_DataSeries;
75 std::shared_ptr<IDataSeries> m_DataSeries;
76 SqpRange m_RealRange;
76 SqpRange m_RealRange;
77 int m_NbPoints;
77 int m_NbPoints;
78
78
79 QReadWriteLock m_Lock;
79 QReadWriteLock m_Lock;
80 };
80 };
81
81
82 Variable::Variable(const QString &name, const QVariantHash &metadata)
82 Variable::Variable(const QString &name, const QVariantHash &metadata)
83 : impl{spimpl::make_unique_impl<VariablePrivate>(name, metadata)}
83 : impl{spimpl::make_unique_impl<VariablePrivate>(name, metadata)}
84 {
84 {
85 }
85 }
86
86
87 Variable::Variable(const Variable &other)
87 Variable::Variable(const Variable &other)
88 : impl{spimpl::make_unique_impl<VariablePrivate>(*other.impl)}
88 : impl{spimpl::make_unique_impl<VariablePrivate>(*other.impl)}
89 {
89 {
90 }
90 }
91
91
92 std::shared_ptr<Variable> Variable::clone() const
92 std::shared_ptr<Variable> Variable::clone() const
93 {
93 {
94 return std::make_shared<Variable>(*this);
94 return std::make_shared<Variable>(*this);
95 }
95 }
96
96
97 QString Variable::name() const noexcept
97 QString Variable::name() const noexcept
98 {
98 {
99 impl->lockRead();
99 impl->lockRead();
100 auto name = impl->m_Name;
100 auto name = impl->m_Name;
101 impl->unlock();
101 impl->unlock();
102 return name;
102 return name;
103 }
103 }
104
104
105 void Variable::setName(const QString &name) noexcept
105 void Variable::setName(const QString &name) noexcept
106 {
106 {
107 impl->lockWrite();
107 impl->lockWrite();
108 impl->m_Name = name;
108 impl->m_Name = name;
109 impl->unlock();
109 impl->unlock();
110 }
110 }
111
111
112 SqpRange Variable::range() const noexcept
112 SqpRange Variable::range() const noexcept
113 {
113 {
114 impl->lockRead();
114 impl->lockRead();
115 auto range = impl->m_Range;
115 auto range = impl->m_Range;
116 impl->unlock();
116 impl->unlock();
117 return range;
117 return range;
118 }
118 }
119
119
120 void Variable::setRange(const SqpRange &range) noexcept
120 void Variable::setRange(const SqpRange &range) noexcept
121 {
121 {
122 impl->lockWrite();
122 impl->lockWrite();
123 impl->m_Range = range;
123 impl->m_Range = range;
124 impl->updateRealRange();
124 impl->updateRealRange();
125 impl->unlock();
125 impl->unlock();
126 }
126 }
127
127
128 SqpRange Variable::cacheRange() const noexcept
128 SqpRange Variable::cacheRange() const noexcept
129 {
129 {
130 impl->lockRead();
130 impl->lockRead();
131 auto cacheRange = impl->m_CacheRange;
131 auto cacheRange = impl->m_CacheRange;
132 impl->unlock();
132 impl->unlock();
133 return cacheRange;
133 return cacheRange;
134 }
134 }
135
135
136 void Variable::setCacheRange(const SqpRange &cacheRange) noexcept
136 void Variable::setCacheRange(const SqpRange &cacheRange) noexcept
137 {
137 {
138 impl->lockWrite();
138 impl->lockWrite();
139 if (cacheRange != impl->m_CacheRange) {
139 if (cacheRange != impl->m_CacheRange) {
140 impl->m_CacheRange = cacheRange;
140 impl->m_CacheRange = cacheRange;
141 impl->purgeDataSeries();
142 }
141 }
143 impl->unlock();
142 impl->unlock();
144 }
143 }
145
144
146 int Variable::nbPoints() const noexcept
145 int Variable::nbPoints() const noexcept
147 {
146 {
148 return impl->m_NbPoints;
147 return impl->m_NbPoints;
149 }
148 }
150
149
151 SqpRange Variable::realRange() const noexcept
150 SqpRange Variable::realRange() const noexcept
152 {
151 {
153 return impl->m_RealRange;
152 return impl->m_RealRange;
154 }
153 }
155
154
156 void Variable::mergeDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept
155 void Variable::mergeDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept
157 {
156 {
158 qCDebug(LOG_Variable()) << "TORM Variable::mergeDataSeries"
157 qCDebug(LOG_Variable()) << "TORM Variable::mergeDataSeries"
159 << QThread::currentThread()->objectName();
158 << QThread::currentThread()->objectName();
160 if (!dataSeries) {
159 if (!dataSeries) {
161 /// @todo ALX : log
160 /// @todo ALX : log
162 return;
161 return;
163 }
162 }
164
163
165 // Add or merge the data
164 // Add or merge the data
166 impl->lockWrite();
165 impl->lockWrite();
167 if (!impl->m_DataSeries) {
166 if (!impl->m_DataSeries) {
168 impl->m_DataSeries = dataSeries->clone();
167 impl->m_DataSeries = dataSeries->clone();
169 }
168 }
170 else {
169 else {
171 impl->m_DataSeries->merge(dataSeries.get());
170 impl->m_DataSeries->merge(dataSeries.get());
172 }
171 }
173 impl->purgeDataSeries();
172 impl->purgeDataSeries();
174 impl->unlock();
173 impl->unlock();
175 }
174 }
176
175
176
177 std::shared_ptr<IDataSeries> Variable::dataSeries() const noexcept
177 std::shared_ptr<IDataSeries> Variable::dataSeries() const noexcept
178 {
178 {
179 impl->lockRead();
179 impl->lockRead();
180 auto dataSeries = impl->m_DataSeries;
180 auto dataSeries = impl->m_DataSeries;
181 impl->unlock();
181 impl->unlock();
182
182
183 return dataSeries;
183 return dataSeries;
184 }
184 }
185
185
186 QVariantHash Variable::metadata() const noexcept
186 QVariantHash Variable::metadata() const noexcept
187 {
187 {
188 impl->lockRead();
188 impl->lockRead();
189 auto metadata = impl->m_Metadata;
189 auto metadata = impl->m_Metadata;
190 impl->unlock();
190 impl->unlock();
191 return metadata;
191 return metadata;
192 }
192 }
193
193
194 bool Variable::contains(const SqpRange &range) const noexcept
194 bool Variable::contains(const SqpRange &range) const noexcept
195 {
195 {
196 impl->lockRead();
196 impl->lockRead();
197 auto res = impl->m_Range.contains(range);
197 auto res = impl->m_Range.contains(range);
198 impl->unlock();
198 impl->unlock();
199 return res;
199 return res;
200 }
200 }
201
201
202 bool Variable::intersect(const SqpRange &range) const noexcept
202 bool Variable::intersect(const SqpRange &range) const noexcept
203 {
203 {
204
204
205 impl->lockRead();
205 impl->lockRead();
206 auto res = impl->m_Range.intersect(range);
206 auto res = impl->m_Range.intersect(range);
207 impl->unlock();
207 impl->unlock();
208 return res;
208 return res;
209 }
209 }
210
210
211 bool Variable::isInside(const SqpRange &range) const noexcept
211 bool Variable::isInside(const SqpRange &range) const noexcept
212 {
212 {
213 impl->lockRead();
213 impl->lockRead();
214 auto res = range.contains(SqpRange{impl->m_Range.m_TStart, impl->m_Range.m_TEnd});
214 auto res = range.contains(SqpRange{impl->m_Range.m_TStart, impl->m_Range.m_TEnd});
215 impl->unlock();
215 impl->unlock();
216 return res;
216 return res;
217 }
217 }
218
218
219 bool Variable::cacheContains(const SqpRange &range) const noexcept
219 bool Variable::cacheContains(const SqpRange &range) const noexcept
220 {
220 {
221 impl->lockRead();
221 impl->lockRead();
222 auto res = impl->m_CacheRange.contains(range);
222 auto res = impl->m_CacheRange.contains(range);
223 impl->unlock();
223 impl->unlock();
224 return res;
224 return res;
225 }
225 }
226
226
227 bool Variable::cacheIntersect(const SqpRange &range) const noexcept
227 bool Variable::cacheIntersect(const SqpRange &range) const noexcept
228 {
228 {
229 impl->lockRead();
229 impl->lockRead();
230 auto res = impl->m_CacheRange.intersect(range);
230 auto res = impl->m_CacheRange.intersect(range);
231 impl->unlock();
231 impl->unlock();
232 return res;
232 return res;
233 }
233 }
234
234
235 bool Variable::cacheIsInside(const SqpRange &range) const noexcept
235 bool Variable::cacheIsInside(const SqpRange &range) const noexcept
236 {
236 {
237 impl->lockRead();
237 impl->lockRead();
238 auto res = range.contains(SqpRange{impl->m_CacheRange.m_TStart, impl->m_CacheRange.m_TEnd});
238 auto res = range.contains(SqpRange{impl->m_CacheRange.m_TStart, impl->m_CacheRange.m_TEnd});
239 impl->unlock();
239 impl->unlock();
240 return res;
240 return res;
241 }
241 }
242
242
243
243
244 QVector<SqpRange> Variable::provideNotInCacheRangeList(const SqpRange &range) const noexcept
244 QVector<SqpRange> Variable::provideNotInCacheRangeList(const SqpRange &range) const noexcept
245 {
245 {
246 // This code assume that cach in contigue. Can return 0, 1 or 2 SqpRange
246 // This code assume that cach in contigue. Can return 0, 1 or 2 SqpRange
247 auto notInCache = QVector<SqpRange>{};
247 auto notInCache = QVector<SqpRange>{};
248 if (impl->m_CacheRange != INVALID_RANGE) {
248 if (impl->m_CacheRange != INVALID_RANGE) {
249
249
250 if (!this->cacheContains(range)) {
250 if (!this->cacheContains(range)) {
251 if (range.m_TEnd <= impl->m_CacheRange.m_TStart
251 if (range.m_TEnd <= impl->m_CacheRange.m_TStart
252 || range.m_TStart >= impl->m_CacheRange.m_TEnd) {
252 || range.m_TStart >= impl->m_CacheRange.m_TEnd) {
253 notInCache << range;
253 notInCache << range;
254 }
254 }
255 else if (range.m_TStart < impl->m_CacheRange.m_TStart
255 else if (range.m_TStart < impl->m_CacheRange.m_TStart
256 && range.m_TEnd <= impl->m_CacheRange.m_TEnd) {
256 && range.m_TEnd <= impl->m_CacheRange.m_TEnd) {
257 notInCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TStart};
257 notInCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TStart};
258 }
258 }
259 else if (range.m_TStart < impl->m_CacheRange.m_TStart
259 else if (range.m_TStart < impl->m_CacheRange.m_TStart
260 && range.m_TEnd > impl->m_CacheRange.m_TEnd) {
260 && range.m_TEnd > impl->m_CacheRange.m_TEnd) {
261 notInCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TStart}
261 notInCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TStart}
262 << SqpRange{impl->m_CacheRange.m_TEnd, range.m_TEnd};
262 << SqpRange{impl->m_CacheRange.m_TEnd, range.m_TEnd};
263 }
263 }
264 else if (range.m_TStart < impl->m_CacheRange.m_TEnd) {
264 else if (range.m_TStart < impl->m_CacheRange.m_TEnd) {
265 notInCache << SqpRange{impl->m_CacheRange.m_TEnd, range.m_TEnd};
265 notInCache << SqpRange{impl->m_CacheRange.m_TEnd, range.m_TEnd};
266 }
266 }
267 else {
267 else {
268 qCCritical(LOG_Variable()) << tr("Detection of unknown case.")
268 qCCritical(LOG_Variable()) << tr("Detection of unknown case.")
269 << QThread::currentThread();
269 << QThread::currentThread();
270 }
270 }
271 }
271 }
272 }
272 }
273 else {
273 else {
274 notInCache << range;
274 notInCache << range;
275 }
275 }
276
276
277 return notInCache;
277 return notInCache;
278 }
278 }
279
279
280 QVector<SqpRange> Variable::provideInCacheRangeList(const SqpRange &range) const noexcept
280 QVector<SqpRange> Variable::provideInCacheRangeList(const SqpRange &range) const noexcept
281 {
281 {
282 // This code assume that cach in contigue. Can return 0 or 1 SqpRange
282 // This code assume that cach in contigue. Can return 0 or 1 SqpRange
283
283
284 auto inCache = QVector<SqpRange>{};
284 auto inCache = QVector<SqpRange>{};
285
285
286 if (impl->m_CacheRange != INVALID_RANGE) {
286 if (impl->m_CacheRange != INVALID_RANGE) {
287
287
288 if (this->intersect(range)) {
288 if (this->cacheIntersect(range)) {
289 if (range.m_TStart <= impl->m_CacheRange.m_TStart
289 if (range.m_TStart <= impl->m_CacheRange.m_TStart
290 && range.m_TEnd >= impl->m_CacheRange.m_TStart
290 && range.m_TEnd >= impl->m_CacheRange.m_TStart
291 && range.m_TEnd < impl->m_CacheRange.m_TEnd) {
291 && range.m_TEnd < impl->m_CacheRange.m_TEnd) {
292 inCache << SqpRange{impl->m_CacheRange.m_TStart, range.m_TEnd};
292 inCache << SqpRange{impl->m_CacheRange.m_TStart, range.m_TEnd};
293 }
293 }
294
294
295 else if (range.m_TStart >= impl->m_CacheRange.m_TStart
295 else if (range.m_TStart >= impl->m_CacheRange.m_TStart
296 && range.m_TEnd <= impl->m_CacheRange.m_TEnd) {
296 && range.m_TEnd <= impl->m_CacheRange.m_TEnd) {
297 inCache << range;
297 inCache << range;
298 }
298 }
299 else if (range.m_TStart > impl->m_CacheRange.m_TStart
299 else if (range.m_TStart > impl->m_CacheRange.m_TStart
300 && range.m_TEnd > impl->m_CacheRange.m_TEnd) {
300 && range.m_TEnd > impl->m_CacheRange.m_TEnd) {
301 inCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TEnd};
301 inCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TEnd};
302 }
302 }
303 else if (range.m_TStart <= impl->m_CacheRange.m_TStart
303 else if (range.m_TStart <= impl->m_CacheRange.m_TStart
304 && range.m_TEnd >= impl->m_CacheRange.m_TEnd) {
304 && range.m_TEnd >= impl->m_CacheRange.m_TEnd) {
305 inCache << impl->m_CacheRange;
305 inCache << impl->m_CacheRange;
306 }
306 }
307 else {
307 else {
308 qCCritical(LOG_Variable()) << tr("Detection of unknown case.")
308 qCCritical(LOG_Variable()) << tr("Detection of unknown case.")
309 << QThread::currentThread();
309 << QThread::currentThread();
310 }
310 }
311 }
311 }
312 }
312 }
313
313
314 return inCache;
314 return inCache;
315 }
315 }
316
317
318 QVector<SqpRange> Variable::provideNotInCacheRangeList(const SqpRange &oldRange,
319 const SqpRange &nextRange)
320 {
321
322 // This code assume that cach in contigue. Can return 0, 1 or 2 SqpRange
323 auto notInCache = QVector<SqpRange>{};
324 if (oldRange != INVALID_RANGE) {
325
326 if (!oldRange.contains(nextRange)) {
327 if (nextRange.m_TEnd <= oldRange.m_TStart || nextRange.m_TStart >= oldRange.m_TEnd) {
328 notInCache << nextRange;
329 }
330 else if (nextRange.m_TStart < oldRange.m_TStart
331 && nextRange.m_TEnd <= oldRange.m_TEnd) {
332 notInCache << SqpRange{nextRange.m_TStart, oldRange.m_TStart};
333 }
334 else if (nextRange.m_TStart < oldRange.m_TStart && nextRange.m_TEnd > oldRange.m_TEnd) {
335 notInCache << SqpRange{nextRange.m_TStart, oldRange.m_TStart}
336 << SqpRange{oldRange.m_TEnd, nextRange.m_TEnd};
337 }
338 else if (nextRange.m_TStart < oldRange.m_TEnd) {
339 notInCache << SqpRange{oldRange.m_TEnd, nextRange.m_TEnd};
340 }
341 else {
342 qCCritical(LOG_Variable()) << tr("Detection of unknown case.")
343 << QThread::currentThread();
344 }
345 }
346 }
347 else {
348 notInCache << nextRange;
349 }
350
351 return notInCache;
352 }
353
354 QVector<SqpRange> Variable::provideInCacheRangeList(const SqpRange &oldRange,
355 const SqpRange &nextRange)
356 {
357 // This code assume that cach is contigue. Can return 0 or 1 SqpRange
358
359 auto inCache = QVector<SqpRange>{};
360
361 if (oldRange != INVALID_RANGE) {
362
363 if (oldRange.intersect(nextRange)) {
364 if (nextRange.m_TStart <= oldRange.m_TStart && nextRange.m_TEnd >= oldRange.m_TStart
365 && nextRange.m_TEnd < oldRange.m_TEnd) {
366 inCache << SqpRange{oldRange.m_TStart, nextRange.m_TEnd};
367 }
368
369 else if (nextRange.m_TStart >= oldRange.m_TStart
370 && nextRange.m_TEnd <= oldRange.m_TEnd) {
371 inCache << nextRange;
372 }
373 else if (nextRange.m_TStart > oldRange.m_TStart && nextRange.m_TEnd > oldRange.m_TEnd) {
374 inCache << SqpRange{nextRange.m_TStart, oldRange.m_TEnd};
375 }
376 else if (nextRange.m_TStart <= oldRange.m_TStart
377 && nextRange.m_TEnd >= oldRange.m_TEnd) {
378 inCache << oldRange;
379 }
380 else {
381 qCCritical(LOG_Variable()) << tr("Detection of unknown case.")
382 << QThread::currentThread();
383 }
384 }
385 }
386
387 return inCache;
388 }
@@ -1,322 +1,416
1 #include "Variable/VariableAcquisitionWorker.h"
1 #include "Variable/VariableAcquisitionWorker.h"
2
2
3 #include "Variable/Variable.h"
3 #include "Variable/Variable.h"
4
4
5 #include <Data/AcquisitionRequest.h>
5 #include <Data/AcquisitionRequest.h>
6 #include <Data/SqpRange.h>
6 #include <Data/SqpRange.h>
7
7
8 #include <unordered_map>
8 #include <unordered_map>
9 #include <utility>
9 #include <utility>
10
10
11 #include <QMutex>
11 #include <QMutex>
12 #include <QReadWriteLock>
12 #include <QReadWriteLock>
13 #include <QThread>
13 #include <QThread>
14
14
15 #include <cmath>
15 #include <cmath>
16
16
17 Q_LOGGING_CATEGORY(LOG_VariableAcquisitionWorker, "VariableAcquisitionWorker")
17 Q_LOGGING_CATEGORY(LOG_VariableAcquisitionWorker, "VariableAcquisitionWorker")
18
18
19 struct VariableAcquisitionWorker::VariableAcquisitionWorkerPrivate {
19 struct VariableAcquisitionWorker::VariableAcquisitionWorkerPrivate {
20
20
21 explicit VariableAcquisitionWorkerPrivate(VariableAcquisitionWorker *parent)
21 explicit VariableAcquisitionWorkerPrivate(VariableAcquisitionWorker *parent)
22 : m_Lock{QReadWriteLock::Recursive}, q{parent}
22 : m_Lock{QReadWriteLock::Recursive}, q{parent}
23 {
23 {
24 }
24 }
25
25
26 void lockRead() { m_Lock.lockForRead(); }
26 void lockRead() { m_Lock.lockForRead(); }
27 void lockWrite() { m_Lock.lockForWrite(); }
27 void lockWrite() { m_Lock.lockForWrite(); }
28 void unlock() { m_Lock.unlock(); }
28 void unlock() { m_Lock.unlock(); }
29
29
30 void removeVariableRequest(QUuid vIdentifier);
30 void removeVariableRequest(QUuid vIdentifier);
31
31
32 /// Remove the current request and execute the next one if exist
32 /// Remove the current request and execute the next one if exist
33 void updateToNextRequest(QUuid vIdentifier);
33 void updateToNextRequest(QUuid vIdentifier);
34
34
35 /// Remove and/or abort all AcqRequest in link with varRequestId
36 void cancelVarRequest(QUuid varRequestId);
37 void removeAcqRequest(QUuid acqRequestId);
38
35 QMutex m_WorkingMutex;
39 QMutex m_WorkingMutex;
36 QReadWriteLock m_Lock;
40 QReadWriteLock m_Lock;
37
41
38 std::map<QUuid, QVector<AcquisitionDataPacket> > m_AcqIdentifierToAcqDataPacketVectorMap;
42 std::map<QUuid, QVector<AcquisitionDataPacket> > m_AcqIdentifierToAcqDataPacketVectorMap;
39 std::map<QUuid, AcquisitionRequest> m_AcqIdentifierToAcqRequestMap;
43 std::map<QUuid, AcquisitionRequest> m_AcqIdentifierToAcqRequestMap;
40 std::map<QUuid, std::pair<QUuid, QUuid> > m_VIdentifierToCurrrentAcqIdNextIdPairMap;
44 std::map<QUuid, std::pair<QUuid, QUuid> > m_VIdentifierToCurrrentAcqIdNextIdPairMap;
41 VariableAcquisitionWorker *q;
45 VariableAcquisitionWorker *q;
42 };
46 };
43
47
44
48
45 VariableAcquisitionWorker::VariableAcquisitionWorker(QObject *parent)
49 VariableAcquisitionWorker::VariableAcquisitionWorker(QObject *parent)
46 : QObject{parent}, impl{spimpl::make_unique_impl<VariableAcquisitionWorkerPrivate>(this)}
50 : QObject{parent}, impl{spimpl::make_unique_impl<VariableAcquisitionWorkerPrivate>(this)}
47 {
51 {
48 }
52 }
49
53
50 VariableAcquisitionWorker::~VariableAcquisitionWorker()
54 VariableAcquisitionWorker::~VariableAcquisitionWorker()
51 {
55 {
52 qCInfo(LOG_VariableAcquisitionWorker()) << tr("VariableAcquisitionWorker destruction")
56 qCInfo(LOG_VariableAcquisitionWorker()) << tr("VariableAcquisitionWorker destruction")
53 << QThread::currentThread();
57 << QThread::currentThread();
54 this->waitForFinish();
58 this->waitForFinish();
55 }
59 }
56
60
57
61
58 QUuid VariableAcquisitionWorker::pushVariableRequest(QUuid varRequestId, QUuid vIdentifier,
62 QUuid VariableAcquisitionWorker::pushVariableRequest(QUuid varRequestId, QUuid vIdentifier,
59 SqpRange rangeRequested,
63 SqpRange rangeRequested,
60 SqpRange cacheRangeRequested,
64 SqpRange cacheRangeRequested,
61 DataProviderParameters parameters,
65 DataProviderParameters parameters,
62 std::shared_ptr<IDataProvider> provider)
66 std::shared_ptr<IDataProvider> provider)
63 {
67 {
64 qCDebug(LOG_VariableAcquisitionWorker())
68 qCDebug(LOG_VariableAcquisitionWorker())
65 << tr("TORM VariableAcquisitionWorker::pushVariableRequest ") << cacheRangeRequested;
69 << tr("TORM VariableAcquisitionWorker::pushVariableRequest ") << cacheRangeRequested;
66 auto varRequestIdCanceled = QUuid();
70 auto varRequestIdCanceled = QUuid();
67
71
68 // Request creation
72 // Request creation
69 auto acqRequest = AcquisitionRequest{};
73 auto acqRequest = AcquisitionRequest{};
70 qCInfo(LOG_VariableAcquisitionWorker()) << tr("TpushVariableRequest ") << vIdentifier;
74 qCDebug(LOG_VariableAcquisitionWorker()) << tr("PushVariableRequest ") << vIdentifier
75 << varRequestId;
71 acqRequest.m_VarRequestId = varRequestId;
76 acqRequest.m_VarRequestId = varRequestId;
72 acqRequest.m_vIdentifier = vIdentifier;
77 acqRequest.m_vIdentifier = vIdentifier;
73 acqRequest.m_DataProviderParameters = parameters;
78 acqRequest.m_DataProviderParameters = parameters;
74 acqRequest.m_RangeRequested = rangeRequested;
79 acqRequest.m_RangeRequested = rangeRequested;
75 acqRequest.m_CacheRangeRequested = cacheRangeRequested;
80 acqRequest.m_CacheRangeRequested = cacheRangeRequested;
76 acqRequest.m_Size = parameters.m_Times.size();
81 acqRequest.m_Size = parameters.m_Times.size();
77 acqRequest.m_Provider = provider;
82 acqRequest.m_Provider = provider;
78
83
79
84
80 // Register request
85 // Register request
81 impl->lockWrite();
86 impl->lockWrite();
82 impl->m_AcqIdentifierToAcqRequestMap.insert(
87 impl->m_AcqIdentifierToAcqRequestMap.insert(
83 std::make_pair(acqRequest.m_AcqIdentifier, acqRequest));
88 std::make_pair(acqRequest.m_AcqIdentifier, acqRequest));
84
89
85 auto it = impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.find(vIdentifier);
90 auto it = impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.find(vIdentifier);
86 if (it != impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.cend()) {
91 if (it != impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.cend()) {
87 // A current request already exists, we can replace the next one
92 // A current request already exists, we can replace the next one
88 auto nextAcqId = it->second.second;
93 auto oldAcqId = it->second.second;
89 auto acqIdentifierToAcqRequestMapIt = impl->m_AcqIdentifierToAcqRequestMap.find(nextAcqId);
94 auto acqIdentifierToAcqRequestMapIt = impl->m_AcqIdentifierToAcqRequestMap.find(oldAcqId);
90 if (acqIdentifierToAcqRequestMapIt != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
95 if (acqIdentifierToAcqRequestMapIt != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
91 auto request = acqIdentifierToAcqRequestMapIt->second;
96 auto oldAcqRequest = acqIdentifierToAcqRequestMapIt->second;
92 varRequestIdCanceled = request.m_VarRequestId;
97 varRequestIdCanceled = oldAcqRequest.m_VarRequestId;
93 }
98 }
94
99
95 it->second.second = acqRequest.m_AcqIdentifier;
100 it->second.second = acqRequest.m_AcqIdentifier;
96 impl->unlock();
101 impl->unlock();
102
103 // remove old acqIdentifier from the worker
104 impl->cancelVarRequest(varRequestIdCanceled);
105 // impl->m_AcqIdentifierToAcqRequestMap.erase(oldAcqId);
97 }
106 }
98 else {
107 else {
99 // First request for the variable, it must be stored and executed
108 // First request for the variable, it must be stored and executed
100 impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.insert(
109 impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.insert(
101 std::make_pair(vIdentifier, std::make_pair(acqRequest.m_AcqIdentifier, QUuid())));
110 std::make_pair(vIdentifier, std::make_pair(acqRequest.m_AcqIdentifier, QUuid())));
102 impl->unlock();
111 impl->unlock();
103
112
104 QMetaObject::invokeMethod(this, "onExecuteRequest", Qt::QueuedConnection,
113 QMetaObject::invokeMethod(this, "onExecuteRequest", Qt::QueuedConnection,
105 Q_ARG(QUuid, acqRequest.m_AcqIdentifier));
114 Q_ARG(QUuid, acqRequest.m_AcqIdentifier));
106 }
115 }
107
116
108 return varRequestIdCanceled;
117 return varRequestIdCanceled;
109 }
118 }
110
119
111 void VariableAcquisitionWorker::abortProgressRequested(QUuid vIdentifier)
120 void VariableAcquisitionWorker::abortProgressRequested(QUuid vIdentifier)
112 {
121 {
113 impl->lockRead();
122 impl->lockRead();
114
123
115 auto it = impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.find(vIdentifier);
124 auto it = impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.find(vIdentifier);
116 if (it != impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.cend()) {
125 if (it != impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.cend()) {
117 auto currentAcqId = it->second.first;
126 auto currentAcqId = it->second.first;
118
127
119 auto it = impl->m_AcqIdentifierToAcqRequestMap.find(currentAcqId);
128 auto it = impl->m_AcqIdentifierToAcqRequestMap.find(currentAcqId);
120 if (it != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
129 if (it != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
121 auto request = it->second;
130 auto request = it->second;
122 impl->unlock();
131 impl->unlock();
123
132
124 // Remove the current request from the worker
133 // Remove the current request from the worker
125
126 impl->lockWrite();
127 impl->updateToNextRequest(vIdentifier);
134 impl->updateToNextRequest(vIdentifier);
128 impl->unlock();
129
135
130 // notify the request aborting to the provider
136 // notify the request aborting to the provider
131 request.m_Provider->requestDataAborting(currentAcqId);
137 request.m_Provider->requestDataAborting(currentAcqId);
132 }
138 }
133 else {
139 else {
134 impl->unlock();
140 impl->unlock();
135 qCWarning(LOG_VariableAcquisitionWorker())
141 qCWarning(LOG_VariableAcquisitionWorker())
136 << tr("Impossible to abort an unknown acquisition request") << currentAcqId;
142 << tr("Impossible to abort an unknown acquisition request") << currentAcqId;
137 }
143 }
138 }
144 }
139 else {
145 else {
140 impl->unlock();
146 impl->unlock();
141 }
147 }
142 }
148 }
143
149
144 void VariableAcquisitionWorker::onVariableRetrieveDataInProgress(QUuid acqIdentifier,
150 void VariableAcquisitionWorker::onVariableRetrieveDataInProgress(QUuid acqIdentifier,
145 double progress)
151 double progress)
146 {
152 {
147 qCDebug(LOG_VariableAcquisitionWorker()) << tr("TORM: onVariableRetrieveDataInProgress ")
153 qCDebug(LOG_VariableAcquisitionWorker()) << tr("TORM: onVariableRetrieveDataInProgress ")
148 << acqIdentifier << progress;
154 << acqIdentifier << progress;
149 impl->lockRead();
155 impl->lockRead();
150 auto aIdToARit = impl->m_AcqIdentifierToAcqRequestMap.find(acqIdentifier);
156 auto aIdToARit = impl->m_AcqIdentifierToAcqRequestMap.find(acqIdentifier);
151 if (aIdToARit != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
157 if (aIdToARit != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
152 auto currentPartSize = (aIdToARit->second.m_Size != 0) ? 100 / aIdToARit->second.m_Size : 0;
158 auto currentPartSize = (aIdToARit->second.m_Size != 0) ? 100 / aIdToARit->second.m_Size : 0;
153
159
154 auto currentPartProgress
160 auto currentPartProgress
155 = std::isnan(progress) ? 0.0 : (progress * currentPartSize) / 100.0;
161 = std::isnan(progress) ? 0.0 : (progress * currentPartSize) / 100.0;
156 auto currentAlreadyProgress = aIdToARit->second.m_Progression * currentPartSize;
162 auto currentAlreadyProgress = aIdToARit->second.m_Progression * currentPartSize;
157
163
158 auto finalProgression = currentAlreadyProgress + currentPartProgress;
164 auto finalProgression = currentAlreadyProgress + currentPartProgress;
159 emit variableRequestInProgress(aIdToARit->second.m_vIdentifier, finalProgression);
165 emit variableRequestInProgress(aIdToARit->second.m_vIdentifier, finalProgression);
160 qCDebug(LOG_VariableAcquisitionWorker())
166 qCDebug(LOG_VariableAcquisitionWorker())
161 << tr("TORM: onVariableRetrieveDataInProgress ")
167 << tr("TORM: onVariableRetrieveDataInProgress ")
162 << QThread::currentThread()->objectName() << aIdToARit->second.m_vIdentifier
168 << QThread::currentThread()->objectName() << aIdToARit->second.m_vIdentifier
163 << currentPartSize << currentAlreadyProgress << currentPartProgress << finalProgression;
169 << currentPartSize << currentAlreadyProgress << currentPartProgress << finalProgression;
164 if (finalProgression == 100.0) {
170 if (finalProgression == 100.0) {
165 emit variableRequestInProgress(aIdToARit->second.m_vIdentifier, 0.0);
171 emit variableRequestInProgress(aIdToARit->second.m_vIdentifier, 0.0);
166 }
172 }
167 }
173 }
168 impl->unlock();
174 impl->unlock();
169 }
175 }
170
176
171 void VariableAcquisitionWorker::onVariableAcquisitionFailed(QUuid acqIdentifier)
177 void VariableAcquisitionWorker::onVariableAcquisitionFailed(QUuid acqIdentifier)
172 {
178 {
173 qCDebug(LOG_VariableAcquisitionWorker()) << tr("onVariableAcquisitionFailed")
179 qCDebug(LOG_VariableAcquisitionWorker()) << tr("onVariableAcquisitionFailed")
174 << QThread::currentThread();
180 << QThread::currentThread();
175 impl->lockRead();
181 impl->lockRead();
176 auto it = impl->m_AcqIdentifierToAcqRequestMap.find(acqIdentifier);
182 auto it = impl->m_AcqIdentifierToAcqRequestMap.find(acqIdentifier);
177 if (it != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
183 if (it != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
178 auto request = it->second;
184 auto request = it->second;
179 impl->unlock();
185 impl->unlock();
180 qCInfo(LOG_VariableAcquisitionWorker()) << tr("onVariableAcquisitionFailed")
186 qCInfo(LOG_VariableAcquisitionWorker()) << tr("onVariableAcquisitionFailed")
181 << acqIdentifier << request.m_vIdentifier
187 << acqIdentifier << request.m_vIdentifier
182 << QThread::currentThread();
188 << QThread::currentThread();
183 emit variableCanceledRequested(request.m_vIdentifier);
189 emit variableCanceledRequested(request.m_vIdentifier);
184 }
190 }
185 else {
191 else {
186 impl->unlock();
192 impl->unlock();
187 // TODO log no acqIdentifier recognized
193 // TODO log no acqIdentifier recognized
188 }
194 }
189 }
195 }
190
196
191 void VariableAcquisitionWorker::onVariableDataAcquired(QUuid acqIdentifier,
197 void VariableAcquisitionWorker::onVariableDataAcquired(QUuid acqIdentifier,
192 std::shared_ptr<IDataSeries> dataSeries,
198 std::shared_ptr<IDataSeries> dataSeries,
193 SqpRange dataRangeAcquired)
199 SqpRange dataRangeAcquired)
194 {
200 {
195 qCDebug(LOG_VariableAcquisitionWorker()) << tr("TORM: onVariableDataAcquired on range ")
201 qCDebug(LOG_VariableAcquisitionWorker()) << tr("TORM: onVariableDataAcquired on range ")
196 << acqIdentifier << dataRangeAcquired;
202 << acqIdentifier << dataRangeAcquired;
197 impl->lockWrite();
203 impl->lockWrite();
198 auto aIdToARit = impl->m_AcqIdentifierToAcqRequestMap.find(acqIdentifier);
204 auto aIdToARit = impl->m_AcqIdentifierToAcqRequestMap.find(acqIdentifier);
199 if (aIdToARit != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
205 if (aIdToARit != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
200 // Store the result
206 // Store the result
201 auto dataPacket = AcquisitionDataPacket{};
207 auto dataPacket = AcquisitionDataPacket{};
202 dataPacket.m_Range = dataRangeAcquired;
208 dataPacket.m_Range = dataRangeAcquired;
203 dataPacket.m_DateSeries = dataSeries;
209 dataPacket.m_DateSeries = dataSeries;
204
210
205 auto aIdToADPVit = impl->m_AcqIdentifierToAcqDataPacketVectorMap.find(acqIdentifier);
211 auto aIdToADPVit = impl->m_AcqIdentifierToAcqDataPacketVectorMap.find(acqIdentifier);
206 if (aIdToADPVit != impl->m_AcqIdentifierToAcqDataPacketVectorMap.cend()) {
212 if (aIdToADPVit != impl->m_AcqIdentifierToAcqDataPacketVectorMap.cend()) {
207 // A current request result already exists, we can update it
213 // A current request result already exists, we can update it
208 aIdToADPVit->second.push_back(dataPacket);
214 aIdToADPVit->second.push_back(dataPacket);
209 }
215 }
210 else {
216 else {
211 // First request result for the variable, it must be stored
217 // First request result for the variable, it must be stored
212 impl->m_AcqIdentifierToAcqDataPacketVectorMap.insert(
218 impl->m_AcqIdentifierToAcqDataPacketVectorMap.insert(
213 std::make_pair(acqIdentifier, QVector<AcquisitionDataPacket>() << dataPacket));
219 std::make_pair(acqIdentifier, QVector<AcquisitionDataPacket>() << dataPacket));
214 }
220 }
215
221
216
222
217 // Decrement the counter of the request
223 // Decrement the counter of the request
218 auto &acqRequest = aIdToARit->second;
224 auto &acqRequest = aIdToARit->second;
219 acqRequest.m_Progression = acqRequest.m_Progression + 1;
225 acqRequest.m_Progression = acqRequest.m_Progression + 1;
220
226
221 // if the counter is 0, we can return data then run the next request if it exists and
227 // if the counter is 0, we can return data then run the next request if it exists and
222 // removed the finished request
228 // removed the finished request
223 if (acqRequest.m_Size == acqRequest.m_Progression) {
229 if (acqRequest.m_Size == acqRequest.m_Progression) {
230 auto varId = acqRequest.m_vIdentifier;
231 auto rangeRequested = acqRequest.m_RangeRequested;
232 auto cacheRangeRequested = acqRequest.m_CacheRangeRequested;
224 // Return the data
233 // Return the data
225 aIdToADPVit = impl->m_AcqIdentifierToAcqDataPacketVectorMap.find(acqIdentifier);
234 aIdToADPVit = impl->m_AcqIdentifierToAcqDataPacketVectorMap.find(acqIdentifier);
226 if (aIdToADPVit != impl->m_AcqIdentifierToAcqDataPacketVectorMap.cend()) {
235 if (aIdToADPVit != impl->m_AcqIdentifierToAcqDataPacketVectorMap.cend()) {
227 emit dataProvided(acqRequest.m_vIdentifier, acqRequest.m_RangeRequested,
236 emit dataProvided(varId, rangeRequested, cacheRangeRequested, aIdToADPVit->second);
228 acqRequest.m_CacheRangeRequested, aIdToADPVit->second);
229 }
237 }
238 impl->unlock();
230
239
231 // Update to the next request
240 // Update to the next request
232 impl->updateToNextRequest(acqRequest.m_vIdentifier);
241 impl->updateToNextRequest(acqRequest.m_vIdentifier);
233 }
242 }
243 else {
244 impl->unlock();
245 }
234 }
246 }
235 else {
247 else {
248 impl->unlock();
236 qCWarning(LOG_VariableAcquisitionWorker())
249 qCWarning(LOG_VariableAcquisitionWorker())
237 << tr("Impossible to retrieve AcquisitionRequest for the incoming data.");
250 << tr("Impossible to retrieve AcquisitionRequest for the incoming data.");
238 }
251 }
239 impl->unlock();
240 }
252 }
241
253
242 void VariableAcquisitionWorker::onExecuteRequest(QUuid acqIdentifier)
254 void VariableAcquisitionWorker::onExecuteRequest(QUuid acqIdentifier)
243 {
255 {
244 qCDebug(LOG_VariableAcquisitionWorker()) << tr("onExecuteRequest") << QThread::currentThread();
256 qCDebug(LOG_VariableAcquisitionWorker()) << tr("onExecuteRequest") << QThread::currentThread();
245 impl->lockRead();
257 impl->lockRead();
246 auto it = impl->m_AcqIdentifierToAcqRequestMap.find(acqIdentifier);
258 auto it = impl->m_AcqIdentifierToAcqRequestMap.find(acqIdentifier);
247 if (it != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
259 if (it != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
248 auto request = it->second;
260 auto request = it->second;
249 impl->unlock();
261 impl->unlock();
250 emit variableRequestInProgress(request.m_vIdentifier, 0.1);
262 emit variableRequestInProgress(request.m_vIdentifier, 0.1);
251 request.m_Provider->requestDataLoading(acqIdentifier, request.m_DataProviderParameters);
263 request.m_Provider->requestDataLoading(acqIdentifier, request.m_DataProviderParameters);
252 }
264 }
253 else {
265 else {
254 impl->unlock();
266 impl->unlock();
255 // TODO log no acqIdentifier recognized
267 // TODO log no acqIdentifier recognized
256 }
268 }
257 }
269 }
258
270
259 void VariableAcquisitionWorker::initialize()
271 void VariableAcquisitionWorker::initialize()
260 {
272 {
261 qCDebug(LOG_VariableAcquisitionWorker()) << tr("VariableAcquisitionWorker init")
273 qCDebug(LOG_VariableAcquisitionWorker()) << tr("VariableAcquisitionWorker init")
262 << QThread::currentThread();
274 << QThread::currentThread();
263 impl->m_WorkingMutex.lock();
275 impl->m_WorkingMutex.lock();
264 qCDebug(LOG_VariableAcquisitionWorker()) << tr("VariableAcquisitionWorker init END");
276 qCDebug(LOG_VariableAcquisitionWorker()) << tr("VariableAcquisitionWorker init END");
265 }
277 }
266
278
267 void VariableAcquisitionWorker::finalize()
279 void VariableAcquisitionWorker::finalize()
268 {
280 {
269 impl->m_WorkingMutex.unlock();
281 impl->m_WorkingMutex.unlock();
270 }
282 }
271
283
272 void VariableAcquisitionWorker::waitForFinish()
284 void VariableAcquisitionWorker::waitForFinish()
273 {
285 {
274 QMutexLocker locker{&impl->m_WorkingMutex};
286 QMutexLocker locker{&impl->m_WorkingMutex};
275 }
287 }
276
288
277 void VariableAcquisitionWorker::VariableAcquisitionWorkerPrivate::removeVariableRequest(
289 void VariableAcquisitionWorker::VariableAcquisitionWorkerPrivate::removeVariableRequest(
278 QUuid vIdentifier)
290 QUuid vIdentifier)
279 {
291 {
280 lockWrite();
292 lockWrite();
281 auto it = m_VIdentifierToCurrrentAcqIdNextIdPairMap.find(vIdentifier);
293 auto it = m_VIdentifierToCurrrentAcqIdNextIdPairMap.find(vIdentifier);
282
294
283 if (it != m_VIdentifierToCurrrentAcqIdNextIdPairMap.cend()) {
295 if (it != m_VIdentifierToCurrrentAcqIdNextIdPairMap.cend()) {
284 // A current request already exists, we can replace the next one
296 // A current request already exists, we can replace the next one
285
297
286 m_AcqIdentifierToAcqRequestMap.erase(it->second.first);
298 m_AcqIdentifierToAcqRequestMap.erase(it->second.first);
287 m_AcqIdentifierToAcqDataPacketVectorMap.erase(it->second.first);
299 m_AcqIdentifierToAcqDataPacketVectorMap.erase(it->second.first);
288
300
289 m_AcqIdentifierToAcqRequestMap.erase(it->second.second);
301 m_AcqIdentifierToAcqRequestMap.erase(it->second.second);
290 m_AcqIdentifierToAcqDataPacketVectorMap.erase(it->second.second);
302 m_AcqIdentifierToAcqDataPacketVectorMap.erase(it->second.second);
291 }
303 }
292 m_VIdentifierToCurrrentAcqIdNextIdPairMap.erase(vIdentifier);
304 m_VIdentifierToCurrrentAcqIdNextIdPairMap.erase(vIdentifier);
293 unlock();
305 unlock();
294 }
306 }
295
307
296 void VariableAcquisitionWorker::VariableAcquisitionWorkerPrivate::updateToNextRequest(
308 void VariableAcquisitionWorker::VariableAcquisitionWorkerPrivate::updateToNextRequest(
297 QUuid vIdentifier)
309 QUuid vIdentifier)
298 {
310 {
311 lockRead();
299 auto it = m_VIdentifierToCurrrentAcqIdNextIdPairMap.find(vIdentifier);
312 auto it = m_VIdentifierToCurrrentAcqIdNextIdPairMap.find(vIdentifier);
300 if (it != m_VIdentifierToCurrrentAcqIdNextIdPairMap.cend()) {
313 if (it != m_VIdentifierToCurrrentAcqIdNextIdPairMap.cend()) {
301 if (it->second.second.isNull()) {
314 if (it->second.second.isNull()) {
315 unlock();
302 // There is no next request, we can remove the variable request
316 // There is no next request, we can remove the variable request
303 removeVariableRequest(vIdentifier);
317 removeVariableRequest(vIdentifier);
304 }
318 }
305 else {
319 else {
306 auto acqIdentifierToRemove = it->second.first;
320 auto acqIdentifierToRemove = it->second.first;
307 // Move the next request to the current request
321 // Move the next request to the current request
308 it->second.first = it->second.second;
322 auto nextRequestId = it->second.second;
323 it->second.first = nextRequestId;
309 it->second.second = QUuid();
324 it->second.second = QUuid();
325 unlock();
310 // Remove AcquisitionRequest and results;
326 // Remove AcquisitionRequest and results;
327 lockWrite();
311 m_AcqIdentifierToAcqRequestMap.erase(acqIdentifierToRemove);
328 m_AcqIdentifierToAcqRequestMap.erase(acqIdentifierToRemove);
312 m_AcqIdentifierToAcqDataPacketVectorMap.erase(acqIdentifierToRemove);
329 m_AcqIdentifierToAcqDataPacketVectorMap.erase(acqIdentifierToRemove);
330 unlock();
313 // Execute the current request
331 // Execute the current request
314 QMetaObject::invokeMethod(q, "onExecuteRequest", Qt::QueuedConnection,
332 QMetaObject::invokeMethod(q, "onExecuteRequest", Qt::QueuedConnection,
315 Q_ARG(QUuid, it->second.first));
333 Q_ARG(QUuid, nextRequestId));
316 }
334 }
317 }
335 }
318 else {
336 else {
337 unlock();
319 qCCritical(LOG_VariableAcquisitionWorker())
338 qCCritical(LOG_VariableAcquisitionWorker())
320 << tr("Impossible to execute the acquisition on an unfound variable ");
339 << tr("Impossible to execute the acquisition on an unfound variable ");
321 }
340 }
322 }
341 }
342
343 void VariableAcquisitionWorker::VariableAcquisitionWorkerPrivate::cancelVarRequest(
344 QUuid varRequestId)
345 {
346 qCDebug(LOG_VariableAcquisitionWorker())
347 << "VariableAcquisitionWorkerPrivate::cancelVarRequest 0";
348 lockRead();
349 // get all AcqIdentifier in link with varRequestId
350 QVector<QUuid> acqIdsToRm;
351 auto cend = m_AcqIdentifierToAcqRequestMap.cend();
352 for (auto it = m_AcqIdentifierToAcqRequestMap.cbegin(); it != cend; ++it) {
353 if (it->second.m_VarRequestId == varRequestId) {
354 acqIdsToRm << it->first;
355 }
356 }
357 unlock();
358 // run aborting or removing of acqIdsToRm
359
360 for (auto acqId : acqIdsToRm) {
361 removeAcqRequest(acqId);
362 }
363 qCDebug(LOG_VariableAcquisitionWorker())
364 << "VariableAcquisitionWorkerPrivate::cancelVarRequest end";
365 }
366
367 void VariableAcquisitionWorker::VariableAcquisitionWorkerPrivate::removeAcqRequest(
368 QUuid acqRequestId)
369 {
370 qCDebug(LOG_VariableAcquisitionWorker())
371 << "VariableAcquisitionWorkerPrivate::removeAcqRequest";
372 QUuid vIdentifier;
373 std::shared_ptr<IDataProvider> provider;
374 lockRead();
375 auto acqIt = m_AcqIdentifierToAcqRequestMap.find(acqRequestId);
376 if (acqIt != m_AcqIdentifierToAcqRequestMap.cend()) {
377 vIdentifier = acqIt->second.m_vIdentifier;
378 provider = acqIt->second.m_Provider;
379
380 auto it = m_VIdentifierToCurrrentAcqIdNextIdPairMap.find(vIdentifier);
381 if (it != m_VIdentifierToCurrrentAcqIdNextIdPairMap.cend()) {
382 if (it->second.first == acqRequestId) {
383 // acqRequest is currently running -> let's aborting it
384 unlock();
385
386 // Remove the current request from the worker
387 updateToNextRequest(vIdentifier);
388
389 // notify the request aborting to the provider
390 provider->requestDataAborting(acqRequestId);
391 }
392 else if (it->second.second == acqRequestId) {
393 it->second.second = QUuid();
394 unlock();
395 }
396 else {
397 unlock();
398 }
399 }
400 else {
401 unlock();
402 }
403 }
404 else {
405 unlock();
406 }
407
408 lockWrite();
409
410 m_AcqIdentifierToAcqDataPacketVectorMap.erase(acqRequestId);
411 m_AcqIdentifierToAcqRequestMap.erase(acqRequestId);
412
413 unlock();
414 qCDebug(LOG_VariableAcquisitionWorker())
415 << "VariableAcquisitionWorkerPrivate::removeAcqRequest END";
416 }
@@ -1,840 +1,889
1 #include <Variable/Variable.h>
1 #include <Variable/Variable.h>
2 #include <Variable/VariableAcquisitionWorker.h>
2 #include <Variable/VariableAcquisitionWorker.h>
3 #include <Variable/VariableCacheStrategy.h>
3 #include <Variable/VariableCacheStrategy.h>
4 #include <Variable/VariableCacheStrategyFactory.h>
4 #include <Variable/VariableCacheStrategyFactory.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 <Data/VariableRequest.h>
12 #include <Data/VariableRequest.h>
13 #include <Time/TimeController.h>
13 #include <Time/TimeController.h>
14
14
15 #include <QMutex>
15 #include <QMutex>
16 #include <QThread>
16 #include <QThread>
17 #include <QUuid>
17 #include <QUuid>
18 #include <QtCore/QItemSelectionModel>
18 #include <QtCore/QItemSelectionModel>
19
19
20 #include <deque>
20 #include <deque>
21 #include <set>
21 #include <set>
22 #include <unordered_map>
22 #include <unordered_map>
23
23
24 Q_LOGGING_CATEGORY(LOG_VariableController, "VariableController")
24 Q_LOGGING_CATEGORY(LOG_VariableController, "VariableController")
25
25
26 namespace {
26 namespace {
27
27
28 SqpRange computeSynchroRangeRequested(const SqpRange &varRange, const SqpRange &graphRange,
28 SqpRange computeSynchroRangeRequested(const SqpRange &varRange, const SqpRange &graphRange,
29 const SqpRange &oldGraphRange)
29 const SqpRange &oldGraphRange)
30 {
30 {
31 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
31 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
32
32
33 auto varRangeRequested = varRange;
33 auto varRangeRequested = varRange;
34 switch (zoomType) {
34 switch (zoomType) {
35 case AcquisitionZoomType::ZoomIn: {
35 case AcquisitionZoomType::ZoomIn: {
36 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
36 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
37 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
37 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
38 varRangeRequested.m_TStart += deltaLeft;
38 varRangeRequested.m_TStart += deltaLeft;
39 varRangeRequested.m_TEnd -= deltaRight;
39 varRangeRequested.m_TEnd -= deltaRight;
40 break;
40 break;
41 }
41 }
42
42
43 case AcquisitionZoomType::ZoomOut: {
43 case AcquisitionZoomType::ZoomOut: {
44 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
44 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
45 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
45 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
46 varRangeRequested.m_TStart -= deltaLeft;
46 varRangeRequested.m_TStart -= deltaLeft;
47 varRangeRequested.m_TEnd += deltaRight;
47 varRangeRequested.m_TEnd += deltaRight;
48 break;
48 break;
49 }
49 }
50 case AcquisitionZoomType::PanRight: {
50 case AcquisitionZoomType::PanRight: {
51 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
51 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
52 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
52 varRangeRequested.m_TStart += deltaRight;
53 varRangeRequested.m_TStart += deltaLeft;
53 varRangeRequested.m_TEnd += deltaRight;
54 varRangeRequested.m_TEnd += deltaRight;
54 break;
55 break;
55 }
56 }
56 case AcquisitionZoomType::PanLeft: {
57 case AcquisitionZoomType::PanLeft: {
57 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
58 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
59 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
58 varRangeRequested.m_TStart -= deltaLeft;
60 varRangeRequested.m_TStart -= deltaLeft;
59 varRangeRequested.m_TEnd -= deltaLeft;
61 varRangeRequested.m_TEnd -= deltaRight;
60 break;
62 break;
61 }
63 }
62 case AcquisitionZoomType::Unknown: {
64 case AcquisitionZoomType::Unknown: {
63 qCCritical(LOG_VariableController())
65 qCCritical(LOG_VariableController())
64 << VariableController::tr("Impossible to synchronize: zoom type unknown");
66 << VariableController::tr("Impossible to synchronize: zoom type unknown");
65 break;
67 break;
66 }
68 }
67 default:
69 default:
68 qCCritical(LOG_VariableController()) << VariableController::tr(
70 qCCritical(LOG_VariableController()) << VariableController::tr(
69 "Impossible to synchronize: zoom type not take into account");
71 "Impossible to synchronize: zoom type not take into account");
70 // No action
72 // No action
71 break;
73 break;
72 }
74 }
73
75
74 return varRangeRequested;
76 return varRangeRequested;
75 }
77 }
76 }
78 }
77
79
78 struct VariableController::VariableControllerPrivate {
80 struct VariableController::VariableControllerPrivate {
79 explicit VariableControllerPrivate(VariableController *parent)
81 explicit VariableControllerPrivate(VariableController *parent)
80 : m_WorkingMutex{},
82 : m_WorkingMutex{},
81 m_VariableModel{new VariableModel{parent}},
83 m_VariableModel{new VariableModel{parent}},
82 m_VariableSelectionModel{new QItemSelectionModel{m_VariableModel, parent}},
84 m_VariableSelectionModel{new QItemSelectionModel{m_VariableModel, parent}},
83 // m_VariableCacheStrategy{std::make_unique<VariableCacheStrategy>()},
85 // m_VariableCacheStrategy{std::make_unique<VariableCacheStrategy>()},
84 m_VariableCacheStrategy{VariableCacheStrategyFactory::createCacheStrategy(
86 m_VariableCacheStrategy{VariableCacheStrategyFactory::createCacheStrategy(
85 CacheStrategy::SingleThreshold)},
87 CacheStrategy::SingleThreshold)},
86 m_VariableAcquisitionWorker{std::make_unique<VariableAcquisitionWorker>()},
88 m_VariableAcquisitionWorker{std::make_unique<VariableAcquisitionWorker>()},
87 q{parent}
89 q{parent}
88 {
90 {
89
91
90 m_VariableAcquisitionWorker->moveToThread(&m_VariableAcquisitionWorkerThread);
92 m_VariableAcquisitionWorker->moveToThread(&m_VariableAcquisitionWorkerThread);
91 m_VariableAcquisitionWorkerThread.setObjectName("VariableAcquisitionWorkerThread");
93 m_VariableAcquisitionWorkerThread.setObjectName("VariableAcquisitionWorkerThread");
92 }
94 }
93
95
94
96
95 virtual ~VariableControllerPrivate()
97 virtual ~VariableControllerPrivate()
96 {
98 {
97 qCDebug(LOG_VariableController()) << tr("VariableControllerPrivate destruction");
99 qCDebug(LOG_VariableController()) << tr("VariableControllerPrivate destruction");
98 m_VariableAcquisitionWorkerThread.quit();
100 m_VariableAcquisitionWorkerThread.quit();
99 m_VariableAcquisitionWorkerThread.wait();
101 m_VariableAcquisitionWorkerThread.wait();
100 }
102 }
101
103
102
104
103 void processRequest(std::shared_ptr<Variable> var, const SqpRange &rangeRequested,
105 void processRequest(std::shared_ptr<Variable> var, const SqpRange &rangeRequested,
104 QUuid varRequestId);
106 QUuid varRequestId);
105
107
106 QVector<SqpRange> provideNotInCacheDateTimeList(std::shared_ptr<Variable> variable,
107 const SqpRange &dateTime);
108
109 std::shared_ptr<Variable> findVariable(QUuid vIdentifier);
108 std::shared_ptr<Variable> findVariable(QUuid vIdentifier);
110 std::shared_ptr<IDataSeries>
109 std::shared_ptr<IDataSeries>
111 retrieveDataSeries(const QVector<AcquisitionDataPacket> acqDataPacketVector);
110 retrieveDataSeries(const QVector<AcquisitionDataPacket> acqDataPacketVector);
112
111
113 void registerProvider(std::shared_ptr<IDataProvider> provider);
112 void registerProvider(std::shared_ptr<IDataProvider> provider);
114
113
115 void storeVariableRequest(QUuid varId, QUuid varRequestId, const VariableRequest &varRequest);
114 void storeVariableRequest(QUuid varId, QUuid varRequestId, const VariableRequest &varRequest);
116 QUuid acceptVariableRequest(QUuid varId, std::shared_ptr<IDataSeries> dataSeries);
115 QUuid acceptVariableRequest(QUuid varId, std::shared_ptr<IDataSeries> dataSeries);
117 void updateVariableRequest(QUuid varRequestId);
116 void updateVariableRequest(QUuid varRequestId);
118 void cancelVariableRequest(QUuid varRequestId);
117 void cancelVariableRequest(QUuid varRequestId);
119
118
119 SqpRange getLastRequestedRange(QUuid varId);
120
120 QMutex m_WorkingMutex;
121 QMutex m_WorkingMutex;
121 /// Variable model. The VariableController has the ownership
122 /// Variable model. The VariableController has the ownership
122 VariableModel *m_VariableModel;
123 VariableModel *m_VariableModel;
123 QItemSelectionModel *m_VariableSelectionModel;
124 QItemSelectionModel *m_VariableSelectionModel;
124
125
125
126
126 TimeController *m_TimeController{nullptr};
127 TimeController *m_TimeController{nullptr};
127 std::unique_ptr<VariableCacheStrategy> m_VariableCacheStrategy;
128 std::unique_ptr<VariableCacheStrategy> m_VariableCacheStrategy;
128 std::unique_ptr<VariableAcquisitionWorker> m_VariableAcquisitionWorker;
129 std::unique_ptr<VariableAcquisitionWorker> m_VariableAcquisitionWorker;
129 QThread m_VariableAcquisitionWorkerThread;
130 QThread m_VariableAcquisitionWorkerThread;
130
131
131 std::unordered_map<std::shared_ptr<Variable>, std::shared_ptr<IDataProvider> >
132 std::unordered_map<std::shared_ptr<Variable>, std::shared_ptr<IDataProvider> >
132 m_VariableToProviderMap;
133 m_VariableToProviderMap;
133 std::unordered_map<std::shared_ptr<Variable>, QUuid> m_VariableToIdentifierMap;
134 std::unordered_map<std::shared_ptr<Variable>, QUuid> m_VariableToIdentifierMap;
134 std::map<QUuid, std::shared_ptr<VariableSynchronizationGroup> >
135 std::map<QUuid, std::shared_ptr<VariableSynchronizationGroup> >
135 m_GroupIdToVariableSynchronizationGroupMap;
136 m_GroupIdToVariableSynchronizationGroupMap;
136 std::map<QUuid, QUuid> m_VariableIdGroupIdMap;
137 std::map<QUuid, QUuid> m_VariableIdGroupIdMap;
137 std::set<std::shared_ptr<IDataProvider> > m_ProviderSet;
138 std::set<std::shared_ptr<IDataProvider> > m_ProviderSet;
138
139
139 std::map<QUuid, std::map<QUuid, VariableRequest> > m_VarRequestIdToVarIdVarRequestMap;
140 std::map<QUuid, std::map<QUuid, VariableRequest> > m_VarRequestIdToVarIdVarRequestMap;
140
141
141 std::map<QUuid, std::deque<QUuid> > m_VarIdToVarRequestIdQueueMap;
142 std::map<QUuid, std::deque<QUuid> > m_VarIdToVarRequestIdQueueMap;
142
143
143
144
144 VariableController *q;
145 VariableController *q;
145 };
146 };
146
147
147
148
148 VariableController::VariableController(QObject *parent)
149 VariableController::VariableController(QObject *parent)
149 : QObject{parent}, impl{spimpl::make_unique_impl<VariableControllerPrivate>(this)}
150 : QObject{parent}, impl{spimpl::make_unique_impl<VariableControllerPrivate>(this)}
150 {
151 {
151 qCDebug(LOG_VariableController()) << tr("VariableController construction")
152 qCDebug(LOG_VariableController()) << tr("VariableController construction")
152 << QThread::currentThread();
153 << QThread::currentThread();
153
154
154 connect(impl->m_VariableModel, &VariableModel::abortProgessRequested, this,
155 connect(impl->m_VariableModel, &VariableModel::abortProgessRequested, this,
155 &VariableController::onAbortProgressRequested);
156 &VariableController::onAbortProgressRequested);
156
157
157 connect(impl->m_VariableAcquisitionWorker.get(),
158 connect(impl->m_VariableAcquisitionWorker.get(),
158 &VariableAcquisitionWorker::variableCanceledRequested, this,
159 &VariableAcquisitionWorker::variableCanceledRequested, this,
159 &VariableController::onAbortAcquisitionRequested);
160 &VariableController::onAbortAcquisitionRequested);
160
161
161 connect(impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::dataProvided, this,
162 connect(impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::dataProvided, this,
162 &VariableController::onDataProvided);
163 &VariableController::onDataProvided);
163 connect(impl->m_VariableAcquisitionWorker.get(),
164 connect(impl->m_VariableAcquisitionWorker.get(),
164 &VariableAcquisitionWorker::variableRequestInProgress, this,
165 &VariableAcquisitionWorker::variableRequestInProgress, this,
165 &VariableController::onVariableRetrieveDataInProgress);
166 &VariableController::onVariableRetrieveDataInProgress);
166
167
167
168
168 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::started,
169 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::started,
169 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::initialize);
170 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::initialize);
170 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::finished,
171 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::finished,
171 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::finalize);
172 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::finalize);
172
173
173
174
174 impl->m_VariableAcquisitionWorkerThread.start();
175 impl->m_VariableAcquisitionWorkerThread.start();
175 }
176 }
176
177
177 VariableController::~VariableController()
178 VariableController::~VariableController()
178 {
179 {
179 qCDebug(LOG_VariableController()) << tr("VariableController destruction")
180 qCDebug(LOG_VariableController()) << tr("VariableController destruction")
180 << QThread::currentThread();
181 << QThread::currentThread();
181 this->waitForFinish();
182 this->waitForFinish();
182 }
183 }
183
184
184 VariableModel *VariableController::variableModel() noexcept
185 VariableModel *VariableController::variableModel() noexcept
185 {
186 {
186 return impl->m_VariableModel;
187 return impl->m_VariableModel;
187 }
188 }
188
189
189 QItemSelectionModel *VariableController::variableSelectionModel() noexcept
190 QItemSelectionModel *VariableController::variableSelectionModel() noexcept
190 {
191 {
191 return impl->m_VariableSelectionModel;
192 return impl->m_VariableSelectionModel;
192 }
193 }
193
194
194 void VariableController::setTimeController(TimeController *timeController) noexcept
195 void VariableController::setTimeController(TimeController *timeController) noexcept
195 {
196 {
196 impl->m_TimeController = timeController;
197 impl->m_TimeController = timeController;
197 }
198 }
198
199
199 std::shared_ptr<Variable>
200 std::shared_ptr<Variable>
200 VariableController::cloneVariable(std::shared_ptr<Variable> variable) noexcept
201 VariableController::cloneVariable(std::shared_ptr<Variable> variable) noexcept
201 {
202 {
202 if (impl->m_VariableModel->containsVariable(variable)) {
203 if (impl->m_VariableModel->containsVariable(variable)) {
203 // Clones variable
204 // Clones variable
204 auto duplicate = variable->clone();
205 auto duplicate = variable->clone();
205
206
206 // Adds clone to model
207 // Adds clone to model
207 impl->m_VariableModel->addVariable(duplicate);
208 impl->m_VariableModel->addVariable(duplicate);
208
209
209 // Generates clone identifier
210 // Generates clone identifier
210 impl->m_VariableToIdentifierMap[duplicate] = QUuid::createUuid();
211 impl->m_VariableToIdentifierMap[duplicate] = QUuid::createUuid();
211
212
212 // Registers provider
213 // Registers provider
213 auto variableProvider = impl->m_VariableToProviderMap.at(variable);
214 auto variableProvider = impl->m_VariableToProviderMap.at(variable);
214 auto duplicateProvider = variableProvider != nullptr ? variableProvider->clone() : nullptr;
215 auto duplicateProvider = variableProvider != nullptr ? variableProvider->clone() : nullptr;
215
216
216 impl->m_VariableToProviderMap[duplicate] = duplicateProvider;
217 impl->m_VariableToProviderMap[duplicate] = duplicateProvider;
217 if (duplicateProvider) {
218 if (duplicateProvider) {
218 impl->registerProvider(duplicateProvider);
219 impl->registerProvider(duplicateProvider);
219 }
220 }
220
221
221 return duplicate;
222 return duplicate;
222 }
223 }
223 else {
224 else {
224 qCCritical(LOG_VariableController())
225 qCCritical(LOG_VariableController())
225 << tr("Can't create duplicate of variable %1: variable not registered in the model")
226 << tr("Can't create duplicate of variable %1: variable not registered in the model")
226 .arg(variable->name());
227 .arg(variable->name());
227 return nullptr;
228 return nullptr;
228 }
229 }
229 }
230 }
230
231
231 void VariableController::deleteVariable(std::shared_ptr<Variable> variable) noexcept
232 void VariableController::deleteVariable(std::shared_ptr<Variable> variable) noexcept
232 {
233 {
233 if (!variable) {
234 if (!variable) {
234 qCCritical(LOG_VariableController()) << "Can't delete variable: variable is null";
235 qCCritical(LOG_VariableController()) << "Can't delete variable: variable is null";
235 return;
236 return;
236 }
237 }
237
238
238 // Spreads in SciQlop that the variable will be deleted, so that potential receivers can
239 // Spreads in SciQlop that the variable will be deleted, so that potential receivers can
239 // make some treatments before the deletion
240 // make some treatments before the deletion
240 emit variableAboutToBeDeleted(variable);
241 emit variableAboutToBeDeleted(variable);
241
242
242 // Deletes identifier
243 // Deletes identifier
243 impl->m_VariableToIdentifierMap.erase(variable);
244 impl->m_VariableToIdentifierMap.erase(variable);
244
245
245 // Deletes provider
246 // Deletes provider
246 auto nbProvidersDeleted = impl->m_VariableToProviderMap.erase(variable);
247 auto nbProvidersDeleted = impl->m_VariableToProviderMap.erase(variable);
247 qCDebug(LOG_VariableController())
248 qCDebug(LOG_VariableController())
248 << tr("Number of providers deleted for variable %1: %2")
249 << tr("Number of providers deleted for variable %1: %2")
249 .arg(variable->name(), QString::number(nbProvidersDeleted));
250 .arg(variable->name(), QString::number(nbProvidersDeleted));
250
251
251
252
252 // Deletes from model
253 // Deletes from model
253 impl->m_VariableModel->deleteVariable(variable);
254 impl->m_VariableModel->deleteVariable(variable);
254 }
255 }
255
256
256 void VariableController::deleteVariables(
257 void VariableController::deleteVariables(
257 const QVector<std::shared_ptr<Variable> > &variables) noexcept
258 const QVector<std::shared_ptr<Variable> > &variables) noexcept
258 {
259 {
259 for (auto variable : qAsConst(variables)) {
260 for (auto variable : qAsConst(variables)) {
260 deleteVariable(variable);
261 deleteVariable(variable);
261 }
262 }
262 }
263 }
263
264
264 std::shared_ptr<Variable>
265 std::shared_ptr<Variable>
265 VariableController::createVariable(const QString &name, const QVariantHash &metadata,
266 VariableController::createVariable(const QString &name, const QVariantHash &metadata,
266 std::shared_ptr<IDataProvider> provider) noexcept
267 std::shared_ptr<IDataProvider> provider) noexcept
267 {
268 {
268 if (!impl->m_TimeController) {
269 if (!impl->m_TimeController) {
269 qCCritical(LOG_VariableController())
270 qCCritical(LOG_VariableController())
270 << tr("Impossible to create variable: The time controller is null");
271 << tr("Impossible to create variable: The time controller is null");
271 return nullptr;
272 return nullptr;
272 }
273 }
273
274
274 auto range = impl->m_TimeController->dateTime();
275 auto range = impl->m_TimeController->dateTime();
275
276
276 if (auto newVariable = impl->m_VariableModel->createVariable(name, metadata)) {
277 if (auto newVariable = impl->m_VariableModel->createVariable(name, metadata)) {
277 auto identifier = QUuid::createUuid();
278 auto identifier = QUuid::createUuid();
278
279
279 // store the provider
280 // store the provider
280 impl->registerProvider(provider);
281 impl->registerProvider(provider);
281
282
282 // Associate the provider
283 // Associate the provider
283 impl->m_VariableToProviderMap[newVariable] = provider;
284 impl->m_VariableToProviderMap[newVariable] = provider;
284 qCInfo(LOG_VariableController()) << "createVariable: " << identifier;
285 qCInfo(LOG_VariableController()) << "createVariable: " << identifier;
285 impl->m_VariableToIdentifierMap[newVariable] = identifier;
286 impl->m_VariableToIdentifierMap[newVariable] = identifier;
286
287
287
288
288 auto varRequestId = QUuid::createUuid();
289 auto varRequestId = QUuid::createUuid();
289 impl->processRequest(newVariable, range, varRequestId);
290 impl->processRequest(newVariable, range, varRequestId);
290 impl->updateVariableRequest(varRequestId);
291 impl->updateVariableRequest(varRequestId);
291
292
292 return newVariable;
293 return newVariable;
293 }
294 }
294 }
295 }
295
296
296 void VariableController::onDateTimeOnSelection(const SqpRange &dateTime)
297 void VariableController::onDateTimeOnSelection(const SqpRange &dateTime)
297 {
298 {
298 // TODO check synchronisation and Rescale
299 // NOTE: Even if acquisition request is aborting, the graphe range will be changed
299 qCDebug(LOG_VariableController()) << "VariableController::onDateTimeOnSelection"
300 qCDebug(LOG_VariableController()) << "VariableController::onDateTimeOnSelection"
300 << QThread::currentThread()->objectName();
301 << QThread::currentThread()->objectName();
301 auto selectedRows = impl->m_VariableSelectionModel->selectedRows();
302 auto selectedRows = impl->m_VariableSelectionModel->selectedRows();
302 auto varRequestId = QUuid::createUuid();
303 auto variables = QVector<std::shared_ptr<Variable> >{};
303
304
304 for (const auto &selectedRow : qAsConst(selectedRows)) {
305 for (const auto &selectedRow : qAsConst(selectedRows)) {
305 if (auto selectedVariable = impl->m_VariableModel->variable(selectedRow.row())) {
306 if (auto selectedVariable = impl->m_VariableModel->variable(selectedRow.row())) {
306 selectedVariable->setRange(dateTime);
307 variables << selectedVariable;
307 impl->processRequest(selectedVariable, dateTime, varRequestId);
308
308
309 // notify that rescale operation has to be done
309 // notify that rescale operation has to be done
310 emit rangeChanged(selectedVariable, dateTime);
310 emit rangeChanged(selectedVariable, dateTime);
311 }
311 }
312 }
312 }
313 impl->updateVariableRequest(varRequestId);
313
314 if (!variables.isEmpty()) {
315 this->onRequestDataLoading(variables, dateTime, true);
316 }
314 }
317 }
315
318
316 void VariableController::onDataProvided(QUuid vIdentifier, const SqpRange &rangeRequested,
319 void VariableController::onDataProvided(QUuid vIdentifier, const SqpRange &rangeRequested,
317 const SqpRange &cacheRangeRequested,
320 const SqpRange &cacheRangeRequested,
318 QVector<AcquisitionDataPacket> dataAcquired)
321 QVector<AcquisitionDataPacket> dataAcquired)
319 {
322 {
320 auto retrievedDataSeries = impl->retrieveDataSeries(dataAcquired);
323 auto retrievedDataSeries = impl->retrieveDataSeries(dataAcquired);
321 auto varRequestId = impl->acceptVariableRequest(vIdentifier, retrievedDataSeries);
324 auto varRequestId = impl->acceptVariableRequest(vIdentifier, retrievedDataSeries);
322 if (!varRequestId.isNull()) {
325 if (!varRequestId.isNull()) {
323 impl->updateVariableRequest(varRequestId);
326 impl->updateVariableRequest(varRequestId);
324 }
327 }
325 }
328 }
326
329
327 void VariableController::onVariableRetrieveDataInProgress(QUuid identifier, double progress)
330 void VariableController::onVariableRetrieveDataInProgress(QUuid identifier, double progress)
328 {
331 {
329 qCDebug(LOG_VariableController())
332 qCDebug(LOG_VariableController())
330 << "TORM: variableController::onVariableRetrieveDataInProgress"
333 << "TORM: variableController::onVariableRetrieveDataInProgress"
331 << QThread::currentThread()->objectName() << progress;
334 << QThread::currentThread()->objectName() << progress;
332 if (auto var = impl->findVariable(identifier)) {
335 if (auto var = impl->findVariable(identifier)) {
333 impl->m_VariableModel->setDataProgress(var, progress);
336 impl->m_VariableModel->setDataProgress(var, progress);
334 }
337 }
335 else {
338 else {
336 qCCritical(LOG_VariableController())
339 qCCritical(LOG_VariableController())
337 << tr("Impossible to notify progression of a null variable");
340 << tr("Impossible to notify progression of a null variable");
338 }
341 }
339 }
342 }
340
343
341 void VariableController::onAbortProgressRequested(std::shared_ptr<Variable> variable)
344 void VariableController::onAbortProgressRequested(std::shared_ptr<Variable> variable)
342 {
345 {
343 auto it = impl->m_VariableToIdentifierMap.find(variable);
346 auto it = impl->m_VariableToIdentifierMap.find(variable);
344 if (it != impl->m_VariableToIdentifierMap.cend()) {
347 if (it != impl->m_VariableToIdentifierMap.cend()) {
345 impl->m_VariableAcquisitionWorker->abortProgressRequested(it->second);
348 impl->m_VariableAcquisitionWorker->abortProgressRequested(it->second);
346
349
347 QUuid varRequestId;
350 QUuid varRequestId;
348 auto varIdToVarRequestIdQueueMapIt = impl->m_VarIdToVarRequestIdQueueMap.find(it->second);
351 auto varIdToVarRequestIdQueueMapIt = impl->m_VarIdToVarRequestIdQueueMap.find(it->second);
349 if (varIdToVarRequestIdQueueMapIt != impl->m_VarIdToVarRequestIdQueueMap.cend()) {
352 if (varIdToVarRequestIdQueueMapIt != impl->m_VarIdToVarRequestIdQueueMap.cend()) {
350 auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second;
353 auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second;
351 varRequestId = varRequestIdQueue.front();
354 varRequestId = varRequestIdQueue.front();
352 impl->cancelVariableRequest(varRequestId);
355 impl->cancelVariableRequest(varRequestId);
353
356
354 // Finish the progression for the request
357 // Finish the progression for the request
355 impl->m_VariableModel->setDataProgress(variable, 0.0);
358 impl->m_VariableModel->setDataProgress(variable, 0.0);
356 }
359 }
357 else {
360 else {
358 qCWarning(LOG_VariableController())
361 qCWarning(LOG_VariableController())
359 << tr("Aborting progression of inexistant variable request detected !!!")
362 << tr("Aborting progression of inexistant variable request detected !!!")
360 << QThread::currentThread()->objectName();
363 << QThread::currentThread()->objectName();
361 }
364 }
362 }
365 }
363 else {
366 else {
364 qCWarning(LOG_VariableController())
367 qCWarning(LOG_VariableController())
365 << tr("Aborting progression of inexistant variable detected !!!")
368 << tr("Aborting progression of inexistant variable detected !!!")
366 << QThread::currentThread()->objectName();
369 << QThread::currentThread()->objectName();
367 }
370 }
368 }
371 }
369
372
370 void VariableController::onAbortAcquisitionRequested(QUuid vIdentifier)
373 void VariableController::onAbortAcquisitionRequested(QUuid vIdentifier)
371 {
374 {
372 qCDebug(LOG_VariableController()) << "TORM: variableController::onAbortAcquisitionRequested"
375 qCDebug(LOG_VariableController()) << "TORM: variableController::onAbortAcquisitionRequested"
373 << QThread::currentThread()->objectName() << vIdentifier;
376 << QThread::currentThread()->objectName() << vIdentifier;
374
377
375 if (auto var = impl->findVariable(vIdentifier)) {
378 if (auto var = impl->findVariable(vIdentifier)) {
376 this->onAbortProgressRequested(var);
379 this->onAbortProgressRequested(var);
377 }
380 }
378 else {
381 else {
379 qCCritical(LOG_VariableController())
382 qCCritical(LOG_VariableController())
380 << tr("Impossible to abort Acquisition Requestof a null variable");
383 << tr("Impossible to abort Acquisition Requestof a null variable");
381 }
384 }
382 }
385 }
383
386
384 void VariableController::onAddSynchronizationGroupId(QUuid synchronizationGroupId)
387 void VariableController::onAddSynchronizationGroupId(QUuid synchronizationGroupId)
385 {
388 {
386 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronizationGroupId"
389 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronizationGroupId"
387 << QThread::currentThread()->objectName()
390 << QThread::currentThread()->objectName()
388 << synchronizationGroupId;
391 << synchronizationGroupId;
389 auto vSynchroGroup = std::make_shared<VariableSynchronizationGroup>();
392 auto vSynchroGroup = std::make_shared<VariableSynchronizationGroup>();
390 impl->m_GroupIdToVariableSynchronizationGroupMap.insert(
393 impl->m_GroupIdToVariableSynchronizationGroupMap.insert(
391 std::make_pair(synchronizationGroupId, vSynchroGroup));
394 std::make_pair(synchronizationGroupId, vSynchroGroup));
392 }
395 }
393
396
394 void VariableController::onRemoveSynchronizationGroupId(QUuid synchronizationGroupId)
397 void VariableController::onRemoveSynchronizationGroupId(QUuid synchronizationGroupId)
395 {
398 {
396 impl->m_GroupIdToVariableSynchronizationGroupMap.erase(synchronizationGroupId);
399 impl->m_GroupIdToVariableSynchronizationGroupMap.erase(synchronizationGroupId);
397 }
400 }
398
401
399 void VariableController::onAddSynchronized(std::shared_ptr<Variable> variable,
402 void VariableController::onAddSynchronized(std::shared_ptr<Variable> variable,
400 QUuid synchronizationGroupId)
403 QUuid synchronizationGroupId)
401
404
402 {
405 {
403 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronized"
406 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronized"
404 << synchronizationGroupId;
407 << synchronizationGroupId;
405 auto varToVarIdIt = impl->m_VariableToIdentifierMap.find(variable);
408 auto varToVarIdIt = impl->m_VariableToIdentifierMap.find(variable);
406 if (varToVarIdIt != impl->m_VariableToIdentifierMap.cend()) {
409 if (varToVarIdIt != impl->m_VariableToIdentifierMap.cend()) {
407 auto groupIdToVSGIt
410 auto groupIdToVSGIt
408 = impl->m_GroupIdToVariableSynchronizationGroupMap.find(synchronizationGroupId);
411 = impl->m_GroupIdToVariableSynchronizationGroupMap.find(synchronizationGroupId);
409 if (groupIdToVSGIt != impl->m_GroupIdToVariableSynchronizationGroupMap.cend()) {
412 if (groupIdToVSGIt != impl->m_GroupIdToVariableSynchronizationGroupMap.cend()) {
410 impl->m_VariableIdGroupIdMap.insert(
413 impl->m_VariableIdGroupIdMap.insert(
411 std::make_pair(varToVarIdIt->second, synchronizationGroupId));
414 std::make_pair(varToVarIdIt->second, synchronizationGroupId));
412 groupIdToVSGIt->second->addVariableId(varToVarIdIt->second);
415 groupIdToVSGIt->second->addVariableId(varToVarIdIt->second);
413 }
416 }
414 else {
417 else {
415 qCCritical(LOG_VariableController())
418 qCCritical(LOG_VariableController())
416 << tr("Impossible to synchronize a variable with an unknown sycnhronization group")
419 << tr("Impossible to synchronize a variable with an unknown sycnhronization group")
417 << variable->name();
420 << variable->name();
418 }
421 }
419 }
422 }
420 else {
423 else {
421 qCCritical(LOG_VariableController())
424 qCCritical(LOG_VariableController())
422 << tr("Impossible to synchronize a variable with no identifier") << variable->name();
425 << tr("Impossible to synchronize a variable with no identifier") << variable->name();
423 }
426 }
424 }
427 }
425
428
426 void VariableController::desynchronize(std::shared_ptr<Variable> variable,
429 void VariableController::desynchronize(std::shared_ptr<Variable> variable,
427 QUuid synchronizationGroupId)
430 QUuid synchronizationGroupId)
428 {
431 {
429 // Gets variable id
432 // Gets variable id
430 auto variableIt = impl->m_VariableToIdentifierMap.find(variable);
433 auto variableIt = impl->m_VariableToIdentifierMap.find(variable);
431 if (variableIt == impl->m_VariableToIdentifierMap.cend()) {
434 if (variableIt == impl->m_VariableToIdentifierMap.cend()) {
432 qCCritical(LOG_VariableController())
435 qCCritical(LOG_VariableController())
433 << tr("Can't desynchronize variable %1: variable identifier not found")
436 << tr("Can't desynchronize variable %1: variable identifier not found")
434 .arg(variable->name());
437 .arg(variable->name());
435 return;
438 return;
436 }
439 }
437
440
438 // Gets synchronization group
441 // Gets synchronization group
439 auto groupIt = impl->m_GroupIdToVariableSynchronizationGroupMap.find(synchronizationGroupId);
442 auto groupIt = impl->m_GroupIdToVariableSynchronizationGroupMap.find(synchronizationGroupId);
440 if (groupIt == impl->m_GroupIdToVariableSynchronizationGroupMap.cend()) {
443 if (groupIt == impl->m_GroupIdToVariableSynchronizationGroupMap.cend()) {
441 qCCritical(LOG_VariableController())
444 qCCritical(LOG_VariableController())
442 << tr("Can't desynchronize variable %1: unknown synchronization group")
445 << tr("Can't desynchronize variable %1: unknown synchronization group")
443 .arg(variable->name());
446 .arg(variable->name());
444 return;
447 return;
445 }
448 }
446
449
447 auto variableId = variableIt->second;
450 auto variableId = variableIt->second;
448
451
449 // Removes variable from synchronization group
452 // Removes variable from synchronization group
450 auto synchronizationGroup = groupIt->second;
453 auto synchronizationGroup = groupIt->second;
451 synchronizationGroup->removeVariableId(variableId);
454 synchronizationGroup->removeVariableId(variableId);
452
455
453 // Removes link between variable and synchronization group
456 // Removes link between variable and synchronization group
454 impl->m_VariableIdGroupIdMap.erase(variableId);
457 impl->m_VariableIdGroupIdMap.erase(variableId);
455 }
458 }
456
459
457 void VariableController::onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables,
460 void VariableController::onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables,
458 const SqpRange &range, const SqpRange &oldRange,
461 const SqpRange &range, bool synchronise)
459 bool synchronise)
460 {
462 {
461 // NOTE: oldRange isn't really necessary since oldRange == variable->range().
463 // NOTE: oldRange isn't really necessary since oldRange == variable->range().
462
464
463 // we want to load data of the variable for the dateTime.
465 // we want to load data of the variable for the dateTime.
464 // First we check if the cache contains some of them.
466 // First we check if the cache contains some of them.
465 // For the other, we ask the provider to give them.
467 // For the other, we ask the provider to give them.
466
468
467 auto varRequestId = QUuid::createUuid();
469 auto varRequestId = QUuid::createUuid();
468 qCDebug(LOG_VariableController()) << "VariableController::onRequestDataLoading"
470 qCDebug(LOG_VariableController()) << "VariableController::onRequestDataLoading"
469 << QThread::currentThread()->objectName() << varRequestId;
471 << QThread::currentThread()->objectName() << varRequestId;
470
472
471 for (const auto &var : variables) {
473 for (const auto &var : variables) {
472 qCDebug(LOG_VariableController()) << "processRequest for" << var->name() << varRequestId;
474 qCDebug(LOG_VariableController()) << "processRequest for" << var->name() << varRequestId;
473 impl->processRequest(var, range, varRequestId);
475 impl->processRequest(var, range, varRequestId);
474 }
476 }
475
477
476 if (synchronise) {
478 if (synchronise) {
477 // Get the group ids
479 // Get the group ids
478 qCDebug(LOG_VariableController())
480 qCDebug(LOG_VariableController())
479 << "TORM VariableController::onRequestDataLoading for synchro var ENABLE";
481 << "TORM VariableController::onRequestDataLoading for synchro var ENABLE";
480 auto groupIds = std::set<QUuid>{};
482 auto groupIds = std::set<QUuid>{};
481 auto groupIdToOldRangeMap = std::map<QUuid, SqpRange>{};
483 auto groupIdToOldRangeMap = std::map<QUuid, SqpRange>{};
482 for (const auto &var : variables) {
484 for (const auto &var : variables) {
483 auto varToVarIdIt = impl->m_VariableToIdentifierMap.find(var);
485 auto varToVarIdIt = impl->m_VariableToIdentifierMap.find(var);
484 if (varToVarIdIt != impl->m_VariableToIdentifierMap.cend()) {
486 if (varToVarIdIt != impl->m_VariableToIdentifierMap.cend()) {
485 auto vId = varToVarIdIt->second;
487 auto vId = varToVarIdIt->second;
486 auto varIdToGroupIdIt = impl->m_VariableIdGroupIdMap.find(vId);
488 auto varIdToGroupIdIt = impl->m_VariableIdGroupIdMap.find(vId);
487 if (varIdToGroupIdIt != impl->m_VariableIdGroupIdMap.cend()) {
489 if (varIdToGroupIdIt != impl->m_VariableIdGroupIdMap.cend()) {
488 auto gId = varIdToGroupIdIt->second;
490 auto gId = varIdToGroupIdIt->second;
489 groupIdToOldRangeMap.insert(std::make_pair(gId, var->range()));
491 groupIdToOldRangeMap.insert(std::make_pair(gId, var->range()));
490 if (groupIds.find(gId) == groupIds.cend()) {
492 if (groupIds.find(gId) == groupIds.cend()) {
491 qCDebug(LOG_VariableController()) << "Synchro detect group " << gId;
493 qCDebug(LOG_VariableController()) << "Synchro detect group " << gId;
492 groupIds.insert(gId);
494 groupIds.insert(gId);
493 }
495 }
494 }
496 }
495 }
497 }
496 }
498 }
497
499
498 // We assume here all group ids exist
500 // We assume here all group ids exist
499 for (const auto &gId : groupIds) {
501 for (const auto &gId : groupIds) {
500 auto vSynchronizationGroup = impl->m_GroupIdToVariableSynchronizationGroupMap.at(gId);
502 auto vSynchronizationGroup = impl->m_GroupIdToVariableSynchronizationGroupMap.at(gId);
501 auto vSyncIds = vSynchronizationGroup->getIds();
503 auto vSyncIds = vSynchronizationGroup->getIds();
502 qCDebug(LOG_VariableController()) << "Var in synchro group ";
504 qCDebug(LOG_VariableController()) << "Var in synchro group ";
503 for (auto vId : vSyncIds) {
505 for (auto vId : vSyncIds) {
504 auto var = impl->findVariable(vId);
506 auto var = impl->findVariable(vId);
505
507
506 // Don't process already processed var
508 // Don't process already processed var
507 if (!variables.contains(var)) {
509 if (!variables.contains(var)) {
508 if (var != nullptr) {
510 if (var != nullptr) {
509 qCDebug(LOG_VariableController()) << "processRequest synchro for"
511 qCDebug(LOG_VariableController()) << "processRequest synchro for"
510 << var->name();
512 << var->name();
511 auto vSyncRangeRequested = computeSynchroRangeRequested(
513 auto vSyncRangeRequested = computeSynchroRangeRequested(
512 var->range(), range, groupIdToOldRangeMap.at(gId));
514 var->range(), range, groupIdToOldRangeMap.at(gId));
513 qCDebug(LOG_VariableController()) << "synchro RR" << vSyncRangeRequested;
515 qCDebug(LOG_VariableController()) << "synchro RR" << vSyncRangeRequested;
514 impl->processRequest(var, vSyncRangeRequested, varRequestId);
516 impl->processRequest(var, vSyncRangeRequested, varRequestId);
515 }
517 }
516 else {
518 else {
517 qCCritical(LOG_VariableController())
519 qCCritical(LOG_VariableController())
518
520
519 << tr("Impossible to synchronize a null variable");
521 << tr("Impossible to synchronize a null variable");
520 }
522 }
521 }
523 }
522 }
524 }
523 }
525 }
524 }
526 }
525
527
526 impl->updateVariableRequest(varRequestId);
528 impl->updateVariableRequest(varRequestId);
527 }
529 }
528
530
529
531
530 void VariableController::initialize()
532 void VariableController::initialize()
531 {
533 {
532 qCDebug(LOG_VariableController()) << tr("VariableController init") << QThread::currentThread();
534 qCDebug(LOG_VariableController()) << tr("VariableController init") << QThread::currentThread();
533 impl->m_WorkingMutex.lock();
535 impl->m_WorkingMutex.lock();
534 qCDebug(LOG_VariableController()) << tr("VariableController init END");
536 qCDebug(LOG_VariableController()) << tr("VariableController init END");
535 }
537 }
536
538
537 void VariableController::finalize()
539 void VariableController::finalize()
538 {
540 {
539 impl->m_WorkingMutex.unlock();
541 impl->m_WorkingMutex.unlock();
540 }
542 }
541
543
542 void VariableController::waitForFinish()
544 void VariableController::waitForFinish()
543 {
545 {
544 QMutexLocker locker{&impl->m_WorkingMutex};
546 QMutexLocker locker{&impl->m_WorkingMutex};
545 }
547 }
546
548
547 AcquisitionZoomType VariableController::getZoomType(const SqpRange &range, const SqpRange &oldRange)
549 AcquisitionZoomType VariableController::getZoomType(const SqpRange &range, const SqpRange &oldRange)
548 {
550 {
549 // t1.m_TStart <= t2.m_TStart && t2.m_TEnd <= t1.m_TEnd
551 // t1.m_TStart <= t2.m_TStart && t2.m_TEnd <= t1.m_TEnd
550 auto zoomType = AcquisitionZoomType::Unknown;
552 auto zoomType = AcquisitionZoomType::Unknown;
551 if (range.m_TStart <= oldRange.m_TStart && oldRange.m_TEnd <= range.m_TEnd) {
553 if (range.m_TStart <= oldRange.m_TStart && oldRange.m_TEnd <= range.m_TEnd) {
554 qCDebug(LOG_VariableController()) << "zoomtype: ZoomOut";
552 zoomType = AcquisitionZoomType::ZoomOut;
555 zoomType = AcquisitionZoomType::ZoomOut;
553 }
556 }
554 else if (range.m_TStart > oldRange.m_TStart && range.m_TEnd > oldRange.m_TEnd) {
557 else if (range.m_TStart > oldRange.m_TStart && range.m_TEnd > oldRange.m_TEnd) {
558 qCDebug(LOG_VariableController()) << "zoomtype: PanRight";
555 zoomType = AcquisitionZoomType::PanRight;
559 zoomType = AcquisitionZoomType::PanRight;
556 }
560 }
557 else if (range.m_TStart < oldRange.m_TStart && range.m_TEnd < oldRange.m_TEnd) {
561 else if (range.m_TStart < oldRange.m_TStart && range.m_TEnd < oldRange.m_TEnd) {
562 qCDebug(LOG_VariableController()) << "zoomtype: PanLeft";
558 zoomType = AcquisitionZoomType::PanLeft;
563 zoomType = AcquisitionZoomType::PanLeft;
559 }
564 }
560 else if (range.m_TStart > oldRange.m_TStart && oldRange.m_TEnd > range.m_TEnd) {
565 else if (range.m_TStart > oldRange.m_TStart && oldRange.m_TEnd > range.m_TEnd) {
566 qCDebug(LOG_VariableController()) << "zoomtype: ZoomIn";
561 zoomType = AcquisitionZoomType::ZoomIn;
567 zoomType = AcquisitionZoomType::ZoomIn;
562 }
568 }
563 else {
569 else {
564 qCCritical(LOG_VariableController()) << "getZoomType: Unknown type detected";
570 qCDebug(LOG_VariableController()) << "getZoomType: Unknown type detected";
565 }
571 }
566 return zoomType;
572 return zoomType;
567 }
573 }
568
574
569 void VariableController::VariableControllerPrivate::processRequest(std::shared_ptr<Variable> var,
575 void VariableController::VariableControllerPrivate::processRequest(std::shared_ptr<Variable> var,
570 const SqpRange &rangeRequested,
576 const SqpRange &rangeRequested,
571 QUuid varRequestId)
577 QUuid varRequestId)
572 {
578 {
573
574 // TODO: protect at
575 auto varRequest = VariableRequest{};
579 auto varRequest = VariableRequest{};
576 auto varId = m_VariableToIdentifierMap.at(var);
577
580
578 auto varStrategyRangesRequested
581 auto it = m_VariableToIdentifierMap.find(var);
579 = m_VariableCacheStrategy->computeRange(var->range(), rangeRequested);
582 if (it != m_VariableToIdentifierMap.cend()) {
580
583
581 auto notInCacheRangeList = QVector<SqpRange>{varStrategyRangesRequested.second};
584 auto varId = it->second;
582 auto inCacheRangeList = QVector<SqpRange>{};
583 if (m_VarIdToVarRequestIdQueueMap.find(varId) == m_VarIdToVarRequestIdQueueMap.cend()) {
584 notInCacheRangeList = var->provideNotInCacheRangeList(varStrategyRangesRequested.second);
585 inCacheRangeList = var->provideInCacheRangeList(varStrategyRangesRequested.second);
586 }
587
585
588 if (!notInCacheRangeList.empty()) {
586 auto oldRange = getLastRequestedRange(varId);
589 varRequest.m_RangeRequested = varStrategyRangesRequested.first;
590 varRequest.m_CacheRangeRequested = varStrategyRangesRequested.second;
591
587
592 // store VarRequest
588 // check for update oldRange to the last request range.
593 storeVariableRequest(varId, varRequestId, varRequest);
589 if (oldRange == INVALID_RANGE) {
590 oldRange = var->range();
591 }
594
592
595 auto varProvider = m_VariableToProviderMap.at(var);
593 auto varStrategyRangesRequested
596 if (varProvider != nullptr) {
594 = m_VariableCacheStrategy->computeRange(oldRange, rangeRequested);
597 auto varRequestIdCanceled = m_VariableAcquisitionWorker->pushVariableRequest(
595
598 varRequestId, varId, varStrategyRangesRequested.first,
596 auto notInCacheRangeList
599 varStrategyRangesRequested.second,
597 = Variable::provideNotInCacheRangeList(oldRange, varStrategyRangesRequested.second);
600 DataProviderParameters{std::move(notInCacheRangeList), var->metadata()},
598 auto inCacheRangeList
601 varProvider);
599 = Variable::provideInCacheRangeList(oldRange, varStrategyRangesRequested.second);
600
601 if (!notInCacheRangeList.empty()) {
602 varRequest.m_RangeRequested = varStrategyRangesRequested.first;
603 varRequest.m_CacheRangeRequested = varStrategyRangesRequested.second;
604
605 // store VarRequest
606 storeVariableRequest(varId, varRequestId, varRequest);
607
608 auto varProvider = m_VariableToProviderMap.at(var);
609 if (varProvider != nullptr) {
610 auto varRequestIdCanceled = m_VariableAcquisitionWorker->pushVariableRequest(
611 varRequestId, varId, varStrategyRangesRequested.first,
612 varStrategyRangesRequested.second,
613 DataProviderParameters{std::move(notInCacheRangeList), var->metadata()},
614 varProvider);
615
616 if (!varRequestIdCanceled.isNull()) {
617 qCInfo(LOG_VariableAcquisitionWorker()) << tr("varRequestIdCanceled: ")
618 << varRequestIdCanceled;
619 cancelVariableRequest(varRequestIdCanceled);
620 }
621 }
622 else {
623 qCCritical(LOG_VariableController())
624 << "Impossible to provide data with a null provider";
625 }
602
626
603 if (!varRequestIdCanceled.isNull()) {
627 if (!inCacheRangeList.empty()) {
604 qCDebug(LOG_VariableAcquisitionWorker()) << tr("vsarRequestIdCanceled: ")
628 emit q->updateVarDisplaying(var, inCacheRangeList.first());
605 << varRequestIdCanceled;
606 cancelVariableRequest(varRequestIdCanceled);
607 }
629 }
608 }
630 }
609 else {
631 else {
610 qCCritical(LOG_VariableController())
632 varRequest.m_RangeRequested = varStrategyRangesRequested.first;
611 << "Impossible to provide data with a null provider";
633 varRequest.m_CacheRangeRequested = varStrategyRangesRequested.second;
612 }
634 // store VarRequest
613
635 storeVariableRequest(varId, varRequestId, varRequest);
614 if (!inCacheRangeList.empty()) {
636 acceptVariableRequest(
615 emit q->updateVarDisplaying(var, inCacheRangeList.first());
637 varId, var->dataSeries()->subDataSeries(varStrategyRangesRequested.second));
616 }
638 }
617 }
639 }
618 else {
619 varRequest.m_RangeRequested = varStrategyRangesRequested.first;
620 varRequest.m_CacheRangeRequested = varStrategyRangesRequested.second;
621 // store VarRequest
622 storeVariableRequest(varId, varRequestId, varRequest);
623 acceptVariableRequest(varId,
624 var->dataSeries()->subDataSeries(varStrategyRangesRequested.second));
625 }
626 }
640 }
627
641
628 std::shared_ptr<Variable>
642 std::shared_ptr<Variable>
629 VariableController::VariableControllerPrivate::findVariable(QUuid vIdentifier)
643 VariableController::VariableControllerPrivate::findVariable(QUuid vIdentifier)
630 {
644 {
631 std::shared_ptr<Variable> var;
645 std::shared_ptr<Variable> var;
632 auto findReply = [vIdentifier](const auto &entry) { return vIdentifier == entry.second; };
646 auto findReply = [vIdentifier](const auto &entry) { return vIdentifier == entry.second; };
633
647
634 auto end = m_VariableToIdentifierMap.cend();
648 auto end = m_VariableToIdentifierMap.cend();
635 auto it = std::find_if(m_VariableToIdentifierMap.cbegin(), end, findReply);
649 auto it = std::find_if(m_VariableToIdentifierMap.cbegin(), end, findReply);
636 if (it != end) {
650 if (it != end) {
637 var = it->first;
651 var = it->first;
638 }
652 }
639 else {
653 else {
640 qCCritical(LOG_VariableController())
654 qCCritical(LOG_VariableController())
641 << tr("Impossible to find the variable with the identifier: ") << vIdentifier;
655 << tr("Impossible to find the variable with the identifier: ") << vIdentifier;
642 }
656 }
643
657
644 return var;
658 return var;
645 }
659 }
646
660
647 std::shared_ptr<IDataSeries> VariableController::VariableControllerPrivate::retrieveDataSeries(
661 std::shared_ptr<IDataSeries> VariableController::VariableControllerPrivate::retrieveDataSeries(
648 const QVector<AcquisitionDataPacket> acqDataPacketVector)
662 const QVector<AcquisitionDataPacket> acqDataPacketVector)
649 {
663 {
650 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size")
664 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size")
651 << acqDataPacketVector.size();
665 << acqDataPacketVector.size();
652 std::shared_ptr<IDataSeries> dataSeries;
666 std::shared_ptr<IDataSeries> dataSeries;
653 if (!acqDataPacketVector.isEmpty()) {
667 if (!acqDataPacketVector.isEmpty()) {
654 dataSeries = acqDataPacketVector[0].m_DateSeries;
668 dataSeries = acqDataPacketVector[0].m_DateSeries;
655 for (int i = 1; i < acqDataPacketVector.size(); ++i) {
669 for (int i = 1; i < acqDataPacketVector.size(); ++i) {
656 dataSeries->merge(acqDataPacketVector[i].m_DateSeries.get());
670 dataSeries->merge(acqDataPacketVector[i].m_DateSeries.get());
657 }
671 }
658 }
672 }
659 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size END")
673 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size END")
660 << acqDataPacketVector.size();
674 << acqDataPacketVector.size();
661 return dataSeries;
675 return dataSeries;
662 }
676 }
663
677
664 void VariableController::VariableControllerPrivate::registerProvider(
678 void VariableController::VariableControllerPrivate::registerProvider(
665 std::shared_ptr<IDataProvider> provider)
679 std::shared_ptr<IDataProvider> provider)
666 {
680 {
667 if (m_ProviderSet.find(provider) == m_ProviderSet.end()) {
681 if (m_ProviderSet.find(provider) == m_ProviderSet.end()) {
668 qCDebug(LOG_VariableController()) << tr("Registering of a new provider")
682 qCDebug(LOG_VariableController()) << tr("Registering of a new provider")
669 << provider->objectName();
683 << provider->objectName();
670 m_ProviderSet.insert(provider);
684 m_ProviderSet.insert(provider);
671 connect(provider.get(), &IDataProvider::dataProvided, m_VariableAcquisitionWorker.get(),
685 connect(provider.get(), &IDataProvider::dataProvided, m_VariableAcquisitionWorker.get(),
672 &VariableAcquisitionWorker::onVariableDataAcquired);
686 &VariableAcquisitionWorker::onVariableDataAcquired);
673 connect(provider.get(), &IDataProvider::dataProvidedProgress,
687 connect(provider.get(), &IDataProvider::dataProvidedProgress,
674 m_VariableAcquisitionWorker.get(),
688 m_VariableAcquisitionWorker.get(),
675 &VariableAcquisitionWorker::onVariableRetrieveDataInProgress);
689 &VariableAcquisitionWorker::onVariableRetrieveDataInProgress);
676 connect(provider.get(), &IDataProvider::dataProvidedFailed,
690 connect(provider.get(), &IDataProvider::dataProvidedFailed,
677 m_VariableAcquisitionWorker.get(),
691 m_VariableAcquisitionWorker.get(),
678 &VariableAcquisitionWorker::onVariableAcquisitionFailed);
692 &VariableAcquisitionWorker::onVariableAcquisitionFailed);
679 }
693 }
680 else {
694 else {
681 qCDebug(LOG_VariableController()) << tr("Cannot register provider, it already exists ");
695 qCDebug(LOG_VariableController()) << tr("Cannot register provider, it already exists ");
682 }
696 }
683 }
697 }
684
698
685 void VariableController::VariableControllerPrivate::storeVariableRequest(
699 void VariableController::VariableControllerPrivate::storeVariableRequest(
686 QUuid varId, QUuid varRequestId, const VariableRequest &varRequest)
700 QUuid varId, QUuid varRequestId, const VariableRequest &varRequest)
687 {
701 {
688 // First request for the variable. we can create an entry for it
702 // First request for the variable. we can create an entry for it
689 auto varIdToVarRequestIdQueueMapIt = m_VarIdToVarRequestIdQueueMap.find(varId);
703 auto varIdToVarRequestIdQueueMapIt = m_VarIdToVarRequestIdQueueMap.find(varId);
690 if (varIdToVarRequestIdQueueMapIt == m_VarIdToVarRequestIdQueueMap.cend()) {
704 if (varIdToVarRequestIdQueueMapIt == m_VarIdToVarRequestIdQueueMap.cend()) {
691 auto varRequestIdQueue = std::deque<QUuid>{};
705 auto varRequestIdQueue = std::deque<QUuid>{};
692 qCDebug(LOG_VariableController()) << tr("Store REQUEST in QUEUE");
706 qCDebug(LOG_VariableController()) << tr("Store REQUEST in QUEUE");
693 varRequestIdQueue.push_back(varRequestId);
707 varRequestIdQueue.push_back(varRequestId);
694 m_VarIdToVarRequestIdQueueMap.insert(std::make_pair(varId, std::move(varRequestIdQueue)));
708 m_VarIdToVarRequestIdQueueMap.insert(std::make_pair(varId, std::move(varRequestIdQueue)));
695 }
709 }
696 else {
710 else {
697 qCDebug(LOG_VariableController()) << tr("Store REQUEST in EXISTING QUEUE");
711 qCDebug(LOG_VariableController()) << tr("Store REQUEST in EXISTING QUEUE");
698 auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second;
712 auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second;
699 varRequestIdQueue.push_back(varRequestId);
713 varRequestIdQueue.push_back(varRequestId);
700 }
714 }
701
715
702 auto varRequestIdToVarIdVarRequestMapIt = m_VarRequestIdToVarIdVarRequestMap.find(varRequestId);
716 auto varRequestIdToVarIdVarRequestMapIt = m_VarRequestIdToVarIdVarRequestMap.find(varRequestId);
703 if (varRequestIdToVarIdVarRequestMapIt == m_VarRequestIdToVarIdVarRequestMap.cend()) {
717 if (varRequestIdToVarIdVarRequestMapIt == m_VarRequestIdToVarIdVarRequestMap.cend()) {
704 auto varIdToVarRequestMap = std::map<QUuid, VariableRequest>{};
718 auto varIdToVarRequestMap = std::map<QUuid, VariableRequest>{};
705 varIdToVarRequestMap.insert(std::make_pair(varId, varRequest));
719 varIdToVarRequestMap.insert(std::make_pair(varId, varRequest));
706 qCDebug(LOG_VariableController()) << tr("Store REQUESTID in MAP");
720 qCDebug(LOG_VariableController()) << tr("Store REQUESTID in MAP");
707 m_VarRequestIdToVarIdVarRequestMap.insert(
721 m_VarRequestIdToVarIdVarRequestMap.insert(
708 std::make_pair(varRequestId, std::move(varIdToVarRequestMap)));
722 std::make_pair(varRequestId, std::move(varIdToVarRequestMap)));
709 }
723 }
710 else {
724 else {
711 auto &varIdToVarRequestMap = varRequestIdToVarIdVarRequestMapIt->second;
725 auto &varIdToVarRequestMap = varRequestIdToVarIdVarRequestMapIt->second;
712 qCDebug(LOG_VariableController()) << tr("Store REQUESTID in EXISTING MAP");
726 qCDebug(LOG_VariableController()) << tr("Store REQUESTID in EXISTING MAP");
713 varIdToVarRequestMap.insert(std::make_pair(varId, varRequest));
727 varIdToVarRequestMap.insert(std::make_pair(varId, varRequest));
714 }
728 }
715 }
729 }
716
730
717 QUuid VariableController::VariableControllerPrivate::acceptVariableRequest(
731 QUuid VariableController::VariableControllerPrivate::acceptVariableRequest(
718 QUuid varId, std::shared_ptr<IDataSeries> dataSeries)
732 QUuid varId, std::shared_ptr<IDataSeries> dataSeries)
719 {
733 {
720 QUuid varRequestId;
734 QUuid varRequestId;
721 auto varIdToVarRequestIdQueueMapIt = m_VarIdToVarRequestIdQueueMap.find(varId);
735 auto varIdToVarRequestIdQueueMapIt = m_VarIdToVarRequestIdQueueMap.find(varId);
722 if (varIdToVarRequestIdQueueMapIt != m_VarIdToVarRequestIdQueueMap.cend()) {
736 if (varIdToVarRequestIdQueueMapIt != m_VarIdToVarRequestIdQueueMap.cend()) {
723 auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second;
737 auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second;
724 varRequestId = varRequestIdQueue.front();
738 varRequestId = varRequestIdQueue.front();
725 auto varRequestIdToVarIdVarRequestMapIt
739 auto varRequestIdToVarIdVarRequestMapIt
726 = m_VarRequestIdToVarIdVarRequestMap.find(varRequestId);
740 = m_VarRequestIdToVarIdVarRequestMap.find(varRequestId);
727 if (varRequestIdToVarIdVarRequestMapIt != m_VarRequestIdToVarIdVarRequestMap.cend()) {
741 if (varRequestIdToVarIdVarRequestMapIt != m_VarRequestIdToVarIdVarRequestMap.cend()) {
728 auto &varIdToVarRequestMap = varRequestIdToVarIdVarRequestMapIt->second;
742 auto &varIdToVarRequestMap = varRequestIdToVarIdVarRequestMapIt->second;
729 auto varIdToVarRequestMapIt = varIdToVarRequestMap.find(varId);
743 auto varIdToVarRequestMapIt = varIdToVarRequestMap.find(varId);
730 if (varIdToVarRequestMapIt != varIdToVarRequestMap.cend()) {
744 if (varIdToVarRequestMapIt != varIdToVarRequestMap.cend()) {
731 qCDebug(LOG_VariableController()) << tr("acceptVariableRequest");
745 qCDebug(LOG_VariableController()) << tr("acceptVariableRequest");
732 auto &varRequest = varIdToVarRequestMapIt->second;
746 auto &varRequest = varIdToVarRequestMapIt->second;
733 varRequest.m_DataSeries = dataSeries;
747 varRequest.m_DataSeries = dataSeries;
734 varRequest.m_CanUpdate = true;
748 varRequest.m_CanUpdate = true;
735 }
749 }
736 else {
750 else {
737 qCDebug(LOG_VariableController())
751 qCDebug(LOG_VariableController())
738 << tr("Impossible to acceptVariableRequest of a unknown variable id attached "
752 << tr("Impossible to acceptVariableRequest of a unknown variable id attached "
739 "to a variableRequestId")
753 "to a variableRequestId")
740 << varRequestId << varId;
754 << varRequestId << varId;
741 }
755 }
742 }
756 }
743 else {
757 else {
744 qCCritical(LOG_VariableController())
758 qCCritical(LOG_VariableController())
745 << tr("Impossible to acceptVariableRequest of a unknown variableRequestId")
759 << tr("Impossible to acceptVariableRequest of a unknown variableRequestId")
746 << varRequestId;
760 << varRequestId;
747 }
761 }
748
762
749 varRequestIdQueue.pop_front();
763 varRequestIdQueue.pop_front();
750 if (varRequestIdQueue.empty()) {
764 if (varRequestIdQueue.empty()) {
751 qCDebug(LOG_VariableController())
765 qCDebug(LOG_VariableController())
752 << tr("TORM Erase REQUEST because it has been accepted") << varId;
766 << tr("TORM Erase REQUEST because it has been accepted") << varId;
753 m_VarIdToVarRequestIdQueueMap.erase(varId);
767 m_VarIdToVarRequestIdQueueMap.erase(varId);
754 }
768 }
755 }
769 }
756 else {
770 else {
757 qCCritical(LOG_VariableController())
771 qCCritical(LOG_VariableController())
758 << tr("Impossible to acceptVariableRequest of a unknown variable id") << varId;
772 << tr("Impossible to acceptVariableRequest of a unknown variable id") << varId;
759 }
773 }
760
774
761 return varRequestId;
775 return varRequestId;
762 }
776 }
763
777
764 void VariableController::VariableControllerPrivate::updateVariableRequest(QUuid varRequestId)
778 void VariableController::VariableControllerPrivate::updateVariableRequest(QUuid varRequestId)
765 {
779 {
766
780
767 auto varRequestIdToVarIdVarRequestMapIt = m_VarRequestIdToVarIdVarRequestMap.find(varRequestId);
781 auto varRequestIdToVarIdVarRequestMapIt = m_VarRequestIdToVarIdVarRequestMap.find(varRequestId);
768 if (varRequestIdToVarIdVarRequestMapIt != m_VarRequestIdToVarIdVarRequestMap.cend()) {
782 if (varRequestIdToVarIdVarRequestMapIt != m_VarRequestIdToVarIdVarRequestMap.cend()) {
769 bool processVariableUpdate = true;
783 bool processVariableUpdate = true;
770 auto &varIdToVarRequestMap = varRequestIdToVarIdVarRequestMapIt->second;
784 auto &varIdToVarRequestMap = varRequestIdToVarIdVarRequestMapIt->second;
771 for (auto varIdToVarRequestMapIt = varIdToVarRequestMap.cbegin();
785 for (auto varIdToVarRequestMapIt = varIdToVarRequestMap.cbegin();
772 (varIdToVarRequestMapIt != varIdToVarRequestMap.cend()) && processVariableUpdate;
786 (varIdToVarRequestMapIt != varIdToVarRequestMap.cend()) && processVariableUpdate;
773 ++varIdToVarRequestMapIt) {
787 ++varIdToVarRequestMapIt) {
774 processVariableUpdate &= varIdToVarRequestMapIt->second.m_CanUpdate;
788 processVariableUpdate &= varIdToVarRequestMapIt->second.m_CanUpdate;
775 qCDebug(LOG_VariableController()) << tr("updateVariableRequest")
789 qCDebug(LOG_VariableController()) << tr("updateVariableRequest")
776 << processVariableUpdate;
790 << processVariableUpdate;
777 }
791 }
778
792
779 if (processVariableUpdate) {
793 if (processVariableUpdate) {
780 for (auto varIdToVarRequestMapIt = varIdToVarRequestMap.cbegin();
794 for (auto varIdToVarRequestMapIt = varIdToVarRequestMap.cbegin();
781 varIdToVarRequestMapIt != varIdToVarRequestMap.cend(); ++varIdToVarRequestMapIt) {
795 varIdToVarRequestMapIt != varIdToVarRequestMap.cend(); ++varIdToVarRequestMapIt) {
782 if (auto var = findVariable(varIdToVarRequestMapIt->first)) {
796 if (auto var = findVariable(varIdToVarRequestMapIt->first)) {
783 auto &varRequest = varIdToVarRequestMapIt->second;
797 auto &varRequest = varIdToVarRequestMapIt->second;
784 var->setRange(varRequest.m_RangeRequested);
798 var->setRange(varRequest.m_RangeRequested);
785 var->setCacheRange(varRequest.m_CacheRangeRequested);
799 var->setCacheRange(varRequest.m_CacheRangeRequested);
786 qCDebug(LOG_VariableController()) << tr("1: onDataProvided")
800 qCDebug(LOG_VariableController()) << tr("1: onDataProvided")
787 << varRequest.m_RangeRequested;
801 << varRequest.m_RangeRequested
788 qCDebug(LOG_VariableController()) << tr("2: onDataProvided")
789 << varRequest.m_CacheRangeRequested;
802 << varRequest.m_CacheRangeRequested;
803 qCDebug(LOG_VariableController()) << tr("2: onDataProvided var points before")
804 << var->nbPoints()
805 << varRequest.m_DataSeries->nbPoints();
790 var->mergeDataSeries(varRequest.m_DataSeries);
806 var->mergeDataSeries(varRequest.m_DataSeries);
791 qCDebug(LOG_VariableController()) << tr("3: onDataProvided");
807 qCDebug(LOG_VariableController()) << tr("3: onDataProvided var points after")
808 << var->nbPoints();
792
809
793 /// @todo MPL: confirm
794 // Variable update is notified only if there is no pending request for it
795 // if
796 // (m_VarIdToVarRequestIdQueueMap.count(varIdToVarRequestMapIt->first)
797 // == 0) {
798 emit var->updated();
810 emit var->updated();
799 // }
800 }
811 }
801 else {
812 else {
802 qCCritical(LOG_VariableController())
813 qCCritical(LOG_VariableController())
803 << tr("Impossible to update data to a null variable");
814 << tr("Impossible to update data to a null variable");
804 }
815 }
805 }
816 }
806
807 // cleaning varRequestId
817 // cleaning varRequestId
808 qCDebug(LOG_VariableController()) << tr("0: erase REQUEST in MAP ?")
818 qCDebug(LOG_VariableController()) << tr("0: erase REQUEST in MAP ?")
809 << m_VarRequestIdToVarIdVarRequestMap.size();
819 << m_VarRequestIdToVarIdVarRequestMap.size();
810 m_VarRequestIdToVarIdVarRequestMap.erase(varRequestId);
820 m_VarRequestIdToVarIdVarRequestMap.erase(varRequestId);
811 qCDebug(LOG_VariableController()) << tr("1: erase REQUEST in MAP ?")
821 qCDebug(LOG_VariableController()) << tr("1: erase REQUEST in MAP ?")
812 << m_VarRequestIdToVarIdVarRequestMap.size();
822 << m_VarRequestIdToVarIdVarRequestMap.size();
813 }
823 }
814 }
824 }
815 else {
825 else {
816 qCCritical(LOG_VariableController())
826 qCCritical(LOG_VariableController())
817 << tr("Cannot updateVariableRequest for a unknow varRequestId") << varRequestId;
827 << tr("Cannot updateVariableRequest for a unknow varRequestId") << varRequestId;
818 }
828 }
819 }
829 }
820
830
821 void VariableController::VariableControllerPrivate::cancelVariableRequest(QUuid varRequestId)
831 void VariableController::VariableControllerPrivate::cancelVariableRequest(QUuid varRequestId)
822 {
832 {
823 // cleaning varRequestId
833 // cleaning varRequestId
824 m_VarRequestIdToVarIdVarRequestMap.erase(varRequestId);
834 m_VarRequestIdToVarIdVarRequestMap.erase(varRequestId);
825
835
826 for (auto varIdToVarRequestIdQueueMapIt = m_VarIdToVarRequestIdQueueMap.begin();
836 for (auto varIdToVarRequestIdQueueMapIt = m_VarIdToVarRequestIdQueueMap.begin();
827 varIdToVarRequestIdQueueMapIt != m_VarIdToVarRequestIdQueueMap.end();) {
837 varIdToVarRequestIdQueueMapIt != m_VarIdToVarRequestIdQueueMap.end();) {
828 auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second;
838 auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second;
829 varRequestIdQueue.erase(
839 varRequestIdQueue.erase(
830 std::remove(varRequestIdQueue.begin(), varRequestIdQueue.end(), varRequestId),
840 std::remove(varRequestIdQueue.begin(), varRequestIdQueue.end(), varRequestId),
831 varRequestIdQueue.end());
841 varRequestIdQueue.end());
832 if (varRequestIdQueue.empty()) {
842 if (varRequestIdQueue.empty()) {
833 varIdToVarRequestIdQueueMapIt
843 varIdToVarRequestIdQueueMapIt
834 = m_VarIdToVarRequestIdQueueMap.erase(varIdToVarRequestIdQueueMapIt);
844 = m_VarIdToVarRequestIdQueueMap.erase(varIdToVarRequestIdQueueMapIt);
845
846 // Recompute if there is any next request based on the removed request.
835 }
847 }
836 else {
848 else {
837 ++varIdToVarRequestIdQueueMapIt;
849 ++varIdToVarRequestIdQueueMapIt;
838 }
850 }
839 }
851 }
840 }
852 }
853
854 SqpRange VariableController::VariableControllerPrivate::getLastRequestedRange(QUuid varId)
855 {
856 auto lastRangeRequested = SqpRange{INVALID_RANGE};
857 auto varIdToVarRequestIdQueueMapIt = m_VarIdToVarRequestIdQueueMap.find(varId);
858 if (varIdToVarRequestIdQueueMapIt != m_VarIdToVarRequestIdQueueMap.cend()) {
859 auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second;
860 auto varRequestId = varRequestIdQueue.back();
861 auto varRequestIdToVarIdVarRequestMapIt
862 = m_VarRequestIdToVarIdVarRequestMap.find(varRequestId);
863 if (varRequestIdToVarIdVarRequestMapIt != m_VarRequestIdToVarIdVarRequestMap.cend()) {
864 auto &varIdToVarRequestMap = varRequestIdToVarIdVarRequestMapIt->second;
865 auto varIdToVarRequestMapIt = varIdToVarRequestMap.find(varId);
866 if (varIdToVarRequestMapIt != varIdToVarRequestMap.cend()) {
867 auto &varRequest = varIdToVarRequestMapIt->second;
868 lastRangeRequested = varRequest.m_RangeRequested;
869 }
870 else {
871 qCDebug(LOG_VariableController())
872 << tr("Impossible to getLastRequestedRange of a unknown variable id attached "
873 "to a variableRequestId")
874 << varRequestId << varId;
875 }
876 }
877 else {
878 qCCritical(LOG_VariableController())
879 << tr("Impossible to getLastRequestedRange of a unknown variableRequestId")
880 << varRequestId;
881 }
882 }
883 else {
884 qDebug(LOG_VariableController())
885 << tr("Impossible to getLastRequestedRange of a unknown variable id") << varId;
886 }
887
888 return lastRangeRequested;
889 }
@@ -1,310 +1,390
1 #include <QObject>
1 #include <QObject>
2 #include <QtTest>
2 #include <QtTest>
3
3
4 #include <memory>
4 #include <memory>
5
5
6 #include <Data/DataProviderParameters.h>
6 #include <Data/DataProviderParameters.h>
7 #include <Data/IDataProvider.h>
7 #include <Data/IDataProvider.h>
8 #include <Data/ScalarSeries.h>
8 #include <Data/ScalarSeries.h>
9 #include <Time/TimeController.h>
9 #include <Time/TimeController.h>
10 #include <Variable/Variable.h>
10 #include <Variable/Variable.h>
11 #include <Variable/VariableController.h>
11 #include <Variable/VariableController.h>
12 #include <Variable/VariableModel.h>
12 #include <Variable/VariableModel.h>
13
13
14 namespace {
14 namespace {
15
15
16 /// Delay after each operation on the variable before validating it (in ms)
16 /// Delay after each operation on the variable before validating it (in ms)
17 const auto OPERATION_DELAY = 100;
17 const auto OPERATION_DELAY = 100;
18
18
19 /**
19 /**
20 * Generates values according to a range. The value generated for a time t is the number of seconds
20 * Generates values according to a range. The value generated for a time t is the number of seconds
21 * of difference between t and a reference value (which is midnight -> 00:00:00)
21 * of difference between t and a reference value (which is midnight -> 00:00:00)
22 *
22 *
23 * Example: For a range between 00:00:10 and 00:00:20, the generated values are
23 * Example: For a range between 00:00:10 and 00:00:20, the generated values are
24 * {10,11,12,13,14,15,16,17,18,19,20}
24 * {10,11,12,13,14,15,16,17,18,19,20}
25 */
25 */
26 std::vector<double> values(const SqpRange &range)
26 std::vector<double> values(const SqpRange &range)
27 {
27 {
28 QTime referenceTime{0, 0};
28 QTime referenceTime{0, 0};
29
29
30 std::vector<double> result{};
30 std::vector<double> result{};
31
31
32 for (auto i = range.m_TStart; i <= range.m_TEnd; ++i) {
32 for (auto i = range.m_TStart; i <= range.m_TEnd; ++i) {
33 auto time = DateUtils::dateTime(i).time();
33 auto time = DateUtils::dateTime(i).time();
34 result.push_back(referenceTime.secsTo(time));
34 result.push_back(referenceTime.secsTo(time));
35 }
35 }
36
36
37 return result;
37 return result;
38 }
38 }
39
39
40 /// Provider used for the tests
40 /// Provider used for the tests
41 class TestProvider : public IDataProvider {
41 class TestProvider : public IDataProvider {
42 std::shared_ptr<IDataProvider> clone() const { return std::make_shared<TestProvider>(); }
42 std::shared_ptr<IDataProvider> clone() const { return std::make_shared<TestProvider>(); }
43
43
44 void requestDataLoading(QUuid acqIdentifier, const DataProviderParameters &parameters) override
44 void requestDataLoading(QUuid acqIdentifier, const DataProviderParameters &parameters) override
45 {
45 {
46 const auto &ranges = parameters.m_Times;
46 const auto &ranges = parameters.m_Times;
47
47
48 for (const auto &range : ranges) {
48 for (const auto &range : ranges) {
49 // Generates data series
49 // Generates data series
50 auto valuesData = values(range);
50 auto valuesData = values(range);
51
51
52 std::vector<double> xAxisData{};
52 std::vector<double> xAxisData{};
53 for (auto i = range.m_TStart; i <= range.m_TEnd; ++i) {
53 for (auto i = range.m_TStart; i <= range.m_TEnd; ++i) {
54 xAxisData.push_back(i);
54 xAxisData.push_back(i);
55 }
55 }
56
56
57 auto dataSeries = std::make_shared<ScalarSeries>(
57 auto dataSeries = std::make_shared<ScalarSeries>(
58 std::move(xAxisData), std::move(valuesData), Unit{"t", true}, Unit{});
58 std::move(xAxisData), std::move(valuesData), Unit{"t", true}, Unit{});
59
59
60 emit dataProvided(acqIdentifier, dataSeries, range);
60 emit dataProvided(acqIdentifier, dataSeries, range);
61 }
61 }
62 }
62 }
63
63
64 void requestDataAborting(QUuid acqIdentifier) override
64 void requestDataAborting(QUuid acqIdentifier) override
65 {
65 {
66 // Does nothing
66 // Does nothing
67 }
67 }
68 };
68 };
69
69
70 /**
70 /**
71 * Interface representing an operation performed on a variable controller.
71 * Interface representing an operation performed on a variable controller.
72 * This interface is used in tests to apply a set of operations and check the status of the
72 * This interface is used in tests to apply a set of operations and check the status of the
73 * controller after each operation
73 * controller after each operation
74 */
74 */
75 struct IOperation {
75 struct IOperation {
76 virtual ~IOperation() = default;
76 virtual ~IOperation() = default;
77 /// Executes the operation on the variable controller
77 /// Executes the operation on the variable controller
78 virtual void exec(VariableController &variableController) const = 0;
78 virtual void exec(VariableController &variableController) const = 0;
79 };
79 };
80
80
81 /**
81 /**
82 *Variable creation operation in the controller
82 *Variable creation operation in the controller
83 */
83 */
84 struct Create : public IOperation {
84 struct Create : public IOperation {
85 explicit Create(int index) : m_Index{index} {}
85 explicit Create(int index) : m_Index{index} {}
86
86
87 void exec(VariableController &variableController) const override
87 void exec(VariableController &variableController) const override
88 {
88 {
89 auto variable = variableController.createVariable(QString::number(m_Index), {},
89 auto variable = variableController.createVariable(QString::number(m_Index), {},
90 std::make_unique<TestProvider>());
90 std::make_unique<TestProvider>());
91 }
91 }
92
92
93 int m_Index; ///< The index of the variable to create in the controller
93 int m_Index; ///< The index of the variable to create in the controller
94 };
94 };
95
95
96 /**
96 /**
97 * Variable move/shift operation in the controller
97 * Variable move/shift operation in the controller
98 */
98 */
99 struct Move : public IOperation {
99 struct Move : public IOperation {
100 explicit Move(int index, const SqpRange &newRange, bool shift = false)
100 explicit Move(int index, const SqpRange &newRange, bool shift = false)
101 : m_Index{index}, m_NewRange{newRange}, m_Shift{shift}
101 : m_Index{index}, m_NewRange{newRange}, m_Shift{shift}
102 {
102 {
103 }
103 }
104
104
105 void exec(VariableController &variableController) const override
105 void exec(VariableController &variableController) const override
106 {
106 {
107 if (auto variable = variableController.variableModel()->variable(m_Index)) {
107 if (auto variable = variableController.variableModel()->variable(m_Index)) {
108 variableController.onRequestDataLoading({variable}, m_NewRange, variable->range(),
108 variableController.onRequestDataLoading({variable}, m_NewRange, !m_Shift);
109 !m_Shift);
110 }
109 }
111 }
110 }
112
111
113 int m_Index; ///< The index of the variable to move
112 int m_Index; ///< The index of the variable to move
114 SqpRange m_NewRange; ///< The new range of the variable
113 SqpRange m_NewRange; ///< The new range of the variable
115 bool m_Shift; ///< Performs a shift (
114 bool m_Shift; ///< Performs a shift (
116 };
115 };
117
116
118 /**
117 /**
119 * Variable synchronization/desynchronization operation in the controller
118 * Variable synchronization/desynchronization operation in the controller
120 */
119 */
121 struct Synchronize : public IOperation {
120 struct Synchronize : public IOperation {
122 explicit Synchronize(int index, QUuid syncId, bool synchronize = true)
121 explicit Synchronize(int index, QUuid syncId, bool synchronize = true)
123 : m_Index{index}, m_SyncId{syncId}, m_Synchronize{synchronize}
122 : m_Index{index}, m_SyncId{syncId}, m_Synchronize{synchronize}
124 {
123 {
125 }
124 }
126
125
127 void exec(VariableController &variableController) const override
126 void exec(VariableController &variableController) const override
128 {
127 {
129 if (auto variable = variableController.variableModel()->variable(m_Index)) {
128 if (auto variable = variableController.variableModel()->variable(m_Index)) {
130 if (m_Synchronize) {
129 if (m_Synchronize) {
131 variableController.onAddSynchronized(variable, m_SyncId);
130 variableController.onAddSynchronized(variable, m_SyncId);
132 }
131 }
133 else {
132 else {
134 variableController.desynchronize(variable, m_SyncId);
133 variableController.desynchronize(variable, m_SyncId);
135 }
134 }
136 }
135 }
137 }
136 }
138
137
139 int m_Index; ///< The index of the variable to sync/desync
138 int m_Index; ///< The index of the variable to sync/desync
140 QUuid m_SyncId; ///< The synchronization group of the variable
139 QUuid m_SyncId; ///< The synchronization group of the variable
141 bool m_Synchronize; ///< Performs sync or desync operation
140 bool m_Synchronize; ///< Performs sync or desync operation
142 };
141 };
143
142
144 /**
143 /**
145 * Test Iteration
144 * Test Iteration
146 *
145 *
147 * A test iteration includes an operation to be performed, and a set of expected ranges after each
146 * A test iteration includes an operation to be performed, and a set of expected ranges after each
148 * operation. Each range is tested after the operation to ensure that:
147 * operation. Each range is tested after the operation to ensure that:
149 * - the range of the variable is the expected range
148 * - the range of the variable is the expected range
150 * - the data of the variable are those generated for the expected range
149 * - the data of the variable are those generated for the expected range
151 */
150 */
152 struct Iteration {
151 struct Iteration {
153 std::shared_ptr<IOperation> m_Operation; ///< Operation to perform
152 std::shared_ptr<IOperation> m_Operation; ///< Operation to perform
154 std::map<int, SqpRange> m_ExpectedRanges; ///< Expected ranges (by variable index)
153 std::map<int, SqpRange> m_ExpectedRanges; ///< Expected ranges (by variable index)
155 };
154 };
156
155
157 using Iterations = std::vector<Iteration>;
156 using Iterations = std::vector<Iteration>;
158
157
159 } // namespace
158 } // namespace
160
159
161 Q_DECLARE_METATYPE(Iterations)
160 Q_DECLARE_METATYPE(Iterations)
162
161
163 class TestVariableSync : public QObject {
162 class TestVariableSync : public QObject {
164 Q_OBJECT
163 Q_OBJECT
165
164
166 private slots:
165 private slots:
167 /// Input data for @sa testSync()
166 /// Input data for @sa testSync()
168 void testSync_data();
167 void testSync_data();
169
168
170 /// Tests synchronization between variables through several operations
169 /// Tests synchronization between variables through several operations
171 void testSync();
170 void testSync();
172 };
171 };
173
172
174 void TestVariableSync::testSync_data()
173 namespace {
175 {
176 // ////////////// //
177 // Test structure //
178 // ////////////// //
179
180 QTest::addColumn<QUuid>("syncId");
181 QTest::addColumn<SqpRange>("initialRange");
182 QTest::addColumn<Iterations>("iterations");
183
184 // ////////// //
185 // Test cases //
186 // ////////// //
187
174
175 void testSyncCase1()
176 {
188 // Id used to synchronize variables in the controller
177 // Id used to synchronize variables in the controller
189 auto syncId = QUuid::createUuid();
178 auto syncId = QUuid::createUuid();
190
179
191 /// Generates a range according to a start time and a end time (the date is the same)
180 /// Generates a range according to a start time and a end time (the date is the same)
192 auto range = [](const QTime &startTime, const QTime &endTime) {
181 auto range = [](const QTime &startTime, const QTime &endTime) {
193 return SqpRange{DateUtils::secondsSinceEpoch(QDateTime{{2017, 1, 1}, startTime, Qt::UTC}),
182 return SqpRange{DateUtils::secondsSinceEpoch(QDateTime{{2017, 1, 1}, startTime, Qt::UTC}),
194 DateUtils::secondsSinceEpoch(QDateTime{{2017, 1, 1}, endTime, Qt::UTC})};
183 DateUtils::secondsSinceEpoch(QDateTime{{2017, 1, 1}, endTime, Qt::UTC})};
195 };
184 };
196
185
197 auto initialRange = range({12, 0}, {13, 0});
186 auto initialRange = range({12, 0}, {13, 0});
198
187
199 Iterations iterations{};
188 Iterations iterations{};
200 // Creates variables var0, var1 and var2
189 // Creates variables var0, var1 and var2
201 iterations.push_back({std::make_shared<Create>(0), {{0, initialRange}}});
190 iterations.push_back({std::make_shared<Create>(0), {{0, initialRange}}});
202 iterations.push_back({std::make_shared<Create>(1), {{0, initialRange}, {1, initialRange}}});
191 iterations.push_back({std::make_shared<Create>(1), {{0, initialRange}, {1, initialRange}}});
203 iterations.push_back(
192 iterations.push_back(
204 {std::make_shared<Create>(2), {{0, initialRange}, {1, initialRange}, {2, initialRange}}});
193 {std::make_shared<Create>(2), {{0, initialRange}, {1, initialRange}, {2, initialRange}}});
205
194
206 // Adds variables into the sync group (ranges don't need to be tested here)
195 // Adds variables into the sync group (ranges don't need to be tested here)
207 iterations.push_back({std::make_shared<Synchronize>(0, syncId)});
196 iterations.push_back({std::make_shared<Synchronize>(0, syncId)});
208 iterations.push_back({std::make_shared<Synchronize>(1, syncId)});
197 iterations.push_back({std::make_shared<Synchronize>(1, syncId)});
209 iterations.push_back({std::make_shared<Synchronize>(2, syncId)});
198 iterations.push_back({std::make_shared<Synchronize>(2, syncId)});
210
199
211 // Moves var0: ranges of var0, var1 and var2 change
200 // Moves var0: ranges of var0, var1 and var2 change
212 auto newRange = range({12, 30}, {13, 30});
201 auto newRange = range({12, 30}, {13, 30});
213 iterations.push_back(
202 iterations.push_back(
214 {std::make_shared<Move>(0, newRange), {{0, newRange}, {1, newRange}, {2, newRange}}});
203 {std::make_shared<Move>(0, newRange), {{0, newRange}, {1, newRange}, {2, newRange}}});
215
204
216 // Moves var1: ranges of var0, var1 and var2 change
205 // Moves var1: ranges of var0, var1 and var2 change
217 newRange = range({13, 0}, {14, 0});
206 newRange = range({13, 0}, {14, 0});
218 iterations.push_back(
207 iterations.push_back(
219 {std::make_shared<Move>(0, newRange), {{0, newRange}, {1, newRange}, {2, newRange}}});
208 {std::make_shared<Move>(0, newRange), {{0, newRange}, {1, newRange}, {2, newRange}}});
220
209
221 // Moves var2: ranges of var0, var1 and var2 change
210 // Moves var2: ranges of var0, var1 and var2 change
222 newRange = range({13, 30}, {14, 30});
211 newRange = range({13, 30}, {14, 30});
223 iterations.push_back(
212 iterations.push_back(
224 {std::make_shared<Move>(0, newRange), {{0, newRange}, {1, newRange}, {2, newRange}}});
213 {std::make_shared<Move>(0, newRange), {{0, newRange}, {1, newRange}, {2, newRange}}});
225
214
226 // Desyncs var2 and moves var0:
215 // Desyncs var2 and moves var0:
227 // - ranges of var0 and var1 change
216 // - ranges of var0 and var1 change
228 // - range of var2 doesn't change anymore
217 // - range of var2 doesn't change anymore
229 auto var2Range = newRange;
218 auto var2Range = newRange;
230 newRange = range({13, 45}, {14, 45});
219 newRange = range({13, 45}, {14, 45});
231 iterations.push_back({std::make_shared<Synchronize>(2, syncId, false)});
220 iterations.push_back({std::make_shared<Synchronize>(2, syncId, false)});
232 iterations.push_back(
221 iterations.push_back(
233 {std::make_shared<Move>(0, newRange), {{0, newRange}, {1, newRange}, {2, var2Range}}});
222 {std::make_shared<Move>(0, newRange), {{0, newRange}, {1, newRange}, {2, var2Range}}});
234
223
235 // Shifts var0: although var1 is synchronized with var0, its range doesn't change
224 // Shifts var0: although var1 is synchronized with var0, its range doesn't change
236 auto var1Range = newRange;
225 auto var1Range = newRange;
237 newRange = range({14, 45}, {15, 45});
226 newRange = range({14, 45}, {15, 45});
238 iterations.push_back({std::make_shared<Move>(0, newRange, true),
227 iterations.push_back({std::make_shared<Move>(0, newRange, true),
239 {{0, newRange}, {1, var1Range}, {2, var2Range}}});
228 {{0, newRange}, {1, var1Range}, {2, var2Range}}});
240
229
241 // Moves var0 through several operations:
230 // Moves var0 through several operations:
242 // - range of var0 changes
231 // - range of var0 changes
243 // - range or var1 changes according to the previous shift (one hour)
232 // - range or var1 changes according to the previous shift (one hour)
244 auto moveVar0 = [&iterations](const auto &var0NewRange, const auto &var1ExpectedRange) {
233 auto moveVar0 = [&iterations](const auto &var0NewRange, const auto &var1ExpectedRange) {
245 iterations.push_back(
234 iterations.push_back(
246 {std::make_shared<Move>(0, var0NewRange), {{0, var0NewRange}, {1, var1ExpectedRange}}});
235 {std::make_shared<Move>(0, var0NewRange), {{0, var0NewRange}, {1, var1ExpectedRange}}});
247 };
236 };
248 // Pan left
237 // Pan left
249 moveVar0(range({14, 30}, {15, 30}), range({13, 30}, {14, 30}));
238 moveVar0(range({14, 30}, {15, 30}), range({13, 30}, {14, 30}));
250 // Pan right
239 // Pan right
251 moveVar0(range({16, 0}, {17, 0}), range({15, 0}, {16, 0}));
240 moveVar0(range({16, 0}, {17, 0}), range({15, 0}, {16, 0}));
252 // Zoom in
241 // Zoom in
253 moveVar0(range({16, 30}, {16, 45}), range({15, 30}, {15, 45}));
242 moveVar0(range({16, 30}, {16, 45}), range({15, 30}, {15, 45}));
254 // Zoom out
243 // Zoom out
255 moveVar0(range({12, 0}, {18, 0}), range({11, 0}, {17, 0}));
244 moveVar0(range({12, 0}, {18, 0}), range({11, 0}, {17, 0}));
256
245
257 QTest::newRow("sync1") << syncId << initialRange << std::move(iterations);
246 QTest::newRow("sync1") << syncId << initialRange << std::move(iterations) << 200;
247 }
248
249 void testSyncCase2()
250 {
251 // Id used to synchronize variables in the controller
252 auto syncId = QUuid::createUuid();
253
254 /// Generates a range according to a start time and a end time (the date is the same)
255 auto dateTime = [](int year, int month, int day, int hours, int minutes, int seconds) {
256 return DateUtils::secondsSinceEpoch(
257 QDateTime{{year, month, day}, QTime{hours, minutes, seconds}, Qt::UTC});
258 };
259
260 auto initialRange = SqpRange{dateTime(2017, 1, 1, 12, 0, 0), dateTime(2017, 1, 1, 13, 0, 0)};
261
262 Iterations iterations{};
263 // Creates variables var0 and var1
264 iterations.push_back({std::make_shared<Create>(0), {{0, initialRange}}});
265 iterations.push_back({std::make_shared<Create>(1), {{0, initialRange}, {1, initialRange}}});
266
267 // Adds variables into the sync group (ranges don't need to be tested here)
268 iterations.push_back({std::make_shared<Synchronize>(0, syncId)});
269 iterations.push_back({std::make_shared<Synchronize>(1, syncId)});
270
271
272 // Moves var0 through several operations:
273 // - range of var0 changes
274 // - range or var1 changes according to the previous shift (one hour)
275 auto moveVar0 = [&iterations](const auto &var0NewRange) {
276 iterations.push_back(
277 {std::make_shared<Move>(0, var0NewRange), {{0, var0NewRange}, {1, var0NewRange}}});
278 };
279 moveVar0(SqpRange{dateTime(2017, 1, 1, 12, 0, 0), dateTime(2017, 1, 1, 13, 0, 0)});
280 moveVar0(SqpRange{dateTime(2017, 1, 1, 14, 0, 0), dateTime(2017, 1, 1, 15, 0, 0)});
281 moveVar0(SqpRange{dateTime(2017, 1, 1, 8, 0, 0), dateTime(2017, 1, 1, 9, 0, 0)});
282 // moveVar0(SqpRange{dateTime(2017, 1, 1, 7, 30, 0), dateTime(2017, 1, 1, 9, 30, 0)});
283 moveVar0(SqpRange{dateTime(2017, 1, 1, 2, 0, 0), dateTime(2017, 1, 1, 4, 0, 0)});
284 moveVar0(SqpRange{dateTime(2017, 1, 1, 6, 0, 0), dateTime(2017, 1, 1, 8, 0, 0)});
285
286 moveVar0(SqpRange{dateTime(2017, 1, 10, 6, 0, 0), dateTime(2017, 1, 15, 8, 0, 0)});
287 moveVar0(SqpRange{dateTime(2017, 1, 17, 6, 0, 0), dateTime(2017, 1, 25, 8, 0, 0)});
288 moveVar0(SqpRange{dateTime(2017, 1, 2, 6, 0, 0), dateTime(2017, 1, 8, 8, 0, 0)});
289
290 moveVar0(SqpRange{dateTime(2017, 4, 10, 6, 0, 0), dateTime(2017, 6, 15, 8, 0, 0)});
291 moveVar0(SqpRange{dateTime(2017, 1, 17, 6, 0, 0), dateTime(2017, 2, 25, 8, 0, 0)});
292 moveVar0(SqpRange{dateTime(2017, 7, 2, 6, 0, 0), dateTime(2017, 10, 8, 8, 0, 0)});
293 moveVar0(SqpRange{dateTime(2017, 4, 10, 6, 0, 0), dateTime(2017, 6, 15, 8, 0, 0)});
294 moveVar0(SqpRange{dateTime(2017, 1, 17, 6, 0, 0), dateTime(2017, 2, 25, 8, 0, 0)});
295 moveVar0(SqpRange{dateTime(2017, 7, 2, 6, 0, 0), dateTime(2017, 10, 8, 8, 0, 0)});
296 moveVar0(SqpRange{dateTime(2017, 4, 10, 6, 0, 0), dateTime(2017, 6, 15, 8, 0, 0)});
297 moveVar0(SqpRange{dateTime(2017, 1, 17, 6, 0, 0), dateTime(2017, 2, 25, 8, 0, 0)});
298 moveVar0(SqpRange{dateTime(2017, 7, 2, 6, 0, 0), dateTime(2017, 10, 8, 8, 0, 0)});
299 moveVar0(SqpRange{dateTime(2017, 4, 10, 6, 0, 0), dateTime(2017, 6, 15, 8, 0, 0)});
300 moveVar0(SqpRange{dateTime(2017, 1, 17, 6, 0, 0), dateTime(2017, 2, 25, 8, 0, 0)});
301 moveVar0(SqpRange{dateTime(2017, 7, 2, 6, 0, 0), dateTime(2017, 10, 8, 8, 0, 0)});
302
303
304 QTest::newRow("sync2") << syncId << initialRange << iterations << 4000;
305 // QTest::newRow("sync3") << syncId << initialRange << iterations << 5000;
306 }
307 }
308
309 void TestVariableSync::testSync_data()
310 {
311 // ////////////// //
312 // Test structure //
313 // ////////////// //
314
315 QTest::addColumn<QUuid>("syncId");
316 QTest::addColumn<SqpRange>("initialRange");
317 QTest::addColumn<Iterations>("iterations");
318 QTest::addColumn<int>("operationDelay");
319
320 // ////////// //
321 // Test cases //
322 // ////////// //
323
324 testSyncCase1();
325 testSyncCase2();
258 }
326 }
259
327
260 void TestVariableSync::testSync()
328 void TestVariableSync::testSync()
261 {
329 {
262 // Inits controllers
330 // Inits controllers
263 TimeController timeController{};
331 TimeController timeController{};
264 VariableController variableController{};
332 VariableController variableController{};
265 variableController.setTimeController(&timeController);
333 variableController.setTimeController(&timeController);
266
334
267 QFETCH(QUuid, syncId);
335 QFETCH(QUuid, syncId);
268 QFETCH(SqpRange, initialRange);
336 QFETCH(SqpRange, initialRange);
269 timeController.onTimeToUpdate(initialRange);
337 timeController.onTimeToUpdate(initialRange);
270
338
271 // Synchronization group used
339 // Synchronization group used
272 variableController.onAddSynchronizationGroupId(syncId);
340 variableController.onAddSynchronizationGroupId(syncId);
273
341
274 // For each iteration:
342 auto validateRanges = [&variableController](const auto &expectedRanges) {
275 // - execute operation
343 for (const auto &expectedRangeEntry : expectedRanges) {
276 // - compare the variables' state to the expected states
277 QFETCH(Iterations, iterations);
278 for (const auto &iteration : iterations) {
279 iteration.m_Operation->exec(variableController);
280 QTest::qWait(OPERATION_DELAY);
281
282 for (const auto &expectedRangeEntry : iteration.m_ExpectedRanges) {
283 auto variableIndex = expectedRangeEntry.first;
344 auto variableIndex = expectedRangeEntry.first;
284 auto expectedRange = expectedRangeEntry.second;
345 auto expectedRange = expectedRangeEntry.second;
285
346
286 // Gets the variable in the controller
347 // Gets the variable in the controller
287 auto variable = variableController.variableModel()->variable(variableIndex);
348 auto variable = variableController.variableModel()->variable(variableIndex);
288
349
289 // Compares variable's range to the expected range
350 // Compares variable's range to the expected range
290 QVERIFY(variable != nullptr);
351 QVERIFY(variable != nullptr);
291 auto range = variable->range();
352 auto range = variable->range();
292 QCOMPARE(range, expectedRange);
353 QCOMPARE(range, expectedRange);
293
354
294 // Compares variable's data with values expected for its range
355 // Compares variable's data with values expected for its range
295 auto dataSeries = variable->dataSeries();
356 auto dataSeries = variable->dataSeries();
296 QVERIFY(dataSeries != nullptr);
357 QVERIFY(dataSeries != nullptr);
297
358
298 auto it = dataSeries->xAxisRange(range.m_TStart, range.m_TEnd);
359 auto it = dataSeries->xAxisRange(range.m_TStart, range.m_TEnd);
299 auto expectedValues = values(range);
360 auto expectedValues = values(range);
361 qInfo() << std::distance(it.first, it.second) << expectedValues.size();
300 QVERIFY(std::equal(it.first, it.second, expectedValues.cbegin(), expectedValues.cend(),
362 QVERIFY(std::equal(it.first, it.second, expectedValues.cbegin(), expectedValues.cend(),
301 [](const auto &dataSeriesIt, const auto &expectedValue) {
363 [](const auto &dataSeriesIt, const auto &expectedValue) {
302 return dataSeriesIt.value() == expectedValue;
364 return dataSeriesIt.value() == expectedValue;
303 }));
365 }));
304 }
366 }
367 };
368
369 // For each iteration:
370 // - execute operation
371 // - compare the variables' state to the expected states
372 QFETCH(Iterations, iterations);
373 QFETCH(int, operationDelay);
374 for (const auto &iteration : iterations) {
375 iteration.m_Operation->exec(variableController);
376 QTest::qWait(operationDelay);
377
378 validateRanges(iteration.m_ExpectedRanges);
379 }
380
381 for (const auto &iteration : iterations) {
382 iteration.m_Operation->exec(variableController);
305 }
383 }
384 QTest::qWait(operationDelay);
385 validateRanges(iterations.back().m_ExpectedRanges);
306 }
386 }
307
387
308 QTEST_MAIN(TestVariableSync)
388 QTEST_MAIN(TestVariableSync)
309
389
310 #include "TestVariableSync.moc"
390 #include "TestVariableSync.moc"
@@ -1,98 +1,97
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 QCustomPlot;
16 class QCustomPlot;
17 class SqpRange;
17 class SqpRange;
18 class Variable;
18 class Variable;
19
19
20 namespace Ui {
20 namespace Ui {
21 class VisualizationGraphWidget;
21 class VisualizationGraphWidget;
22 } // namespace Ui
22 } // namespace Ui
23
23
24 class VisualizationGraphWidget : public QWidget, public IVisualizationWidget {
24 class VisualizationGraphWidget : public QWidget, public IVisualizationWidget {
25 Q_OBJECT
25 Q_OBJECT
26
26
27 friend class QCustomPlotSynchronizer;
27 friend class QCustomPlotSynchronizer;
28 friend class VisualizationGraphRenderingDelegate;
28 friend class VisualizationGraphRenderingDelegate;
29
29
30 public:
30 public:
31 explicit VisualizationGraphWidget(const QString &name = {}, QWidget *parent = 0);
31 explicit VisualizationGraphWidget(const QString &name = {}, QWidget *parent = 0);
32 virtual ~VisualizationGraphWidget();
32 virtual ~VisualizationGraphWidget();
33
33
34 /// If acquisition isn't enable, requestDataLoading signal cannot be emit
34 /// If acquisition isn't enable, requestDataLoading signal cannot be emit
35 void enableAcquisition(bool enable);
35 void enableAcquisition(bool enable);
36
36
37 void addVariable(std::shared_ptr<Variable> variable, SqpRange range);
37 void addVariable(std::shared_ptr<Variable> variable, SqpRange range);
38
38
39 /// Removes a variable from the graph
39 /// Removes a variable from the graph
40 void removeVariable(std::shared_ptr<Variable> variable) noexcept;
40 void removeVariable(std::shared_ptr<Variable> variable) noexcept;
41
41
42 void setRange(std::shared_ptr<Variable> variable, const SqpRange &range);
43 void setYRange(const SqpRange &range);
42 void setYRange(const SqpRange &range);
44 SqpRange graphRange() const noexcept;
43 SqpRange graphRange() const noexcept;
45 void setGraphRange(const SqpRange &range);
44 void setGraphRange(const SqpRange &range);
46
45
47 // IVisualizationWidget interface
46 // IVisualizationWidget interface
48 void accept(IVisualizationWidgetVisitor *visitor) override;
47 void accept(IVisualizationWidgetVisitor *visitor) override;
49 bool canDrop(const Variable &variable) const override;
48 bool canDrop(const Variable &variable) const override;
50 bool contains(const Variable &variable) const override;
49 bool contains(const Variable &variable) const override;
51 QString name() const override;
50 QString name() const override;
52
51
53
52
54 signals:
53 signals:
55 void synchronize(const SqpRange &range, const SqpRange &oldRange);
54 void synchronize(const SqpRange &range, const SqpRange &oldRange);
56 void requestDataLoading(QVector<std::shared_ptr<Variable> > variable, const SqpRange &range,
55 void requestDataLoading(QVector<std::shared_ptr<Variable> > variable, const SqpRange &range,
57 const SqpRange &oldRange, bool synchronise);
56 bool synchronise);
58
57
59 /// Signal emitted when the variable is about to be removed from the graph
58 /// Signal emitted when the variable is about to be removed from the graph
60 void variableAboutToBeRemoved(std::shared_ptr<Variable> var);
59 void variableAboutToBeRemoved(std::shared_ptr<Variable> var);
61 /// Signal emitted when the variable has been added to the graph
60 /// Signal emitted when the variable has been added to the graph
62 void variableAdded(std::shared_ptr<Variable> var);
61 void variableAdded(std::shared_ptr<Variable> var);
63
62
64 protected:
63 protected:
65 void closeEvent(QCloseEvent *event) override;
64 void closeEvent(QCloseEvent *event) override;
66 void enterEvent(QEvent *event) override;
65 void enterEvent(QEvent *event) override;
67 void leaveEvent(QEvent *event) override;
66 void leaveEvent(QEvent *event) override;
68
67
69 QCustomPlot &plot() noexcept;
68 QCustomPlot &plot() noexcept;
70
69
71 private:
70 private:
72 Ui::VisualizationGraphWidget *ui;
71 Ui::VisualizationGraphWidget *ui;
73
72
74 class VisualizationGraphWidgetPrivate;
73 class VisualizationGraphWidgetPrivate;
75 spimpl::unique_impl_ptr<VisualizationGraphWidgetPrivate> impl;
74 spimpl::unique_impl_ptr<VisualizationGraphWidgetPrivate> impl;
76
75
77 private slots:
76 private slots:
78 /// Slot called when right clicking on the graph (displays a menu)
77 /// Slot called when right clicking on the graph (displays a menu)
79 void onGraphMenuRequested(const QPoint &pos) noexcept;
78 void onGraphMenuRequested(const QPoint &pos) noexcept;
80
79
81 /// Rescale the X axe to range parameter
80 /// Rescale the X axe to range parameter
82 void onRangeChanged(const QCPRange &t1, const QCPRange &t2);
81 void onRangeChanged(const QCPRange &t1, const QCPRange &t2);
83
82
84 /// Slot called when a mouse move was made
83 /// Slot called when a mouse move was made
85 void onMouseMove(QMouseEvent *event) noexcept;
84 void onMouseMove(QMouseEvent *event) noexcept;
86 /// Slot called when a mouse wheel was made, to perform some processing before the zoom is done
85 /// Slot called when a mouse wheel was made, to perform some processing before the zoom is done
87 void onMouseWheel(QWheelEvent *event) noexcept;
86 void onMouseWheel(QWheelEvent *event) noexcept;
88 /// Slot called when a mouse press was made, to activate the calibration of a graph
87 /// Slot called when a mouse press was made, to activate the calibration of a graph
89 void onMousePress(QMouseEvent *event) noexcept;
88 void onMousePress(QMouseEvent *event) noexcept;
90 /// Slot called when a mouse release was made, to deactivate the calibration of a graph
89 /// Slot called when a mouse release was made, to deactivate the calibration of a graph
91 void onMouseRelease(QMouseEvent *event) noexcept;
90 void onMouseRelease(QMouseEvent *event) noexcept;
92
91
93 void onDataCacheVariableUpdated();
92 void onDataCacheVariableUpdated();
94
93
95 void onUpdateVarDisplaying(std::shared_ptr<Variable> variable, const SqpRange &range);
94 void onUpdateVarDisplaying(std::shared_ptr<Variable> variable, const SqpRange &range);
96 };
95 };
97
96
98 #endif // SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
97 #endif // SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
@@ -1,356 +1,342
1 #include "Visualization/VisualizationGraphWidget.h"
1 #include "Visualization/VisualizationGraphWidget.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 #include "Visualization/VisualizationDefs.h"
3 #include "Visualization/VisualizationDefs.h"
4 #include "Visualization/VisualizationGraphHelper.h"
4 #include "Visualization/VisualizationGraphHelper.h"
5 #include "Visualization/VisualizationGraphRenderingDelegate.h"
5 #include "Visualization/VisualizationGraphRenderingDelegate.h"
6 #include "ui_VisualizationGraphWidget.h"
6 #include "ui_VisualizationGraphWidget.h"
7
7
8 #include <Data/ArrayData.h>
8 #include <Data/ArrayData.h>
9 #include <Data/IDataSeries.h>
9 #include <Data/IDataSeries.h>
10 #include <Settings/SqpSettingsDefs.h>
10 #include <Settings/SqpSettingsDefs.h>
11 #include <SqpApplication.h>
11 #include <SqpApplication.h>
12 #include <Variable/Variable.h>
12 #include <Variable/Variable.h>
13 #include <Variable/VariableController.h>
13 #include <Variable/VariableController.h>
14
14
15 #include <unordered_map>
15 #include <unordered_map>
16
16
17 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
17 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
18
18
19 namespace {
19 namespace {
20
20
21 /// Key pressed to enable zoom on horizontal axis
21 /// Key pressed to enable zoom on horizontal axis
22 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::NoModifier;
22 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::NoModifier;
23
23
24 /// Key pressed to enable zoom on vertical axis
24 /// Key pressed to enable zoom on vertical axis
25 const auto VERTICAL_ZOOM_MODIFIER = Qt::ControlModifier;
25 const auto VERTICAL_ZOOM_MODIFIER = Qt::ControlModifier;
26
26
27 } // namespace
27 } // namespace
28
28
29 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
29 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
30
30
31 explicit VisualizationGraphWidgetPrivate(const QString &name)
31 explicit VisualizationGraphWidgetPrivate(const QString &name)
32 : m_Name{name},
32 : m_Name{name},
33 m_DoAcquisition{true},
33 m_DoAcquisition{true},
34 m_IsCalibration{false},
34 m_IsCalibration{false},
35 m_RenderingDelegate{nullptr}
35 m_RenderingDelegate{nullptr}
36 {
36 {
37 }
37 }
38
38
39 QString m_Name;
39 QString m_Name;
40 // 1 variable -> n qcpplot
40 // 1 variable -> n qcpplot
41 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
41 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
42 bool m_DoAcquisition;
42 bool m_DoAcquisition;
43 bool m_IsCalibration;
43 bool m_IsCalibration;
44 QCPItemTracer *m_TextTracer;
44 QCPItemTracer *m_TextTracer;
45 /// Delegate used to attach rendering features to the plot
45 /// Delegate used to attach rendering features to the plot
46 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
46 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
47 };
47 };
48
48
49 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
49 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
50 : QWidget{parent},
50 : QWidget{parent},
51 ui{new Ui::VisualizationGraphWidget},
51 ui{new Ui::VisualizationGraphWidget},
52 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
52 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
53 {
53 {
54 ui->setupUi(this);
54 ui->setupUi(this);
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
58
59 // Set qcpplot properties :
59 // Set qcpplot properties :
60 // - Drag (on x-axis) and zoom are enabled
60 // - Drag (on x-axis) and zoom are enabled
61 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
61 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
62 ui->widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectItems);
62 ui->widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectItems);
63 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal);
63 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal);
64
64
65 // The delegate must be initialized after the ui as it uses the plot
65 // The delegate must be initialized after the ui as it uses the plot
66 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
66 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
67
67
68 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
68 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
69 connect(ui->widget, &QCustomPlot::mouseRelease, this,
69 connect(ui->widget, &QCustomPlot::mouseRelease, this,
70 &VisualizationGraphWidget::onMouseRelease);
70 &VisualizationGraphWidget::onMouseRelease);
71 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
71 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
72 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
72 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
73 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
73 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
74 &QCPAxis::rangeChanged),
74 &QCPAxis::rangeChanged),
75 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
75 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
76
76
77 // Activates menu when right clicking on the graph
77 // Activates menu when right clicking on the graph
78 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
78 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
79 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
79 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
80 &VisualizationGraphWidget::onGraphMenuRequested);
80 &VisualizationGraphWidget::onGraphMenuRequested);
81
81
82 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
82 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
83 &VariableController::onRequestDataLoading);
83 &VariableController::onRequestDataLoading);
84
84
85 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
85 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
86 &VisualizationGraphWidget::onUpdateVarDisplaying);
86 &VisualizationGraphWidget::onUpdateVarDisplaying);
87 }
87 }
88
88
89
89
90 VisualizationGraphWidget::~VisualizationGraphWidget()
90 VisualizationGraphWidget::~VisualizationGraphWidget()
91 {
91 {
92 delete ui;
92 delete ui;
93 }
93 }
94
94
95 void VisualizationGraphWidget::enableAcquisition(bool enable)
95 void VisualizationGraphWidget::enableAcquisition(bool enable)
96 {
96 {
97 impl->m_DoAcquisition = enable;
97 impl->m_DoAcquisition = enable;
98 }
98 }
99
99
100 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
100 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
101 {
101 {
102 // Uses delegate to create the qcpplot components according to the variable
102 // Uses delegate to create the qcpplot components according to the variable
103 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
103 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
104 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
104 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
105
105
106 // Set axes properties according to the units of the data series
106 // Set axes properties according to the units of the data series
107 /// @todo : for the moment, no control is performed on the axes: the units and the tickers
107 /// @todo : for the moment, no control is performed on the axes: the units and the tickers
108 /// are fixed for the default x-axis and y-axis of the plot, and according to the new graph
108 /// are fixed for the default x-axis and y-axis of the plot, and according to the new graph
109 auto xAxisUnit = Unit{};
109 auto xAxisUnit = Unit{};
110 auto valuesUnit = Unit{};
110 auto valuesUnit = Unit{};
111
111
112 if (auto dataSeries = variable->dataSeries()) {
112 if (auto dataSeries = variable->dataSeries()) {
113 dataSeries->lockRead();
113 dataSeries->lockRead();
114 xAxisUnit = dataSeries->xAxisUnit();
114 xAxisUnit = dataSeries->xAxisUnit();
115 valuesUnit = dataSeries->valuesUnit();
115 valuesUnit = dataSeries->valuesUnit();
116 dataSeries->unlock();
116 dataSeries->unlock();
117 }
117 }
118 impl->m_RenderingDelegate->setAxesProperties(xAxisUnit, valuesUnit);
118 impl->m_RenderingDelegate->setAxesProperties(xAxisUnit, valuesUnit);
119
119
120 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
120 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
121
121
122 auto varRange = variable->range();
123
124 this->enableAcquisition(false);
122 this->enableAcquisition(false);
125 this->setGraphRange(range);
123 this->setGraphRange(range);
126 this->enableAcquisition(true);
124 this->enableAcquisition(true);
127
125
128 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable, range, varRange,
126 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable, range, false);
129 false);
130
127
131 emit variableAdded(variable);
128 emit variableAdded(variable);
132 }
129 }
133
130
134 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
131 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
135 {
132 {
136 // Each component associated to the variable :
133 // Each component associated to the variable :
137 // - is removed from qcpplot (which deletes it)
134 // - is removed from qcpplot (which deletes it)
138 // - is no longer referenced in the map
135 // - is no longer referenced in the map
139 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
136 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
140 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
137 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
141 emit variableAboutToBeRemoved(variable);
138 emit variableAboutToBeRemoved(variable);
142
139
143 auto &plottablesMap = variableIt->second;
140 auto &plottablesMap = variableIt->second;
144
141
145 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
142 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
146 plottableIt != plottableEnd;) {
143 plottableIt != plottableEnd;) {
147 ui->widget->removePlottable(plottableIt->second);
144 ui->widget->removePlottable(plottableIt->second);
148 plottableIt = plottablesMap.erase(plottableIt);
145 plottableIt = plottablesMap.erase(plottableIt);
149 }
146 }
150
147
151 impl->m_VariableToPlotMultiMap.erase(variableIt);
148 impl->m_VariableToPlotMultiMap.erase(variableIt);
152 }
149 }
153
150
154 // Updates graph
151 // Updates graph
155 ui->widget->replot();
152 ui->widget->replot();
156 }
153 }
157
154
158 void VisualizationGraphWidget::setRange(std::shared_ptr<Variable> variable, const SqpRange &range)
159 {
160 // Note: in case of different axes that depends on variable, we could start with a code like
161 // that:
162 // auto componentsIt = impl->m_VariableToPlotMultiMap.equal_range(variable);
163 // for (auto it = componentsIt.first; it != componentsIt.second;) {
164 // }
165 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
166 ui->widget->replot();
167 }
168
169 void VisualizationGraphWidget::setYRange(const SqpRange &range)
155 void VisualizationGraphWidget::setYRange(const SqpRange &range)
170 {
156 {
171 ui->widget->yAxis->setRange(range.m_TStart, range.m_TEnd);
157 ui->widget->yAxis->setRange(range.m_TStart, range.m_TEnd);
172 }
158 }
173
159
174 SqpRange VisualizationGraphWidget::graphRange() const noexcept
160 SqpRange VisualizationGraphWidget::graphRange() const noexcept
175 {
161 {
176 auto graphRange = ui->widget->xAxis->range();
162 auto graphRange = ui->widget->xAxis->range();
177 return SqpRange{graphRange.lower, graphRange.upper};
163 return SqpRange{graphRange.lower, graphRange.upper};
178 }
164 }
179
165
180 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
166 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
181 {
167 {
182 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
168 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
183 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
169 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
184 ui->widget->replot();
170 ui->widget->replot();
185 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
171 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
186 }
172 }
187
173
188 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
174 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
189 {
175 {
190 if (visitor) {
176 if (visitor) {
191 visitor->visit(this);
177 visitor->visit(this);
192 }
178 }
193 else {
179 else {
194 qCCritical(LOG_VisualizationGraphWidget())
180 qCCritical(LOG_VisualizationGraphWidget())
195 << tr("Can't visit widget : the visitor is null");
181 << tr("Can't visit widget : the visitor is null");
196 }
182 }
197 }
183 }
198
184
199 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
185 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
200 {
186 {
201 /// @todo : for the moment, a graph can always accomodate a variable
187 /// @todo : for the moment, a graph can always accomodate a variable
202 Q_UNUSED(variable);
188 Q_UNUSED(variable);
203 return true;
189 return true;
204 }
190 }
205
191
206 bool VisualizationGraphWidget::contains(const Variable &variable) const
192 bool VisualizationGraphWidget::contains(const Variable &variable) const
207 {
193 {
208 // Finds the variable among the keys of the map
194 // Finds the variable among the keys of the map
209 auto variablePtr = &variable;
195 auto variablePtr = &variable;
210 auto findVariable
196 auto findVariable
211 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
197 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
212
198
213 auto end = impl->m_VariableToPlotMultiMap.cend();
199 auto end = impl->m_VariableToPlotMultiMap.cend();
214 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
200 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
215 return it != end;
201 return it != end;
216 }
202 }
217
203
218 QString VisualizationGraphWidget::name() const
204 QString VisualizationGraphWidget::name() const
219 {
205 {
220 return impl->m_Name;
206 return impl->m_Name;
221 }
207 }
222
208
223 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
209 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
224 {
210 {
225 Q_UNUSED(event);
211 Q_UNUSED(event);
226
212
227 // Prevents that all variables will be removed from graph when it will be closed
213 // Prevents that all variables will be removed from graph when it will be closed
228 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
214 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
229 emit variableAboutToBeRemoved(variableEntry.first);
215 emit variableAboutToBeRemoved(variableEntry.first);
230 }
216 }
231 }
217 }
232
218
233 void VisualizationGraphWidget::enterEvent(QEvent *event)
219 void VisualizationGraphWidget::enterEvent(QEvent *event)
234 {
220 {
235 Q_UNUSED(event);
221 Q_UNUSED(event);
236 impl->m_RenderingDelegate->showGraphOverlay(true);
222 impl->m_RenderingDelegate->showGraphOverlay(true);
237 }
223 }
238
224
239 void VisualizationGraphWidget::leaveEvent(QEvent *event)
225 void VisualizationGraphWidget::leaveEvent(QEvent *event)
240 {
226 {
241 Q_UNUSED(event);
227 Q_UNUSED(event);
242 impl->m_RenderingDelegate->showGraphOverlay(false);
228 impl->m_RenderingDelegate->showGraphOverlay(false);
243 }
229 }
244
230
245 QCustomPlot &VisualizationGraphWidget::plot() noexcept
231 QCustomPlot &VisualizationGraphWidget::plot() noexcept
246 {
232 {
247 return *ui->widget;
233 return *ui->widget;
248 }
234 }
249
235
250 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
236 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
251 {
237 {
252 QMenu graphMenu{};
238 QMenu graphMenu{};
253
239
254 // Iterates on variables (unique keys)
240 // Iterates on variables (unique keys)
255 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
241 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
256 end = impl->m_VariableToPlotMultiMap.cend();
242 end = impl->m_VariableToPlotMultiMap.cend();
257 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
243 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
258 // 'Remove variable' action
244 // 'Remove variable' action
259 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
245 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
260 [ this, var = it->first ]() { removeVariable(var); });
246 [ this, var = it->first ]() { removeVariable(var); });
261 }
247 }
262
248
263 if (!graphMenu.isEmpty()) {
249 if (!graphMenu.isEmpty()) {
264 graphMenu.exec(QCursor::pos());
250 graphMenu.exec(QCursor::pos());
265 }
251 }
266 }
252 }
267
253
268 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
254 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
269 {
255 {
270 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
256 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
271 << QThread::currentThread()->objectName() << "DoAcqui"
257 << QThread::currentThread()->objectName() << "DoAcqui"
272 << impl->m_DoAcquisition;
258 << impl->m_DoAcquisition;
273
259
274 auto graphRange = SqpRange{t1.lower, t1.upper};
260 auto graphRange = SqpRange{t1.lower, t1.upper};
275 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
261 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
276
262
277 if (impl->m_DoAcquisition) {
263 if (impl->m_DoAcquisition) {
278 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
264 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
279
265
280 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
266 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
281 end = impl->m_VariableToPlotMultiMap.end();
267 end = impl->m_VariableToPlotMultiMap.end();
282 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
268 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
283 variableUnderGraphVector.push_back(it->first);
269 variableUnderGraphVector.push_back(it->first);
284 }
270 }
285 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange, oldGraphRange,
271 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
286 !impl->m_IsCalibration);
272 !impl->m_IsCalibration);
287
273
288 if (!impl->m_IsCalibration) {
274 if (!impl->m_IsCalibration) {
289 qCDebug(LOG_VisualizationGraphWidget())
275 qCDebug(LOG_VisualizationGraphWidget())
290 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
276 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
291 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
277 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
292 emit synchronize(graphRange, oldGraphRange);
278 emit synchronize(graphRange, oldGraphRange);
293 }
279 }
294 }
280 }
295 }
281 }
296
282
297 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
283 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
298 {
284 {
299 // Handles plot rendering when mouse is moving
285 // Handles plot rendering when mouse is moving
300 impl->m_RenderingDelegate->onMouseMove(event);
286 impl->m_RenderingDelegate->onMouseMove(event);
301 }
287 }
302
288
303 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
289 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
304 {
290 {
305 auto zoomOrientations = QFlags<Qt::Orientation>{};
291 auto zoomOrientations = QFlags<Qt::Orientation>{};
306
292
307 // Lambda that enables a zoom orientation if the key modifier related to this orientation
293 // Lambda that enables a zoom orientation if the key modifier related to this orientation
308 // has
294 // has
309 // been pressed
295 // been pressed
310 auto enableOrientation
296 auto enableOrientation
311 = [&zoomOrientations, event](const auto &orientation, const auto &modifier) {
297 = [&zoomOrientations, event](const auto &orientation, const auto &modifier) {
312 auto orientationEnabled = event->modifiers().testFlag(modifier);
298 auto orientationEnabled = event->modifiers().testFlag(modifier);
313 zoomOrientations.setFlag(orientation, orientationEnabled);
299 zoomOrientations.setFlag(orientation, orientationEnabled);
314 };
300 };
315 enableOrientation(Qt::Vertical, VERTICAL_ZOOM_MODIFIER);
301 enableOrientation(Qt::Vertical, VERTICAL_ZOOM_MODIFIER);
316 enableOrientation(Qt::Horizontal, HORIZONTAL_ZOOM_MODIFIER);
302 enableOrientation(Qt::Horizontal, HORIZONTAL_ZOOM_MODIFIER);
317
303
318 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
304 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
319 }
305 }
320
306
321 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
307 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
322 {
308 {
323 impl->m_IsCalibration = event->modifiers().testFlag(Qt::ControlModifier);
309 impl->m_IsCalibration = event->modifiers().testFlag(Qt::ControlModifier);
324 }
310 }
325
311
326 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
312 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
327 {
313 {
328 impl->m_IsCalibration = false;
314 impl->m_IsCalibration = false;
329 }
315 }
330
316
331 void VisualizationGraphWidget::onDataCacheVariableUpdated()
317 void VisualizationGraphWidget::onDataCacheVariableUpdated()
332 {
318 {
333 auto graphRange = ui->widget->xAxis->range();
319 auto graphRange = ui->widget->xAxis->range();
334 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
320 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
335
321
336 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
322 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
337 auto variable = variableEntry.first;
323 auto variable = variableEntry.first;
338 qCDebug(LOG_VisualizationGraphWidget())
324 qCDebug(LOG_VisualizationGraphWidget())
339 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
325 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
340 qCDebug(LOG_VisualizationGraphWidget())
326 qCDebug(LOG_VisualizationGraphWidget())
341 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
327 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
342 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
328 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
343 VisualizationGraphHelper::updateData(variableEntry.second, variable->dataSeries(),
329 VisualizationGraphHelper::updateData(variableEntry.second, variable->dataSeries(),
344 variable->range());
330 variable->range());
345 }
331 }
346 }
332 }
347 }
333 }
348
334
349 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
335 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
350 const SqpRange &range)
336 const SqpRange &range)
351 {
337 {
352 auto it = impl->m_VariableToPlotMultiMap.find(variable);
338 auto it = impl->m_VariableToPlotMultiMap.find(variable);
353 if (it != impl->m_VariableToPlotMultiMap.end()) {
339 if (it != impl->m_VariableToPlotMultiMap.end()) {
354 VisualizationGraphHelper::updateData(it->second, variable->dataSeries(), range);
340 VisualizationGraphHelper::updateData(it->second, variable->dataSeries(), range);
355 }
341 }
356 }
342 }
@@ -1,302 +1,304
1 #include "Visualization/VisualizationZoneWidget.h"
1 #include "Visualization/VisualizationZoneWidget.h"
2
2
3 #include "Visualization/IVisualizationWidgetVisitor.h"
3 #include "Visualization/IVisualizationWidgetVisitor.h"
4 #include "Visualization/QCustomPlotSynchronizer.h"
4 #include "Visualization/QCustomPlotSynchronizer.h"
5 #include "Visualization/VisualizationGraphWidget.h"
5 #include "Visualization/VisualizationGraphWidget.h"
6 #include "ui_VisualizationZoneWidget.h"
6 #include "ui_VisualizationZoneWidget.h"
7
7
8 #include <Data/SqpRange.h>
8 #include <Data/SqpRange.h>
9 #include <Variable/Variable.h>
9 #include <Variable/Variable.h>
10 #include <Variable/VariableController.h>
10 #include <Variable/VariableController.h>
11
11
12 #include <QUuid>
12 #include <QUuid>
13 #include <SqpApplication.h>
13 #include <SqpApplication.h>
14 #include <cmath>
14 #include <cmath>
15
15
16 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
16 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
17
17
18 namespace {
18 namespace {
19
19
20 /// Minimum height for graph added in zones (in pixels)
20 /// Minimum height for graph added in zones (in pixels)
21 const auto GRAPH_MINIMUM_HEIGHT = 300;
21 const auto GRAPH_MINIMUM_HEIGHT = 300;
22
22
23 /// Generates a default name for a new graph, according to the number of graphs already displayed in
23 /// Generates a default name for a new graph, according to the number of graphs already displayed in
24 /// the zone
24 /// the zone
25 QString defaultGraphName(const QLayout &layout)
25 QString defaultGraphName(const QLayout &layout)
26 {
26 {
27 auto count = 0;
27 auto count = 0;
28 for (auto i = 0; i < layout.count(); ++i) {
28 for (auto i = 0; i < layout.count(); ++i) {
29 if (dynamic_cast<VisualizationGraphWidget *>(layout.itemAt(i)->widget())) {
29 if (dynamic_cast<VisualizationGraphWidget *>(layout.itemAt(i)->widget())) {
30 count++;
30 count++;
31 }
31 }
32 }
32 }
33
33
34 return QObject::tr("Graph %1").arg(count + 1);
34 return QObject::tr("Graph %1").arg(count + 1);
35 }
35 }
36
36
37 /**
37 /**
38 * Applies a function to all graphs of the zone represented by its layout
38 * Applies a function to all graphs of the zone represented by its layout
39 * @param layout the layout that contains graphs
39 * @param layout the layout that contains graphs
40 * @param fun the function to apply to each graph
40 * @param fun the function to apply to each graph
41 */
41 */
42 template <typename Fun>
42 template <typename Fun>
43 void processGraphs(QLayout &layout, Fun fun)
43 void processGraphs(QLayout &layout, Fun fun)
44 {
44 {
45 for (auto i = 0; i < layout.count(); ++i) {
45 for (auto i = 0; i < layout.count(); ++i) {
46 if (auto item = layout.itemAt(i)) {
46 if (auto item = layout.itemAt(i)) {
47 if (auto visualizationGraphWidget
47 if (auto visualizationGraphWidget
48 = dynamic_cast<VisualizationGraphWidget *>(item->widget())) {
48 = dynamic_cast<VisualizationGraphWidget *>(item->widget())) {
49 fun(*visualizationGraphWidget);
49 fun(*visualizationGraphWidget);
50 }
50 }
51 }
51 }
52 }
52 }
53 }
53 }
54
54
55 } // namespace
55 } // namespace
56
56
57 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate {
57 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate {
58
58
59 explicit VisualizationZoneWidgetPrivate()
59 explicit VisualizationZoneWidgetPrivate()
60 : m_SynchronisationGroupId{QUuid::createUuid()},
60 : m_SynchronisationGroupId{QUuid::createUuid()},
61 m_Synchronizer{std::make_unique<QCustomPlotSynchronizer>()}
61 m_Synchronizer{std::make_unique<QCustomPlotSynchronizer>()}
62 {
62 {
63 }
63 }
64 QUuid m_SynchronisationGroupId;
64 QUuid m_SynchronisationGroupId;
65 std::unique_ptr<IGraphSynchronizer> m_Synchronizer;
65 std::unique_ptr<IGraphSynchronizer> m_Synchronizer;
66 };
66 };
67
67
68 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
68 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
69 : QWidget{parent},
69 : QWidget{parent},
70 ui{new Ui::VisualizationZoneWidget},
70 ui{new Ui::VisualizationZoneWidget},
71 impl{spimpl::make_unique_impl<VisualizationZoneWidgetPrivate>()}
71 impl{spimpl::make_unique_impl<VisualizationZoneWidgetPrivate>()}
72 {
72 {
73 ui->setupUi(this);
73 ui->setupUi(this);
74
74
75 ui->zoneNameLabel->setText(name);
75 ui->zoneNameLabel->setText(name);
76
76
77 // 'Close' options : widget is deleted when closed
77 // 'Close' options : widget is deleted when closed
78 setAttribute(Qt::WA_DeleteOnClose);
78 setAttribute(Qt::WA_DeleteOnClose);
79 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
79 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
80 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
80 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
81
81
82 // Synchronisation id
82 // Synchronisation id
83 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronizationGroupId",
83 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronizationGroupId",
84 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
84 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
85 }
85 }
86
86
87 VisualizationZoneWidget::~VisualizationZoneWidget()
87 VisualizationZoneWidget::~VisualizationZoneWidget()
88 {
88 {
89 delete ui;
89 delete ui;
90 }
90 }
91
91
92 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
92 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
93 {
93 {
94 // Synchronize new graph with others in the zone
94 // Synchronize new graph with others in the zone
95 impl->m_Synchronizer->addGraph(*graphWidget);
95 impl->m_Synchronizer->addGraph(*graphWidget);
96
96
97 ui->visualizationZoneFrame->layout()->addWidget(graphWidget);
97 ui->visualizationZoneFrame->layout()->addWidget(graphWidget);
98 }
98 }
99
99
100 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
100 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
101 {
101 {
102 auto graphWidget = new VisualizationGraphWidget{
102 auto graphWidget = new VisualizationGraphWidget{
103 defaultGraphName(*ui->visualizationZoneFrame->layout()), this};
103 defaultGraphName(*ui->visualizationZoneFrame->layout()), this};
104
104
105
105
106 // Set graph properties
106 // Set graph properties
107 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
107 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
108 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
108 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
109
109
110
110
111 // Lambda to synchronize zone widget
111 // Lambda to synchronize zone widget
112 auto synchronizeZoneWidget = [this, graphWidget](const SqpRange &graphRange,
112 auto synchronizeZoneWidget = [this, graphWidget](const SqpRange &graphRange,
113 const SqpRange &oldGraphRange) {
113 const SqpRange &oldGraphRange) {
114
114
115 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
115 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
116 auto frameLayout = ui->visualizationZoneFrame->layout();
116 auto frameLayout = ui->visualizationZoneFrame->layout();
117 for (auto i = 0; i < frameLayout->count(); ++i) {
117 for (auto i = 0; i < frameLayout->count(); ++i) {
118 auto graphChild
118 auto graphChild
119 = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
119 = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
120 if (graphChild && (graphChild != graphWidget)) {
120 if (graphChild && (graphChild != graphWidget)) {
121
121
122 auto graphChildRange = graphChild->graphRange();
122 auto graphChildRange = graphChild->graphRange();
123 switch (zoomType) {
123 switch (zoomType) {
124 case AcquisitionZoomType::ZoomIn: {
124 case AcquisitionZoomType::ZoomIn: {
125 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
125 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
126 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
126 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
127 graphChildRange.m_TStart += deltaLeft;
127 graphChildRange.m_TStart += deltaLeft;
128 graphChildRange.m_TEnd -= deltaRight;
128 graphChildRange.m_TEnd -= deltaRight;
129 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomIn");
129 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomIn");
130 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
130 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
131 << deltaLeft;
131 << deltaLeft;
132 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
132 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
133 << deltaRight;
133 << deltaRight;
134 qCDebug(LOG_VisualizationZoneWidget())
134 qCDebug(LOG_VisualizationZoneWidget())
135 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
135 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
136
136
137 break;
137 break;
138 }
138 }
139
139
140 case AcquisitionZoomType::ZoomOut: {
140 case AcquisitionZoomType::ZoomOut: {
141 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomOut");
141 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomOut");
142 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
142 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
143 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
143 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
144 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
144 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
145 << deltaLeft;
145 << deltaLeft;
146 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
146 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
147 << deltaRight;
147 << deltaRight;
148 qCDebug(LOG_VisualizationZoneWidget())
148 qCDebug(LOG_VisualizationZoneWidget())
149 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
149 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
150 graphChildRange.m_TStart -= deltaLeft;
150 graphChildRange.m_TStart -= deltaLeft;
151 graphChildRange.m_TEnd += deltaRight;
151 graphChildRange.m_TEnd += deltaRight;
152 break;
152 break;
153 }
153 }
154 case AcquisitionZoomType::PanRight: {
154 case AcquisitionZoomType::PanRight: {
155 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanRight");
155 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanRight");
156 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
156 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
157 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
157 graphChildRange.m_TStart += deltaRight;
158 graphChildRange.m_TStart += deltaLeft;
158 graphChildRange.m_TEnd += deltaRight;
159 graphChildRange.m_TEnd += deltaRight;
159 qCDebug(LOG_VisualizationZoneWidget())
160 qCDebug(LOG_VisualizationZoneWidget())
160 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
161 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
161 break;
162 break;
162 }
163 }
163 case AcquisitionZoomType::PanLeft: {
164 case AcquisitionZoomType::PanLeft: {
164 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanLeft");
165 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanLeft");
165 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
166 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
167 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
166 graphChildRange.m_TStart -= deltaLeft;
168 graphChildRange.m_TStart -= deltaLeft;
167 graphChildRange.m_TEnd -= deltaLeft;
169 graphChildRange.m_TEnd -= deltaRight;
168 break;
170 break;
169 }
171 }
170 case AcquisitionZoomType::Unknown: {
172 case AcquisitionZoomType::Unknown: {
171 qCDebug(LOG_VisualizationZoneWidget())
173 qCDebug(LOG_VisualizationZoneWidget())
172 << tr("Impossible to synchronize: zoom type unknown");
174 << tr("Impossible to synchronize: zoom type unknown");
173 break;
175 break;
174 }
176 }
175 default:
177 default:
176 qCCritical(LOG_VisualizationZoneWidget())
178 qCCritical(LOG_VisualizationZoneWidget())
177 << tr("Impossible to synchronize: zoom type not take into account");
179 << tr("Impossible to synchronize: zoom type not take into account");
178 // No action
180 // No action
179 break;
181 break;
180 }
182 }
181 graphChild->enableAcquisition(false);
183 graphChild->enableAcquisition(false);
182 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range before: ")
184 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range before: ")
183 << graphChild->graphRange();
185 << graphChild->graphRange();
184 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range after : ")
186 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range after : ")
185 << graphChildRange;
187 << graphChildRange;
186 qCDebug(LOG_VisualizationZoneWidget())
188 qCDebug(LOG_VisualizationZoneWidget())
187 << tr("TORM: child dt") << graphChildRange.m_TEnd - graphChildRange.m_TStart;
189 << tr("TORM: child dt") << graphChildRange.m_TEnd - graphChildRange.m_TStart;
188 graphChild->setGraphRange(graphChildRange);
190 graphChild->setGraphRange(graphChildRange);
189 graphChild->enableAcquisition(true);
191 graphChild->enableAcquisition(true);
190 }
192 }
191 }
193 }
192 };
194 };
193
195
194 // connection for synchronization
196 // connection for synchronization
195 connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
197 connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
196 connect(graphWidget, &VisualizationGraphWidget::variableAdded, this,
198 connect(graphWidget, &VisualizationGraphWidget::variableAdded, this,
197 &VisualizationZoneWidget::onVariableAdded);
199 &VisualizationZoneWidget::onVariableAdded);
198 connect(graphWidget, &VisualizationGraphWidget::variableAboutToBeRemoved, this,
200 connect(graphWidget, &VisualizationGraphWidget::variableAboutToBeRemoved, this,
199 &VisualizationZoneWidget::onVariableAboutToBeRemoved);
201 &VisualizationZoneWidget::onVariableAboutToBeRemoved);
200
202
201 auto range = SqpRange{};
203 auto range = SqpRange{};
202
204
203 // Apply visitor to graph children
205 // Apply visitor to graph children
204 auto layout = ui->visualizationZoneFrame->layout();
206 auto layout = ui->visualizationZoneFrame->layout();
205 if (layout->count() > 0) {
207 if (layout->count() > 0) {
206 // Case of a new graph in a existant zone
208 // Case of a new graph in a existant zone
207 if (auto visualizationGraphWidget
209 if (auto visualizationGraphWidget
208 = dynamic_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
210 = dynamic_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
209 range = visualizationGraphWidget->graphRange();
211 range = visualizationGraphWidget->graphRange();
210 }
212 }
211 }
213 }
212 else {
214 else {
213 // Case of a new graph as the first of the zone
215 // Case of a new graph as the first of the zone
214 range = variable->range();
216 range = variable->range();
215 }
217 }
216
218
217 this->addGraph(graphWidget);
219 this->addGraph(graphWidget);
218
220
219 graphWidget->addVariable(variable, range);
221 graphWidget->addVariable(variable, range);
220
222
221 // get y using variable range
223 // get y using variable range
222 if (auto dataSeries = variable->dataSeries()) {
224 if (auto dataSeries = variable->dataSeries()) {
223 dataSeries->lockRead();
225 dataSeries->lockRead();
224 auto valuesBounds
226 auto valuesBounds
225 = dataSeries->valuesBounds(variable->range().m_TStart, variable->range().m_TEnd);
227 = dataSeries->valuesBounds(variable->range().m_TStart, variable->range().m_TEnd);
226 auto end = dataSeries->cend();
228 auto end = dataSeries->cend();
227 if (valuesBounds.first != end && valuesBounds.second != end) {
229 if (valuesBounds.first != end && valuesBounds.second != end) {
228 auto rangeValue = [](const auto &value) { return std::isnan(value) ? 0. : value; };
230 auto rangeValue = [](const auto &value) { return std::isnan(value) ? 0. : value; };
229
231
230 auto minValue = rangeValue(valuesBounds.first->minValue());
232 auto minValue = rangeValue(valuesBounds.first->minValue());
231 auto maxValue = rangeValue(valuesBounds.second->maxValue());
233 auto maxValue = rangeValue(valuesBounds.second->maxValue());
232
234
233 graphWidget->setYRange(SqpRange{minValue, maxValue});
235 graphWidget->setYRange(SqpRange{minValue, maxValue});
234 }
236 }
235 dataSeries->unlock();
237 dataSeries->unlock();
236 }
238 }
237
239
238 return graphWidget;
240 return graphWidget;
239 }
241 }
240
242
241 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
243 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
242 {
244 {
243 if (visitor) {
245 if (visitor) {
244 visitor->visitEnter(this);
246 visitor->visitEnter(this);
245
247
246 // Apply visitor to graph children: widgets different from graphs are not visited (no
248 // Apply visitor to graph children: widgets different from graphs are not visited (no
247 // action)
249 // action)
248 processGraphs(
250 processGraphs(
249 *ui->visualizationZoneFrame->layout(),
251 *ui->visualizationZoneFrame->layout(),
250 [visitor](VisualizationGraphWidget &graphWidget) { graphWidget.accept(visitor); });
252 [visitor](VisualizationGraphWidget &graphWidget) { graphWidget.accept(visitor); });
251
253
252 visitor->visitLeave(this);
254 visitor->visitLeave(this);
253 }
255 }
254 else {
256 else {
255 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
257 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
256 }
258 }
257 }
259 }
258
260
259 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
261 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
260 {
262 {
261 // A tab can always accomodate a variable
263 // A tab can always accomodate a variable
262 Q_UNUSED(variable);
264 Q_UNUSED(variable);
263 return true;
265 return true;
264 }
266 }
265
267
266 bool VisualizationZoneWidget::contains(const Variable &variable) const
268 bool VisualizationZoneWidget::contains(const Variable &variable) const
267 {
269 {
268 Q_UNUSED(variable);
270 Q_UNUSED(variable);
269 return false;
271 return false;
270 }
272 }
271
273
272 QString VisualizationZoneWidget::name() const
274 QString VisualizationZoneWidget::name() const
273 {
275 {
274 return ui->zoneNameLabel->text();
276 return ui->zoneNameLabel->text();
275 }
277 }
276
278
277 void VisualizationZoneWidget::closeEvent(QCloseEvent *event)
279 void VisualizationZoneWidget::closeEvent(QCloseEvent *event)
278 {
280 {
279 // Closes graphs in the zone
281 // Closes graphs in the zone
280 processGraphs(*ui->visualizationZoneFrame->layout(),
282 processGraphs(*ui->visualizationZoneFrame->layout(),
281 [](VisualizationGraphWidget &graphWidget) { graphWidget.close(); });
283 [](VisualizationGraphWidget &graphWidget) { graphWidget.close(); });
282
284
283 // Delete synchronization group from variable controller
285 // Delete synchronization group from variable controller
284 QMetaObject::invokeMethod(&sqpApp->variableController(), "onRemoveSynchronizationGroupId",
286 QMetaObject::invokeMethod(&sqpApp->variableController(), "onRemoveSynchronizationGroupId",
285 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
287 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
286
288
287 QWidget::closeEvent(event);
289 QWidget::closeEvent(event);
288 }
290 }
289
291
290 void VisualizationZoneWidget::onVariableAdded(std::shared_ptr<Variable> variable)
292 void VisualizationZoneWidget::onVariableAdded(std::shared_ptr<Variable> variable)
291 {
293 {
292 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronized",
294 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronized",
293 Qt::QueuedConnection, Q_ARG(std::shared_ptr<Variable>, variable),
295 Qt::QueuedConnection, Q_ARG(std::shared_ptr<Variable>, variable),
294 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
296 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
295 }
297 }
296
298
297 void VisualizationZoneWidget::onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable)
299 void VisualizationZoneWidget::onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable)
298 {
300 {
299 QMetaObject::invokeMethod(&sqpApp->variableController(), "desynchronize", Qt::QueuedConnection,
301 QMetaObject::invokeMethod(&sqpApp->variableController(), "desynchronize", Qt::QueuedConnection,
300 Q_ARG(std::shared_ptr<Variable>, variable),
302 Q_ARG(std::shared_ptr<Variable>, variable),
301 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
303 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
302 }
304 }
@@ -1,69 +1,71
1 #include "Visualization/operations/RescaleAxeOperation.h"
1 #include "Visualization/operations/RescaleAxeOperation.h"
2 #include "Visualization/VisualizationGraphWidget.h"
2 #include "Visualization/VisualizationGraphWidget.h"
3
3
4 Q_LOGGING_CATEGORY(LOG_RescaleAxeOperation, "RescaleAxeOperation")
4 Q_LOGGING_CATEGORY(LOG_RescaleAxeOperation, "RescaleAxeOperation")
5
5
6 struct RescaleAxeOperation::RescaleAxeOperationPrivate {
6 struct RescaleAxeOperation::RescaleAxeOperationPrivate {
7 explicit RescaleAxeOperationPrivate(std::shared_ptr<Variable> variable, const SqpRange &range)
7 explicit RescaleAxeOperationPrivate(std::shared_ptr<Variable> variable, const SqpRange &range)
8 : m_Variable{variable}, m_Range{range}
8 : m_Variable{variable}, m_Range{range}
9 {
9 {
10 }
10 }
11
11
12 std::shared_ptr<Variable> m_Variable;
12 std::shared_ptr<Variable> m_Variable;
13 SqpRange m_Range;
13 SqpRange m_Range;
14 };
14 };
15
15
16 RescaleAxeOperation::RescaleAxeOperation(std::shared_ptr<Variable> variable, const SqpRange &range)
16 RescaleAxeOperation::RescaleAxeOperation(std::shared_ptr<Variable> variable, const SqpRange &range)
17 : impl{spimpl::make_unique_impl<RescaleAxeOperationPrivate>(variable, range)}
17 : impl{spimpl::make_unique_impl<RescaleAxeOperationPrivate>(variable, range)}
18 {
18 {
19 }
19 }
20
20
21 void RescaleAxeOperation::visitEnter(VisualizationWidget *widget)
21 void RescaleAxeOperation::visitEnter(VisualizationWidget *widget)
22 {
22 {
23 // VisualizationWidget is not intended to contain a variable
23 // VisualizationWidget is not intended to contain a variable
24 Q_UNUSED(widget)
24 Q_UNUSED(widget)
25 }
25 }
26
26
27 void RescaleAxeOperation::visitLeave(VisualizationWidget *widget)
27 void RescaleAxeOperation::visitLeave(VisualizationWidget *widget)
28 {
28 {
29 // VisualizationWidget is not intended to contain a variable
29 // VisualizationWidget is not intended to contain a variable
30 Q_UNUSED(widget)
30 Q_UNUSED(widget)
31 }
31 }
32
32
33 void RescaleAxeOperation::visitEnter(VisualizationTabWidget *tabWidget)
33 void RescaleAxeOperation::visitEnter(VisualizationTabWidget *tabWidget)
34 {
34 {
35 // VisualizationTabWidget is not intended to contain a variable
35 // VisualizationTabWidget is not intended to contain a variable
36 Q_UNUSED(tabWidget)
36 Q_UNUSED(tabWidget)
37 }
37 }
38
38
39 void RescaleAxeOperation::visitLeave(VisualizationTabWidget *tabWidget)
39 void RescaleAxeOperation::visitLeave(VisualizationTabWidget *tabWidget)
40 {
40 {
41 // VisualizationTabWidget is not intended to contain a variable
41 // VisualizationTabWidget is not intended to contain a variable
42 Q_UNUSED(tabWidget)
42 Q_UNUSED(tabWidget)
43 }
43 }
44
44
45 void RescaleAxeOperation::visitEnter(VisualizationZoneWidget *zoneWidget)
45 void RescaleAxeOperation::visitEnter(VisualizationZoneWidget *zoneWidget)
46 {
46 {
47 // VisualizationZoneWidget is not intended to contain a variable
47 // VisualizationZoneWidget is not intended to contain a variable
48 Q_UNUSED(zoneWidget)
48 Q_UNUSED(zoneWidget)
49 }
49 }
50
50
51 void RescaleAxeOperation::visitLeave(VisualizationZoneWidget *zoneWidget)
51 void RescaleAxeOperation::visitLeave(VisualizationZoneWidget *zoneWidget)
52 {
52 {
53 // VisualizationZoneWidget is not intended to contain a variable
53 // VisualizationZoneWidget is not intended to contain a variable
54 Q_UNUSED(zoneWidget)
54 Q_UNUSED(zoneWidget)
55 }
55 }
56
56
57 void RescaleAxeOperation::visit(VisualizationGraphWidget *graphWidget)
57 void RescaleAxeOperation::visit(VisualizationGraphWidget *graphWidget)
58 {
58 {
59 if (graphWidget) {
59 if (graphWidget) {
60 // If the widget contains the variable, rescale it
60 // If the widget contains the variable, rescale it
61 if (impl->m_Variable && graphWidget->contains(*impl->m_Variable)) {
61 if (impl->m_Variable && graphWidget->contains(*impl->m_Variable)) {
62 graphWidget->setRange(impl->m_Variable, impl->m_Range);
62 graphWidget->enableAcquisition(false);
63 graphWidget->setGraphRange(impl->m_Range);
64 graphWidget->enableAcquisition(true);
63 }
65 }
64 }
66 }
65 else {
67 else {
66 qCCritical(LOG_RescaleAxeOperation(),
68 qCCritical(LOG_RescaleAxeOperation(),
67 "Can't visit VisualizationGraphWidget : the widget is null");
69 "Can't visit VisualizationGraphWidget : the widget is null");
68 }
70 }
69 }
71 }
@@ -1,197 +1,196
1 #include "AmdaProvider.h"
1 #include "AmdaProvider.h"
2 #include "AmdaResultParser.h"
2 #include "AmdaResultParser.h"
3
3
4 #include "SqpApplication.h"
4 #include "SqpApplication.h"
5 #include <Data/DataSeries.h>
5 #include <Data/DataSeries.h>
6 #include <Data/IDataSeries.h>
6 #include <Data/IDataSeries.h>
7 #include <Data/ScalarSeries.h>
7 #include <Data/ScalarSeries.h>
8 #include <Time/TimeController.h>
8 #include <Time/TimeController.h>
9 #include <Variable/Variable.h>
9 #include <Variable/Variable.h>
10 #include <Variable/VariableController.h>
10 #include <Variable/VariableController.h>
11
11
12 #include <QObject>
12 #include <QObject>
13 #include <QtTest>
13 #include <QtTest>
14
14
15 #include <memory>
15 #include <memory>
16
16
17 // TEST with REF:
17 // TEST with REF:
18 // AmdaData-2012-01-01-12-00-00_2012-01-03-12-00-00
18 // AmdaData-2012-01-01-12-00-00_2012-01-03-12-00-00
19 // imf(0) - Type : Local Parameter @ CDPP/AMDA -
19 // imf(0) - Type : Local Parameter @ CDPP/AMDA -
20 // Name : bx_gse - Units : nT - Size : 1 -
20 // Name : bx_gse - Units : nT - Size : 1 -
21 // Frame : GSE - Mission : ACE -
21 // Frame : GSE - Mission : ACE -
22 // Instrument : MFI - Dataset : mfi_final-prelim
22 // Instrument : MFI - Dataset : mfi_final-prelim
23 // REFERENCE DOWNLOAD FILE =
23 // REFERENCE DOWNLOAD FILE =
24 // http://amda.irap.omp.eu/php/rest/getParameter.php?startTime=2012-01-01T12:00:00&stopTime=2012-01-03T12:00:00&parameterID=imf(0)&outputFormat=ASCII&timeFormat=ISO8601&gzip=0
24 // http://amda.irap.omp.eu/php/rest/getParameter.php?startTime=2012-01-01T12:00:00&stopTime=2012-01-03T12:00:00&parameterID=imf(0)&outputFormat=ASCII&timeFormat=ISO8601&gzip=0
25
25
26 namespace {
26 namespace {
27
27
28 /// Path for the tests
28 /// Path for the tests
29 const auto TESTS_RESOURCES_PATH
29 const auto TESTS_RESOURCES_PATH
30 = QFileInfo{QString{AMDA_TESTS_RESOURCES_DIR}, "TestAmdaAcquisition"}.absoluteFilePath();
30 = QFileInfo{QString{AMDA_TESTS_RESOURCES_DIR}, "TestAmdaAcquisition"}.absoluteFilePath();
31
31
32 const auto TESTS_AMDA_REF_FILE = QString{"AmdaData-2012-01-01-12-00-00_2012-01-03-12-00-00.txt"};
32 const auto TESTS_AMDA_REF_FILE = QString{"AmdaData-2012-01-01-12-00-00_2012-01-03-12-00-00.txt"};
33
33
34 template <typename T>
34 template <typename T>
35 bool compareDataSeries(std::shared_ptr<IDataSeries> candidate, SqpRange candidateCacheRange,
35 bool compareDataSeries(std::shared_ptr<IDataSeries> candidate, SqpRange candidateCacheRange,
36 std::shared_ptr<IDataSeries> reference)
36 std::shared_ptr<IDataSeries> reference)
37 {
37 {
38 auto compareLambda = [](const auto &it1, const auto &it2) {
38 auto compareLambda = [](const auto &it1, const auto &it2) {
39 return (it1.x() == it2.x()) && (it1.value() == it2.value());
39 return (it1.x() == it2.x()) && (it1.value() == it2.value());
40 };
40 };
41
41
42 auto candidateDS = std::dynamic_pointer_cast<T>(candidate);
42 auto candidateDS = std::dynamic_pointer_cast<T>(candidate);
43 auto referenceDS = std::dynamic_pointer_cast<T>(reference);
43 auto referenceDS = std::dynamic_pointer_cast<T>(reference);
44
44
45 if (candidateDS && referenceDS) {
45 if (candidateDS && referenceDS) {
46
46
47 auto itRefs
47 auto itRefs
48 = referenceDS->xAxisRange(candidateCacheRange.m_TStart, candidateCacheRange.m_TEnd);
48 = referenceDS->xAxisRange(candidateCacheRange.m_TStart, candidateCacheRange.m_TEnd);
49 qDebug() << " DISTANCE" << std::distance(candidateDS->cbegin(), candidateDS->cend())
49 qDebug() << " DISTANCE" << std::distance(candidateDS->cbegin(), candidateDS->cend())
50 << std::distance(itRefs.first, itRefs.second);
50 << std::distance(itRefs.first, itRefs.second);
51
51
52 // auto xcValue = candidateDS->valuesData()->data();
52 // auto xcValue = candidateDS->valuesData()->data();
53 // auto dist = std::distance(itRefs.first, itRefs.second);
53 // auto dist = std::distance(itRefs.first, itRefs.second);
54 // auto it = itRefs.first;
54 // auto it = itRefs.first;
55 // for (auto i = 0; i < dist - 1; ++i) {
55 // for (auto i = 0; i < dist - 1; ++i) {
56 // ++it;
56 // ++it;
57 // qInfo() << "END:" << it->value();
57 // qInfo() << "END:" << it->value();
58 // }
58 // }
59 // qDebug() << "END:" << it->value() << xcValue.last();
59 // qDebug() << "END:" << it->value() << xcValue.last();
60
60
61 return std::equal(candidateDS->cbegin(), candidateDS->cend(), itRefs.first, itRefs.second,
61 return std::equal(candidateDS->cbegin(), candidateDS->cend(), itRefs.first, itRefs.second,
62 compareLambda);
62 compareLambda);
63 }
63 }
64 else {
64 else {
65 return false;
65 return false;
66 }
66 }
67 }
67 }
68 }
68 }
69
69
70 class TestAmdaAcquisition : public QObject {
70 class TestAmdaAcquisition : public QObject {
71 Q_OBJECT
71 Q_OBJECT
72
72
73 private slots:
73 private slots:
74 void testAcquisition();
74 void testAcquisition();
75 };
75 };
76
76
77 void TestAmdaAcquisition::testAcquisition()
77 void TestAmdaAcquisition::testAcquisition()
78 {
78 {
79 /// @todo: update test to be compatible with AMDA v2
79 /// @todo: update test to be compatible with AMDA v2
80
80
81 // READ the ref file:
81 // READ the ref file:
82 auto filePath = QFileInfo{TESTS_RESOURCES_PATH, TESTS_AMDA_REF_FILE}.absoluteFilePath();
82 auto filePath = QFileInfo{TESTS_RESOURCES_PATH, TESTS_AMDA_REF_FILE}.absoluteFilePath();
83 auto results = AmdaResultParser::readTxt(filePath, AmdaResultParser::ValueType::SCALAR);
83 auto results = AmdaResultParser::readTxt(filePath, AmdaResultParser::ValueType::SCALAR);
84
84
85 auto provider = std::make_shared<AmdaProvider>();
85 auto provider = std::make_shared<AmdaProvider>();
86 auto timeController = std::make_unique<TimeController>();
86 auto timeController = std::make_unique<TimeController>();
87
87
88 auto varRS = QDateTime{QDate{2012, 01, 02}, QTime{2, 3, 0, 0}};
88 auto varRS = QDateTime{QDate{2012, 01, 02}, QTime{2, 3, 0, 0}};
89 auto varRE = QDateTime{QDate{2012, 01, 02}, QTime{2, 4, 0, 0}};
89 auto varRE = QDateTime{QDate{2012, 01, 02}, QTime{2, 4, 0, 0}};
90
90
91 auto sqpR = SqpRange{DateUtils::secondsSinceEpoch(varRS), DateUtils::secondsSinceEpoch(varRE)};
91 auto sqpR = SqpRange{DateUtils::secondsSinceEpoch(varRS), DateUtils::secondsSinceEpoch(varRE)};
92
92
93 timeController->onTimeToUpdate(sqpR);
93 timeController->onTimeToUpdate(sqpR);
94
94
95 QVariantHash metaData;
95 QVariantHash metaData;
96 metaData.insert("dataType", "scalar");
96 metaData.insert("dataType", "scalar");
97 metaData.insert("xml:id", "imf(0)");
97 metaData.insert("xml:id", "imf(0)");
98
98
99 VariableController vc;
99 VariableController vc;
100 vc.setTimeController(timeController.get());
100 vc.setTimeController(timeController.get());
101
101
102 auto var = vc.createVariable("bx_gse", metaData, provider);
102 auto var = vc.createVariable("bx_gse", metaData, provider);
103
103
104 // 1 : Variable creation
104 // 1 : Variable creation
105
105
106 qDebug() << " 1: TIMECONTROLLER" << timeController->dateTime();
106 qDebug() << " 1: TIMECONTROLLER" << timeController->dateTime();
107 qDebug() << " 1: RANGE " << var->range();
107 qDebug() << " 1: RANGE " << var->range();
108 qDebug() << " 1: CACHERANGE" << var->cacheRange();
108 qDebug() << " 1: CACHERANGE" << var->cacheRange();
109
109
110 // wait for 10 sec before asking next request toi permit asynchrone process to finish.
110 // wait for 10 sec before asking next request toi permit asynchrone process to finish.
111 auto timeToWaitMs = 10000;
111 auto timeToWaitMs = 10000;
112
112
113 QEventLoop loop;
113 QEventLoop loop;
114 QTimer::singleShot(timeToWaitMs, &loop, &QEventLoop::quit);
114 QTimer::singleShot(timeToWaitMs, &loop, &QEventLoop::quit);
115 loop.exec();
115 loop.exec();
116
116
117 // Tests on acquisition operation
117 // Tests on acquisition operation
118
118
119 int count = 1;
119 int count = 1;
120
120
121 auto requestDataLoading = [&vc, var, timeToWaitMs, results, &count](auto tStart, auto tEnd) {
121 auto requestDataLoading = [&vc, var, timeToWaitMs, results, &count](auto tStart, auto tEnd) {
122 ++count;
122 ++count;
123
123
124 auto nextSqpR
124 auto nextSqpR
125 = SqpRange{DateUtils::secondsSinceEpoch(tStart), DateUtils::secondsSinceEpoch(tEnd)};
125 = SqpRange{DateUtils::secondsSinceEpoch(tStart), DateUtils::secondsSinceEpoch(tEnd)};
126 vc.onRequestDataLoading(QVector<std::shared_ptr<Variable> >{} << var, nextSqpR,
126 vc.onRequestDataLoading(QVector<std::shared_ptr<Variable> >{} << var, nextSqpR, true);
127 var->range(), true);
128
127
129 QEventLoop loop;
128 QEventLoop loop;
130 QTimer::singleShot(timeToWaitMs, &loop, &QEventLoop::quit);
129 QTimer::singleShot(timeToWaitMs, &loop, &QEventLoop::quit);
131 loop.exec();
130 loop.exec();
132
131
133 qInfo() << count << "RANGE " << var->range();
132 qInfo() << count << "RANGE " << var->range();
134 qInfo() << count << "CACHERANGE" << var->cacheRange();
133 qInfo() << count << "CACHERANGE" << var->cacheRange();
135
134
136 QCOMPARE(var->range().m_TStart, nextSqpR.m_TStart);
135 QCOMPARE(var->range().m_TStart, nextSqpR.m_TStart);
137 QCOMPARE(var->range().m_TEnd, nextSqpR.m_TEnd);
136 QCOMPARE(var->range().m_TEnd, nextSqpR.m_TEnd);
138
137
139 // Verify dataserie
138 // Verify dataserie
140 QVERIFY(compareDataSeries<ScalarSeries>(var->dataSeries(), var->cacheRange(), results));
139 QVERIFY(compareDataSeries<ScalarSeries>(var->dataSeries(), var->cacheRange(), results));
141
140
142 };
141 };
143
142
144 // 2 : pan (jump) left for one hour
143 // 2 : pan (jump) left for one hour
145 auto nextVarRS = QDateTime{QDate{2012, 01, 02}, QTime{2, 1, 0, 0}};
144 auto nextVarRS = QDateTime{QDate{2012, 01, 02}, QTime{2, 1, 0, 0}};
146 auto nextVarRE = QDateTime{QDate{2012, 01, 02}, QTime{2, 2, 0, 0}};
145 auto nextVarRE = QDateTime{QDate{2012, 01, 02}, QTime{2, 2, 0, 0}};
147 // requestDataLoading(nextVarRS, nextVarRE);
146 // requestDataLoading(nextVarRS, nextVarRE);
148
147
149
148
150 // 3 : pan (jump) right for one hour
149 // 3 : pan (jump) right for one hour
151 nextVarRS = QDateTime{QDate{2012, 01, 02}, QTime{2, 5, 0, 0}};
150 nextVarRS = QDateTime{QDate{2012, 01, 02}, QTime{2, 5, 0, 0}};
152 nextVarRE = QDateTime{QDate{2012, 01, 02}, QTime{2, 6, 0, 0}};
151 nextVarRE = QDateTime{QDate{2012, 01, 02}, QTime{2, 6, 0, 0}};
153 // requestDataLoading(nextVarRS, nextVarRE);
152 // requestDataLoading(nextVarRS, nextVarRE);
154
153
155 // 4 : pan (overlay) right for 30 min
154 // 4 : pan (overlay) right for 30 min
156 nextVarRS = QDateTime{QDate{2012, 01, 02}, QTime{2, 5, 30, 0}};
155 nextVarRS = QDateTime{QDate{2012, 01, 02}, QTime{2, 5, 30, 0}};
157 nextVarRE = QDateTime{QDate{2012, 01, 02}, QTime{2, 6, 30, 0}};
156 nextVarRE = QDateTime{QDate{2012, 01, 02}, QTime{2, 6, 30, 0}};
158 // requestDataLoading(nextVarRS, nextVarRE);
157 // requestDataLoading(nextVarRS, nextVarRE);
159
158
160 // 5 : pan (overlay) left for 30 min
159 // 5 : pan (overlay) left for 30 min
161 nextVarRS = QDateTime{QDate{2012, 01, 02}, QTime{2, 5, 0, 0}};
160 nextVarRS = QDateTime{QDate{2012, 01, 02}, QTime{2, 5, 0, 0}};
162 nextVarRE = QDateTime{QDate{2012, 01, 02}, QTime{2, 6, 0, 0}};
161 nextVarRE = QDateTime{QDate{2012, 01, 02}, QTime{2, 6, 0, 0}};
163 // requestDataLoading(nextVarRS, nextVarRE);
162 // requestDataLoading(nextVarRS, nextVarRE);
164
163
165 // 6 : pan (overlay) left for 30 min - BIS
164 // 6 : pan (overlay) left for 30 min - BIS
166 nextVarRS = QDateTime{QDate{2012, 01, 02}, QTime{2, 4, 30, 0}};
165 nextVarRS = QDateTime{QDate{2012, 01, 02}, QTime{2, 4, 30, 0}};
167 nextVarRE = QDateTime{QDate{2012, 01, 02}, QTime{2, 5, 30, 0}};
166 nextVarRE = QDateTime{QDate{2012, 01, 02}, QTime{2, 5, 30, 0}};
168 // requestDataLoading(nextVarRS, nextVarRE);
167 // requestDataLoading(nextVarRS, nextVarRE);
169
168
170 // 7 : Zoom in Inside 20 min range
169 // 7 : Zoom in Inside 20 min range
171 nextVarRS = QDateTime{QDate{2012, 01, 02}, QTime{2, 4, 50, 0}};
170 nextVarRS = QDateTime{QDate{2012, 01, 02}, QTime{2, 4, 50, 0}};
172 nextVarRE = QDateTime{QDate{2012, 01, 02}, QTime{2, 5, 10, 0}};
171 nextVarRE = QDateTime{QDate{2012, 01, 02}, QTime{2, 5, 10, 0}};
173 // requestDataLoading(nextVarRS, nextVarRE);
172 // requestDataLoading(nextVarRS, nextVarRE);
174
173
175 // 8 : Zoom out Inside 2 hours range
174 // 8 : Zoom out Inside 2 hours range
176 nextVarRS = QDateTime{QDate{2012, 01, 02}, QTime{2, 4, 0, 0}};
175 nextVarRS = QDateTime{QDate{2012, 01, 02}, QTime{2, 4, 0, 0}};
177 nextVarRE = QDateTime{QDate{2012, 01, 02}, QTime{2, 6, 0, 0}};
176 nextVarRE = QDateTime{QDate{2012, 01, 02}, QTime{2, 6, 0, 0}};
178 // requestDataLoading(nextVarRS, nextVarRE);
177 // requestDataLoading(nextVarRS, nextVarRE);
179
178
180
179
181 // Close the app after 10 sec
180 // Close the app after 10 sec
182 QTimer::singleShot(timeToWaitMs, &loop, &QEventLoop::quit);
181 QTimer::singleShot(timeToWaitMs, &loop, &QEventLoop::quit);
183 loop.exec();
182 loop.exec();
184 }
183 }
185
184
186 int main(int argc, char *argv[])
185 int main(int argc, char *argv[])
187 {
186 {
188 SqpApplication app(argc, argv);
187 SqpApplication app(argc, argv);
189 app.setAttribute(Qt::AA_Use96Dpi, true);
188 app.setAttribute(Qt::AA_Use96Dpi, true);
190 TestAmdaAcquisition tc;
189 TestAmdaAcquisition tc;
191 QTEST_SET_MAIN_SOURCE_PATH
190 QTEST_SET_MAIN_SOURCE_PATH
192 return QTest::qExec(&tc, argc, argv);
191 return QTest::qExec(&tc, argc, argv);
193 }
192 }
194
193
195 // QTEST_MAIN(TestAmdaAcquisition)
194 // QTEST_MAIN(TestAmdaAcquisition)
196
195
197 #include "TestAmdaAcquisition.moc"
196 #include "TestAmdaAcquisition.moc"
@@ -1,36 +1,41
1 #ifndef SCIQLOP_COSINUSPROVIDER_H
1 #ifndef SCIQLOP_COSINUSPROVIDER_H
2 #define SCIQLOP_COSINUSPROVIDER_H
2 #define SCIQLOP_COSINUSPROVIDER_H
3
3
4 #include "MockPluginGlobal.h"
4 #include "MockPluginGlobal.h"
5
5
6 #include <Data/IDataProvider.h>
6 #include <Data/IDataProvider.h>
7
7
8 #include <QLoggingCategory>
8 #include <QLoggingCategory>
9 #include <QUuid>
9 #include <QUuid>
10
10
11 #include <QHash>
11 #include <QHash>
12 Q_DECLARE_LOGGING_CATEGORY(LOG_CosinusProvider)
12 Q_DECLARE_LOGGING_CATEGORY(LOG_CosinusProvider)
13
13
14 /**
14 /**
15 * @brief The CosinusProvider class is an example of how a data provider can generate data
15 * @brief The CosinusProvider class is an example of how a data provider can generate data
16 */
16 */
17 class SCIQLOP_MOCKPLUGIN_EXPORT CosinusProvider : public IDataProvider {
17 class SCIQLOP_MOCKPLUGIN_EXPORT CosinusProvider : public IDataProvider {
18 public:
18 public:
19 std::shared_ptr<IDataProvider> clone() const override;
19 std::shared_ptr<IDataProvider> clone() const override;
20
20
21 /// @sa IDataProvider::requestDataLoading(). The current impl isn't thread safe.
21 /// @sa IDataProvider::requestDataLoading(). The current impl isn't thread safe.
22 void requestDataLoading(QUuid acqIdentifier, const DataProviderParameters &parameters) override;
22 void requestDataLoading(QUuid acqIdentifier, const DataProviderParameters &parameters) override;
23
23
24
24
25 /// @sa IDataProvider::requestDataAborting(). The current impl isn't thread safe.
25 /// @sa IDataProvider::requestDataAborting(). The current impl isn't thread safe.
26 void requestDataAborting(QUuid acqIdentifier) override;
26 void requestDataAborting(QUuid acqIdentifier) override;
27
27
28
28
29 /// Provide data
30 std::shared_ptr<IDataSeries> provideDataSeries(const SqpRange &dataRangeRequested,
31 const QVariantHash &data);
32
33
29 private:
34 private:
30 std::shared_ptr<IDataSeries>
35 std::shared_ptr<IDataSeries>
31 retrieveData(QUuid acqIdentifier, const SqpRange &dataRangeRequested, const QVariantHash &data);
36 retrieveData(QUuid acqIdentifier, const SqpRange &dataRangeRequested, const QVariantHash &data);
32
37
33 QHash<QUuid, bool> m_VariableToEnableProvider;
38 QHash<QUuid, bool> m_VariableToEnableProvider;
34 };
39 };
35
40
36 #endif // SCIQLOP_COSINUSPROVIDER_H
41 #endif // SCIQLOP_COSINUSPROVIDER_H
@@ -1,201 +1,211
1 #include "CosinusProvider.h"
1 #include "CosinusProvider.h"
2 #include "MockDefs.h"
2 #include "MockDefs.h"
3
3
4 #include <Data/DataProviderParameters.h>
4 #include <Data/DataProviderParameters.h>
5 #include <Data/ScalarSeries.h>
5 #include <Data/ScalarSeries.h>
6 #include <Data/VectorSeries.h>
6 #include <Data/VectorSeries.h>
7
7
8 #include <cmath>
8 #include <cmath>
9
9
10 #include <QFuture>
10 #include <QFuture>
11 #include <QThread>
11 #include <QThread>
12 #include <QtConcurrent/QtConcurrent>
12 #include <QtConcurrent/QtConcurrent>
13
13
14 Q_LOGGING_CATEGORY(LOG_CosinusProvider, "CosinusProvider")
14 Q_LOGGING_CATEGORY(LOG_CosinusProvider, "CosinusProvider")
15
15
16 namespace {
16 namespace {
17
17
18 /// Abstract cosinus type
18 /// Abstract cosinus type
19 struct ICosinusType {
19 struct ICosinusType {
20 virtual ~ICosinusType() = default;
20 virtual ~ICosinusType() = default;
21 /// @return the number of components generated for the type
21 /// @return the number of components generated for the type
22 virtual int componentCount() const = 0;
22 virtual int componentCount() const = 0;
23 /// @return the data series created for the type
23 /// @return the data series created for the type
24 virtual std::shared_ptr<IDataSeries> createDataSeries(std::vector<double> xAxisData,
24 virtual std::shared_ptr<IDataSeries> createDataSeries(std::vector<double> xAxisData,
25 std::vector<double> valuesData,
25 std::vector<double> valuesData,
26 Unit xAxisUnit,
26 Unit xAxisUnit,
27 Unit valuesUnit) const = 0;
27 Unit valuesUnit) const = 0;
28 };
28 };
29
29
30 struct ScalarCosinus : public ICosinusType {
30 struct ScalarCosinus : public ICosinusType {
31 int componentCount() const override { return 1; }
31 int componentCount() const override { return 1; }
32
32
33 std::shared_ptr<IDataSeries> createDataSeries(std::vector<double> xAxisData,
33 std::shared_ptr<IDataSeries> createDataSeries(std::vector<double> xAxisData,
34 std::vector<double> valuesData, Unit xAxisUnit,
34 std::vector<double> valuesData, Unit xAxisUnit,
35 Unit valuesUnit) const override
35 Unit valuesUnit) const override
36 {
36 {
37 return std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData),
37 return std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData),
38 xAxisUnit, valuesUnit);
38 xAxisUnit, valuesUnit);
39 }
39 }
40 };
40 };
41 struct VectorCosinus : public ICosinusType {
41 struct VectorCosinus : public ICosinusType {
42 int componentCount() const override { return 3; }
42 int componentCount() const override { return 3; }
43
43
44 std::shared_ptr<IDataSeries> createDataSeries(std::vector<double> xAxisData,
44 std::shared_ptr<IDataSeries> createDataSeries(std::vector<double> xAxisData,
45 std::vector<double> valuesData, Unit xAxisUnit,
45 std::vector<double> valuesData, Unit xAxisUnit,
46 Unit valuesUnit) const override
46 Unit valuesUnit) const override
47 {
47 {
48 return std::make_shared<VectorSeries>(std::move(xAxisData), std::move(valuesData),
48 return std::make_shared<VectorSeries>(std::move(xAxisData), std::move(valuesData),
49 xAxisUnit, valuesUnit);
49 xAxisUnit, valuesUnit);
50 }
50 }
51 };
51 };
52
52
53 /// Converts string to cosinus type
53 /// Converts string to cosinus type
54 /// @return the cosinus type if the string could be converted, nullptr otherwise
54 /// @return the cosinus type if the string could be converted, nullptr otherwise
55 std::unique_ptr<ICosinusType> cosinusType(const QString &type) noexcept
55 std::unique_ptr<ICosinusType> cosinusType(const QString &type) noexcept
56 {
56 {
57 if (type.compare(QStringLiteral("scalar"), Qt::CaseInsensitive) == 0) {
57 if (type.compare(QStringLiteral("scalar"), Qt::CaseInsensitive) == 0) {
58 return std::make_unique<ScalarCosinus>();
58 return std::make_unique<ScalarCosinus>();
59 }
59 }
60 else if (type.compare(QStringLiteral("vector"), Qt::CaseInsensitive) == 0) {
60 else if (type.compare(QStringLiteral("vector"), Qt::CaseInsensitive) == 0) {
61 return std::make_unique<VectorCosinus>();
61 return std::make_unique<VectorCosinus>();
62 }
62 }
63 else {
63 else {
64 return nullptr;
64 return nullptr;
65 }
65 }
66 }
66 }
67
67
68 } // namespace
68 } // namespace
69
69
70 std::shared_ptr<IDataProvider> CosinusProvider::clone() const
70 std::shared_ptr<IDataProvider> CosinusProvider::clone() const
71 {
71 {
72 // No copy is made in clone
72 // No copy is made in clone
73 return std::make_shared<CosinusProvider>();
73 return std::make_shared<CosinusProvider>();
74 }
74 }
75
75
76 std::shared_ptr<IDataSeries> CosinusProvider::retrieveData(QUuid acqIdentifier,
76 std::shared_ptr<IDataSeries> CosinusProvider::retrieveData(QUuid acqIdentifier,
77 const SqpRange &dataRangeRequested,
77 const SqpRange &dataRangeRequested,
78 const QVariantHash &data)
78 const QVariantHash &data)
79 {
79 {
80 // TODO: Add Mutex
80 // TODO: Add Mutex
81 auto dataIndex = 0;
81 auto dataIndex = 0;
82
82
83 // Retrieves cosinus type
83 // Retrieves cosinus type
84 auto typeVariant = data.value(COSINUS_TYPE_KEY, COSINUS_TYPE_DEFAULT_VALUE);
84 auto typeVariant = data.value(COSINUS_TYPE_KEY, COSINUS_TYPE_DEFAULT_VALUE);
85 if (!typeVariant.canConvert<QString>()) {
85 if (!typeVariant.canConvert<QString>()) {
86 qCCritical(LOG_CosinusProvider()) << tr("Can't retrieve data: invalid type");
86 qCCritical(LOG_CosinusProvider()) << tr("Can't retrieve data: invalid type");
87 return nullptr;
87 return nullptr;
88 }
88 }
89
89
90 auto type = cosinusType(typeVariant.toString());
90 auto type = cosinusType(typeVariant.toString());
91 if (!type) {
91 if (!type) {
92 qCCritical(LOG_CosinusProvider()) << tr("Can't retrieve data: unknown type");
92 qCCritical(LOG_CosinusProvider()) << tr("Can't retrieve data: unknown type");
93 return nullptr;
93 return nullptr;
94 }
94 }
95
95
96 // Retrieves frequency
96 // Retrieves frequency
97 auto freqVariant = data.value(COSINUS_FREQUENCY_KEY, COSINUS_FREQUENCY_DEFAULT_VALUE);
97 auto freqVariant = data.value(COSINUS_FREQUENCY_KEY, COSINUS_FREQUENCY_DEFAULT_VALUE);
98 if (!freqVariant.canConvert<double>()) {
98 if (!freqVariant.canConvert<double>()) {
99 qCCritical(LOG_CosinusProvider()) << tr("Can't retrieve data: invalid frequency");
99 qCCritical(LOG_CosinusProvider()) << tr("Can't retrieve data: invalid frequency");
100 return nullptr;
100 return nullptr;
101 }
101 }
102
102
103 // Gets the timerange from the parameters
103 // Gets the timerange from the parameters
104 double freq = freqVariant.toDouble();
104 double freq = freqVariant.toDouble();
105 double start = std::ceil(dataRangeRequested.m_TStart * freq);
105 double start = std::ceil(dataRangeRequested.m_TStart * freq);
106 double end = std::floor(dataRangeRequested.m_TEnd * freq);
106 double end = std::floor(dataRangeRequested.m_TEnd * freq);
107
107
108 // We assure that timerange is valid
108 // We assure that timerange is valid
109 if (end < start) {
109 if (end < start) {
110 std::swap(start, end);
110 std::swap(start, end);
111 }
111 }
112
112
113 // Generates scalar series containing cosinus values (one value per second, end value is
113 // Generates scalar series containing cosinus values (one value per second, end value is
114 // included)
114 // included)
115 auto dataCount = end - start + 1;
115 auto dataCount = end - start + 1;
116
116
117 // Number of components (depending on the cosinus type)
117 // Number of components (depending on the cosinus type)
118 auto componentCount = type->componentCount();
118 auto componentCount = type->componentCount();
119
119
120 auto xAxisData = std::vector<double>{};
120 auto xAxisData = std::vector<double>{};
121 xAxisData.resize(dataCount);
121 xAxisData.resize(dataCount);
122
122
123 auto valuesData = std::vector<double>{};
123 auto valuesData = std::vector<double>{};
124 valuesData.resize(dataCount * componentCount);
124 valuesData.resize(dataCount * componentCount);
125
125
126 int progress = 0;
126 int progress = 0;
127 auto progressEnd = dataCount;
127 auto progressEnd = dataCount;
128 for (auto time = start; time <= end; ++time, ++dataIndex) {
128 for (auto time = start; time <= end; ++time, ++dataIndex) {
129 auto it = m_VariableToEnableProvider.find(acqIdentifier);
129 auto it = m_VariableToEnableProvider.find(acqIdentifier);
130 if (it != m_VariableToEnableProvider.end() && it.value()) {
130 if (it != m_VariableToEnableProvider.end() && it.value()) {
131 const auto timeOnFreq = time / freq;
131 const auto timeOnFreq = time / freq;
132
132
133 xAxisData[dataIndex] = timeOnFreq;
133 xAxisData[dataIndex] = timeOnFreq;
134
134
135 // Generates all components' values
135 // Generates all components' values
136 // Example: for a vector, values will be : cos(x), cos(x)/2, cos(x)/3
136 // Example: for a vector, values will be : cos(x), cos(x)/2, cos(x)/3
137 auto value = std::cos(timeOnFreq);
137 auto value = std::cos(timeOnFreq);
138 for (auto i = 0; i < componentCount; ++i) {
138 for (auto i = 0; i < componentCount; ++i) {
139 valuesData[componentCount * dataIndex + i] = value / (i + 1);
139 valuesData[componentCount * dataIndex + i] = value / (i + 1);
140 }
140 }
141
141
142 // progression
142 // progression
143 int currentProgress = (time - start) * 100.0 / progressEnd;
143 int currentProgress = (time - start) * 100.0 / progressEnd;
144 if (currentProgress != progress) {
144 if (currentProgress != progress) {
145 progress = currentProgress;
145 progress = currentProgress;
146
146
147 emit dataProvidedProgress(acqIdentifier, progress);
147 emit dataProvidedProgress(acqIdentifier, progress);
148 qCInfo(LOG_CosinusProvider()) << "TORM: CosinusProvider::retrieveData"
148 qCDebug(LOG_CosinusProvider()) << "TORM: CosinusProvider::retrieveData"
149 << QThread::currentThread()->objectName() << progress;
149 << QThread::currentThread()->objectName()
150 << progress;
150 // NOTE: Try to use multithread if possible
151 // NOTE: Try to use multithread if possible
151 }
152 }
152 }
153 }
153 else {
154 else {
154 if (!it.value()) {
155 if (!it.value()) {
155 qCDebug(LOG_CosinusProvider())
156 qCDebug(LOG_CosinusProvider())
156 << "CosinusProvider::retrieveData: ARRET De l'acquisition detectΓ©"
157 << "CosinusProvider::retrieveData: ARRET De l'acquisition detectΓ©"
157 << end - time;
158 << end - time;
158 }
159 }
159 }
160 }
160 }
161 }
161 if (progress != 100) {
162 if (progress != 100) {
162 // We can close progression beacause all data has been retrieved
163 // We can close progression beacause all data has been retrieved
163 emit dataProvidedProgress(acqIdentifier, 100);
164 emit dataProvidedProgress(acqIdentifier, 100);
164 }
165 }
165 return type->createDataSeries(std::move(xAxisData), std::move(valuesData),
166 return type->createDataSeries(std::move(xAxisData), std::move(valuesData),
166 Unit{QStringLiteral("t"), true}, Unit{});
167 Unit{QStringLiteral("t"), true}, Unit{});
167 }
168 }
168
169
169 void CosinusProvider::requestDataLoading(QUuid acqIdentifier,
170 void CosinusProvider::requestDataLoading(QUuid acqIdentifier,
170 const DataProviderParameters &parameters)
171 const DataProviderParameters &parameters)
171 {
172 {
172 // TODO: Add Mutex
173 // TODO: Add Mutex
173 m_VariableToEnableProvider[acqIdentifier] = true;
174 m_VariableToEnableProvider[acqIdentifier] = true;
174 qCDebug(LOG_CosinusProvider()) << "TORM: CosinusProvider::requestDataLoading"
175 qCDebug(LOG_CosinusProvider()) << "TORM: CosinusProvider::requestDataLoading"
175 << QThread::currentThread()->objectName();
176 << QThread::currentThread()->objectName();
176 // NOTE: Try to use multithread if possible
177 // NOTE: Try to use multithread if possible
177 const auto times = parameters.m_Times;
178 const auto times = parameters.m_Times;
178
179
179 for (const auto &dateTime : qAsConst(times)) {
180 for (const auto &dateTime : qAsConst(times)) {
180 if (m_VariableToEnableProvider[acqIdentifier]) {
181 if (m_VariableToEnableProvider[acqIdentifier]) {
181 auto scalarSeries = this->retrieveData(acqIdentifier, dateTime, parameters.m_Data);
182 auto scalarSeries = this->retrieveData(acqIdentifier, dateTime, parameters.m_Data);
182 qCDebug(LOG_CosinusProvider()) << "TORM: CosinusProvider::dataProvided";
183 emit dataProvided(acqIdentifier, scalarSeries, dateTime);
183 emit dataProvided(acqIdentifier, scalarSeries, dateTime);
184 }
184 }
185 }
185 }
186 }
186 }
187
187
188 void CosinusProvider::requestDataAborting(QUuid acqIdentifier)
188 void CosinusProvider::requestDataAborting(QUuid acqIdentifier)
189 {
189 {
190 // TODO: Add Mutex
191 qCDebug(LOG_CosinusProvider()) << "CosinusProvider::requestDataAborting" << acqIdentifier
190 qCDebug(LOG_CosinusProvider()) << "CosinusProvider::requestDataAborting" << acqIdentifier
192 << QThread::currentThread()->objectName();
191 << QThread::currentThread()->objectName();
193 auto it = m_VariableToEnableProvider.find(acqIdentifier);
192 auto it = m_VariableToEnableProvider.find(acqIdentifier);
194 if (it != m_VariableToEnableProvider.end()) {
193 if (it != m_VariableToEnableProvider.end()) {
195 it.value() = false;
194 it.value() = false;
196 }
195 }
197 else {
196 else {
198 qCWarning(LOG_CosinusProvider())
197 qCDebug(LOG_CosinusProvider())
199 << tr("Aborting progression of inexistant identifier detected !!!");
198 << tr("Aborting progression of inexistant identifier detected !!!");
200 }
199 }
201 }
200 }
201
202 std::shared_ptr<IDataSeries> CosinusProvider::provideDataSeries(const SqpRange &dataRangeRequested,
203 const QVariantHash &data)
204 {
205 auto uid = QUuid::createUuid();
206 m_VariableToEnableProvider[uid] = true;
207 auto dataSeries = this->retrieveData(uid, dataRangeRequested, data);
208
209 m_VariableToEnableProvider.remove(uid);
210 return dataSeries;
211 }
@@ -1,193 +1,192
1 #include "CosinusProvider.h"
1 #include "CosinusProvider.h"
2 #include "MockDefs.h"
2 #include "MockDefs.h"
3
3
4 #include <Data/DataProviderParameters.h>
4 #include <Data/DataProviderParameters.h>
5 #include <Data/ScalarSeries.h>
5 #include <Data/ScalarSeries.h>
6 #include <SqpApplication.h>
6 #include <SqpApplication.h>
7 #include <Time/TimeController.h>
7 #include <Time/TimeController.h>
8 #include <Variable/Variable.h>
8 #include <Variable/Variable.h>
9 #include <Variable/VariableController.h>
9 #include <Variable/VariableController.h>
10
10
11 #include <QObject>
11 #include <QObject>
12 #include <QtTest>
12 #include <QtTest>
13
13
14 #include <cmath>
14 #include <cmath>
15 #include <memory>
15 #include <memory>
16
16
17 namespace {
17 namespace {
18
18
19 /// Path for the tests
19 /// Path for the tests
20 const auto TESTS_RESOURCES_PATH = QFileInfo{
20 const auto TESTS_RESOURCES_PATH = QFileInfo{
21 QString{MOCKPLUGIN_TESTS_RESOURCES_DIR},
21 QString{MOCKPLUGIN_TESTS_RESOURCES_DIR},
22 "TestCosinusAcquisition"}.absoluteFilePath();
22 "TestCosinusAcquisition"}.absoluteFilePath();
23
23
24 /// Format of dates in data files
24 /// Format of dates in data files
25 const auto DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd hh:mm:ss:zzz");
25 const auto DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd hh:mm:ss:zzz");
26
26
27 /// Delay after each operation on the variable before validating it (in ms)
28 const auto OPERATION_DELAY = 250;
29
30 /**
27 /**
31 * Verifies that the data in the candidate series are identical to the data in the reference series
28 * Verifies that the data in the candidate series are identical to the data in the reference series
32 * in a specific range
29 * in a specific range
33 * @param candidate the candidate data series
30 * @param candidate the candidate data series
34 * @param range the range to check
31 * @param range the range to check
35 * @param reference the reference data series
32 * @param reference the reference data series
36 * @return true if the data of the candidate series and the reference series are identical in the
33 * @return true if the data of the candidate series and the reference series are identical in the
37 * range, false otherwise
34 * range, false otherwise
38 */
35 */
39 bool checkDataSeries(std::shared_ptr<IDataSeries> candidate, const SqpRange &range,
36 bool checkDataSeries(std::shared_ptr<IDataSeries> candidate, const SqpRange &range,
40 std::shared_ptr<IDataSeries> reference)
37 std::shared_ptr<IDataSeries> reference)
41 {
38 {
42 if (candidate == nullptr || reference == nullptr) {
39 if (candidate == nullptr || reference == nullptr) {
43 return candidate == reference;
40 return candidate == reference;
44 }
41 }
45
42
46 auto referenceIt = reference->xAxisRange(range.m_TStart, range.m_TEnd);
43 auto referenceIt = reference->xAxisRange(range.m_TStart, range.m_TEnd);
47
44
45 qInfo() << "candidateSize" << std::distance(candidate->cbegin(), candidate->cend());
46 qInfo() << "refSize" << std::distance(referenceIt.first, referenceIt.second);
47
48 return std::equal(candidate->cbegin(), candidate->cend(), referenceIt.first, referenceIt.second,
48 return std::equal(candidate->cbegin(), candidate->cend(), referenceIt.first, referenceIt.second,
49 [](const auto &it1, const auto &it2) {
49 [](const auto &it1, const auto &it2) {
50 // - milliseconds precision for time
50 // - milliseconds precision for time
51 // - 1e-6 precision for value
51 // - 1e-6 precision for value
52 return std::abs(it1.x() - it2.x()) < 1e-3
52 return std::abs(it1.x() - it2.x()) < 1e-3
53 && std::abs(it1.value() - it2.value()) < 1e-6;
53 && std::abs(it1.value() - it2.value()) < 1e-6;
54 });
54 });
55 }
55 }
56
56
57 /// Generates the data series from the reading of a data stream
58 std::shared_ptr<IDataSeries> readDataStream(QTextStream &stream)
59 {
60 std::vector<double> xAxisData, valuesData;
61
62 QString line{};
63 while (stream.readLineInto(&line)) {
64 // Separates date (x-axis data) to value data
65 auto splitLine = line.split('\t');
66 if (splitLine.size() == 2) {
67 // Converts datetime to double
68 auto dateTime = QDateTime::fromString(splitLine[0], DATETIME_FORMAT);
69 dateTime.setTimeSpec(Qt::UTC);
70 xAxisData.push_back(DateUtils::secondsSinceEpoch(dateTime));
71
72 valuesData.push_back(splitLine[1].toDouble());
73 }
74 }
75
76 return std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData),
77 Unit{{}, true}, Unit{});
78 }
79
80 } // namespace
57 } // namespace
81
58
82 /**
59 /**
83 * @brief The TestCosinusAcquisition class tests acquisition in SciQlop (operations like zooms in,
60 * @brief The TestCosinusAcquisition class tests acquisition in SciQlop (operations like zooms in,
84 * zooms out, pans) of data from CosinusProvider
61 * zooms out, pans) of data from CosinusProvider
85 * @sa CosinusProvider
62 * @sa CosinusProvider
86 */
63 */
87 class TestCosinusAcquisition : public QObject {
64 class TestCosinusAcquisition : public QObject {
88 Q_OBJECT
65 Q_OBJECT
89
66
90 private slots:
67 private slots:
91 /// Input data for @sa testAcquisition()
68 /// Input data for @sa testAcquisition()
92 void testAcquisition_data();
69 void testAcquisition_data();
93 void testAcquisition();
70 void testAcquisition();
94 };
71 };
95
72
96 void TestCosinusAcquisition::testAcquisition_data()
73 void TestCosinusAcquisition::testAcquisition_data()
97 {
74 {
98 // ////////////// //
75 // ////////////// //
99 // Test structure //
76 // Test structure //
100 // ////////////// //
77 // ////////////// //
101
78
102 QTest::addColumn<QString>("dataFilename"); // File containing expected data of acquisitions
79 QTest::addColumn<SqpRange>("referenceRange"); // Range for generating reference series
103 QTest::addColumn<SqpRange>("initialRange"); // First acquisition
80 QTest::addColumn<SqpRange>("initialRange"); // First acquisition
81 QTest::addColumn<int>("operationDelay"); // Acquisitions to make
104 QTest::addColumn<std::vector<SqpRange> >("operations"); // Acquisitions to make
82 QTest::addColumn<std::vector<SqpRange> >("operations"); // Acquisitions to make
105
83
106 // ////////// //
84 // ////////// //
107 // Test cases //
85 // Test cases //
108 // ////////// //
86 // ////////// //
109
87
110 auto dateTime = [](int year, int month, int day, int hours, int minutes, int seconds) {
88 auto dateTime = [](int year, int month, int day, int hours, int minutes, int seconds) {
111 return DateUtils::secondsSinceEpoch(
89 return DateUtils::secondsSinceEpoch(
112 QDateTime{{year, month, day}, {hours, minutes, seconds}, Qt::UTC});
90 QDateTime{{year, month, day}, {hours, minutes, seconds}, Qt::UTC});
113 };
91 };
114
92
115 QTest::newRow("cosinus")
93 QTest::newRow("cosinus")
116 << "Cosinus_100Hz_20170101_1200_20170101_1300.txt"
94 << SqpRange{dateTime(2017, 1, 1, 12, 0, 0), dateTime(2017, 1, 1, 13, 0, 0)}
117 << SqpRange{dateTime(2017, 1, 1, 12, 30, 0), dateTime(2017, 1, 1, 12, 35, 1)}
95 << SqpRange{dateTime(2017, 1, 1, 12, 30, 0), dateTime(2017, 1, 1, 12, 35, 1)} << 250
118 << std::vector<SqpRange>{
96 << std::vector<SqpRange>{
119 // Pan (jump) left
97 // Pan (jump) left
120 SqpRange{dateTime(2017, 1, 1, 12, 45, 0), dateTime(2017, 1, 1, 12, 50, 0)},
98 SqpRange{dateTime(2017, 1, 1, 12, 45, 0), dateTime(2017, 1, 1, 12, 50, 0)},
121 // Pan (jump) right
99 // Pan (jump) right
122 SqpRange{dateTime(2017, 1, 1, 12, 15, 0), dateTime(2017, 1, 1, 12, 20, 0)},
100 SqpRange{dateTime(2017, 1, 1, 12, 15, 0), dateTime(2017, 1, 1, 12, 20, 0)},
123 // Pan (overlay) right
101 // Pan (overlay) right
124 SqpRange{dateTime(2017, 1, 1, 12, 14, 0), dateTime(2017, 1, 1, 12, 19, 0)},
102 SqpRange{dateTime(2017, 1, 1, 12, 14, 0), dateTime(2017, 1, 1, 12, 19, 0)},
125 // Pan (overlay) left
103 // Pan (overlay) left
126 SqpRange{dateTime(2017, 1, 1, 12, 15, 0), dateTime(2017, 1, 1, 12, 20, 0)},
104 SqpRange{dateTime(2017, 1, 1, 12, 15, 0), dateTime(2017, 1, 1, 12, 20, 0)},
127 // Pan (overlay) left
105 // Pan (overlay) left
128 SqpRange{dateTime(2017, 1, 1, 12, 16, 0), dateTime(2017, 1, 1, 12, 21, 0)},
106 SqpRange{dateTime(2017, 1, 1, 12, 16, 0), dateTime(2017, 1, 1, 12, 21, 0)},
129 // Zoom in
107 // Zoom in
130 SqpRange{dateTime(2017, 1, 1, 12, 17, 30), dateTime(2017, 1, 1, 12, 19, 30)},
108 SqpRange{dateTime(2017, 1, 1, 12, 17, 30), dateTime(2017, 1, 1, 12, 19, 30)},
131 // Zoom out
109 // Zoom out
132 SqpRange{dateTime(2017, 1, 1, 12, 12, 30), dateTime(2017, 1, 1, 12, 24, 30)}};
110 SqpRange{dateTime(2017, 1, 1, 12, 12, 30), dateTime(2017, 1, 1, 12, 24, 30)}};
111
112 QTest::newRow("cosinus_big")
113 << SqpRange{dateTime(2017, 1, 1, 1, 0, 0), dateTime(2017, 1, 5, 13, 0, 0)}
114 << SqpRange{dateTime(2017, 1, 2, 6, 30, 0), dateTime(2017, 1, 2, 18, 30, 0)} << 5000
115 << std::vector<SqpRange>{
116 // Pan (jump) left
117 SqpRange{dateTime(2017, 1, 1, 13, 30, 0), dateTime(2017, 1, 1, 18, 30, 0)},
118 // Pan (jump) right
119 SqpRange{dateTime(2017, 1, 3, 4, 30, 0), dateTime(2017, 1, 3, 10, 30, 0)},
120 // Pan (overlay) right
121 SqpRange{dateTime(2017, 1, 3, 8, 30, 0), dateTime(2017, 1, 3, 12, 30, 0)},
122 // Pan (overlay) left
123 SqpRange{dateTime(2017, 1, 2, 8, 30, 0), dateTime(2017, 1, 3, 10, 30, 0)},
124 // Pan (overlay) left
125 SqpRange{dateTime(2017, 1, 1, 12, 30, 0), dateTime(2017, 1, 3, 5, 30, 0)},
126 // Zoom in
127 SqpRange{dateTime(2017, 1, 2, 2, 30, 0), dateTime(2017, 1, 2, 8, 30, 0)},
128 // Zoom out
129 SqpRange{dateTime(2017, 1, 1, 14, 30, 0), dateTime(2017, 1, 3, 12, 30, 0)}};
133 }
130 }
134
131
135 void TestCosinusAcquisition::testAcquisition()
132 void TestCosinusAcquisition::testAcquisition()
136 {
133 {
137 // Retrieves data file
134 // Retrieves reference range
138 QFETCH(QString, dataFilename);
135 QFETCH(SqpRange, referenceRange);
139
136 CosinusProvider referenceProvider{};
140 auto dataFilePath = QFileInfo{TESTS_RESOURCES_PATH, dataFilename}.absoluteFilePath();
137 auto dataSeries = referenceProvider.provideDataSeries(
141 QFile dataFile{dataFilePath};
138 referenceRange, {{COSINUS_TYPE_KEY, "scalar"}, {COSINUS_FREQUENCY_KEY, 100.}});
142
139
143 if (dataFile.open(QFile::ReadOnly)) {
140 auto end = dataSeries->cend() - 1;
144 // Generates data series to compare with
141 qInfo() << dataSeries->nbPoints() << dataSeries->cbegin()->x() << end->x();
145 QTextStream dataStream{&dataFile};
142
146 auto dataSeries = readDataStream(dataStream);
143 /// Lambda used to validate a variable at each step
147
144 auto validateVariable
148 /// Lambda used to validate a variable at each step
145 = [dataSeries](std::shared_ptr<Variable> variable, const SqpRange &range) {
149 auto validateVariable = [dataSeries](std::shared_ptr<Variable> variable,
146 // Checks that the variable's range has changed
150 const SqpRange &range) {
147 QCOMPARE(variable->range(), range);
151 // Checks that the variable's range has changed
148
152 QCOMPARE(variable->range(), range);
149 // Checks the variable's data series
153
150 QVERIFY(checkDataSeries(variable->dataSeries(), variable->cacheRange(), dataSeries));
154 // Checks the variable's data series
151 };
155 QVERIFY(checkDataSeries(variable->dataSeries(), variable->cacheRange(), dataSeries));
152
156 };
153 // Creates variable
157
154 QFETCH(SqpRange, initialRange);
158 // Creates variable
155 sqpApp->timeController().onTimeToUpdate(initialRange);
159 QFETCH(SqpRange, initialRange);
156 auto provider = std::make_shared<CosinusProvider>();
160 sqpApp->timeController().onTimeToUpdate(initialRange);
157 auto variable = sqpApp->variableController().createVariable(
161 auto provider = std::make_shared<CosinusProvider>();
158 "MMS", {{COSINUS_TYPE_KEY, "scalar"}, {COSINUS_FREQUENCY_KEY, 100.}}, provider);
162 auto variable = sqpApp->variableController().createVariable(
159
163 "MMS", {{COSINUS_TYPE_KEY, "scalar"}, {COSINUS_FREQUENCY_KEY, 100.}}, provider);
160 QFETCH(int, operationDelay);
164
161 QTest::qWait(operationDelay);
165 QTest::qWait(OPERATION_DELAY);
162 validateVariable(variable, initialRange);
166 validateVariable(variable, initialRange);
163
167
164 // Makes operations on the variable
168 // Makes operations on the variable
165 QFETCH(std::vector<SqpRange>, operations);
169 QFETCH(std::vector<SqpRange>, operations);
166 for (const auto &operation : operations) {
170 for (const auto &operation : operations) {
167 // Asks request on the variable and waits during its execution
171 // Asks request on the variable and waits during its execution
168 sqpApp->variableController().onRequestDataLoading({variable}, operation, true);
172 sqpApp->variableController().onRequestDataLoading({variable}, operation,
169
173 variable->range(), true);
170 QTest::qWait(operationDelay);
174
171 validateVariable(variable, operation);
175 QTest::qWait(OPERATION_DELAY);
176 validateVariable(variable, operation);
177 }
178 }
172 }
179 else {
173
180 QFAIL("Can't read input data file");
174
175 for (const auto &operation : operations) {
176 // Asks request on the variable and waits during its execution
177 sqpApp->variableController().onRequestDataLoading({variable}, operation, true);
181 }
178 }
179 QTest::qWait(operationDelay);
180 validateVariable(variable, operations.back());
182 }
181 }
183
182
184 int main(int argc, char *argv[])
183 int main(int argc, char *argv[])
185 {
184 {
186 SqpApplication app{argc, argv};
185 SqpApplication app{argc, argv};
187 app.setAttribute(Qt::AA_Use96Dpi, true);
186 app.setAttribute(Qt::AA_Use96Dpi, true);
188 TestCosinusAcquisition testObject{};
187 TestCosinusAcquisition testObject{};
189 QTEST_SET_MAIN_SOURCE_PATH
188 QTEST_SET_MAIN_SOURCE_PATH
190 return QTest::qExec(&testObject, argc, argv);
189 return QTest::qExec(&testObject, argc, argv);
191 }
190 }
192
191
193 #include "TestCosinusAcquisition.moc"
192 #include "TestCosinusAcquisition.moc"
General Comments 0
You need to be logged in to leave comments. Login now