##// END OF EJS Templates
Merge branch 'feature/AcquisitionTest' into develop
perrinel -
r1400:a4f96b874829 merge
parent child
Show More
@@ -1,40 +1,38
1 #ifndef SCIQLOP_ACQUISITIONREQUEST_H
1 #ifndef SCIQLOP_ACQUISITIONREQUEST_H
2 #define SCIQLOP_ACQUISITIONREQUEST_H
2 #define SCIQLOP_ACQUISITIONREQUEST_H
3
3
4 #include <QObject>
4 #include <QObject>
5
5
6 #include <QUuid>
6 #include <QUuid>
7
7
8 #include <Common/DateUtils.h>
8 #include <Common/DateUtils.h>
9 #include <Common/MetaTypes.h>
9 #include <Common/MetaTypes.h>
10 #include <Data/DataProviderParameters.h>
10 #include <Data/DataProviderParameters.h>
11 #include <Data/IDataProvider.h>
11 #include <Data/IDataProvider.h>
12 #include <Data/SqpRange.h>
12 #include <Data/SqpRange.h>
13
13
14 #include <memory>
14 #include <memory>
15
15
16 /**
16 /**
17 * @brief The AcquisitionRequest struct holds the information of an variable request
17 * @brief The AcquisitionRequest struct holds the information of an variable request
18 */
18 */
19 struct AcquisitionRequest {
19 struct AcquisitionRequest {
20 AcquisitionRequest()
20 AcquisitionRequest()
21 {
21 {
22 m_AcqIdentifier = QUuid::createUuid();
22 m_AcqIdentifier = QUuid::createUuid();
23 m_Size = 0;
23 m_Size = 0;
24 m_Progression = 0;
24 m_Progression = 0;
25 }
25 }
26
26
27 QUuid m_VarRequestId;
27 QUuid m_VarRequestId;
28 QUuid m_AcqIdentifier;
28 QUuid m_AcqIdentifier;
29 QUuid m_vIdentifier;
29 QUuid m_vIdentifier;
30 DataProviderParameters m_DataProviderParameters;
30 DataProviderParameters m_DataProviderParameters;
31 SqpRange m_RangeRequested;
32 SqpRange m_CacheRangeRequested;
33 int m_Size;
31 int m_Size;
34 int m_Progression;
32 int m_Progression;
35 std::shared_ptr<IDataProvider> m_Provider;
33 std::shared_ptr<IDataProvider> m_Provider;
36 };
34 };
37
35
38 SCIQLOP_REGISTER_META_TYPE(ACQUISITIONREQUEST_REGISTRY, AcquisitionRequest)
36 SCIQLOP_REGISTER_META_TYPE(ACQUISITIONREQUEST_REGISTRY, AcquisitionRequest)
39
37
40 #endif // SCIQLOP_ACQUISITIONREQUEST_H
38 #endif // SCIQLOP_ACQUISITIONREQUEST_H
@@ -1,66 +1,64
1 #ifndef SCIQLOP_VARIABLEACQUISITIONWORKER_H
1 #ifndef SCIQLOP_VARIABLEACQUISITIONWORKER_H
2 #define SCIQLOP_VARIABLEACQUISITIONWORKER_H
2 #define SCIQLOP_VARIABLEACQUISITIONWORKER_H
3
3
4 #include "CoreGlobal.h"
4 #include "CoreGlobal.h"
5
5
6 #include <Data/DataProviderParameters.h>
6 #include <Data/DataProviderParameters.h>
7 #include <QLoggingCategory>
7 #include <QLoggingCategory>
8 #include <QObject>
8 #include <QObject>
9 #include <QUuid>
9 #include <QUuid>
10
10
11 #include <Data/AcquisitionDataPacket.h>
11 #include <Data/AcquisitionDataPacket.h>
12 #include <Data/IDataSeries.h>
12 #include <Data/IDataSeries.h>
13 #include <Data/SqpRange.h>
13 #include <Data/SqpRange.h>
14
14
15 #include <QLoggingCategory>
15 #include <QLoggingCategory>
16
16
17 #include <Common/spimpl.h>
17 #include <Common/spimpl.h>
18
18
19 Q_DECLARE_LOGGING_CATEGORY(LOG_VariableAcquisitionWorker)
19 Q_DECLARE_LOGGING_CATEGORY(LOG_VariableAcquisitionWorker)
20
20
21 class Variable;
21 class Variable;
22 class IDataProvider;
22 class IDataProvider;
23
23
24 /// This class aims to handle all acquisition request
24 /// This class aims to handle all acquisition request
25 class SCIQLOP_CORE_EXPORT VariableAcquisitionWorker : public QObject {
25 class SCIQLOP_CORE_EXPORT VariableAcquisitionWorker : public QObject {
26 Q_OBJECT
26 Q_OBJECT
27 public:
27 public:
28 explicit VariableAcquisitionWorker(QObject *parent = 0);
28 explicit VariableAcquisitionWorker(QObject *parent = 0);
29 virtual ~VariableAcquisitionWorker();
29 virtual ~VariableAcquisitionWorker();
30
30
31 QUuid pushVariableRequest(QUuid varRequestId, QUuid vIdentifier, SqpRange rangeRequested,
31 QUuid pushVariableRequest(QUuid varRequestId, QUuid vIdentifier,
32 SqpRange cacheRangeRequested, DataProviderParameters parameters,
32 DataProviderParameters parameters,
33 std::shared_ptr<IDataProvider> provider);
33 std::shared_ptr<IDataProvider> provider);
34
34
35 void abortProgressRequested(QUuid vIdentifier);
35 void abortProgressRequested(QUuid vIdentifier);
36
36
37 void initialize();
37 void initialize();
38 void finalize();
38 void finalize();
39 signals:
39 signals:
40 void dataProvided(QUuid vIdentifier, const SqpRange &rangeRequested,
40 void dataProvided(QUuid vIdentifier, QVector<AcquisitionDataPacket> dataAcquired);
41 const SqpRange &cacheRangeRequested,
42 QVector<AcquisitionDataPacket> dataAcquired);
43
41
44 void variableRequestInProgress(QUuid vIdentifier, double progress);
42 void variableRequestInProgress(QUuid vIdentifier, double progress);
45
43
46
44
47 void variableCanceledRequested(QUuid vIdentifier);
45 void variableCanceledRequested(QUuid vIdentifier);
48
46
49
47
50 public slots:
48 public slots:
51 void onVariableDataAcquired(QUuid acqIdentifier, std::shared_ptr<IDataSeries> dataSeries,
49 void onVariableDataAcquired(QUuid acqIdentifier, std::shared_ptr<IDataSeries> dataSeries,
52 SqpRange dataRangeAcquired);
50 SqpRange dataRangeAcquired);
53 void onVariableRetrieveDataInProgress(QUuid acqIdentifier, double progress);
51 void onVariableRetrieveDataInProgress(QUuid acqIdentifier, double progress);
54 void onVariableAcquisitionFailed(QUuid acqIdentifier);
52 void onVariableAcquisitionFailed(QUuid acqIdentifier);
55
53
56 private:
54 private:
57 void waitForFinish();
55 void waitForFinish();
58
56
59 class VariableAcquisitionWorkerPrivate;
57 class VariableAcquisitionWorkerPrivate;
60 spimpl::unique_impl_ptr<VariableAcquisitionWorkerPrivate> impl;
58 spimpl::unique_impl_ptr<VariableAcquisitionWorkerPrivate> impl;
61
59
62 private slots:
60 private slots:
63 void onExecuteRequest(QUuid acqIdentifier);
61 void onExecuteRequest(QUuid acqIdentifier);
64 };
62 };
65
63
66 #endif // SCIQLOP_VARIABLEACQUISITIONWORKER_H
64 #endif // SCIQLOP_VARIABLEACQUISITIONWORKER_H
@@ -1,144 +1,142
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 /// Returns the MIME data associated to a list of variables
51 /// Returns the MIME data associated to a list of variables
52 QByteArray mimeDataForVariables(const QList<std::shared_ptr<Variable> > &variables) const;
52 QByteArray mimeDataForVariables(const QList<std::shared_ptr<Variable> > &variables) const;
53
53
54 /// Returns the list of variables contained in a MIME data
54 /// Returns the list of variables contained in a MIME data
55 QList<std::shared_ptr<Variable> > variablesForMimeData(const QByteArray &mimeData) const;
55 QList<std::shared_ptr<Variable> > variablesForMimeData(const QByteArray &mimeData) const;
56
56
57 static AcquisitionZoomType getZoomType(const SqpRange &range, const SqpRange &oldRange);
57 static AcquisitionZoomType getZoomType(const SqpRange &range, const SqpRange &oldRange);
58 signals:
58 signals:
59 /// Signal emitted when a variable is about to be deleted from the controller
59 /// Signal emitted when a variable is about to be deleted from the controller
60 void variableAboutToBeDeleted(std::shared_ptr<Variable> variable);
60 void variableAboutToBeDeleted(std::shared_ptr<Variable> variable);
61
61
62 /// Signal emitted when a data acquisition is requested on a range for a variable
62 /// Signal emitted when a data acquisition is requested on a range for a variable
63 void rangeChanged(std::shared_ptr<Variable> variable, const SqpRange &range);
63 void rangeChanged(std::shared_ptr<Variable> variable, const SqpRange &range);
64
64
65 /// Signal emitted when a sub range of the cacheRange of the variable can be displayed
65 /// Signal emitted when a sub range of the cacheRange of the variable can be displayed
66 void updateVarDisplaying(std::shared_ptr<Variable> variable, const SqpRange &range);
66 void updateVarDisplaying(std::shared_ptr<Variable> variable, const SqpRange &range);
67
67
68 /// Signal emitted when all acquisitions related to the variables have been completed (whether
68 /// Signal emitted when all acquisitions related to the variables have been completed (whether
69 /// validated, canceled, or failed)
69 /// validated, canceled, or failed)
70 void acquisitionFinished();
70 void acquisitionFinished();
71
71
72 void variableAdded(const std::shared_ptr<Variable> &variable);
72 void variableAdded(const std::shared_ptr<Variable> &variable);
73
73
74 public slots:
74 public slots:
75 /**
75 /**
76 * Deletes from the controller the variable passed in parameter.
76 * Deletes from the controller the variable passed in parameter.
77 *
77 *
78 * Delete a variable includes:
78 * Delete a variable includes:
79 * - the deletion of the various references to the variable in SciQlop
79 * - the deletion of the various references to the variable in SciQlop
80 * - the deletion of the model variable
80 * - the deletion of the model variable
81 * - the deletion of the provider associated with the variable
81 * - the deletion of the provider associated with the variable
82 * - removing the cache associated with the variable
82 * - removing the cache associated with the variable
83 *
83 *
84 * @param variable the variable to delete from the controller.
84 * @param variable the variable to delete from the controller.
85 */
85 */
86 void deleteVariable(std::shared_ptr<Variable> variable) noexcept;
86 void deleteVariable(std::shared_ptr<Variable> variable) noexcept;
87
87
88 /**
88 /**
89 * Deletes from the controller the variables passed in parameter.
89 * Deletes from the controller the variables passed in parameter.
90 * @param variables the variables to delete from the controller.
90 * @param variables the variables to delete from the controller.
91 * @sa deleteVariable()
91 * @sa deleteVariable()
92 */
92 */
93 void deleteVariables(const QVector<std::shared_ptr<Variable> > &variables) noexcept;
93 void deleteVariables(const QVector<std::shared_ptr<Variable> > &variables) noexcept;
94
94
95 /// Request the data loading of the variable whithin range
95 /// Request the data loading of the variable whithin range
96 void onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables, const SqpRange &range,
96 void onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables, const SqpRange &range,
97 bool synchronise);
97 bool synchronise);
98 /**
98 /**
99 * Creates a new variable and adds it to the model
99 * Creates a new variable and adds it to the model
100 * @param name the name of the new variable
100 * @param name the name of the new variable
101 * @param metadata the metadata of the new variable
101 * @param metadata the metadata of the new variable
102 * @param provider the data provider for the new variable
102 * @param provider the data provider for the new variable
103 * @return the pointer to the new variable or nullptr if the creation failed
103 * @return the pointer to the new variable or nullptr if the creation failed
104 */
104 */
105 std::shared_ptr<Variable> createVariable(const QString &name, const QVariantHash &metadata,
105 std::shared_ptr<Variable> createVariable(const QString &name, const QVariantHash &metadata,
106 std::shared_ptr<IDataProvider> provider) noexcept;
106 std::shared_ptr<IDataProvider> provider) noexcept;
107
107
108 /// Update the temporal parameters of every selected variable to dateTime
108 /// Update the temporal parameters of every selected variable to dateTime
109 void onDateTimeOnSelection(const SqpRange &dateTime);
109 void onDateTimeOnSelection(const SqpRange &dateTime);
110
110
111 /// Update the temporal parameters of the specified variable
111 /// Update the temporal parameters of the specified variable
112 void onUpdateDateTime(std::shared_ptr<Variable> variable, const SqpRange &dateTime);
112 void onUpdateDateTime(std::shared_ptr<Variable> variable, const SqpRange &dateTime);
113
113
114
114
115 void onDataProvided(QUuid vIdentifier, const SqpRange &rangeRequested,
115 void onDataProvided(QUuid vIdentifier, QVector<AcquisitionDataPacket> dataAcquired);
116 const SqpRange &cacheRangeRequested,
117 QVector<AcquisitionDataPacket> dataAcquired);
118
116
119 void onVariableRetrieveDataInProgress(QUuid identifier, double progress);
117 void onVariableRetrieveDataInProgress(QUuid identifier, double progress);
120
118
121 /// Cancel the current request for the variable
119 /// Cancel the current request for the variable
122 void onAbortProgressRequested(std::shared_ptr<Variable> variable);
120 void onAbortProgressRequested(std::shared_ptr<Variable> variable);
123 void onAbortAcquisitionRequested(QUuid vIdentifier);
121 void onAbortAcquisitionRequested(QUuid vIdentifier);
124
122
125 // synchronization group methods
123 // synchronization group methods
126 void onAddSynchronizationGroupId(QUuid synchronizationGroupId);
124 void onAddSynchronizationGroupId(QUuid synchronizationGroupId);
127 void onRemoveSynchronizationGroupId(QUuid synchronizationGroupId);
125 void onRemoveSynchronizationGroupId(QUuid synchronizationGroupId);
128 void onAddSynchronized(std::shared_ptr<Variable> variable, QUuid synchronizationGroupId);
126 void onAddSynchronized(std::shared_ptr<Variable> variable, QUuid synchronizationGroupId);
129
127
130 /// Desynchronizes the variable of the group whose identifier is passed in parameter
128 /// Desynchronizes the variable of the group whose identifier is passed in parameter
131 /// @remarks the method does nothing if the variable is not part of the group
129 /// @remarks the method does nothing if the variable is not part of the group
132 void desynchronize(std::shared_ptr<Variable> variable, QUuid synchronizationGroupId);
130 void desynchronize(std::shared_ptr<Variable> variable, QUuid synchronizationGroupId);
133
131
134 void initialize();
132 void initialize();
135 void finalize();
133 void finalize();
136
134
137 private:
135 private:
138 void waitForFinish();
136 void waitForFinish();
139
137
140 class VariableControllerPrivate;
138 class VariableControllerPrivate;
141 spimpl::unique_impl_ptr<VariableControllerPrivate> impl;
139 spimpl::unique_impl_ptr<VariableControllerPrivate> impl;
142 };
140 };
143
141
144 #endif // SCIQLOP_VARIABLECONTROLLER_H
142 #endif // SCIQLOP_VARIABLECONTROLLER_H
@@ -1,416 +1,369
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
33 void updateToNextRequest(QUuid vIdentifier);
34
35 /// Remove and/or abort all AcqRequest in link with varRequestId
32 /// Remove and/or abort all AcqRequest in link with varRequestId
36 void cancelVarRequest(QUuid varRequestId);
33 void cancelVarRequest(QUuid varRequestId);
37 void removeAcqRequest(QUuid acqRequestId);
34 void removeAcqRequest(QUuid acqRequestId);
38
35
39 QMutex m_WorkingMutex;
36 QMutex m_WorkingMutex;
40 QReadWriteLock m_Lock;
37 QReadWriteLock m_Lock;
41
38
42 std::map<QUuid, QVector<AcquisitionDataPacket> > m_AcqIdentifierToAcqDataPacketVectorMap;
39 std::map<QUuid, QVector<AcquisitionDataPacket> > m_AcqIdentifierToAcqDataPacketVectorMap;
43 std::map<QUuid, AcquisitionRequest> m_AcqIdentifierToAcqRequestMap;
40 std::map<QUuid, AcquisitionRequest> m_AcqIdentifierToAcqRequestMap;
44 std::map<QUuid, std::pair<QUuid, QUuid> > m_VIdentifierToCurrrentAcqIdNextIdPairMap;
41 std::map<QUuid, QUuid> m_VIdentifierToCurrrentAcqIdMap;
45 VariableAcquisitionWorker *q;
42 VariableAcquisitionWorker *q;
46 };
43 };
47
44
48
45
49 VariableAcquisitionWorker::VariableAcquisitionWorker(QObject *parent)
46 VariableAcquisitionWorker::VariableAcquisitionWorker(QObject *parent)
50 : QObject{parent}, impl{spimpl::make_unique_impl<VariableAcquisitionWorkerPrivate>(this)}
47 : QObject{parent}, impl{spimpl::make_unique_impl<VariableAcquisitionWorkerPrivate>(this)}
51 {
48 {
52 }
49 }
53
50
54 VariableAcquisitionWorker::~VariableAcquisitionWorker()
51 VariableAcquisitionWorker::~VariableAcquisitionWorker()
55 {
52 {
56 qCInfo(LOG_VariableAcquisitionWorker()) << tr("VariableAcquisitionWorker destruction")
53 qCInfo(LOG_VariableAcquisitionWorker()) << tr("VariableAcquisitionWorker destruction")
57 << QThread::currentThread();
54 << QThread::currentThread();
58 this->waitForFinish();
55 this->waitForFinish();
59 }
56 }
60
57
61
58
62 QUuid VariableAcquisitionWorker::pushVariableRequest(QUuid varRequestId, QUuid vIdentifier,
59 QUuid VariableAcquisitionWorker::pushVariableRequest(QUuid varRequestId, QUuid vIdentifier,
63 SqpRange rangeRequested,
64 SqpRange cacheRangeRequested,
65 DataProviderParameters parameters,
60 DataProviderParameters parameters,
66 std::shared_ptr<IDataProvider> provider)
61 std::shared_ptr<IDataProvider> provider)
67 {
62 {
68 qCDebug(LOG_VariableAcquisitionWorker())
63 qCDebug(LOG_VariableAcquisitionWorker())
69 << tr("TORM VariableAcquisitionWorker::pushVariableRequest ") << cacheRangeRequested;
64 << tr("TORM VariableAcquisitionWorker::pushVariableRequest varRequestId: ") << varRequestId
65 << "vId: " << vIdentifier;
70 auto varRequestIdCanceled = QUuid();
66 auto varRequestIdCanceled = QUuid();
71
67
72 // Request creation
68 // Request creation
73 auto acqRequest = AcquisitionRequest{};
69 auto acqRequest = AcquisitionRequest{};
74 qCDebug(LOG_VariableAcquisitionWorker()) << tr("PushVariableRequest ") << vIdentifier
75 << varRequestId;
76 acqRequest.m_VarRequestId = varRequestId;
70 acqRequest.m_VarRequestId = varRequestId;
77 acqRequest.m_vIdentifier = vIdentifier;
71 acqRequest.m_vIdentifier = vIdentifier;
78 acqRequest.m_DataProviderParameters = parameters;
72 acqRequest.m_DataProviderParameters = parameters;
79 acqRequest.m_RangeRequested = rangeRequested;
80 acqRequest.m_CacheRangeRequested = cacheRangeRequested;
81 acqRequest.m_Size = parameters.m_Times.size();
73 acqRequest.m_Size = parameters.m_Times.size();
82 acqRequest.m_Provider = provider;
74 acqRequest.m_Provider = provider;
75 qCInfo(LOG_VariableAcquisitionWorker()) << tr("Add acqRequest ") << acqRequest.m_AcqIdentifier
76 << acqRequest.m_Size;
83
77
84
78
85 // Register request
79 // Register request
86 impl->lockWrite();
80 impl->lockWrite();
87 impl->m_AcqIdentifierToAcqRequestMap.insert(
81 impl->m_AcqIdentifierToAcqRequestMap.insert(
88 std::make_pair(acqRequest.m_AcqIdentifier, acqRequest));
82 std::make_pair(acqRequest.m_AcqIdentifier, acqRequest));
89
83
90 auto it = impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.find(vIdentifier);
84 auto it = impl->m_VIdentifierToCurrrentAcqIdMap.find(vIdentifier);
91 if (it != impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.cend()) {
85 if (it != impl->m_VIdentifierToCurrrentAcqIdMap.cend()) {
92 // A current request already exists, we can replace the next one
86 // A current request already exists, we can cancel it
93 auto oldAcqId = it->second.second;
87 // remove old acqIdentifier from the worker
88 auto oldAcqId = it->second;
94 auto acqIdentifierToAcqRequestMapIt = impl->m_AcqIdentifierToAcqRequestMap.find(oldAcqId);
89 auto acqIdentifierToAcqRequestMapIt = impl->m_AcqIdentifierToAcqRequestMap.find(oldAcqId);
95 if (acqIdentifierToAcqRequestMapIt != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
90 if (acqIdentifierToAcqRequestMapIt != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
96 auto oldAcqRequest = acqIdentifierToAcqRequestMapIt->second;
91 auto oldAcqRequest = acqIdentifierToAcqRequestMapIt->second;
97 varRequestIdCanceled = oldAcqRequest.m_VarRequestId;
92 varRequestIdCanceled = oldAcqRequest.m_VarRequestId;
98 }
93 }
99
100 it->second.second = acqRequest.m_AcqIdentifier;
101 impl->unlock();
94 impl->unlock();
102
103 // remove old acqIdentifier from the worker
104 impl->cancelVarRequest(varRequestIdCanceled);
95 impl->cancelVarRequest(varRequestIdCanceled);
105 // impl->m_AcqIdentifierToAcqRequestMap.erase(oldAcqId);
106 }
96 }
107 else {
97 else {
108 // First request for the variable, it must be stored and executed
109 impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.insert(
110 std::make_pair(vIdentifier, std::make_pair(acqRequest.m_AcqIdentifier, QUuid())));
111 impl->unlock();
98 impl->unlock();
112
113 QMetaObject::invokeMethod(this, "onExecuteRequest", Qt::QueuedConnection,
114 Q_ARG(QUuid, acqRequest.m_AcqIdentifier));
115 }
99 }
116
100
101 // Request for the variable, it must be stored and executed
102 impl->lockWrite();
103 impl->m_VIdentifierToCurrrentAcqIdMap.insert(
104 std::make_pair(vIdentifier, acqRequest.m_AcqIdentifier));
105 impl->unlock();
106
107 QMetaObject::invokeMethod(this, "onExecuteRequest", Qt::QueuedConnection,
108 Q_ARG(QUuid, acqRequest.m_AcqIdentifier));
109
117 return varRequestIdCanceled;
110 return varRequestIdCanceled;
118 }
111 }
119
112
120 void VariableAcquisitionWorker::abortProgressRequested(QUuid vIdentifier)
113 void VariableAcquisitionWorker::abortProgressRequested(QUuid vIdentifier)
121 {
114 {
122 impl->lockRead();
115 impl->lockRead();
123
116
124 auto it = impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.find(vIdentifier);
117 auto it = impl->m_VIdentifierToCurrrentAcqIdMap.find(vIdentifier);
125 if (it != impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.cend()) {
118 if (it != impl->m_VIdentifierToCurrrentAcqIdMap.cend()) {
126 auto currentAcqId = it->second.first;
119 auto currentAcqId = it->second;
127
120
128 auto it = impl->m_AcqIdentifierToAcqRequestMap.find(currentAcqId);
121 auto it = impl->m_AcqIdentifierToAcqRequestMap.find(currentAcqId);
129 if (it != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
122 if (it != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
130 auto request = it->second;
123 auto request = it->second;
131 impl->unlock();
124 impl->unlock();
132
125
133 // Remove the current request from the worker
134 impl->updateToNextRequest(vIdentifier);
135
136 // notify the request aborting to the provider
126 // notify the request aborting to the provider
137 request.m_Provider->requestDataAborting(currentAcqId);
127 request.m_Provider->requestDataAborting(currentAcqId);
138 }
128 }
139 else {
129 else {
140 impl->unlock();
130 impl->unlock();
141 qCWarning(LOG_VariableAcquisitionWorker())
131 qCWarning(LOG_VariableAcquisitionWorker())
142 << tr("Impossible to abort an unknown acquisition request") << currentAcqId;
132 << tr("Impossible to abort an unknown acquisition request") << currentAcqId;
143 }
133 }
144 }
134 }
145 else {
135 else {
146 impl->unlock();
136 impl->unlock();
147 }
137 }
148 }
138 }
149
139
150 void VariableAcquisitionWorker::onVariableRetrieveDataInProgress(QUuid acqIdentifier,
140 void VariableAcquisitionWorker::onVariableRetrieveDataInProgress(QUuid acqIdentifier,
151 double progress)
141 double progress)
152 {
142 {
153 qCDebug(LOG_VariableAcquisitionWorker()) << tr("TORM: onVariableRetrieveDataInProgress ")
143 qCDebug(LOG_VariableAcquisitionWorker()) << tr("TORM: onVariableRetrieveDataInProgress ")
144 << QThread::currentThread()->objectName()
154 << acqIdentifier << progress;
145 << acqIdentifier << progress;
155 impl->lockRead();
146 impl->lockRead();
156 auto aIdToARit = impl->m_AcqIdentifierToAcqRequestMap.find(acqIdentifier);
147 auto aIdToARit = impl->m_AcqIdentifierToAcqRequestMap.find(acqIdentifier);
157 if (aIdToARit != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
148 if (aIdToARit != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
158 auto currentPartSize = (aIdToARit->second.m_Size != 0) ? 100 / aIdToARit->second.m_Size : 0;
149 auto progressPartSize
150 = (aIdToARit->second.m_Size != 0) ? 100 / aIdToARit->second.m_Size : 0;
159
151
160 auto currentPartProgress
152 auto currentPartProgress
161 = std::isnan(progress) ? 0.0 : (progress * currentPartSize) / 100.0;
153 = std::isnan(progress) ? 0.0 : (progress * progressPartSize) / 100.0;
162 auto currentAlreadyProgress = aIdToARit->second.m_Progression * currentPartSize;
154
155 // We can only give an approximation of the currentProgression since its upgrade is async.
156 auto currentProgression = aIdToARit->second.m_Progression;
157 if (currentProgression == aIdToARit->second.m_Size) {
158 currentProgression = aIdToARit->second.m_Size - 1;
159 }
160
161 auto currentAlreadyProgress = progressPartSize * currentProgression;
162
163
163
164 auto finalProgression = currentAlreadyProgress + currentPartProgress;
164 auto finalProgression = currentAlreadyProgress + currentPartProgress;
165 emit variableRequestInProgress(aIdToARit->second.m_vIdentifier, finalProgression);
165 emit variableRequestInProgress(aIdToARit->second.m_vIdentifier, finalProgression);
166 qCDebug(LOG_VariableAcquisitionWorker())
166
167 << tr("TORM: onVariableRetrieveDataInProgress ")
168 << QThread::currentThread()->objectName() << aIdToARit->second.m_vIdentifier
169 << currentPartSize << currentAlreadyProgress << currentPartProgress << finalProgression;
170 if (finalProgression == 100.0) {
167 if (finalProgression == 100.0) {
171 emit variableRequestInProgress(aIdToARit->second.m_vIdentifier, 0.0);
168 emit variableRequestInProgress(aIdToARit->second.m_vIdentifier, 0.0);
172 }
169 }
173 }
170 }
174 impl->unlock();
171 impl->unlock();
175 }
172 }
176
173
177 void VariableAcquisitionWorker::onVariableAcquisitionFailed(QUuid acqIdentifier)
174 void VariableAcquisitionWorker::onVariableAcquisitionFailed(QUuid acqIdentifier)
178 {
175 {
179 qCDebug(LOG_VariableAcquisitionWorker()) << tr("onVariableAcquisitionFailed")
176 qCDebug(LOG_VariableAcquisitionWorker()) << tr("onVariableAcquisitionFailed")
180 << QThread::currentThread();
177 << QThread::currentThread();
181 impl->lockRead();
178 impl->lockRead();
182 auto it = impl->m_AcqIdentifierToAcqRequestMap.find(acqIdentifier);
179 auto it = impl->m_AcqIdentifierToAcqRequestMap.find(acqIdentifier);
183 if (it != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
180 if (it != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
184 auto request = it->second;
181 auto request = it->second;
185 impl->unlock();
182 impl->unlock();
186 qCDebug(LOG_VariableAcquisitionWorker()) << tr("onVariableAcquisitionFailed")
187 << acqIdentifier << request.m_vIdentifier
188 << QThread::currentThread();
189 emit variableCanceledRequested(request.m_vIdentifier);
183 emit variableCanceledRequested(request.m_vIdentifier);
190 }
184 }
191 else {
185 else {
192 impl->unlock();
186 impl->unlock();
193 // TODO log no acqIdentifier recognized
194 }
187 }
195 }
188 }
196
189
197 void VariableAcquisitionWorker::onVariableDataAcquired(QUuid acqIdentifier,
190 void VariableAcquisitionWorker::onVariableDataAcquired(QUuid acqIdentifier,
198 std::shared_ptr<IDataSeries> dataSeries,
191 std::shared_ptr<IDataSeries> dataSeries,
199 SqpRange dataRangeAcquired)
192 SqpRange dataRangeAcquired)
200 {
193 {
201 qCDebug(LOG_VariableAcquisitionWorker()) << tr("TORM: onVariableDataAcquired on range ")
194 qCDebug(LOG_VariableAcquisitionWorker()) << tr("TORM: onVariableDataAcquired on range ")
202 << acqIdentifier << dataRangeAcquired;
195 << acqIdentifier << dataRangeAcquired;
203 impl->lockWrite();
196 impl->lockWrite();
204 auto aIdToARit = impl->m_AcqIdentifierToAcqRequestMap.find(acqIdentifier);
197 auto aIdToARit = impl->m_AcqIdentifierToAcqRequestMap.find(acqIdentifier);
205 if (aIdToARit != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
198 if (aIdToARit != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
206 // Store the result
199 // Store the result
207 auto dataPacket = AcquisitionDataPacket{};
200 auto dataPacket = AcquisitionDataPacket{};
208 dataPacket.m_Range = dataRangeAcquired;
201 dataPacket.m_Range = dataRangeAcquired;
209 dataPacket.m_DateSeries = dataSeries;
202 dataPacket.m_DateSeries = dataSeries;
210
203
211 auto aIdToADPVit = impl->m_AcqIdentifierToAcqDataPacketVectorMap.find(acqIdentifier);
204 auto aIdToADPVit = impl->m_AcqIdentifierToAcqDataPacketVectorMap.find(acqIdentifier);
212 if (aIdToADPVit != impl->m_AcqIdentifierToAcqDataPacketVectorMap.cend()) {
205 if (aIdToADPVit != impl->m_AcqIdentifierToAcqDataPacketVectorMap.cend()) {
213 // A current request result already exists, we can update it
206 // A current request result already exists, we can update it
214 aIdToADPVit->second.push_back(dataPacket);
207 aIdToADPVit->second.push_back(dataPacket);
215 }
208 }
216 else {
209 else {
217 // First request result for the variable, it must be stored
210 // First request result for the variable, it must be stored
218 impl->m_AcqIdentifierToAcqDataPacketVectorMap.insert(
211 impl->m_AcqIdentifierToAcqDataPacketVectorMap.insert(
219 std::make_pair(acqIdentifier, QVector<AcquisitionDataPacket>() << dataPacket));
212 std::make_pair(acqIdentifier, QVector<AcquisitionDataPacket>() << dataPacket));
220 }
213 }
221
214
222
215
223 // Decrement the counter of the request
216 // Decrement the counter of the request
224 auto &acqRequest = aIdToARit->second;
217 auto &acqRequest = aIdToARit->second;
225 acqRequest.m_Progression = acqRequest.m_Progression + 1;
218 acqRequest.m_Progression = acqRequest.m_Progression + 1;
226
219
227 // if the counter is 0, we can return data then run the next request if it exists and
220 // if the counter is 0, we can return data then run the next request if it exists and
228 // removed the finished request
221 // removed the finished request
229 if (acqRequest.m_Size == acqRequest.m_Progression) {
222 if (acqRequest.m_Size == acqRequest.m_Progression) {
230 auto varId = acqRequest.m_vIdentifier;
223 auto varId = acqRequest.m_vIdentifier;
231 auto rangeRequested = acqRequest.m_RangeRequested;
232 auto cacheRangeRequested = acqRequest.m_CacheRangeRequested;
233 // Return the data
224 // Return the data
234 aIdToADPVit = impl->m_AcqIdentifierToAcqDataPacketVectorMap.find(acqIdentifier);
225 aIdToADPVit = impl->m_AcqIdentifierToAcqDataPacketVectorMap.find(acqIdentifier);
235 if (aIdToADPVit != impl->m_AcqIdentifierToAcqDataPacketVectorMap.cend()) {
226 if (aIdToADPVit != impl->m_AcqIdentifierToAcqDataPacketVectorMap.cend()) {
236 emit dataProvided(varId, rangeRequested, cacheRangeRequested, aIdToADPVit->second);
227 emit dataProvided(varId, aIdToADPVit->second);
237 }
228 }
238 impl->unlock();
229 impl->unlock();
239
240 // Update to the next request
241 impl->updateToNextRequest(acqRequest.m_vIdentifier);
242 }
230 }
243 else {
231 else {
244 impl->unlock();
232 impl->unlock();
245 }
233 }
246 }
234 }
247 else {
235 else {
248 impl->unlock();
236 impl->unlock();
249 qCWarning(LOG_VariableAcquisitionWorker())
237 qCWarning(LOG_VariableAcquisitionWorker())
250 << tr("Impossible to retrieve AcquisitionRequest for the incoming data.");
238 << tr("Impossible to retrieve AcquisitionRequest for the incoming data.");
251 }
239 }
252 }
240 }
253
241
254 void VariableAcquisitionWorker::onExecuteRequest(QUuid acqIdentifier)
242 void VariableAcquisitionWorker::onExecuteRequest(QUuid acqIdentifier)
255 {
243 {
256 qCDebug(LOG_VariableAcquisitionWorker()) << tr("onExecuteRequest") << QThread::currentThread();
244 qCDebug(LOG_VariableAcquisitionWorker()) << tr("onExecuteRequest") << QThread::currentThread();
257 impl->lockRead();
245 impl->lockRead();
258 auto it = impl->m_AcqIdentifierToAcqRequestMap.find(acqIdentifier);
246 auto it = impl->m_AcqIdentifierToAcqRequestMap.find(acqIdentifier);
259 if (it != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
247 if (it != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
260 auto request = it->second;
248 auto request = it->second;
261 impl->unlock();
249 impl->unlock();
262 emit variableRequestInProgress(request.m_vIdentifier, 0.1);
250 emit variableRequestInProgress(request.m_vIdentifier, 0.1);
251 qCDebug(LOG_VariableAcquisitionWorker()) << tr("Start request 10%") << acqIdentifier
252 << QThread::currentThread();
263 request.m_Provider->requestDataLoading(acqIdentifier, request.m_DataProviderParameters);
253 request.m_Provider->requestDataLoading(acqIdentifier, request.m_DataProviderParameters);
264 }
254 }
265 else {
255 else {
266 impl->unlock();
256 impl->unlock();
267 // TODO log no acqIdentifier recognized
257 // TODO log no acqIdentifier recognized
268 }
258 }
269 }
259 }
270
260
271 void VariableAcquisitionWorker::initialize()
261 void VariableAcquisitionWorker::initialize()
272 {
262 {
273 qCDebug(LOG_VariableAcquisitionWorker()) << tr("VariableAcquisitionWorker init")
263 qCDebug(LOG_VariableAcquisitionWorker()) << tr("VariableAcquisitionWorker init")
274 << QThread::currentThread();
264 << QThread::currentThread();
275 impl->m_WorkingMutex.lock();
265 impl->m_WorkingMutex.lock();
276 qCDebug(LOG_VariableAcquisitionWorker()) << tr("VariableAcquisitionWorker init END");
266 qCDebug(LOG_VariableAcquisitionWorker()) << tr("VariableAcquisitionWorker init END");
277 }
267 }
278
268
279 void VariableAcquisitionWorker::finalize()
269 void VariableAcquisitionWorker::finalize()
280 {
270 {
281 impl->m_WorkingMutex.unlock();
271 impl->m_WorkingMutex.unlock();
282 }
272 }
283
273
284 void VariableAcquisitionWorker::waitForFinish()
274 void VariableAcquisitionWorker::waitForFinish()
285 {
275 {
286 QMutexLocker locker{&impl->m_WorkingMutex};
276 QMutexLocker locker{&impl->m_WorkingMutex};
287 }
277 }
288
278
289 void VariableAcquisitionWorker::VariableAcquisitionWorkerPrivate::removeVariableRequest(
279 void VariableAcquisitionWorker::VariableAcquisitionWorkerPrivate::removeVariableRequest(
290 QUuid vIdentifier)
280 QUuid vIdentifier)
291 {
281 {
292 lockWrite();
282 lockWrite();
293 auto it = m_VIdentifierToCurrrentAcqIdNextIdPairMap.find(vIdentifier);
283 auto it = m_VIdentifierToCurrrentAcqIdMap.find(vIdentifier);
294
284
295 if (it != m_VIdentifierToCurrrentAcqIdNextIdPairMap.cend()) {
285 if (it != m_VIdentifierToCurrrentAcqIdMap.cend()) {
296 // A current request already exists, we can replace the next one
286 // A current request already exists, we can replace the next one
297
287
298 m_AcqIdentifierToAcqRequestMap.erase(it->second.first);
288 qCDebug(LOG_VariableAcquisitionWorker())
299 m_AcqIdentifierToAcqDataPacketVectorMap.erase(it->second.first);
289 << "VariableAcquisitionWorkerPrivate::removeVariableRequest "
300
290 << QThread::currentThread()->objectName() << it->second;
301 m_AcqIdentifierToAcqRequestMap.erase(it->second.second);
291 m_AcqIdentifierToAcqRequestMap.erase(it->second);
302 m_AcqIdentifierToAcqDataPacketVectorMap.erase(it->second.second);
292 m_AcqIdentifierToAcqDataPacketVectorMap.erase(it->second);
303 }
293 }
304 m_VIdentifierToCurrrentAcqIdNextIdPairMap.erase(vIdentifier);
305 unlock();
306 }
307
294
308 void VariableAcquisitionWorker::VariableAcquisitionWorkerPrivate::updateToNextRequest(
295 // stop any progression
309 QUuid vIdentifier)
296 emit q->variableRequestInProgress(vIdentifier, 0.0);
310 {
297
311 lockRead();
298 m_VIdentifierToCurrrentAcqIdMap.erase(vIdentifier);
312 auto it = m_VIdentifierToCurrrentAcqIdNextIdPairMap.find(vIdentifier);
299 unlock();
313 if (it != m_VIdentifierToCurrrentAcqIdNextIdPairMap.cend()) {
314 if (it->second.second.isNull()) {
315 unlock();
316 // There is no next request, we can remove the variable request
317 removeVariableRequest(vIdentifier);
318 }
319 else {
320 auto acqIdentifierToRemove = it->second.first;
321 // Move the next request to the current request
322 auto nextRequestId = it->second.second;
323 it->second.first = nextRequestId;
324 it->second.second = QUuid();
325 unlock();
326 // Remove AcquisitionRequest and results;
327 lockWrite();
328 m_AcqIdentifierToAcqRequestMap.erase(acqIdentifierToRemove);
329 m_AcqIdentifierToAcqDataPacketVectorMap.erase(acqIdentifierToRemove);
330 unlock();
331 // Execute the current request
332 QMetaObject::invokeMethod(q, "onExecuteRequest", Qt::QueuedConnection,
333 Q_ARG(QUuid, nextRequestId));
334 }
335 }
336 else {
337 unlock();
338 qCCritical(LOG_VariableAcquisitionWorker())
339 << tr("Impossible to execute the acquisition on an unfound variable ");
340 }
341 }
300 }
342
301
343 void VariableAcquisitionWorker::VariableAcquisitionWorkerPrivate::cancelVarRequest(
302 void VariableAcquisitionWorker::VariableAcquisitionWorkerPrivate::cancelVarRequest(
344 QUuid varRequestId)
303 QUuid varRequestId)
345 {
304 {
346 qCDebug(LOG_VariableAcquisitionWorker())
305 qCDebug(LOG_VariableAcquisitionWorker())
347 << "VariableAcquisitionWorkerPrivate::cancelVarRequest 0";
306 << "VariableAcquisitionWorkerPrivate::cancelVarRequest start";
348 lockRead();
307 lockRead();
349 // get all AcqIdentifier in link with varRequestId
308 // get all AcqIdentifier in link with varRequestId
350 QVector<QUuid> acqIdsToRm;
309 QVector<QUuid> acqIdsToRm;
351 auto cend = m_AcqIdentifierToAcqRequestMap.cend();
310 auto cend = m_AcqIdentifierToAcqRequestMap.cend();
352 for (auto it = m_AcqIdentifierToAcqRequestMap.cbegin(); it != cend; ++it) {
311 for (auto it = m_AcqIdentifierToAcqRequestMap.cbegin(); it != cend; ++it) {
353 if (it->second.m_VarRequestId == varRequestId) {
312 if (it->second.m_VarRequestId == varRequestId) {
354 acqIdsToRm << it->first;
313 acqIdsToRm << it->first;
355 }
314 }
356 }
315 }
357 unlock();
316 unlock();
358 // run aborting or removing of acqIdsToRm
317 // run aborting or removing of acqIdsToRm
359
318
360 for (auto acqId : acqIdsToRm) {
319 for (auto acqId : acqIdsToRm) {
361 removeAcqRequest(acqId);
320 removeAcqRequest(acqId);
362 }
321 }
363 qCDebug(LOG_VariableAcquisitionWorker())
322 qCDebug(LOG_VariableAcquisitionWorker())
364 << "VariableAcquisitionWorkerPrivate::cancelVarRequest end";
323 << "VariableAcquisitionWorkerPrivate::cancelVarRequest end";
365 }
324 }
366
325
367 void VariableAcquisitionWorker::VariableAcquisitionWorkerPrivate::removeAcqRequest(
326 void VariableAcquisitionWorker::VariableAcquisitionWorkerPrivate::removeAcqRequest(
368 QUuid acqRequestId)
327 QUuid acqRequestId)
369 {
328 {
370 qCDebug(LOG_VariableAcquisitionWorker())
329 qCDebug(LOG_VariableAcquisitionWorker())
371 << "VariableAcquisitionWorkerPrivate::removeAcqRequest";
330 << "VariableAcquisitionWorkerPrivate::removeAcqRequest";
372 QUuid vIdentifier;
331 QUuid vIdentifier;
373 std::shared_ptr<IDataProvider> provider;
332 std::shared_ptr<IDataProvider> provider;
374 lockRead();
333 lockRead();
375 auto acqIt = m_AcqIdentifierToAcqRequestMap.find(acqRequestId);
334 auto acqIt = m_AcqIdentifierToAcqRequestMap.find(acqRequestId);
376 if (acqIt != m_AcqIdentifierToAcqRequestMap.cend()) {
335 if (acqIt != m_AcqIdentifierToAcqRequestMap.cend()) {
377 vIdentifier = acqIt->second.m_vIdentifier;
336 vIdentifier = acqIt->second.m_vIdentifier;
378 provider = acqIt->second.m_Provider;
337 provider = acqIt->second.m_Provider;
379
338
380 auto it = m_VIdentifierToCurrrentAcqIdNextIdPairMap.find(vIdentifier);
339 auto it = m_VIdentifierToCurrrentAcqIdMap.find(vIdentifier);
381 if (it != m_VIdentifierToCurrrentAcqIdNextIdPairMap.cend()) {
340 if (it != m_VIdentifierToCurrrentAcqIdMap.cend()) {
382 if (it->second.first == acqRequestId) {
341 if (it->second == acqRequestId) {
383 // acqRequest is currently running -> let's aborting it
342 // acqRequest is currently running -> let's aborting it
384 unlock();
343 unlock();
385
344
386 // Remove the current request from the worker
387 updateToNextRequest(vIdentifier);
388
389 // notify the request aborting to the provider
345 // notify the request aborting to the provider
390 provider->requestDataAborting(acqRequestId);
346 provider->requestDataAborting(acqRequestId);
391 }
347 }
392 else if (it->second.second == acqRequestId) {
393 it->second.second = QUuid();
394 unlock();
395 }
396 else {
348 else {
397 unlock();
349 unlock();
398 }
350 }
399 }
351 }
400 else {
352 else {
401 unlock();
353 unlock();
402 }
354 }
403 }
355 }
404 else {
356 else {
405 unlock();
357 unlock();
406 }
358 }
407
359
408 lockWrite();
360 lockWrite();
409
361
410 m_AcqIdentifierToAcqDataPacketVectorMap.erase(acqRequestId);
362 m_AcqIdentifierToAcqDataPacketVectorMap.erase(acqRequestId);
411 m_AcqIdentifierToAcqRequestMap.erase(acqRequestId);
363 m_AcqIdentifierToAcqRequestMap.erase(acqRequestId);
364 m_VIdentifierToCurrrentAcqIdMap.erase(vIdentifier);
412
365
413 unlock();
366 unlock();
414 qCDebug(LOG_VariableAcquisitionWorker())
367 qCDebug(LOG_VariableAcquisitionWorker())
415 << "VariableAcquisitionWorkerPrivate::removeAcqRequest END";
368 << "VariableAcquisitionWorkerPrivate::removeAcqRequest END";
416 }
369 }
@@ -1,1104 +1,1101
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 <QDataStream>
15 #include <QDataStream>
16 #include <QMutex>
16 #include <QMutex>
17 #include <QThread>
17 #include <QThread>
18 #include <QUuid>
18 #include <QUuid>
19 #include <QtCore/QItemSelectionModel>
19 #include <QtCore/QItemSelectionModel>
20
20
21 #include <deque>
21 #include <deque>
22 #include <set>
22 #include <set>
23 #include <unordered_map>
23 #include <unordered_map>
24
24
25 Q_LOGGING_CATEGORY(LOG_VariableController, "VariableController")
25 Q_LOGGING_CATEGORY(LOG_VariableController, "VariableController")
26
26
27 namespace {
27 namespace {
28
28
29 SqpRange computeSynchroRangeRequested(const SqpRange &varRange, const SqpRange &graphRange,
29 SqpRange computeSynchroRangeRequested(const SqpRange &varRange, const SqpRange &graphRange,
30 const SqpRange &oldGraphRange)
30 const SqpRange &oldGraphRange)
31 {
31 {
32 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
32 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
33
33
34 auto varRangeRequested = varRange;
34 auto varRangeRequested = varRange;
35 switch (zoomType) {
35 switch (zoomType) {
36 case AcquisitionZoomType::ZoomIn: {
36 case AcquisitionZoomType::ZoomIn: {
37 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
37 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
38 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
38 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
39 varRangeRequested.m_TStart += deltaLeft;
39 varRangeRequested.m_TStart += deltaLeft;
40 varRangeRequested.m_TEnd -= deltaRight;
40 varRangeRequested.m_TEnd -= deltaRight;
41 break;
41 break;
42 }
42 }
43
43
44 case AcquisitionZoomType::ZoomOut: {
44 case AcquisitionZoomType::ZoomOut: {
45 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
45 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
46 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
46 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
47 varRangeRequested.m_TStart -= deltaLeft;
47 varRangeRequested.m_TStart -= deltaLeft;
48 varRangeRequested.m_TEnd += deltaRight;
48 varRangeRequested.m_TEnd += deltaRight;
49 break;
49 break;
50 }
50 }
51 case AcquisitionZoomType::PanRight: {
51 case AcquisitionZoomType::PanRight: {
52 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
52 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
53 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
53 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
54 varRangeRequested.m_TStart += deltaLeft;
54 varRangeRequested.m_TStart += deltaLeft;
55 varRangeRequested.m_TEnd += deltaRight;
55 varRangeRequested.m_TEnd += deltaRight;
56 break;
56 break;
57 }
57 }
58 case AcquisitionZoomType::PanLeft: {
58 case AcquisitionZoomType::PanLeft: {
59 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
59 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
60 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
60 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
61 varRangeRequested.m_TStart -= deltaLeft;
61 varRangeRequested.m_TStart -= deltaLeft;
62 varRangeRequested.m_TEnd -= deltaRight;
62 varRangeRequested.m_TEnd -= deltaRight;
63 break;
63 break;
64 }
64 }
65 case AcquisitionZoomType::Unknown: {
65 case AcquisitionZoomType::Unknown: {
66 qCCritical(LOG_VariableController())
66 qCCritical(LOG_VariableController())
67 << VariableController::tr("Impossible to synchronize: zoom type unknown");
67 << VariableController::tr("Impossible to synchronize: zoom type unknown");
68 break;
68 break;
69 }
69 }
70 default:
70 default:
71 qCCritical(LOG_VariableController()) << VariableController::tr(
71 qCCritical(LOG_VariableController()) << VariableController::tr(
72 "Impossible to synchronize: zoom type not take into account");
72 "Impossible to synchronize: zoom type not take into account");
73 // No action
73 // No action
74 break;
74 break;
75 }
75 }
76
76
77 return varRangeRequested;
77 return varRangeRequested;
78 }
78 }
79 }
79 }
80
80
81 enum class VariableRequestHandlerState { OFF, RUNNING, PENDING };
81 enum class VariableRequestHandlerState { OFF, RUNNING, PENDING };
82
82
83 struct VariableRequestHandler {
83 struct VariableRequestHandler {
84
84
85 VariableRequestHandler()
85 VariableRequestHandler()
86 {
86 {
87 m_CanUpdate = false;
87 m_CanUpdate = false;
88 m_State = VariableRequestHandlerState::OFF;
88 m_State = VariableRequestHandlerState::OFF;
89 }
89 }
90
90
91 QUuid m_VarId;
91 QUuid m_VarId;
92 VariableRequest m_RunningVarRequest;
92 VariableRequest m_RunningVarRequest;
93 VariableRequest m_PendingVarRequest;
93 VariableRequest m_PendingVarRequest;
94 VariableRequestHandlerState m_State;
94 VariableRequestHandlerState m_State;
95 bool m_CanUpdate;
95 bool m_CanUpdate;
96 };
96 };
97
97
98 struct VariableController::VariableControllerPrivate {
98 struct VariableController::VariableControllerPrivate {
99 explicit VariableControllerPrivate(VariableController *parent)
99 explicit VariableControllerPrivate(VariableController *parent)
100 : m_WorkingMutex{},
100 : m_WorkingMutex{},
101 m_VariableModel{new VariableModel{parent}},
101 m_VariableModel{new VariableModel{parent}},
102 m_VariableSelectionModel{new QItemSelectionModel{m_VariableModel, parent}},
102 m_VariableSelectionModel{new QItemSelectionModel{m_VariableModel, parent}},
103 // m_VariableCacheStrategy{std::make_unique<VariableCacheStrategy>()},
103 // m_VariableCacheStrategy{std::make_unique<VariableCacheStrategy>()},
104 m_VariableCacheStrategy{VariableCacheStrategyFactory::createCacheStrategy(
104 m_VariableCacheStrategy{VariableCacheStrategyFactory::createCacheStrategy(
105 CacheStrategy::SingleThreshold)},
105 CacheStrategy::SingleThreshold)},
106 m_VariableAcquisitionWorker{std::make_unique<VariableAcquisitionWorker>()},
106 m_VariableAcquisitionWorker{std::make_unique<VariableAcquisitionWorker>()},
107 q{parent}
107 q{parent}
108 {
108 {
109
109
110 m_VariableAcquisitionWorker->moveToThread(&m_VariableAcquisitionWorkerThread);
110 m_VariableAcquisitionWorker->moveToThread(&m_VariableAcquisitionWorkerThread);
111 m_VariableAcquisitionWorkerThread.setObjectName("VariableAcquisitionWorkerThread");
111 m_VariableAcquisitionWorkerThread.setObjectName("VariableAcquisitionWorkerThread");
112 }
112 }
113
113
114
114
115 virtual ~VariableControllerPrivate()
115 virtual ~VariableControllerPrivate()
116 {
116 {
117 qCDebug(LOG_VariableController()) << tr("VariableControllerPrivate destruction");
117 qCDebug(LOG_VariableController()) << tr("VariableControllerPrivate destruction");
118 m_VariableAcquisitionWorkerThread.quit();
118 m_VariableAcquisitionWorkerThread.quit();
119 m_VariableAcquisitionWorkerThread.wait();
119 m_VariableAcquisitionWorkerThread.wait();
120 }
120 }
121
121
122
122
123 void processRequest(std::shared_ptr<Variable> var, const SqpRange &rangeRequested,
123 void processRequest(std::shared_ptr<Variable> var, const SqpRange &rangeRequested,
124 QUuid varRequestId);
124 QUuid varRequestId);
125
125
126 std::shared_ptr<Variable> findVariable(QUuid vIdentifier);
126 std::shared_ptr<Variable> findVariable(QUuid vIdentifier);
127 std::shared_ptr<IDataSeries>
127 std::shared_ptr<IDataSeries>
128 retrieveDataSeries(const QVector<AcquisitionDataPacket> acqDataPacketVector);
128 retrieveDataSeries(const QVector<AcquisitionDataPacket> acqDataPacketVector);
129
129
130 void registerProvider(std::shared_ptr<IDataProvider> provider);
130 void registerProvider(std::shared_ptr<IDataProvider> provider);
131
131
132 void storeVariableRequest(QUuid varId, QUuid varRequestId, const VariableRequest &varRequest);
132 void storeVariableRequest(QUuid varId, QUuid varRequestId, const VariableRequest &varRequest);
133 QUuid acceptVariableRequest(QUuid varId, std::shared_ptr<IDataSeries> dataSeries);
133 QUuid acceptVariableRequest(QUuid varId, std::shared_ptr<IDataSeries> dataSeries);
134 void updateVariables(QUuid varRequestId);
134 void updateVariables(QUuid varRequestId);
135 void updateVariableRequest(QUuid varRequestId);
135 void updateVariableRequest(QUuid varRequestId);
136 void cancelVariableRequest(QUuid varRequestId);
136 void cancelVariableRequest(QUuid varRequestId);
137 void executeVarRequest(std::shared_ptr<Variable> var, VariableRequest &varRequest);
137 void executeVarRequest(std::shared_ptr<Variable> var, VariableRequest &varRequest);
138
138
139 template <typename VariableIterator>
139 template <typename VariableIterator>
140 void desynchronize(VariableIterator variableIt, const QUuid &syncGroupId);
140 void desynchronize(VariableIterator variableIt, const QUuid &syncGroupId);
141
141
142 QMutex m_WorkingMutex;
142 QMutex m_WorkingMutex;
143 /// Variable model. The VariableController has the ownership
143 /// Variable model. The VariableController has the ownership
144 VariableModel *m_VariableModel;
144 VariableModel *m_VariableModel;
145 QItemSelectionModel *m_VariableSelectionModel;
145 QItemSelectionModel *m_VariableSelectionModel;
146
146
147
147
148 TimeController *m_TimeController{nullptr};
148 TimeController *m_TimeController{nullptr};
149 std::unique_ptr<VariableCacheStrategy> m_VariableCacheStrategy;
149 std::unique_ptr<VariableCacheStrategy> m_VariableCacheStrategy;
150 std::unique_ptr<VariableAcquisitionWorker> m_VariableAcquisitionWorker;
150 std::unique_ptr<VariableAcquisitionWorker> m_VariableAcquisitionWorker;
151 QThread m_VariableAcquisitionWorkerThread;
151 QThread m_VariableAcquisitionWorkerThread;
152
152
153 std::unordered_map<std::shared_ptr<Variable>, std::shared_ptr<IDataProvider> >
153 std::unordered_map<std::shared_ptr<Variable>, std::shared_ptr<IDataProvider> >
154 m_VariableToProviderMap;
154 m_VariableToProviderMap;
155 std::unordered_map<std::shared_ptr<Variable>, QUuid> m_VariableToIdentifierMap;
155 std::unordered_map<std::shared_ptr<Variable>, QUuid> m_VariableToIdentifierMap;
156 std::map<QUuid, std::shared_ptr<VariableSynchronizationGroup> >
156 std::map<QUuid, std::shared_ptr<VariableSynchronizationGroup> >
157 m_GroupIdToVariableSynchronizationGroupMap;
157 m_GroupIdToVariableSynchronizationGroupMap;
158 std::map<QUuid, QUuid> m_VariableIdGroupIdMap;
158 std::map<QUuid, QUuid> m_VariableIdGroupIdMap;
159 std::set<std::shared_ptr<IDataProvider> > m_ProviderSet;
159 std::set<std::shared_ptr<IDataProvider> > m_ProviderSet;
160
160
161 std::map<QUuid, std::list<QUuid> > m_VarGroupIdToVarIds;
161 std::map<QUuid, std::list<QUuid> > m_VarGroupIdToVarIds;
162 std::map<QUuid, std::unique_ptr<VariableRequestHandler> > m_VarIdToVarRequestHandler;
162 std::map<QUuid, std::unique_ptr<VariableRequestHandler> > m_VarIdToVarRequestHandler;
163
163
164 VariableController *q;
164 VariableController *q;
165 };
165 };
166
166
167
167
168 VariableController::VariableController(QObject *parent)
168 VariableController::VariableController(QObject *parent)
169 : QObject{parent}, impl{spimpl::make_unique_impl<VariableControllerPrivate>(this)}
169 : QObject{parent}, impl{spimpl::make_unique_impl<VariableControllerPrivate>(this)}
170 {
170 {
171 qCDebug(LOG_VariableController()) << tr("VariableController construction")
171 qCDebug(LOG_VariableController()) << tr("VariableController construction")
172 << QThread::currentThread();
172 << QThread::currentThread();
173
173
174 connect(impl->m_VariableModel, &VariableModel::abortProgessRequested, this,
174 connect(impl->m_VariableModel, &VariableModel::abortProgessRequested, this,
175 &VariableController::onAbortProgressRequested);
175 &VariableController::onAbortProgressRequested);
176
176
177 connect(impl->m_VariableAcquisitionWorker.get(),
177 connect(impl->m_VariableAcquisitionWorker.get(),
178 &VariableAcquisitionWorker::variableCanceledRequested, this,
178 &VariableAcquisitionWorker::variableCanceledRequested, this,
179 &VariableController::onAbortAcquisitionRequested);
179 &VariableController::onAbortAcquisitionRequested);
180
180
181 connect(impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::dataProvided, this,
181 connect(impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::dataProvided, this,
182 &VariableController::onDataProvided);
182 &VariableController::onDataProvided);
183 connect(impl->m_VariableAcquisitionWorker.get(),
183 connect(impl->m_VariableAcquisitionWorker.get(),
184 &VariableAcquisitionWorker::variableRequestInProgress, this,
184 &VariableAcquisitionWorker::variableRequestInProgress, this,
185 &VariableController::onVariableRetrieveDataInProgress);
185 &VariableController::onVariableRetrieveDataInProgress);
186
186
187
187
188 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::started,
188 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::started,
189 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::initialize);
189 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::initialize);
190 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::finished,
190 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::finished,
191 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::finalize);
191 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::finalize);
192
192
193 connect(impl->m_VariableModel, &VariableModel::requestVariableRangeUpdate, this,
193 connect(impl->m_VariableModel, &VariableModel::requestVariableRangeUpdate, this,
194 &VariableController::onUpdateDateTime);
194 &VariableController::onUpdateDateTime);
195
195
196 impl->m_VariableAcquisitionWorkerThread.start();
196 impl->m_VariableAcquisitionWorkerThread.start();
197 }
197 }
198
198
199 VariableController::~VariableController()
199 VariableController::~VariableController()
200 {
200 {
201 qCDebug(LOG_VariableController()) << tr("VariableController destruction")
201 qCDebug(LOG_VariableController()) << tr("VariableController destruction")
202 << QThread::currentThread();
202 << QThread::currentThread();
203 this->waitForFinish();
203 this->waitForFinish();
204 }
204 }
205
205
206 VariableModel *VariableController::variableModel() noexcept
206 VariableModel *VariableController::variableModel() noexcept
207 {
207 {
208 return impl->m_VariableModel;
208 return impl->m_VariableModel;
209 }
209 }
210
210
211 QItemSelectionModel *VariableController::variableSelectionModel() noexcept
211 QItemSelectionModel *VariableController::variableSelectionModel() noexcept
212 {
212 {
213 return impl->m_VariableSelectionModel;
213 return impl->m_VariableSelectionModel;
214 }
214 }
215
215
216 void VariableController::setTimeController(TimeController *timeController) noexcept
216 void VariableController::setTimeController(TimeController *timeController) noexcept
217 {
217 {
218 impl->m_TimeController = timeController;
218 impl->m_TimeController = timeController;
219 }
219 }
220
220
221 std::shared_ptr<Variable>
221 std::shared_ptr<Variable>
222 VariableController::cloneVariable(std::shared_ptr<Variable> variable) noexcept
222 VariableController::cloneVariable(std::shared_ptr<Variable> variable) noexcept
223 {
223 {
224 if (impl->m_VariableModel->containsVariable(variable)) {
224 if (impl->m_VariableModel->containsVariable(variable)) {
225 // Clones variable
225 // Clones variable
226 auto duplicate = variable->clone();
226 auto duplicate = variable->clone();
227
227
228 // Adds clone to model
228 // Adds clone to model
229 impl->m_VariableModel->addVariable(duplicate);
229 impl->m_VariableModel->addVariable(duplicate);
230
230
231 // Generates clone identifier
231 // Generates clone identifier
232 impl->m_VariableToIdentifierMap[duplicate] = QUuid::createUuid();
232 impl->m_VariableToIdentifierMap[duplicate] = QUuid::createUuid();
233
233
234 // Registers provider
234 // Registers provider
235 auto variableProvider = impl->m_VariableToProviderMap.at(variable);
235 auto variableProvider = impl->m_VariableToProviderMap.at(variable);
236 auto duplicateProvider = variableProvider != nullptr ? variableProvider->clone() : nullptr;
236 auto duplicateProvider = variableProvider != nullptr ? variableProvider->clone() : nullptr;
237
237
238 impl->m_VariableToProviderMap[duplicate] = duplicateProvider;
238 impl->m_VariableToProviderMap[duplicate] = duplicateProvider;
239 if (duplicateProvider) {
239 if (duplicateProvider) {
240 impl->registerProvider(duplicateProvider);
240 impl->registerProvider(duplicateProvider);
241 }
241 }
242
242
243 return duplicate;
243 return duplicate;
244 }
244 }
245 else {
245 else {
246 qCCritical(LOG_VariableController())
246 qCCritical(LOG_VariableController())
247 << tr("Can't create duplicate of variable %1: variable not registered in the model")
247 << tr("Can't create duplicate of variable %1: variable not registered in the model")
248 .arg(variable->name());
248 .arg(variable->name());
249 return nullptr;
249 return nullptr;
250 }
250 }
251 }
251 }
252
252
253 void VariableController::deleteVariable(std::shared_ptr<Variable> variable) noexcept
253 void VariableController::deleteVariable(std::shared_ptr<Variable> variable) noexcept
254 {
254 {
255 if (!variable) {
255 if (!variable) {
256 qCCritical(LOG_VariableController()) << "Can't delete variable: variable is null";
256 qCCritical(LOG_VariableController()) << "Can't delete variable: variable is null";
257 return;
257 return;
258 }
258 }
259
259
260 // Spreads in SciQlop that the variable will be deleted, so that potential receivers can
260 // Spreads in SciQlop that the variable will be deleted, so that potential receivers can
261 // make some treatments before the deletion
261 // make some treatments before the deletion
262 emit variableAboutToBeDeleted(variable);
262 emit variableAboutToBeDeleted(variable);
263
263
264 auto variableIt = impl->m_VariableToIdentifierMap.find(variable);
264 auto variableIt = impl->m_VariableToIdentifierMap.find(variable);
265 Q_ASSERT(variableIt != impl->m_VariableToIdentifierMap.cend());
265 Q_ASSERT(variableIt != impl->m_VariableToIdentifierMap.cend());
266
266
267 auto variableId = variableIt->second;
267 auto variableId = variableIt->second;
268
268
269 // Removes variable's handler
269 // Removes variable's handler
270 impl->m_VarIdToVarRequestHandler.erase(variableId);
270 impl->m_VarIdToVarRequestHandler.erase(variableId);
271
271
272 // Desynchronizes variable (if the variable is in a sync group)
272 // Desynchronizes variable (if the variable is in a sync group)
273 auto syncGroupIt = impl->m_VariableIdGroupIdMap.find(variableId);
273 auto syncGroupIt = impl->m_VariableIdGroupIdMap.find(variableId);
274 if (syncGroupIt != impl->m_VariableIdGroupIdMap.cend()) {
274 if (syncGroupIt != impl->m_VariableIdGroupIdMap.cend()) {
275 impl->desynchronize(variableIt, syncGroupIt->second);
275 impl->desynchronize(variableIt, syncGroupIt->second);
276 }
276 }
277
277
278 // Deletes identifier
278 // Deletes identifier
279 impl->m_VariableToIdentifierMap.erase(variableIt);
279 impl->m_VariableToIdentifierMap.erase(variableIt);
280
280
281 // Deletes provider
281 // Deletes provider
282 auto nbProvidersDeleted = impl->m_VariableToProviderMap.erase(variable);
282 auto nbProvidersDeleted = impl->m_VariableToProviderMap.erase(variable);
283 qCDebug(LOG_VariableController())
283 qCDebug(LOG_VariableController())
284 << tr("Number of providers deleted for variable %1: %2")
284 << tr("Number of providers deleted for variable %1: %2")
285 .arg(variable->name(), QString::number(nbProvidersDeleted));
285 .arg(variable->name(), QString::number(nbProvidersDeleted));
286
286
287
287
288 // Deletes from model
288 // Deletes from model
289 impl->m_VariableModel->deleteVariable(variable);
289 impl->m_VariableModel->deleteVariable(variable);
290 }
290 }
291
291
292 void VariableController::deleteVariables(
292 void VariableController::deleteVariables(
293 const QVector<std::shared_ptr<Variable> > &variables) noexcept
293 const QVector<std::shared_ptr<Variable> > &variables) noexcept
294 {
294 {
295 for (auto variable : qAsConst(variables)) {
295 for (auto variable : qAsConst(variables)) {
296 deleteVariable(variable);
296 deleteVariable(variable);
297 }
297 }
298 }
298 }
299
299
300 QByteArray
300 QByteArray
301 VariableController::mimeDataForVariables(const QList<std::shared_ptr<Variable> > &variables) const
301 VariableController::mimeDataForVariables(const QList<std::shared_ptr<Variable> > &variables) const
302 {
302 {
303 auto encodedData = QByteArray{};
303 auto encodedData = QByteArray{};
304
304
305 QVariantList ids;
305 QVariantList ids;
306 for (auto &var : variables) {
306 for (auto &var : variables) {
307 auto itVar = impl->m_VariableToIdentifierMap.find(var);
307 auto itVar = impl->m_VariableToIdentifierMap.find(var);
308 if (itVar == impl->m_VariableToIdentifierMap.cend()) {
308 if (itVar == impl->m_VariableToIdentifierMap.cend()) {
309 qCCritical(LOG_VariableController())
309 qCCritical(LOG_VariableController())
310 << tr("Impossible to find the data for an unknown variable.");
310 << tr("Impossible to find the data for an unknown variable.");
311 }
311 }
312
312
313 ids << itVar->second.toByteArray();
313 ids << itVar->second.toByteArray();
314 }
314 }
315
315
316 QDataStream stream{&encodedData, QIODevice::WriteOnly};
316 QDataStream stream{&encodedData, QIODevice::WriteOnly};
317 stream << ids;
317 stream << ids;
318
318
319 return encodedData;
319 return encodedData;
320 }
320 }
321
321
322 QList<std::shared_ptr<Variable> >
322 QList<std::shared_ptr<Variable> >
323 VariableController::variablesForMimeData(const QByteArray &mimeData) const
323 VariableController::variablesForMimeData(const QByteArray &mimeData) const
324 {
324 {
325 auto variables = QList<std::shared_ptr<Variable> >{};
325 auto variables = QList<std::shared_ptr<Variable> >{};
326 QDataStream stream{mimeData};
326 QDataStream stream{mimeData};
327
327
328 QVariantList ids;
328 QVariantList ids;
329 stream >> ids;
329 stream >> ids;
330
330
331 for (auto id : ids) {
331 for (auto id : ids) {
332 auto uuid = QUuid{id.toByteArray()};
332 auto uuid = QUuid{id.toByteArray()};
333 auto var = impl->findVariable(uuid);
333 auto var = impl->findVariable(uuid);
334 variables << var;
334 variables << var;
335 }
335 }
336
336
337 return variables;
337 return variables;
338 }
338 }
339
339
340 std::shared_ptr<Variable>
340 std::shared_ptr<Variable>
341 VariableController::createVariable(const QString &name, const QVariantHash &metadata,
341 VariableController::createVariable(const QString &name, const QVariantHash &metadata,
342 std::shared_ptr<IDataProvider> provider) noexcept
342 std::shared_ptr<IDataProvider> provider) noexcept
343 {
343 {
344 if (!impl->m_TimeController) {
344 if (!impl->m_TimeController) {
345 qCCritical(LOG_VariableController())
345 qCCritical(LOG_VariableController())
346 << tr("Impossible to create variable: The time controller is null");
346 << tr("Impossible to create variable: The time controller is null");
347 return nullptr;
347 return nullptr;
348 }
348 }
349
349
350 auto range = impl->m_TimeController->dateTime();
350 auto range = impl->m_TimeController->dateTime();
351
351
352 if (auto newVariable = impl->m_VariableModel->createVariable(name, metadata)) {
352 if (auto newVariable = impl->m_VariableModel->createVariable(name, metadata)) {
353 auto varId = QUuid::createUuid();
353 auto varId = QUuid::createUuid();
354
354
355 // Create the handler
355 // Create the handler
356 auto varRequestHandler = std::make_unique<VariableRequestHandler>();
356 auto varRequestHandler = std::make_unique<VariableRequestHandler>();
357 varRequestHandler->m_VarId = varId;
357 varRequestHandler->m_VarId = varId;
358
358
359 impl->m_VarIdToVarRequestHandler.insert(
359 impl->m_VarIdToVarRequestHandler.insert(
360 std::make_pair(varId, std::move(varRequestHandler)));
360 std::make_pair(varId, std::move(varRequestHandler)));
361
361
362 // store the provider
362 // store the provider
363 impl->registerProvider(provider);
363 impl->registerProvider(provider);
364
364
365 // Associate the provider
365 // Associate the provider
366 impl->m_VariableToProviderMap[newVariable] = provider;
366 impl->m_VariableToProviderMap[newVariable] = provider;
367 impl->m_VariableToIdentifierMap[newVariable] = varId;
367 impl->m_VariableToIdentifierMap[newVariable] = varId;
368
368
369 this->onRequestDataLoading(QVector<std::shared_ptr<Variable> >{newVariable}, range, false);
369 this->onRequestDataLoading(QVector<std::shared_ptr<Variable> >{newVariable}, range, false);
370
370
371 // auto varRequestId = QUuid::createUuid();
372 // qCInfo(LOG_VariableController()) << "createVariable: " << varId << varRequestId;
373 // impl->processRequest(newVariable, range, varRequestId);
374 // impl->updateVariableRequest(varRequestId);
375
376 emit variableAdded(newVariable);
371 emit variableAdded(newVariable);
377
372
378 return newVariable;
373 return newVariable;
379 }
374 }
380
375
381 qCCritical(LOG_VariableController()) << tr("Impossible to create variable");
376 qCCritical(LOG_VariableController()) << tr("Impossible to create variable");
382 return nullptr;
377 return nullptr;
383 }
378 }
384
379
385 void VariableController::onDateTimeOnSelection(const SqpRange &dateTime)
380 void VariableController::onDateTimeOnSelection(const SqpRange &dateTime)
386 {
381 {
387 // NOTE: Even if acquisition request is aborting, the graphe range will be changed
382 // NOTE: Even if acquisition request is aborting, the graphe range will be changed
388 qCDebug(LOG_VariableController()) << "VariableController::onDateTimeOnSelection"
383 qCDebug(LOG_VariableController()) << "VariableController::onDateTimeOnSelection"
389 << QThread::currentThread()->objectName();
384 << QThread::currentThread()->objectName();
390 auto selectedRows = impl->m_VariableSelectionModel->selectedRows();
385 auto selectedRows = impl->m_VariableSelectionModel->selectedRows();
391
386
392 // NOTE we only permit the time modification for one variable
387 // NOTE we only permit the time modification for one variable
393 // DEPRECATED
394 // auto variables = QVector<std::shared_ptr<Variable> >{};
395 // for (const auto &selectedRow : qAsConst(selectedRows)) {
396 // if (auto selectedVariable =
397 // impl->m_VariableModel->variable(selectedRow.row())) {
398 // variables << selectedVariable;
399
400 // // notify that rescale operation has to be done
401 // emit rangeChanged(selectedVariable, dateTime);
402 // }
403 // }
404 // if (!variables.isEmpty()) {
405 // this->onRequestDataLoading(variables, dateTime, synchro);
406 // }
407 if (selectedRows.size() == 1) {
388 if (selectedRows.size() == 1) {
408
389
409 if (auto selectedVariable
390 if (auto selectedVariable
410 = impl->m_VariableModel->variable(qAsConst(selectedRows).first().row())) {
391 = impl->m_VariableModel->variable(qAsConst(selectedRows).first().row())) {
411
392
412 onUpdateDateTime(selectedVariable, dateTime);
393 onUpdateDateTime(selectedVariable, dateTime);
413 }
394 }
414 }
395 }
415 else if (selectedRows.size() > 1) {
396 else if (selectedRows.size() > 1) {
416 qCCritical(LOG_VariableController())
397 qCCritical(LOG_VariableController())
417 << tr("Impossible to set time for more than 1 variable in the same time");
398 << tr("Impossible to set time for more than 1 variable in the same time");
418 }
399 }
419 else {
400 else {
420 qCWarning(LOG_VariableController())
401 qCWarning(LOG_VariableController())
421 << tr("There is no variable selected to set the time one");
402 << tr("There is no variable selected to set the time one");
422 }
403 }
423 }
404 }
424
405
425 void VariableController::onUpdateDateTime(std::shared_ptr<Variable> variable,
406 void VariableController::onUpdateDateTime(std::shared_ptr<Variable> variable,
426 const SqpRange &dateTime)
407 const SqpRange &dateTime)
427 {
408 {
428 auto itVar = impl->m_VariableToIdentifierMap.find(variable);
409 auto itVar = impl->m_VariableToIdentifierMap.find(variable);
429 if (itVar == impl->m_VariableToIdentifierMap.cend()) {
410 if (itVar == impl->m_VariableToIdentifierMap.cend()) {
430 qCCritical(LOG_VariableController())
411 qCCritical(LOG_VariableController())
431 << tr("Impossible to onDateTimeOnSelection request for unknown variable");
412 << tr("Impossible to onDateTimeOnSelection request for unknown variable");
432 return;
413 return;
433 }
414 }
434
415
435 // notify that rescale operation has to be done
416 // notify that rescale operation has to be done
436 emit rangeChanged(variable, dateTime);
417 emit rangeChanged(variable, dateTime);
437
418
438 auto synchro
419 auto synchro
439 = impl->m_VariableIdGroupIdMap.find(itVar->second) != impl->m_VariableIdGroupIdMap.cend();
420 = impl->m_VariableIdGroupIdMap.find(itVar->second) != impl->m_VariableIdGroupIdMap.cend();
440
421
441 this->onRequestDataLoading(QVector<std::shared_ptr<Variable> >{variable}, dateTime, synchro);
422 this->onRequestDataLoading(QVector<std::shared_ptr<Variable> >{variable}, dateTime, synchro);
442 }
423 }
443
424
444 void VariableController::onDataProvided(QUuid vIdentifier, const SqpRange &rangeRequested,
425 void VariableController::onDataProvided(QUuid vIdentifier,
445 const SqpRange &cacheRangeRequested,
446 QVector<AcquisitionDataPacket> dataAcquired)
426 QVector<AcquisitionDataPacket> dataAcquired)
447 {
427 {
448 qCDebug(LOG_VariableController()) << tr("onDataProvided") << QThread::currentThread();
428 qCDebug(LOG_VariableController()) << tr("onDataProvided") << QThread::currentThread();
449 auto retrievedDataSeries = impl->retrieveDataSeries(dataAcquired);
429 auto retrievedDataSeries = impl->retrieveDataSeries(dataAcquired);
450 auto varRequestId = impl->acceptVariableRequest(vIdentifier, retrievedDataSeries);
430 auto varRequestId = impl->acceptVariableRequest(vIdentifier, retrievedDataSeries);
451 if (!varRequestId.isNull()) {
431 if (!varRequestId.isNull()) {
452 impl->updateVariables(varRequestId);
432 impl->updateVariables(varRequestId);
453 }
433 }
454 }
434 }
455
435
456 void VariableController::onVariableRetrieveDataInProgress(QUuid identifier, double progress)
436 void VariableController::onVariableRetrieveDataInProgress(QUuid identifier, double progress)
457 {
437 {
458 qCDebug(LOG_VariableController())
438 qCDebug(LOG_VariableController())
459 << "TORM: variableController::onVariableRetrieveDataInProgress"
439 << "TORM: variableController::onVariableRetrieveDataInProgress"
460 << QThread::currentThread()->objectName() << progress;
440 << QThread::currentThread()->objectName() << progress;
461 if (auto var = impl->findVariable(identifier)) {
441 if (auto var = impl->findVariable(identifier)) {
442 qCDebug(LOG_VariableController())
443 << "TORM: variableController::onVariableRetrieveDataInProgress FOUND";
462 impl->m_VariableModel->setDataProgress(var, progress);
444 impl->m_VariableModel->setDataProgress(var, progress);
463 }
445 }
464 else {
446 else {
465 qCCritical(LOG_VariableController())
447 qCCritical(LOG_VariableController())
466 << tr("Impossible to notify progression of a null variable");
448 << tr("Impossible to notify progression of a null variable");
467 }
449 }
468 }
450 }
469
451
470 void VariableController::onAbortProgressRequested(std::shared_ptr<Variable> variable)
452 void VariableController::onAbortProgressRequested(std::shared_ptr<Variable> variable)
471 {
453 {
472 qCDebug(LOG_VariableController()) << "TORM: variableController::onAbortProgressRequested"
454 qCDebug(LOG_VariableController()) << "TORM: variableController::onAbortProgressRequested"
473 << QThread::currentThread()->objectName() << variable->name();
455 << QThread::currentThread()->objectName() << variable->name();
474
456
475 auto itVar = impl->m_VariableToIdentifierMap.find(variable);
457 auto itVar = impl->m_VariableToIdentifierMap.find(variable);
476 if (itVar == impl->m_VariableToIdentifierMap.cend()) {
458 if (itVar == impl->m_VariableToIdentifierMap.cend()) {
477 qCCritical(LOG_VariableController())
459 qCCritical(LOG_VariableController())
478 << tr("Impossible to onAbortProgressRequested request for unknown variable");
460 << tr("Impossible to onAbortProgressRequested request for unknown variable");
479 return;
461 return;
480 }
462 }
481
463
482 auto varId = itVar->second;
464 auto varId = itVar->second;
483
465
484 auto itVarHandler = impl->m_VarIdToVarRequestHandler.find(varId);
466 auto itVarHandler = impl->m_VarIdToVarRequestHandler.find(varId);
485 if (itVarHandler == impl->m_VarIdToVarRequestHandler.cend()) {
467 if (itVarHandler == impl->m_VarIdToVarRequestHandler.cend()) {
486 qCCritical(LOG_VariableController())
468 qCCritical(LOG_VariableController())
487 << tr("Impossible to onAbortProgressRequested for variable with unknown handler");
469 << tr("Impossible to onAbortProgressRequested for variable with unknown handler");
488 return;
470 return;
489 }
471 }
490
472
491 auto varHandler = itVarHandler->second.get();
473 auto varHandler = itVarHandler->second.get();
492
474
493 // case where a variable has a running request
475 // case where a variable has a running request
494 if (varHandler->m_State != VariableRequestHandlerState::OFF) {
476 if (varHandler->m_State != VariableRequestHandlerState::OFF) {
495 impl->cancelVariableRequest(varHandler->m_RunningVarRequest.m_VariableGroupId);
477 impl->cancelVariableRequest(varHandler->m_RunningVarRequest.m_VariableGroupId);
496 }
478 }
497 }
479 }
498
480
499 void VariableController::onAbortAcquisitionRequested(QUuid vIdentifier)
481 void VariableController::onAbortAcquisitionRequested(QUuid vIdentifier)
500 {
482 {
501 qCDebug(LOG_VariableController()) << "TORM: variableController::onAbortAcquisitionRequested"
483 qCDebug(LOG_VariableController()) << "TORM: variableController::onAbortAcquisitionRequested"
502 << QThread::currentThread()->objectName() << vIdentifier;
484 << QThread::currentThread()->objectName() << vIdentifier;
503
485
504 if (auto var = impl->findVariable(vIdentifier)) {
486 if (auto var = impl->findVariable(vIdentifier)) {
505 this->onAbortProgressRequested(var);
487 this->onAbortProgressRequested(var);
506 }
488 }
507 else {
489 else {
508 qCCritical(LOG_VariableController())
490 qCCritical(LOG_VariableController())
509 << tr("Impossible to abort Acquisition Requestof a null variable");
491 << tr("Impossible to abort Acquisition Requestof a null variable");
510 }
492 }
511 }
493 }
512
494
513 void VariableController::onAddSynchronizationGroupId(QUuid synchronizationGroupId)
495 void VariableController::onAddSynchronizationGroupId(QUuid synchronizationGroupId)
514 {
496 {
515 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronizationGroupId"
497 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronizationGroupId"
516 << QThread::currentThread()->objectName()
498 << QThread::currentThread()->objectName()
517 << synchronizationGroupId;
499 << synchronizationGroupId;
518 auto vSynchroGroup = std::make_shared<VariableSynchronizationGroup>();
500 auto vSynchroGroup = std::make_shared<VariableSynchronizationGroup>();
519 impl->m_GroupIdToVariableSynchronizationGroupMap.insert(
501 impl->m_GroupIdToVariableSynchronizationGroupMap.insert(
520 std::make_pair(synchronizationGroupId, vSynchroGroup));
502 std::make_pair(synchronizationGroupId, vSynchroGroup));
521 }
503 }
522
504
523 void VariableController::onRemoveSynchronizationGroupId(QUuid synchronizationGroupId)
505 void VariableController::onRemoveSynchronizationGroupId(QUuid synchronizationGroupId)
524 {
506 {
525 impl->m_GroupIdToVariableSynchronizationGroupMap.erase(synchronizationGroupId);
507 impl->m_GroupIdToVariableSynchronizationGroupMap.erase(synchronizationGroupId);
526 }
508 }
527
509
528 void VariableController::onAddSynchronized(std::shared_ptr<Variable> variable,
510 void VariableController::onAddSynchronized(std::shared_ptr<Variable> variable,
529 QUuid synchronizationGroupId)
511 QUuid synchronizationGroupId)
530
512
531 {
513 {
532 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronized"
514 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronized"
533 << synchronizationGroupId;
515 << synchronizationGroupId;
534 auto varToVarIdIt = impl->m_VariableToIdentifierMap.find(variable);
516 auto varToVarIdIt = impl->m_VariableToIdentifierMap.find(variable);
535 if (varToVarIdIt != impl->m_VariableToIdentifierMap.cend()) {
517 if (varToVarIdIt != impl->m_VariableToIdentifierMap.cend()) {
536 auto groupIdToVSGIt
518 auto groupIdToVSGIt
537 = impl->m_GroupIdToVariableSynchronizationGroupMap.find(synchronizationGroupId);
519 = impl->m_GroupIdToVariableSynchronizationGroupMap.find(synchronizationGroupId);
538 if (groupIdToVSGIt != impl->m_GroupIdToVariableSynchronizationGroupMap.cend()) {
520 if (groupIdToVSGIt != impl->m_GroupIdToVariableSynchronizationGroupMap.cend()) {
539 impl->m_VariableIdGroupIdMap.insert(
521 impl->m_VariableIdGroupIdMap.insert(
540 std::make_pair(varToVarIdIt->second, synchronizationGroupId));
522 std::make_pair(varToVarIdIt->second, synchronizationGroupId));
541 groupIdToVSGIt->second->addVariableId(varToVarIdIt->second);
523 groupIdToVSGIt->second->addVariableId(varToVarIdIt->second);
542 }
524 }
543 else {
525 else {
544 qCCritical(LOG_VariableController())
526 qCCritical(LOG_VariableController())
545 << tr("Impossible to synchronize a variable with an unknown sycnhronization group")
527 << tr("Impossible to synchronize a variable with an unknown sycnhronization group")
546 << variable->name();
528 << variable->name();
547 }
529 }
548 }
530 }
549 else {
531 else {
550 qCCritical(LOG_VariableController())
532 qCCritical(LOG_VariableController())
551 << tr("Impossible to synchronize a variable with no identifier") << variable->name();
533 << tr("Impossible to synchronize a variable with no identifier") << variable->name();
552 }
534 }
553 }
535 }
554
536
555 void VariableController::desynchronize(std::shared_ptr<Variable> variable,
537 void VariableController::desynchronize(std::shared_ptr<Variable> variable,
556 QUuid synchronizationGroupId)
538 QUuid synchronizationGroupId)
557 {
539 {
558 // Gets variable id
540 // Gets variable id
559 auto variableIt = impl->m_VariableToIdentifierMap.find(variable);
541 auto variableIt = impl->m_VariableToIdentifierMap.find(variable);
560 if (variableIt == impl->m_VariableToIdentifierMap.cend()) {
542 if (variableIt == impl->m_VariableToIdentifierMap.cend()) {
561 qCCritical(LOG_VariableController())
543 qCCritical(LOG_VariableController())
562 << tr("Can't desynchronize variable %1: variable identifier not found")
544 << tr("Can't desynchronize variable %1: variable identifier not found")
563 .arg(variable->name());
545 .arg(variable->name());
564 return;
546 return;
565 }
547 }
566
548
567 impl->desynchronize(variableIt, synchronizationGroupId);
549 impl->desynchronize(variableIt, synchronizationGroupId);
568 }
550 }
569
551
570 void VariableController::onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables,
552 void VariableController::onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables,
571 const SqpRange &range, bool synchronise)
553 const SqpRange &range, bool synchronise)
572 {
554 {
573 // variables is assumed synchronized
555 // variables is assumed synchronized
574 // TODO: Asser variables synchronization
556 // TODO: Asser variables synchronization
575 // we want to load data of the variable for the dateTime.
557 // we want to load data of the variable for the dateTime.
576 if (variables.isEmpty()) {
558 if (variables.isEmpty()) {
577 return;
559 return;
578 }
560 }
579
561
580 auto varRequestId = QUuid::createUuid();
562 auto varRequestId = QUuid::createUuid();
581 qCDebug(LOG_VariableController()) << "VariableController::onRequestDataLoading"
563 qCDebug(LOG_VariableController()) << "VariableController::onRequestDataLoading"
582 << QThread::currentThread()->objectName() << varRequestId
564 << QThread::currentThread()->objectName() << varRequestId
583 << range << synchronise;
565 << range << synchronise;
584
566
585 if (!synchronise) {
567 if (!synchronise) {
586 auto varIds = std::list<QUuid>{};
568 auto varIds = std::list<QUuid>{};
587 for (const auto &var : variables) {
569 for (const auto &var : variables) {
588 auto vId = impl->m_VariableToIdentifierMap.at(var);
570 auto vId = impl->m_VariableToIdentifierMap.at(var);
589 varIds.push_back(vId);
571 varIds.push_back(vId);
590 }
572 }
591 impl->m_VarGroupIdToVarIds.insert(std::make_pair(varRequestId, varIds));
573 impl->m_VarGroupIdToVarIds.insert(std::make_pair(varRequestId, varIds));
592 for (const auto &var : variables) {
574 for (const auto &var : variables) {
593 qCDebug(LOG_VariableController()) << "processRequest for" << var->name() << varRequestId
575 qCDebug(LOG_VariableController()) << "onRequestDataLoading: for" << varRequestId
594 << varIds.size();
576 << varIds.size();
595 impl->processRequest(var, range, varRequestId);
577 impl->processRequest(var, range, varRequestId);
596 }
578 }
597 }
579 }
598 else {
580 else {
599 auto vId = impl->m_VariableToIdentifierMap.at(variables.first());
581 auto vId = impl->m_VariableToIdentifierMap.at(variables.first());
600 auto varIdToGroupIdIt = impl->m_VariableIdGroupIdMap.find(vId);
582 auto varIdToGroupIdIt = impl->m_VariableIdGroupIdMap.find(vId);
601 if (varIdToGroupIdIt != impl->m_VariableIdGroupIdMap.cend()) {
583 if (varIdToGroupIdIt != impl->m_VariableIdGroupIdMap.cend()) {
602 auto groupId = varIdToGroupIdIt->second;
584 auto groupId = varIdToGroupIdIt->second;
603
585
604 auto vSynchronizationGroup
586 auto vSynchronizationGroup
605 = impl->m_GroupIdToVariableSynchronizationGroupMap.at(groupId);
587 = impl->m_GroupIdToVariableSynchronizationGroupMap.at(groupId);
606 auto vSyncIds = vSynchronizationGroup->getIds();
588 auto vSyncIds = vSynchronizationGroup->getIds();
607
589
608 auto varIds = std::list<QUuid>{};
590 auto varIds = std::list<QUuid>{};
609 for (auto vId : vSyncIds) {
591 for (auto vId : vSyncIds) {
610 varIds.push_back(vId);
592 varIds.push_back(vId);
611 }
593 }
594 qCDebug(LOG_VariableController()) << "onRequestDataLoading sync: for" << varRequestId
595 << varIds.size();
612 impl->m_VarGroupIdToVarIds.insert(std::make_pair(varRequestId, varIds));
596 impl->m_VarGroupIdToVarIds.insert(std::make_pair(varRequestId, varIds));
613
597
614 for (auto vId : vSyncIds) {
598 for (auto vId : vSyncIds) {
615 auto var = impl->findVariable(vId);
599 auto var = impl->findVariable(vId);
616
600
617 // Don't process already processed var
601 // Don't process already processed var
618 if (var != nullptr) {
602 if (var != nullptr) {
619 qCDebug(LOG_VariableController()) << "processRequest synchro for" << var->name()
603 qCDebug(LOG_VariableController()) << "processRequest synchro for" << var->name()
620 << varRequestId;
604 << varRequestId;
621 auto vSyncRangeRequested
605 auto vSyncRangeRequested
622 = variables.contains(var)
606 = variables.contains(var)
623 ? range
607 ? range
624 : computeSynchroRangeRequested(var->range(), range,
608 : computeSynchroRangeRequested(var->range(), range,
625 variables.first()->range());
609 variables.first()->range());
626 qCDebug(LOG_VariableController()) << "synchro RR" << vSyncRangeRequested;
610 qCDebug(LOG_VariableController()) << "synchro RR" << vSyncRangeRequested;
627 impl->processRequest(var, vSyncRangeRequested, varRequestId);
611 impl->processRequest(var, vSyncRangeRequested, varRequestId);
628 }
612 }
629 else {
613 else {
630 qCCritical(LOG_VariableController())
614 qCCritical(LOG_VariableController())
631
615
632 << tr("Impossible to synchronize a null variable");
616 << tr("Impossible to synchronize a null variable");
633 }
617 }
634 }
618 }
635 }
619 }
636 }
620 }
637
621
638 impl->updateVariables(varRequestId);
622 impl->updateVariables(varRequestId);
639 }
623 }
640
624
641
625
642 void VariableController::initialize()
626 void VariableController::initialize()
643 {
627 {
644 qCDebug(LOG_VariableController()) << tr("VariableController init") << QThread::currentThread();
628 qCDebug(LOG_VariableController()) << tr("VariableController init") << QThread::currentThread();
645 impl->m_WorkingMutex.lock();
629 impl->m_WorkingMutex.lock();
646 qCDebug(LOG_VariableController()) << tr("VariableController init END");
630 qCDebug(LOG_VariableController()) << tr("VariableController init END");
647 }
631 }
648
632
649 void VariableController::finalize()
633 void VariableController::finalize()
650 {
634 {
651 impl->m_WorkingMutex.unlock();
635 impl->m_WorkingMutex.unlock();
652 }
636 }
653
637
654 void VariableController::waitForFinish()
638 void VariableController::waitForFinish()
655 {
639 {
656 QMutexLocker locker{&impl->m_WorkingMutex};
640 QMutexLocker locker{&impl->m_WorkingMutex};
657 }
641 }
658
642
659 AcquisitionZoomType VariableController::getZoomType(const SqpRange &range, const SqpRange &oldRange)
643 AcquisitionZoomType VariableController::getZoomType(const SqpRange &range, const SqpRange &oldRange)
660 {
644 {
661 // t1.m_TStart <= t2.m_TStart && t2.m_TEnd <= t1.m_TEnd
645 // t1.m_TStart <= t2.m_TStart && t2.m_TEnd <= t1.m_TEnd
662 auto zoomType = AcquisitionZoomType::Unknown;
646 auto zoomType = AcquisitionZoomType::Unknown;
663 if (range.m_TStart <= oldRange.m_TStart && oldRange.m_TEnd <= range.m_TEnd) {
647 if (range.m_TStart <= oldRange.m_TStart && oldRange.m_TEnd <= range.m_TEnd) {
664 qCDebug(LOG_VariableController()) << "zoomtype: ZoomOut";
648 qCDebug(LOG_VariableController()) << "zoomtype: ZoomOut";
665 zoomType = AcquisitionZoomType::ZoomOut;
649 zoomType = AcquisitionZoomType::ZoomOut;
666 }
650 }
667 else if (range.m_TStart > oldRange.m_TStart && range.m_TEnd > oldRange.m_TEnd) {
651 else if (range.m_TStart > oldRange.m_TStart && range.m_TEnd > oldRange.m_TEnd) {
668 qCDebug(LOG_VariableController()) << "zoomtype: PanRight";
652 qCDebug(LOG_VariableController()) << "zoomtype: PanRight";
669 zoomType = AcquisitionZoomType::PanRight;
653 zoomType = AcquisitionZoomType::PanRight;
670 }
654 }
671 else if (range.m_TStart < oldRange.m_TStart && range.m_TEnd < oldRange.m_TEnd) {
655 else if (range.m_TStart < oldRange.m_TStart && range.m_TEnd < oldRange.m_TEnd) {
672 qCDebug(LOG_VariableController()) << "zoomtype: PanLeft";
656 qCDebug(LOG_VariableController()) << "zoomtype: PanLeft";
673 zoomType = AcquisitionZoomType::PanLeft;
657 zoomType = AcquisitionZoomType::PanLeft;
674 }
658 }
675 else if (range.m_TStart >= oldRange.m_TStart && oldRange.m_TEnd >= range.m_TEnd) {
659 else if (range.m_TStart >= oldRange.m_TStart && oldRange.m_TEnd >= range.m_TEnd) {
676 qCDebug(LOG_VariableController()) << "zoomtype: ZoomIn";
660 qCDebug(LOG_VariableController()) << "zoomtype: ZoomIn";
677 zoomType = AcquisitionZoomType::ZoomIn;
661 zoomType = AcquisitionZoomType::ZoomIn;
678 }
662 }
679 else {
663 else {
680 qCDebug(LOG_VariableController()) << "getZoomType: Unknown type detected";
664 qCDebug(LOG_VariableController()) << "getZoomType: Unknown type detected";
681 }
665 }
682 return zoomType;
666 return zoomType;
683 }
667 }
684
668
685 void VariableController::VariableControllerPrivate::processRequest(std::shared_ptr<Variable> var,
669 void VariableController::VariableControllerPrivate::processRequest(std::shared_ptr<Variable> var,
686 const SqpRange &rangeRequested,
670 const SqpRange &rangeRequested,
687 QUuid varRequestId)
671 QUuid varRequestId)
688 {
672 {
689 auto itVar = m_VariableToIdentifierMap.find(var);
673 auto itVar = m_VariableToIdentifierMap.find(var);
690 if (itVar == m_VariableToIdentifierMap.cend()) {
674 if (itVar == m_VariableToIdentifierMap.cend()) {
691 qCCritical(LOG_VariableController())
675 qCCritical(LOG_VariableController())
692 << tr("Impossible to process request for unknown variable");
676 << tr("Impossible to process request for unknown variable");
693 return;
677 return;
694 }
678 }
695
679
696 auto varId = itVar->second;
680 auto varId = itVar->second;
697
681
698 auto itVarHandler = m_VarIdToVarRequestHandler.find(varId);
682 auto itVarHandler = m_VarIdToVarRequestHandler.find(varId);
699 if (itVarHandler == m_VarIdToVarRequestHandler.cend()) {
683 if (itVarHandler == m_VarIdToVarRequestHandler.cend()) {
700 qCCritical(LOG_VariableController())
684 qCCritical(LOG_VariableController())
701 << tr("Impossible to process request for variable with unknown handler");
685 << tr("Impossible to process request for variable with unknown handler");
702 return;
686 return;
703 }
687 }
704
688
705 auto oldRange = var->range();
689 auto oldRange = var->range();
706
690
707 auto varHandler = itVarHandler->second.get();
691 auto varHandler = itVarHandler->second.get();
708
692
709 if (varHandler->m_State != VariableRequestHandlerState::OFF) {
693 if (varHandler->m_State != VariableRequestHandlerState::OFF) {
710 oldRange = varHandler->m_RunningVarRequest.m_RangeRequested;
694 oldRange = varHandler->m_RunningVarRequest.m_RangeRequested;
711 }
695 }
712
696
713 auto varRequest = VariableRequest{};
697 auto varRequest = VariableRequest{};
714 varRequest.m_VariableGroupId = varRequestId;
698 varRequest.m_VariableGroupId = varRequestId;
715 auto varStrategyRangesRequested
699 auto varStrategyRangesRequested
716 = m_VariableCacheStrategy->computeRange(oldRange, rangeRequested);
700 = m_VariableCacheStrategy->computeRange(oldRange, rangeRequested);
717 varRequest.m_RangeRequested = varStrategyRangesRequested.first;
701 varRequest.m_RangeRequested = varStrategyRangesRequested.first;
718 varRequest.m_CacheRangeRequested = varStrategyRangesRequested.second;
702 varRequest.m_CacheRangeRequested = varStrategyRangesRequested.second;
719
703
720 switch (varHandler->m_State) {
704 switch (varHandler->m_State) {
721 case VariableRequestHandlerState::OFF: {
705 case VariableRequestHandlerState::OFF: {
722 qCDebug(LOG_VariableController()) << tr("Process Request OFF")
706 qCDebug(LOG_VariableController()) << tr("Process Request OFF")
723 << varRequest.m_RangeRequested
707 << varRequest.m_RangeRequested
724 << varRequest.m_CacheRangeRequested;
708 << varRequest.m_CacheRangeRequested;
725 varHandler->m_RunningVarRequest = varRequest;
709 varHandler->m_RunningVarRequest = varRequest;
726 varHandler->m_State = VariableRequestHandlerState::RUNNING;
710 varHandler->m_State = VariableRequestHandlerState::RUNNING;
727 executeVarRequest(var, varRequest);
711 executeVarRequest(var, varRequest);
728 break;
712 break;
729 }
713 }
730 case VariableRequestHandlerState::RUNNING: {
714 case VariableRequestHandlerState::RUNNING: {
731 qCDebug(LOG_VariableController()) << tr("Process Request RUNNING")
715 qCDebug(LOG_VariableController()) << tr("Process Request RUNNING")
732 << varRequest.m_RangeRequested
716 << varRequest.m_RangeRequested
733 << varRequest.m_CacheRangeRequested;
717 << varRequest.m_CacheRangeRequested;
734 varHandler->m_State = VariableRequestHandlerState::PENDING;
718 varHandler->m_State = VariableRequestHandlerState::PENDING;
735 varHandler->m_PendingVarRequest = varRequest;
719 varHandler->m_PendingVarRequest = varRequest;
736 break;
720 break;
737 }
721 }
738 case VariableRequestHandlerState::PENDING: {
722 case VariableRequestHandlerState::PENDING: {
739 qCDebug(LOG_VariableController()) << tr("Process Request PENDING")
723 qCDebug(LOG_VariableController()) << tr("Process Request PENDING")
740 << varRequest.m_RangeRequested
724 << varRequest.m_RangeRequested
741 << varRequest.m_CacheRangeRequested;
725 << varRequest.m_CacheRangeRequested;
742 auto variableGroupIdToCancel = varHandler->m_PendingVarRequest.m_VariableGroupId;
726 auto variableGroupIdToCancel = varHandler->m_PendingVarRequest.m_VariableGroupId;
743 cancelVariableRequest(variableGroupIdToCancel);
727 cancelVariableRequest(variableGroupIdToCancel);
744 // Cancel variable can make state downgrade
728 // Cancel variable can make state downgrade
745 varHandler->m_State = VariableRequestHandlerState::PENDING;
729 varHandler->m_State = VariableRequestHandlerState::PENDING;
746 varHandler->m_PendingVarRequest = varRequest;
730 varHandler->m_PendingVarRequest = varRequest;
747
731
748 break;
732 break;
749 }
733 }
750 default:
734 default:
751 qCCritical(LOG_VariableController())
735 qCCritical(LOG_VariableController())
752 << QObject::tr("Unknown VariableRequestHandlerState");
736 << QObject::tr("Unknown VariableRequestHandlerState");
753 }
737 }
754 }
738 }
755
739
756 std::shared_ptr<Variable>
740 std::shared_ptr<Variable>
757 VariableController::VariableControllerPrivate::findVariable(QUuid vIdentifier)
741 VariableController::VariableControllerPrivate::findVariable(QUuid vIdentifier)
758 {
742 {
759 std::shared_ptr<Variable> var;
743 std::shared_ptr<Variable> var;
760 auto findReply = [vIdentifier](const auto &entry) { return vIdentifier == entry.second; };
744 auto findReply = [vIdentifier](const auto &entry) { return vIdentifier == entry.second; };
761
745
762 auto end = m_VariableToIdentifierMap.cend();
746 auto end = m_VariableToIdentifierMap.cend();
763 auto it = std::find_if(m_VariableToIdentifierMap.cbegin(), end, findReply);
747 auto it = std::find_if(m_VariableToIdentifierMap.cbegin(), end, findReply);
764 if (it != end) {
748 if (it != end) {
765 var = it->first;
749 var = it->first;
766 }
750 }
767 else {
751 else {
768 qCCritical(LOG_VariableController())
752 qCCritical(LOG_VariableController())
769 << tr("Impossible to find the variable with the identifier: ") << vIdentifier;
753 << tr("Impossible to find the variable with the identifier: ") << vIdentifier;
770 }
754 }
771
755
772 return var;
756 return var;
773 }
757 }
774
758
775 std::shared_ptr<IDataSeries> VariableController::VariableControllerPrivate::retrieveDataSeries(
759 std::shared_ptr<IDataSeries> VariableController::VariableControllerPrivate::retrieveDataSeries(
776 const QVector<AcquisitionDataPacket> acqDataPacketVector)
760 const QVector<AcquisitionDataPacket> acqDataPacketVector)
777 {
761 {
778 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size")
762 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size")
779 << acqDataPacketVector.size();
763 << acqDataPacketVector.size();
780 std::shared_ptr<IDataSeries> dataSeries;
764 std::shared_ptr<IDataSeries> dataSeries;
781 if (!acqDataPacketVector.isEmpty()) {
765 if (!acqDataPacketVector.isEmpty()) {
782 dataSeries = acqDataPacketVector[0].m_DateSeries;
766 dataSeries = acqDataPacketVector[0].m_DateSeries;
783 for (int i = 1; i < acqDataPacketVector.size(); ++i) {
767 for (int i = 1; i < acqDataPacketVector.size(); ++i) {
784 dataSeries->merge(acqDataPacketVector[i].m_DateSeries.get());
768 dataSeries->merge(acqDataPacketVector[i].m_DateSeries.get());
785 }
769 }
786 }
770 }
787 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size END")
771 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size END")
788 << acqDataPacketVector.size();
772 << acqDataPacketVector.size();
789 return dataSeries;
773 return dataSeries;
790 }
774 }
791
775
792 void VariableController::VariableControllerPrivate::registerProvider(
776 void VariableController::VariableControllerPrivate::registerProvider(
793 std::shared_ptr<IDataProvider> provider)
777 std::shared_ptr<IDataProvider> provider)
794 {
778 {
795 if (m_ProviderSet.find(provider) == m_ProviderSet.end()) {
779 if (m_ProviderSet.find(provider) == m_ProviderSet.end()) {
796 qCDebug(LOG_VariableController()) << tr("Registering of a new provider")
780 qCDebug(LOG_VariableController()) << tr("Registering of a new provider")
797 << provider->objectName();
781 << provider->objectName();
798 m_ProviderSet.insert(provider);
782 m_ProviderSet.insert(provider);
799 connect(provider.get(), &IDataProvider::dataProvided, m_VariableAcquisitionWorker.get(),
783 connect(provider.get(), &IDataProvider::dataProvided, m_VariableAcquisitionWorker.get(),
800 &VariableAcquisitionWorker::onVariableDataAcquired);
784 &VariableAcquisitionWorker::onVariableDataAcquired);
801 connect(provider.get(), &IDataProvider::dataProvidedProgress,
785 connect(provider.get(), &IDataProvider::dataProvidedProgress,
802 m_VariableAcquisitionWorker.get(),
786 m_VariableAcquisitionWorker.get(),
803 &VariableAcquisitionWorker::onVariableRetrieveDataInProgress);
787 &VariableAcquisitionWorker::onVariableRetrieveDataInProgress);
804 connect(provider.get(), &IDataProvider::dataProvidedFailed,
788 connect(provider.get(), &IDataProvider::dataProvidedFailed,
805 m_VariableAcquisitionWorker.get(),
789 m_VariableAcquisitionWorker.get(),
806 &VariableAcquisitionWorker::onVariableAcquisitionFailed);
790 &VariableAcquisitionWorker::onVariableAcquisitionFailed);
807 }
791 }
808 else {
792 else {
809 qCDebug(LOG_VariableController()) << tr("Cannot register provider, it already exists ");
793 qCDebug(LOG_VariableController()) << tr("Cannot register provider, it already exists ");
810 }
794 }
811 }
795 }
812
796
813 QUuid VariableController::VariableControllerPrivate::acceptVariableRequest(
797 QUuid VariableController::VariableControllerPrivate::acceptVariableRequest(
814 QUuid varId, std::shared_ptr<IDataSeries> dataSeries)
798 QUuid varId, std::shared_ptr<IDataSeries> dataSeries)
815 {
799 {
816 auto itVarHandler = m_VarIdToVarRequestHandler.find(varId);
800 auto itVarHandler = m_VarIdToVarRequestHandler.find(varId);
817 if (itVarHandler == m_VarIdToVarRequestHandler.cend()) {
801 if (itVarHandler == m_VarIdToVarRequestHandler.cend()) {
818 return QUuid();
802 return QUuid();
819 }
803 }
820
804
821 auto varHandler = itVarHandler->second.get();
805 auto varHandler = itVarHandler->second.get();
822 if (varHandler->m_State == VariableRequestHandlerState::OFF) {
806 if (varHandler->m_State == VariableRequestHandlerState::OFF) {
823 qCCritical(LOG_VariableController())
807 qCCritical(LOG_VariableController())
824 << tr("acceptVariableRequest impossible on a variable with OFF state");
808 << tr("acceptVariableRequest impossible on a variable with OFF state");
825 }
809 }
826
810
827 varHandler->m_RunningVarRequest.m_DataSeries = dataSeries;
811 varHandler->m_RunningVarRequest.m_DataSeries = dataSeries;
828 varHandler->m_CanUpdate = true;
812 varHandler->m_CanUpdate = true;
829
813
830 // Element traitΓ©, on a dΓ©jΓ  toutes les donnΓ©es necessaires
814 // Element traitΓ©, on a dΓ©jΓ  toutes les donnΓ©es necessaires
831 auto varGroupId = varHandler->m_RunningVarRequest.m_VariableGroupId;
815 auto varGroupId = varHandler->m_RunningVarRequest.m_VariableGroupId;
832 qCDebug(LOG_VariableController()) << "Variable::acceptVariableRequest" << varGroupId
816 qCDebug(LOG_VariableController()) << "Variable::acceptVariableRequest" << varGroupId
833 << m_VarGroupIdToVarIds.size();
817 << m_VarGroupIdToVarIds.size();
834
818
835 return varHandler->m_RunningVarRequest.m_VariableGroupId;
819 return varHandler->m_RunningVarRequest.m_VariableGroupId;
836 }
820 }
837
821
838 void VariableController::VariableControllerPrivate::updateVariables(QUuid varRequestId)
822 void VariableController::VariableControllerPrivate::updateVariables(QUuid varRequestId)
839 {
823 {
840 qCDebug(LOG_VariableController()) << "VariableControllerPrivate::updateVariables"
824 qCDebug(LOG_VariableController()) << "VariableControllerPrivate::updateVariables"
841 << QThread::currentThread()->objectName() << varRequestId;
825 << QThread::currentThread()->objectName() << varRequestId;
842
826
843 auto varGroupIdToVarIdsIt = m_VarGroupIdToVarIds.find(varRequestId);
827 auto varGroupIdToVarIdsIt = m_VarGroupIdToVarIds.find(varRequestId);
844 if (varGroupIdToVarIdsIt == m_VarGroupIdToVarIds.end()) {
828 if (varGroupIdToVarIdsIt == m_VarGroupIdToVarIds.end()) {
845 qCWarning(LOG_VariableController())
829 qCWarning(LOG_VariableController())
846 << tr("Impossible to updateVariables of unknown variables") << varRequestId;
830 << tr("Impossible to updateVariables of unknown variables") << varRequestId;
847 return;
831 return;
848 }
832 }
849
833
850 auto &varIds = varGroupIdToVarIdsIt->second;
834 auto &varIds = varGroupIdToVarIdsIt->second;
851 auto varIdsEnd = varIds.end();
835 auto varIdsEnd = varIds.end();
852 bool processVariableUpdate = true;
836 bool processVariableUpdate = true;
853 qCDebug(LOG_VariableController()) << "VariableControllerPrivate::updateVariables"
854 << varRequestId << varIds.size();
855 for (auto varIdsIt = varIds.begin(); (varIdsIt != varIdsEnd) && processVariableUpdate;
837 for (auto varIdsIt = varIds.begin(); (varIdsIt != varIdsEnd) && processVariableUpdate;
856 ++varIdsIt) {
838 ++varIdsIt) {
857 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
839 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
858 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
840 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
859 processVariableUpdate &= itVarHandler->second->m_CanUpdate;
841 processVariableUpdate &= itVarHandler->second->m_CanUpdate;
860 }
842 }
861 }
843 }
862
844
863 if (processVariableUpdate) {
845 if (processVariableUpdate) {
864 qCDebug(LOG_VariableController()) << "Final update OK for the var request" << varIds.size();
865 for (auto varIdsIt = varIds.begin(); varIdsIt != varIdsEnd; ++varIdsIt) {
846 for (auto varIdsIt = varIds.begin(); varIdsIt != varIdsEnd; ++varIdsIt) {
866 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
847 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
867 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
848 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
868 if (auto var = findVariable(*varIdsIt)) {
849 if (auto var = findVariable(*varIdsIt)) {
869 auto &varRequest = itVarHandler->second->m_RunningVarRequest;
850 auto &varRequest = itVarHandler->second->m_RunningVarRequest;
870 var->setRange(varRequest.m_RangeRequested);
851 var->setRange(varRequest.m_RangeRequested);
871 var->setCacheRange(varRequest.m_CacheRangeRequested);
852 var->setCacheRange(varRequest.m_CacheRangeRequested);
872 qCDebug(LOG_VariableController()) << tr("1: onDataProvided")
853 qCDebug(LOG_VariableController()) << tr("1: onDataProvided")
873 << varRequest.m_RangeRequested
854 << varRequest.m_RangeRequested
874 << varRequest.m_CacheRangeRequested;
855 << varRequest.m_CacheRangeRequested;
875 qCDebug(LOG_VariableController()) << tr("2: onDataProvided var points before")
856 qCDebug(LOG_VariableController()) << tr("2: onDataProvided var points before")
876 << var->nbPoints()
857 << var->nbPoints()
877 << varRequest.m_DataSeries->nbPoints();
858 << varRequest.m_DataSeries->nbPoints();
878 var->mergeDataSeries(varRequest.m_DataSeries);
859 var->mergeDataSeries(varRequest.m_DataSeries);
879 qCDebug(LOG_VariableController()) << tr("3: onDataProvided var points after")
860 qCDebug(LOG_VariableController()) << tr("3: onDataProvided var points after")
880 << var->nbPoints();
861 << var->nbPoints();
881
862
882 emit var->updated();
863 emit var->updated();
883 qCDebug(LOG_VariableController()) << tr("Update OK");
884 }
864 }
885 else {
865 else {
886 qCCritical(LOG_VariableController())
866 qCCritical(LOG_VariableController())
887 << tr("Impossible to update data to a null variable");
867 << tr("Impossible to update data to a null variable");
888 }
868 }
889 }
869 }
890 }
870 }
891 updateVariableRequest(varRequestId);
871 updateVariableRequest(varRequestId);
892
872
893 // cleaning varRequestId
873 // cleaning varRequestId
894 qCDebug(LOG_VariableController()) << tr("m_VarGroupIdToVarIds erase") << varRequestId;
874 qCDebug(LOG_VariableController()) << tr("m_VarGroupIdToVarIds erase") << varRequestId;
895 m_VarGroupIdToVarIds.erase(varRequestId);
875 m_VarGroupIdToVarIds.erase(varRequestId);
896 if (m_VarGroupIdToVarIds.empty()) {
876 if (m_VarGroupIdToVarIds.empty()) {
897 emit q->acquisitionFinished();
877 emit q->acquisitionFinished();
898 }
878 }
899 }
879 }
900 }
880 }
901
881
902
882
903 void VariableController::VariableControllerPrivate::updateVariableRequest(QUuid varRequestId)
883 void VariableController::VariableControllerPrivate::updateVariableRequest(QUuid varRequestId)
904 {
884 {
905 auto varGroupIdToVarIdsIt = m_VarGroupIdToVarIds.find(varRequestId);
885 auto varGroupIdToVarIdsIt = m_VarGroupIdToVarIds.find(varRequestId);
906 if (varGroupIdToVarIdsIt == m_VarGroupIdToVarIds.end()) {
886 if (varGroupIdToVarIdsIt == m_VarGroupIdToVarIds.end()) {
907 qCCritical(LOG_VariableController()) << QObject::tr(
887 qCCritical(LOG_VariableController()) << QObject::tr(
908 "Impossible to updateVariableRequest since varGroupdId isn't here anymore");
888 "Impossible to updateVariableRequest since varGroupdId isn't here anymore");
909
889
910 return;
890 return;
911 }
891 }
912
892
913 auto &varIds = varGroupIdToVarIdsIt->second;
893 auto &varIds = varGroupIdToVarIdsIt->second;
914 auto varIdsEnd = varIds.end();
894 auto varIdsEnd = varIds.end();
895
896 // First pass all canUpdate of handler to false
915 for (auto varIdsIt = varIds.begin(); (varIdsIt != varIdsEnd); ++varIdsIt) {
897 for (auto varIdsIt = varIds.begin(); (varIdsIt != varIdsEnd); ++varIdsIt) {
916 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
898 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
917 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
899 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
918
900
919 auto varHandler = itVarHandler->second.get();
901 auto varHandler = itVarHandler->second.get();
920 varHandler->m_CanUpdate = false;
902 varHandler->m_CanUpdate = false;
903 }
904 }
905 // Second update requests of handler
906 for (auto varIdsIt = varIds.begin(); (varIdsIt != varIdsEnd); ++varIdsIt) {
907 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
908 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
921
909
910 auto varHandler = itVarHandler->second.get();
922
911
923 switch (varHandler->m_State) {
912 switch (varHandler->m_State) {
924 case VariableRequestHandlerState::OFF: {
913 case VariableRequestHandlerState::OFF: {
925 qCCritical(LOG_VariableController())
914 qCCritical(LOG_VariableController())
926 << QObject::tr("Impossible to update a variable with handler in OFF state");
915 << QObject::tr("Impossible to update a variable with handler in OFF state");
927 } break;
916 } break;
928 case VariableRequestHandlerState::RUNNING: {
917 case VariableRequestHandlerState::RUNNING: {
929 varHandler->m_State = VariableRequestHandlerState::OFF;
918 varHandler->m_State = VariableRequestHandlerState::OFF;
930 varHandler->m_RunningVarRequest = VariableRequest{};
919 varHandler->m_RunningVarRequest = VariableRequest{};
931 break;
920 break;
932 }
921 }
933 case VariableRequestHandlerState::PENDING: {
922 case VariableRequestHandlerState::PENDING: {
934 varHandler->m_State = VariableRequestHandlerState::RUNNING;
923 varHandler->m_State = VariableRequestHandlerState::RUNNING;
935 varHandler->m_RunningVarRequest = varHandler->m_PendingVarRequest;
924 varHandler->m_RunningVarRequest = varHandler->m_PendingVarRequest;
936 varHandler->m_PendingVarRequest = VariableRequest{};
925 varHandler->m_PendingVarRequest = VariableRequest{};
937 auto var = findVariable(itVarHandler->first);
926 auto var = findVariable(itVarHandler->first);
938 executeVarRequest(var, varHandler->m_RunningVarRequest);
927 executeVarRequest(var, varHandler->m_RunningVarRequest);
939 updateVariables(varHandler->m_RunningVarRequest.m_VariableGroupId);
928 updateVariables(varHandler->m_RunningVarRequest.m_VariableGroupId);
940 break;
929 break;
941 }
930 }
942 default:
931 default:
943 qCCritical(LOG_VariableController())
932 qCCritical(LOG_VariableController())
944 << QObject::tr("Unknown VariableRequestHandlerState");
933 << QObject::tr("Unknown VariableRequestHandlerState");
945 }
934 }
946 }
935 }
947 }
936 }
948 }
937 }
949
938
950
939
951 void VariableController::VariableControllerPrivate::cancelVariableRequest(QUuid varRequestId)
940 void VariableController::VariableControllerPrivate::cancelVariableRequest(QUuid varRequestId)
952 {
941 {
953 qCDebug(LOG_VariableController()) << tr("cancelVariableRequest") << varRequestId;
942 qCDebug(LOG_VariableController()) << tr("cancelVariableRequest") << varRequestId;
954
943
955 auto varGroupIdToVarIdsIt = m_VarGroupIdToVarIds.find(varRequestId);
944 auto varGroupIdToVarIdsIt = m_VarGroupIdToVarIds.find(varRequestId);
956 if (varGroupIdToVarIdsIt == m_VarGroupIdToVarIds.end()) {
945 if (varGroupIdToVarIdsIt == m_VarGroupIdToVarIds.end()) {
957 qCCritical(LOG_VariableController())
946 qCCritical(LOG_VariableController())
958 << tr("Impossible to cancelVariableRequest for unknown varGroupdId") << varRequestId;
947 << tr("Impossible to cancelVariableRequest for unknown varGroupdId") << varRequestId;
959 return;
948 return;
960 }
949 }
961
950
962 auto &varIds = varGroupIdToVarIdsIt->second;
951 auto &varIds = varGroupIdToVarIdsIt->second;
963 auto varIdsEnd = varIds.end();
952 auto varIdsEnd = varIds.end();
953
954 // First pass all canUpdate of handler to false
955 for (auto varIdsIt = varIds.begin(); (varIdsIt != varIdsEnd); ++varIdsIt) {
956 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
957 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
958
959 auto varHandler = itVarHandler->second.get();
960 varHandler->m_CanUpdate = false;
961 }
962 }
963
964 for (auto varIdsIt = varIds.begin(); (varIdsIt != varIdsEnd); ++varIdsIt) {
964 for (auto varIdsIt = varIds.begin(); (varIdsIt != varIdsEnd); ++varIdsIt) {
965 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
965 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
966 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
966 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
967
967
968 auto varHandler = itVarHandler->second.get();
968 auto varHandler = itVarHandler->second.get();
969 varHandler->m_VarId = QUuid{};
969 varHandler->m_VarId = QUuid{};
970 switch (varHandler->m_State) {
970 switch (varHandler->m_State) {
971 case VariableRequestHandlerState::OFF: {
971 case VariableRequestHandlerState::OFF: {
972 qCWarning(LOG_VariableController())
972 qCWarning(LOG_VariableController())
973 << QObject::tr("Impossible to cancel a variable with no running request");
973 << QObject::tr("Impossible to cancel a variable with no running request");
974 break;
974 break;
975 }
975 }
976 case VariableRequestHandlerState::RUNNING: {
976 case VariableRequestHandlerState::RUNNING: {
977
977
978 if (varHandler->m_RunningVarRequest.m_VariableGroupId == varRequestId) {
978 if (varHandler->m_RunningVarRequest.m_VariableGroupId == varRequestId) {
979 auto var = findVariable(itVarHandler->first);
979 auto var = findVariable(itVarHandler->first);
980 auto varProvider = m_VariableToProviderMap.at(var);
980 auto varProvider = m_VariableToProviderMap.at(var);
981 if (varProvider != nullptr) {
981 if (varProvider != nullptr) {
982 m_VariableAcquisitionWorker->abortProgressRequested(
982 m_VariableAcquisitionWorker->abortProgressRequested(
983 itVarHandler->first);
983 itVarHandler->first);
984 }
984 }
985 m_VariableModel->setDataProgress(var, 0.0);
985 m_VariableModel->setDataProgress(var, 0.0);
986 varHandler->m_CanUpdate = false;
987 varHandler->m_State = VariableRequestHandlerState::OFF;
986 varHandler->m_State = VariableRequestHandlerState::OFF;
988 varHandler->m_RunningVarRequest = VariableRequest{};
987 varHandler->m_RunningVarRequest = VariableRequest{};
989 }
988 }
990 else {
989 else {
991 // TODO: log Impossible to cancel the running variable request beacause its
990 // TODO: log Impossible to cancel the running variable request beacause its
992 // varRequestId isn't not the canceled one
991 // varRequestId isn't not the canceled one
993 }
992 }
994 break;
993 break;
995 }
994 }
996 case VariableRequestHandlerState::PENDING: {
995 case VariableRequestHandlerState::PENDING: {
997 if (varHandler->m_RunningVarRequest.m_VariableGroupId == varRequestId) {
996 if (varHandler->m_RunningVarRequest.m_VariableGroupId == varRequestId) {
998 auto var = findVariable(itVarHandler->first);
997 auto var = findVariable(itVarHandler->first);
999 auto varProvider = m_VariableToProviderMap.at(var);
998 auto varProvider = m_VariableToProviderMap.at(var);
1000 if (varProvider != nullptr) {
999 if (varProvider != nullptr) {
1001 m_VariableAcquisitionWorker->abortProgressRequested(
1000 m_VariableAcquisitionWorker->abortProgressRequested(
1002 itVarHandler->first);
1001 itVarHandler->first);
1003 }
1002 }
1004 m_VariableModel->setDataProgress(var, 0.0);
1003 m_VariableModel->setDataProgress(var, 0.0);
1005 varHandler->m_CanUpdate = false;
1006 varHandler->m_State = VariableRequestHandlerState::RUNNING;
1004 varHandler->m_State = VariableRequestHandlerState::RUNNING;
1007 varHandler->m_RunningVarRequest = varHandler->m_PendingVarRequest;
1005 varHandler->m_RunningVarRequest = varHandler->m_PendingVarRequest;
1008 varHandler->m_PendingVarRequest = VariableRequest{};
1006 varHandler->m_PendingVarRequest = VariableRequest{};
1009 executeVarRequest(var, varHandler->m_RunningVarRequest);
1007 executeVarRequest(var, varHandler->m_RunningVarRequest);
1010 }
1008 }
1011 else if (varHandler->m_PendingVarRequest.m_VariableGroupId == varRequestId) {
1009 else if (varHandler->m_PendingVarRequest.m_VariableGroupId == varRequestId) {
1012 varHandler->m_State = VariableRequestHandlerState::RUNNING;
1010 varHandler->m_State = VariableRequestHandlerState::RUNNING;
1013 varHandler->m_PendingVarRequest = VariableRequest{};
1011 varHandler->m_PendingVarRequest = VariableRequest{};
1014 }
1012 }
1015 else {
1013 else {
1016 // TODO: log Impossible to cancel the variable request beacause its
1014 // TODO: log Impossible to cancel the variable request beacause its
1017 // varRequestId isn't not the canceled one
1015 // varRequestId isn't not the canceled one
1018 }
1016 }
1019 break;
1017 break;
1020 }
1018 }
1021 default:
1019 default:
1022 qCCritical(LOG_VariableController())
1020 qCCritical(LOG_VariableController())
1023 << QObject::tr("Unknown VariableRequestHandlerState");
1021 << QObject::tr("Unknown VariableRequestHandlerState");
1024 }
1022 }
1025 }
1023 }
1026 }
1024 }
1027 qCDebug(LOG_VariableController()) << tr("cancelVariableRequest: erase") << varRequestId;
1025 qCDebug(LOG_VariableController()) << tr("cancelVariableRequest: erase") << varRequestId;
1028 m_VarGroupIdToVarIds.erase(varRequestId);
1026 m_VarGroupIdToVarIds.erase(varRequestId);
1029 if (m_VarGroupIdToVarIds.empty()) {
1027 if (m_VarGroupIdToVarIds.empty()) {
1030 emit q->acquisitionFinished();
1028 emit q->acquisitionFinished();
1031 }
1029 }
1032 }
1030 }
1033
1031
1034 void VariableController::VariableControllerPrivate::executeVarRequest(std::shared_ptr<Variable> var,
1032 void VariableController::VariableControllerPrivate::executeVarRequest(std::shared_ptr<Variable> var,
1035 VariableRequest &varRequest)
1033 VariableRequest &varRequest)
1036 {
1034 {
1037 qCDebug(LOG_VariableController()) << tr("TORM: executeVarRequest");
1038
1039 auto varIdIt = m_VariableToIdentifierMap.find(var);
1035 auto varIdIt = m_VariableToIdentifierMap.find(var);
1040 if (varIdIt == m_VariableToIdentifierMap.cend()) {
1036 if (varIdIt == m_VariableToIdentifierMap.cend()) {
1041 qCWarning(LOG_VariableController()) << tr(
1037 qCWarning(LOG_VariableController()) << tr(
1042 "Can't execute request of a variable that is not registered (may has been deleted)");
1038 "Can't execute request of a variable that is not registered (may has been deleted)");
1043 return;
1039 return;
1044 }
1040 }
1045
1041
1046 auto varId = varIdIt->second;
1042 auto varId = varIdIt->second;
1047
1043
1048 auto varCacheRange = var->cacheRange();
1044 auto varCacheRange = var->cacheRange();
1049 auto varCacheRangeRequested = varRequest.m_CacheRangeRequested;
1045 auto varCacheRangeRequested = varRequest.m_CacheRangeRequested;
1050 auto notInCacheRangeList
1046 auto notInCacheRangeList
1051 = Variable::provideNotInCacheRangeList(varCacheRange, varCacheRangeRequested);
1047 = Variable::provideNotInCacheRangeList(varCacheRange, varCacheRangeRequested);
1052 auto inCacheRangeList
1048 auto inCacheRangeList
1053 = Variable::provideInCacheRangeList(varCacheRange, varCacheRangeRequested);
1049 = Variable::provideInCacheRangeList(varCacheRange, varCacheRangeRequested);
1054
1050
1055 if (!notInCacheRangeList.empty()) {
1051 if (!notInCacheRangeList.empty()) {
1056
1052
1057 auto varProvider = m_VariableToProviderMap.at(var);
1053 auto varProvider = m_VariableToProviderMap.at(var);
1058 if (varProvider != nullptr) {
1054 if (varProvider != nullptr) {
1059 qCDebug(LOG_VariableController()) << "executeVarRequest " << varRequest.m_RangeRequested
1055 qCDebug(LOG_VariableController()) << "executeVarRequest " << varRequest.m_RangeRequested
1060 << varRequest.m_CacheRangeRequested;
1056 << varRequest.m_CacheRangeRequested;
1061 m_VariableAcquisitionWorker->pushVariableRequest(
1057 m_VariableAcquisitionWorker->pushVariableRequest(
1062 varRequest.m_VariableGroupId, varId, varRequest.m_RangeRequested,
1058 varRequest.m_VariableGroupId, varId,
1063 varRequest.m_CacheRangeRequested,
1064 DataProviderParameters{std::move(notInCacheRangeList), var->metadata()},
1059 DataProviderParameters{std::move(notInCacheRangeList), var->metadata()},
1065 varProvider);
1060 varProvider);
1066 }
1061 }
1067 else {
1062 else {
1068 qCCritical(LOG_VariableController())
1063 qCCritical(LOG_VariableController())
1069 << "Impossible to provide data with a null provider";
1064 << "Impossible to provide data with a null provider";
1070 }
1065 }
1071
1066
1072 if (!inCacheRangeList.empty()) {
1067 if (!inCacheRangeList.empty()) {
1073 emit q->updateVarDisplaying(var, inCacheRangeList.first());
1068 emit q->updateVarDisplaying(var, inCacheRangeList.first());
1074 }
1069 }
1075 }
1070 }
1076 else {
1071 else {
1072 qCDebug(LOG_VariableController()) << "All already in the cache "
1073 << varRequest.m_RangeRequested;
1077 acceptVariableRequest(varId,
1074 acceptVariableRequest(varId,
1078 var->dataSeries()->subDataSeries(varRequest.m_CacheRangeRequested));
1075 var->dataSeries()->subDataSeries(varRequest.m_CacheRangeRequested));
1079 }
1076 }
1080 }
1077 }
1081
1078
1082 template <typename VariableIterator>
1079 template <typename VariableIterator>
1083 void VariableController::VariableControllerPrivate::desynchronize(VariableIterator variableIt,
1080 void VariableController::VariableControllerPrivate::desynchronize(VariableIterator variableIt,
1084 const QUuid &syncGroupId)
1081 const QUuid &syncGroupId)
1085 {
1082 {
1086 const auto &variable = variableIt->first;
1083 const auto &variable = variableIt->first;
1087 const auto &variableId = variableIt->second;
1084 const auto &variableId = variableIt->second;
1088
1085
1089 // Gets synchronization group
1086 // Gets synchronization group
1090 auto groupIt = m_GroupIdToVariableSynchronizationGroupMap.find(syncGroupId);
1087 auto groupIt = m_GroupIdToVariableSynchronizationGroupMap.find(syncGroupId);
1091 if (groupIt == m_GroupIdToVariableSynchronizationGroupMap.cend()) {
1088 if (groupIt == m_GroupIdToVariableSynchronizationGroupMap.cend()) {
1092 qCCritical(LOG_VariableController())
1089 qCCritical(LOG_VariableController())
1093 << tr("Can't desynchronize variable %1: unknown synchronization group")
1090 << tr("Can't desynchronize variable %1: unknown synchronization group")
1094 .arg(variable->name());
1091 .arg(variable->name());
1095 return;
1092 return;
1096 }
1093 }
1097
1094
1098 // Removes variable from synchronization group
1095 // Removes variable from synchronization group
1099 auto synchronizationGroup = groupIt->second;
1096 auto synchronizationGroup = groupIt->second;
1100 synchronizationGroup->removeVariableId(variableId);
1097 synchronizationGroup->removeVariableId(variableId);
1101
1098
1102 // Removes link between variable and synchronization group
1099 // Removes link between variable and synchronization group
1103 m_VariableIdGroupIdMap.erase(variableId);
1100 m_VariableIdGroupIdMap.erase(variableId);
1104 }
1101 }
@@ -1,1082 +1,1082
1 #include "Visualization/VisualizationGraphWidget.h"
1 #include "Visualization/VisualizationGraphWidget.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 #include "Visualization/VisualizationCursorItem.h"
3 #include "Visualization/VisualizationCursorItem.h"
4 #include "Visualization/VisualizationDefs.h"
4 #include "Visualization/VisualizationDefs.h"
5 #include "Visualization/VisualizationGraphHelper.h"
5 #include "Visualization/VisualizationGraphHelper.h"
6 #include "Visualization/VisualizationGraphRenderingDelegate.h"
6 #include "Visualization/VisualizationGraphRenderingDelegate.h"
7 #include "Visualization/VisualizationMultiZoneSelectionDialog.h"
7 #include "Visualization/VisualizationMultiZoneSelectionDialog.h"
8 #include "Visualization/VisualizationSelectionZoneItem.h"
8 #include "Visualization/VisualizationSelectionZoneItem.h"
9 #include "Visualization/VisualizationSelectionZoneManager.h"
9 #include "Visualization/VisualizationSelectionZoneManager.h"
10 #include "Visualization/VisualizationWidget.h"
10 #include "Visualization/VisualizationWidget.h"
11 #include "Visualization/VisualizationZoneWidget.h"
11 #include "Visualization/VisualizationZoneWidget.h"
12 #include "ui_VisualizationGraphWidget.h"
12 #include "ui_VisualizationGraphWidget.h"
13
13
14 #include <Actions/ActionsGuiController.h>
14 #include <Actions/ActionsGuiController.h>
15 #include <Actions/FilteringAction.h>
15 #include <Actions/FilteringAction.h>
16 #include <Common/MimeTypesDef.h>
16 #include <Common/MimeTypesDef.h>
17 #include <Data/ArrayData.h>
17 #include <Data/ArrayData.h>
18 #include <Data/IDataSeries.h>
18 #include <Data/IDataSeries.h>
19 #include <Data/SpectrogramSeries.h>
19 #include <Data/SpectrogramSeries.h>
20 #include <DragAndDrop/DragDropGuiController.h>
20 #include <DragAndDrop/DragDropGuiController.h>
21 #include <Settings/SqpSettingsDefs.h>
21 #include <Settings/SqpSettingsDefs.h>
22 #include <SqpApplication.h>
22 #include <SqpApplication.h>
23 #include <Time/TimeController.h>
23 #include <Time/TimeController.h>
24 #include <Variable/Variable.h>
24 #include <Variable/Variable.h>
25 #include <Variable/VariableController.h>
25 #include <Variable/VariableController.h>
26
26
27 #include <unordered_map>
27 #include <unordered_map>
28
28
29 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
29 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
30
30
31 namespace {
31 namespace {
32
32
33 /// Key pressed to enable drag&drop in all modes
33 /// Key pressed to enable drag&drop in all modes
34 const auto DRAG_DROP_MODIFIER = Qt::AltModifier;
34 const auto DRAG_DROP_MODIFIER = Qt::AltModifier;
35
35
36 /// Key pressed to enable zoom on horizontal axis
36 /// Key pressed to enable zoom on horizontal axis
37 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::ControlModifier;
37 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::ControlModifier;
38
38
39 /// Key pressed to enable zoom on vertical axis
39 /// Key pressed to enable zoom on vertical axis
40 const auto VERTICAL_ZOOM_MODIFIER = Qt::ShiftModifier;
40 const auto VERTICAL_ZOOM_MODIFIER = Qt::ShiftModifier;
41
41
42 /// Speed of a step of a wheel event for a pan, in percentage of the axis range
42 /// Speed of a step of a wheel event for a pan, in percentage of the axis range
43 const auto PAN_SPEED = 5;
43 const auto PAN_SPEED = 5;
44
44
45 /// Key pressed to enable a calibration pan
45 /// Key pressed to enable a calibration pan
46 const auto VERTICAL_PAN_MODIFIER = Qt::AltModifier;
46 const auto VERTICAL_PAN_MODIFIER = Qt::AltModifier;
47
47
48 /// Key pressed to enable multi selection of selection zones
48 /// Key pressed to enable multi selection of selection zones
49 const auto MULTI_ZONE_SELECTION_MODIFIER = Qt::ControlModifier;
49 const auto MULTI_ZONE_SELECTION_MODIFIER = Qt::ControlModifier;
50
50
51 /// Minimum size for the zoom box, in percentage of the axis range
51 /// Minimum size for the zoom box, in percentage of the axis range
52 const auto ZOOM_BOX_MIN_SIZE = 0.8;
52 const auto ZOOM_BOX_MIN_SIZE = 0.8;
53
53
54 /// Format of the dates appearing in the label of a cursor
54 /// Format of the dates appearing in the label of a cursor
55 const auto CURSOR_LABELS_DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd\nhh:mm:ss:zzz");
55 const auto CURSOR_LABELS_DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd\nhh:mm:ss:zzz");
56
56
57 } // namespace
57 } // namespace
58
58
59 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
59 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
60
60
61 explicit VisualizationGraphWidgetPrivate(const QString &name)
61 explicit VisualizationGraphWidgetPrivate(const QString &name)
62 : m_Name{name},
62 : m_Name{name},
63 m_Flags{GraphFlag::EnableAll},
63 m_Flags{GraphFlag::EnableAll},
64 m_IsCalibration{false},
64 m_IsCalibration{false},
65 m_RenderingDelegate{nullptr}
65 m_RenderingDelegate{nullptr}
66 {
66 {
67 }
67 }
68
68
69 void updateData(PlottablesMap &plottables, std::shared_ptr<Variable> variable,
69 void updateData(PlottablesMap &plottables, std::shared_ptr<Variable> variable,
70 const SqpRange &range)
70 const SqpRange &range)
71 {
71 {
72 VisualizationGraphHelper::updateData(plottables, variable, range);
72 VisualizationGraphHelper::updateData(plottables, variable, range);
73
73
74 // Prevents that data has changed to update rendering
74 // Prevents that data has changed to update rendering
75 m_RenderingDelegate->onPlotUpdated();
75 m_RenderingDelegate->onPlotUpdated();
76 }
76 }
77
77
78 QString m_Name;
78 QString m_Name;
79 // 1 variable -> n qcpplot
79 // 1 variable -> n qcpplot
80 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
80 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
81 GraphFlags m_Flags;
81 GraphFlags m_Flags;
82 bool m_IsCalibration;
82 bool m_IsCalibration;
83 /// Delegate used to attach rendering features to the plot
83 /// Delegate used to attach rendering features to the plot
84 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
84 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
85
85
86 QCPItemRect *m_DrawingZoomRect = nullptr;
86 QCPItemRect *m_DrawingZoomRect = nullptr;
87 QStack<QPair<QCPRange, QCPRange> > m_ZoomStack;
87 QStack<QPair<QCPRange, QCPRange> > m_ZoomStack;
88
88
89 std::unique_ptr<VisualizationCursorItem> m_HorizontalCursor = nullptr;
89 std::unique_ptr<VisualizationCursorItem> m_HorizontalCursor = nullptr;
90 std::unique_ptr<VisualizationCursorItem> m_VerticalCursor = nullptr;
90 std::unique_ptr<VisualizationCursorItem> m_VerticalCursor = nullptr;
91
91
92 VisualizationSelectionZoneItem *m_DrawingZone = nullptr;
92 VisualizationSelectionZoneItem *m_DrawingZone = nullptr;
93 VisualizationSelectionZoneItem *m_HoveredZone = nullptr;
93 VisualizationSelectionZoneItem *m_HoveredZone = nullptr;
94 QVector<VisualizationSelectionZoneItem *> m_SelectionZones;
94 QVector<VisualizationSelectionZoneItem *> m_SelectionZones;
95
95
96 bool m_HasMovedMouse = false; // Indicates if the mouse moved in a releaseMouse even
96 bool m_HasMovedMouse = false; // Indicates if the mouse moved in a releaseMouse even
97
97
98 bool m_VariableAutoRangeOnInit = true;
98 bool m_VariableAutoRangeOnInit = true;
99
99
100 void startDrawingRect(const QPoint &pos, QCustomPlot &plot)
100 void startDrawingRect(const QPoint &pos, QCustomPlot &plot)
101 {
101 {
102 removeDrawingRect(plot);
102 removeDrawingRect(plot);
103
103
104 auto axisPos = posToAxisPos(pos, plot);
104 auto axisPos = posToAxisPos(pos, plot);
105
105
106 m_DrawingZoomRect = new QCPItemRect{&plot};
106 m_DrawingZoomRect = new QCPItemRect{&plot};
107 QPen p;
107 QPen p;
108 p.setWidth(2);
108 p.setWidth(2);
109 m_DrawingZoomRect->setPen(p);
109 m_DrawingZoomRect->setPen(p);
110
110
111 m_DrawingZoomRect->topLeft->setCoords(axisPos);
111 m_DrawingZoomRect->topLeft->setCoords(axisPos);
112 m_DrawingZoomRect->bottomRight->setCoords(axisPos);
112 m_DrawingZoomRect->bottomRight->setCoords(axisPos);
113 }
113 }
114
114
115 void removeDrawingRect(QCustomPlot &plot)
115 void removeDrawingRect(QCustomPlot &plot)
116 {
116 {
117 if (m_DrawingZoomRect) {
117 if (m_DrawingZoomRect) {
118 plot.removeItem(m_DrawingZoomRect); // the item is deleted by QCustomPlot
118 plot.removeItem(m_DrawingZoomRect); // the item is deleted by QCustomPlot
119 m_DrawingZoomRect = nullptr;
119 m_DrawingZoomRect = nullptr;
120 plot.replot(QCustomPlot::rpQueuedReplot);
120 plot.replot(QCustomPlot::rpQueuedReplot);
121 }
121 }
122 }
122 }
123
123
124 void startDrawingZone(const QPoint &pos, VisualizationGraphWidget *graph)
124 void startDrawingZone(const QPoint &pos, VisualizationGraphWidget *graph)
125 {
125 {
126 endDrawingZone(graph);
126 endDrawingZone(graph);
127
127
128 auto axisPos = posToAxisPos(pos, graph->plot());
128 auto axisPos = posToAxisPos(pos, graph->plot());
129
129
130 m_DrawingZone = new VisualizationSelectionZoneItem{&graph->plot()};
130 m_DrawingZone = new VisualizationSelectionZoneItem{&graph->plot()};
131 m_DrawingZone->setRange(axisPos.x(), axisPos.x());
131 m_DrawingZone->setRange(axisPos.x(), axisPos.x());
132 m_DrawingZone->setEditionEnabled(false);
132 m_DrawingZone->setEditionEnabled(false);
133 }
133 }
134
134
135 void endDrawingZone(VisualizationGraphWidget *graph)
135 void endDrawingZone(VisualizationGraphWidget *graph)
136 {
136 {
137 if (m_DrawingZone) {
137 if (m_DrawingZone) {
138 auto drawingZoneRange = m_DrawingZone->range();
138 auto drawingZoneRange = m_DrawingZone->range();
139 if (qAbs(drawingZoneRange.m_TEnd - drawingZoneRange.m_TStart) > 0) {
139 if (qAbs(drawingZoneRange.m_TEnd - drawingZoneRange.m_TStart) > 0) {
140 m_DrawingZone->setEditionEnabled(true);
140 m_DrawingZone->setEditionEnabled(true);
141 addSelectionZone(m_DrawingZone);
141 addSelectionZone(m_DrawingZone);
142 }
142 }
143 else {
143 else {
144 graph->plot().removeItem(m_DrawingZone); // the item is deleted by QCustomPlot
144 graph->plot().removeItem(m_DrawingZone); // the item is deleted by QCustomPlot
145 }
145 }
146
146
147 graph->plot().replot(QCustomPlot::rpQueuedReplot);
147 graph->plot().replot(QCustomPlot::rpQueuedReplot);
148 m_DrawingZone = nullptr;
148 m_DrawingZone = nullptr;
149 }
149 }
150 }
150 }
151
151
152 void setSelectionZonesEditionEnabled(bool value)
152 void setSelectionZonesEditionEnabled(bool value)
153 {
153 {
154 for (auto s : m_SelectionZones) {
154 for (auto s : m_SelectionZones) {
155 s->setEditionEnabled(value);
155 s->setEditionEnabled(value);
156 }
156 }
157 }
157 }
158
158
159 void addSelectionZone(VisualizationSelectionZoneItem *zone) { m_SelectionZones << zone; }
159 void addSelectionZone(VisualizationSelectionZoneItem *zone) { m_SelectionZones << zone; }
160
160
161 VisualizationSelectionZoneItem *selectionZoneAt(const QPoint &pos,
161 VisualizationSelectionZoneItem *selectionZoneAt(const QPoint &pos,
162 const QCustomPlot &plot) const
162 const QCustomPlot &plot) const
163 {
163 {
164 VisualizationSelectionZoneItem *selectionZoneItemUnderCursor = nullptr;
164 VisualizationSelectionZoneItem *selectionZoneItemUnderCursor = nullptr;
165 auto minDistanceToZone = -1;
165 auto minDistanceToZone = -1;
166 for (auto zone : m_SelectionZones) {
166 for (auto zone : m_SelectionZones) {
167 auto distanceToZone = zone->selectTest(pos, false);
167 auto distanceToZone = zone->selectTest(pos, false);
168 if ((minDistanceToZone < 0 || distanceToZone <= minDistanceToZone)
168 if ((minDistanceToZone < 0 || distanceToZone <= minDistanceToZone)
169 && distanceToZone >= 0 && distanceToZone < plot.selectionTolerance()) {
169 && distanceToZone >= 0 && distanceToZone < plot.selectionTolerance()) {
170 selectionZoneItemUnderCursor = zone;
170 selectionZoneItemUnderCursor = zone;
171 }
171 }
172 }
172 }
173
173
174 return selectionZoneItemUnderCursor;
174 return selectionZoneItemUnderCursor;
175 }
175 }
176
176
177 QVector<VisualizationSelectionZoneItem *> selectionZonesAt(const QPoint &pos,
177 QVector<VisualizationSelectionZoneItem *> selectionZonesAt(const QPoint &pos,
178 const QCustomPlot &plot) const
178 const QCustomPlot &plot) const
179 {
179 {
180 QVector<VisualizationSelectionZoneItem *> zones;
180 QVector<VisualizationSelectionZoneItem *> zones;
181 for (auto zone : m_SelectionZones) {
181 for (auto zone : m_SelectionZones) {
182 auto distanceToZone = zone->selectTest(pos, false);
182 auto distanceToZone = zone->selectTest(pos, false);
183 if (distanceToZone >= 0 && distanceToZone < plot.selectionTolerance()) {
183 if (distanceToZone >= 0 && distanceToZone < plot.selectionTolerance()) {
184 zones << zone;
184 zones << zone;
185 }
185 }
186 }
186 }
187
187
188 return zones;
188 return zones;
189 }
189 }
190
190
191 void moveSelectionZoneOnTop(VisualizationSelectionZoneItem *zone, QCustomPlot &plot)
191 void moveSelectionZoneOnTop(VisualizationSelectionZoneItem *zone, QCustomPlot &plot)
192 {
192 {
193 if (!m_SelectionZones.isEmpty() && m_SelectionZones.last() != zone) {
193 if (!m_SelectionZones.isEmpty() && m_SelectionZones.last() != zone) {
194 zone->moveToTop();
194 zone->moveToTop();
195 m_SelectionZones.removeAll(zone);
195 m_SelectionZones.removeAll(zone);
196 m_SelectionZones.append(zone);
196 m_SelectionZones.append(zone);
197 }
197 }
198 }
198 }
199
199
200 QPointF posToAxisPos(const QPoint &pos, QCustomPlot &plot) const
200 QPointF posToAxisPos(const QPoint &pos, QCustomPlot &plot) const
201 {
201 {
202 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
202 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
203 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
203 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
204 return QPointF{axisX->pixelToCoord(pos.x()), axisY->pixelToCoord(pos.y())};
204 return QPointF{axisX->pixelToCoord(pos.x()), axisY->pixelToCoord(pos.y())};
205 }
205 }
206
206
207 bool pointIsInAxisRect(const QPointF &axisPoint, QCustomPlot &plot) const
207 bool pointIsInAxisRect(const QPointF &axisPoint, QCustomPlot &plot) const
208 {
208 {
209 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
209 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
210 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
210 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
211 return axisX->range().contains(axisPoint.x()) && axisY->range().contains(axisPoint.y());
211 return axisX->range().contains(axisPoint.x()) && axisY->range().contains(axisPoint.y());
212 }
212 }
213 };
213 };
214
214
215 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
215 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
216 : VisualizationDragWidget{parent},
216 : VisualizationDragWidget{parent},
217 ui{new Ui::VisualizationGraphWidget},
217 ui{new Ui::VisualizationGraphWidget},
218 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
218 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
219 {
219 {
220 ui->setupUi(this);
220 ui->setupUi(this);
221
221
222 // 'Close' options : widget is deleted when closed
222 // 'Close' options : widget is deleted when closed
223 setAttribute(Qt::WA_DeleteOnClose);
223 setAttribute(Qt::WA_DeleteOnClose);
224
224
225 // Set qcpplot properties :
225 // Set qcpplot properties :
226 // - zoom is enabled
226 // - zoom is enabled
227 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
227 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
228 ui->widget->setInteractions(QCP::iRangeZoom);
228 ui->widget->setInteractions(QCP::iRangeZoom);
229 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal | Qt::Vertical);
229 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal | Qt::Vertical);
230
230
231 // The delegate must be initialized after the ui as it uses the plot
231 // The delegate must be initialized after the ui as it uses the plot
232 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
232 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
233
233
234 // Init the cursors
234 // Init the cursors
235 impl->m_HorizontalCursor = std::make_unique<VisualizationCursorItem>(&plot());
235 impl->m_HorizontalCursor = std::make_unique<VisualizationCursorItem>(&plot());
236 impl->m_HorizontalCursor->setOrientation(Qt::Horizontal);
236 impl->m_HorizontalCursor->setOrientation(Qt::Horizontal);
237 impl->m_VerticalCursor = std::make_unique<VisualizationCursorItem>(&plot());
237 impl->m_VerticalCursor = std::make_unique<VisualizationCursorItem>(&plot());
238 impl->m_VerticalCursor->setOrientation(Qt::Vertical);
238 impl->m_VerticalCursor->setOrientation(Qt::Vertical);
239
239
240 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
240 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
241 connect(ui->widget, &QCustomPlot::mouseRelease, this,
241 connect(ui->widget, &QCustomPlot::mouseRelease, this,
242 &VisualizationGraphWidget::onMouseRelease);
242 &VisualizationGraphWidget::onMouseRelease);
243 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
243 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
244 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
244 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
245 connect(ui->widget, &QCustomPlot::mouseDoubleClick, this,
245 connect(ui->widget, &QCustomPlot::mouseDoubleClick, this,
246 &VisualizationGraphWidget::onMouseDoubleClick);
246 &VisualizationGraphWidget::onMouseDoubleClick);
247 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
247 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
248 &QCPAxis::rangeChanged),
248 &QCPAxis::rangeChanged),
249 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
249 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
250
250
251 // Activates menu when right clicking on the graph
251 // Activates menu when right clicking on the graph
252 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
252 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
253 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
253 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
254 &VisualizationGraphWidget::onGraphMenuRequested);
254 &VisualizationGraphWidget::onGraphMenuRequested);
255
255
256 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
256 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
257 &VariableController::onRequestDataLoading);
257 &VariableController::onRequestDataLoading);
258
258
259 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
259 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
260 &VisualizationGraphWidget::onUpdateVarDisplaying);
260 &VisualizationGraphWidget::onUpdateVarDisplaying);
261
261
262 // Necessary for all platform since Qt::AA_EnableHighDpiScaling is enable.
262 // Necessary for all platform since Qt::AA_EnableHighDpiScaling is enable.
263 plot().setPlottingHint(QCP::phFastPolylines, true);
263 plot().setPlottingHint(QCP::phFastPolylines, true);
264 }
264 }
265
265
266
266
267 VisualizationGraphWidget::~VisualizationGraphWidget()
267 VisualizationGraphWidget::~VisualizationGraphWidget()
268 {
268 {
269 delete ui;
269 delete ui;
270 }
270 }
271
271
272 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
272 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
273 {
273 {
274 auto parent = parentWidget();
274 auto parent = parentWidget();
275 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
275 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
276 parent = parent->parentWidget();
276 parent = parent->parentWidget();
277 }
277 }
278
278
279 return qobject_cast<VisualizationZoneWidget *>(parent);
279 return qobject_cast<VisualizationZoneWidget *>(parent);
280 }
280 }
281
281
282 VisualizationWidget *VisualizationGraphWidget::parentVisualizationWidget() const
282 VisualizationWidget *VisualizationGraphWidget::parentVisualizationWidget() const
283 {
283 {
284 auto parent = parentWidget();
284 auto parent = parentWidget();
285 while (parent != nullptr && !qobject_cast<VisualizationWidget *>(parent)) {
285 while (parent != nullptr && !qobject_cast<VisualizationWidget *>(parent)) {
286 parent = parent->parentWidget();
286 parent = parent->parentWidget();
287 }
287 }
288
288
289 return qobject_cast<VisualizationWidget *>(parent);
289 return qobject_cast<VisualizationWidget *>(parent);
290 }
290 }
291
291
292 void VisualizationGraphWidget::setFlags(GraphFlags flags)
292 void VisualizationGraphWidget::setFlags(GraphFlags flags)
293 {
293 {
294 impl->m_Flags = std::move(flags);
294 impl->m_Flags = std::move(flags);
295 }
295 }
296
296
297 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
297 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
298 {
298 {
299 /// Lambda used to set graph's units and range according to the variable passed in parameter
299 /// Lambda used to set graph's units and range according to the variable passed in parameter
300 auto loadRange = [this](std::shared_ptr<Variable> variable, const SqpRange &range) {
300 auto loadRange = [this](std::shared_ptr<Variable> variable, const SqpRange &range) {
301 impl->m_RenderingDelegate->setAxesUnits(*variable);
301 impl->m_RenderingDelegate->setAxesUnits(*variable);
302
302
303 this->setFlags(GraphFlag::DisableAll);
303 this->setFlags(GraphFlag::DisableAll);
304 setGraphRange(range);
304 setGraphRange(range);
305 this->setFlags(GraphFlag::EnableAll);
305 this->setFlags(GraphFlag::EnableAll);
306 emit requestDataLoading({variable}, range, false);
306 emit requestDataLoading({variable}, range, false);
307 };
307 };
308
308
309 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
309 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
310
310
311 // Calls update of graph's range and units when the data of the variable have been initialized.
311 // Calls update of graph's range and units when the data of the variable have been initialized.
312 // Note: we use QueuedConnection here as the update event must be called in the UI thread
312 // Note: we use QueuedConnection here as the update event must be called in the UI thread
313 connect(variable.get(), &Variable::dataInitialized, this,
313 connect(variable.get(), &Variable::dataInitialized, this,
314 [ varW = std::weak_ptr<Variable>{variable}, range, loadRange, this ]() {
314 [ varW = std::weak_ptr<Variable>{variable}, range, loadRange, this ]() {
315 if (auto var = varW.lock()) {
315 if (auto var = varW.lock()) {
316 // If the variable is the first added in the graph, we load its range
316 // If the variable is the first added in the graph, we load its range
317 auto firstVariableInGraph = range == INVALID_RANGE;
317 auto firstVariableInGraph = range == INVALID_RANGE;
318 auto loadedRange = graphRange();
318 auto loadedRange = graphRange();
319 if (impl->m_VariableAutoRangeOnInit) {
319 if (impl->m_VariableAutoRangeOnInit) {
320 loadedRange = firstVariableInGraph ? var->range() : range;
320 loadedRange = firstVariableInGraph ? var->range() : range;
321 }
321 }
322 loadRange(var, loadedRange);
322 loadRange(var, loadedRange);
323 setYRange(var);
323 setYRange(var);
324 }
324 }
325 },
325 },
326 Qt::QueuedConnection);
326 Qt::QueuedConnection);
327
327
328 // Uses delegate to create the qcpplot components according to the variable
328 // Uses delegate to create the qcpplot components according to the variable
329 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
329 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
330
330
331 // Sets graph properties
331 // Sets graph properties
332 impl->m_RenderingDelegate->setGraphProperties(*variable, createdPlottables);
332 impl->m_RenderingDelegate->setGraphProperties(*variable, createdPlottables);
333
333
334 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
334 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
335
335
336 // If the variable already has its data loaded, load its units and its range in the graph
336 // If the variable already has its data loaded, load its units and its range in the graph
337 if (variable->dataSeries() != nullptr) {
337 if (variable->dataSeries() != nullptr) {
338 loadRange(variable, range);
338 loadRange(variable, range);
339 }
339 }
340
340
341 emit variableAdded(variable);
341 emit variableAdded(variable);
342 }
342 }
343
343
344 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
344 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
345 {
345 {
346 // Each component associated to the variable :
346 // Each component associated to the variable :
347 // - is removed from qcpplot (which deletes it)
347 // - is removed from qcpplot (which deletes it)
348 // - is no longer referenced in the map
348 // - is no longer referenced in the map
349 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
349 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
350 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
350 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
351 emit variableAboutToBeRemoved(variable);
351 emit variableAboutToBeRemoved(variable);
352
352
353 auto &plottablesMap = variableIt->second;
353 auto &plottablesMap = variableIt->second;
354
354
355 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
355 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
356 plottableIt != plottableEnd;) {
356 plottableIt != plottableEnd;) {
357 ui->widget->removePlottable(plottableIt->second);
357 ui->widget->removePlottable(plottableIt->second);
358 plottableIt = plottablesMap.erase(plottableIt);
358 plottableIt = plottablesMap.erase(plottableIt);
359 }
359 }
360
360
361 impl->m_VariableToPlotMultiMap.erase(variableIt);
361 impl->m_VariableToPlotMultiMap.erase(variableIt);
362 }
362 }
363
363
364 // Updates graph
364 // Updates graph
365 ui->widget->replot();
365 ui->widget->replot();
366 }
366 }
367
367
368 QList<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
368 QList<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
369 {
369 {
370 auto variables = QList<std::shared_ptr<Variable> >{};
370 auto variables = QList<std::shared_ptr<Variable> >{};
371 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
371 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
372 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
372 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
373 variables << it->first;
373 variables << it->first;
374 }
374 }
375
375
376 return variables;
376 return variables;
377 }
377 }
378
378
379 void VisualizationGraphWidget::setYRange(std::shared_ptr<Variable> variable)
379 void VisualizationGraphWidget::setYRange(std::shared_ptr<Variable> variable)
380 {
380 {
381 if (!variable) {
381 if (!variable) {
382 qCCritical(LOG_VisualizationGraphWidget()) << "Can't set y-axis range: variable is null";
382 qCCritical(LOG_VisualizationGraphWidget()) << "Can't set y-axis range: variable is null";
383 return;
383 return;
384 }
384 }
385
385
386 VisualizationGraphHelper::setYAxisRange(variable, *ui->widget);
386 VisualizationGraphHelper::setYAxisRange(variable, *ui->widget);
387 }
387 }
388
388
389 SqpRange VisualizationGraphWidget::graphRange() const noexcept
389 SqpRange VisualizationGraphWidget::graphRange() const noexcept
390 {
390 {
391 auto graphRange = ui->widget->xAxis->range();
391 auto graphRange = ui->widget->xAxis->range();
392 return SqpRange{graphRange.lower, graphRange.upper};
392 return SqpRange{graphRange.lower, graphRange.upper};
393 }
393 }
394
394
395 void VisualizationGraphWidget::setGraphRange(const SqpRange &range, bool calibration)
395 void VisualizationGraphWidget::setGraphRange(const SqpRange &range, bool calibration)
396 {
396 {
397 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
397 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
398
398
399 if (calibration) {
399 if (calibration) {
400 impl->m_IsCalibration = true;
400 impl->m_IsCalibration = true;
401 }
401 }
402
402
403 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
403 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
404 ui->widget->replot();
404 ui->widget->replot();
405
405
406 if (calibration) {
406 if (calibration) {
407 impl->m_IsCalibration = false;
407 impl->m_IsCalibration = false;
408 }
408 }
409
409
410 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
410 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
411 }
411 }
412
412
413 void VisualizationGraphWidget::setAutoRangeOnVariableInitialization(bool value)
413 void VisualizationGraphWidget::setAutoRangeOnVariableInitialization(bool value)
414 {
414 {
415 impl->m_VariableAutoRangeOnInit = value;
415 impl->m_VariableAutoRangeOnInit = value;
416 }
416 }
417
417
418 QVector<SqpRange> VisualizationGraphWidget::selectionZoneRanges() const
418 QVector<SqpRange> VisualizationGraphWidget::selectionZoneRanges() const
419 {
419 {
420 QVector<SqpRange> ranges;
420 QVector<SqpRange> ranges;
421 for (auto zone : impl->m_SelectionZones) {
421 for (auto zone : impl->m_SelectionZones) {
422 ranges << zone->range();
422 ranges << zone->range();
423 }
423 }
424
424
425 return ranges;
425 return ranges;
426 }
426 }
427
427
428 void VisualizationGraphWidget::addSelectionZones(const QVector<SqpRange> &ranges)
428 void VisualizationGraphWidget::addSelectionZones(const QVector<SqpRange> &ranges)
429 {
429 {
430 for (const auto &range : ranges) {
430 for (const auto &range : ranges) {
431 // note: ownership is transfered to QCustomPlot
431 // note: ownership is transfered to QCustomPlot
432 auto zone = new VisualizationSelectionZoneItem(&plot());
432 auto zone = new VisualizationSelectionZoneItem(&plot());
433 zone->setRange(range.m_TStart, range.m_TEnd);
433 zone->setRange(range.m_TStart, range.m_TEnd);
434 impl->addSelectionZone(zone);
434 impl->addSelectionZone(zone);
435 }
435 }
436
436
437 plot().replot(QCustomPlot::rpQueuedReplot);
437 plot().replot(QCustomPlot::rpQueuedReplot);
438 }
438 }
439
439
440 VisualizationSelectionZoneItem *VisualizationGraphWidget::addSelectionZone(const QString &name,
440 VisualizationSelectionZoneItem *VisualizationGraphWidget::addSelectionZone(const QString &name,
441 const SqpRange &range)
441 const SqpRange &range)
442 {
442 {
443 // note: ownership is transfered to QCustomPlot
443 // note: ownership is transfered to QCustomPlot
444 auto zone = new VisualizationSelectionZoneItem(&plot());
444 auto zone = new VisualizationSelectionZoneItem(&plot());
445 zone->setName(name);
445 zone->setName(name);
446 zone->setRange(range.m_TStart, range.m_TEnd);
446 zone->setRange(range.m_TStart, range.m_TEnd);
447 impl->addSelectionZone(zone);
447 impl->addSelectionZone(zone);
448
448
449 plot().replot(QCustomPlot::rpQueuedReplot);
449 plot().replot(QCustomPlot::rpQueuedReplot);
450
450
451 return zone;
451 return zone;
452 }
452 }
453
453
454 void VisualizationGraphWidget::removeSelectionZone(VisualizationSelectionZoneItem *selectionZone)
454 void VisualizationGraphWidget::removeSelectionZone(VisualizationSelectionZoneItem *selectionZone)
455 {
455 {
456 parentVisualizationWidget()->selectionZoneManager().setSelected(selectionZone, false);
456 parentVisualizationWidget()->selectionZoneManager().setSelected(selectionZone, false);
457
457
458 if (impl->m_HoveredZone == selectionZone) {
458 if (impl->m_HoveredZone == selectionZone) {
459 impl->m_HoveredZone = nullptr;
459 impl->m_HoveredZone = nullptr;
460 setCursor(Qt::ArrowCursor);
460 setCursor(Qt::ArrowCursor);
461 }
461 }
462
462
463 impl->m_SelectionZones.removeAll(selectionZone);
463 impl->m_SelectionZones.removeAll(selectionZone);
464 plot().removeItem(selectionZone);
464 plot().removeItem(selectionZone);
465 plot().replot(QCustomPlot::rpQueuedReplot);
465 plot().replot(QCustomPlot::rpQueuedReplot);
466 }
466 }
467
467
468 void VisualizationGraphWidget::undoZoom()
468 void VisualizationGraphWidget::undoZoom()
469 {
469 {
470 auto zoom = impl->m_ZoomStack.pop();
470 auto zoom = impl->m_ZoomStack.pop();
471 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
471 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
472 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
472 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
473
473
474 axisX->setRange(zoom.first);
474 axisX->setRange(zoom.first);
475 axisY->setRange(zoom.second);
475 axisY->setRange(zoom.second);
476
476
477 plot().replot(QCustomPlot::rpQueuedReplot);
477 plot().replot(QCustomPlot::rpQueuedReplot);
478 }
478 }
479
479
480 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
480 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
481 {
481 {
482 if (visitor) {
482 if (visitor) {
483 visitor->visit(this);
483 visitor->visit(this);
484 }
484 }
485 else {
485 else {
486 qCCritical(LOG_VisualizationGraphWidget())
486 qCCritical(LOG_VisualizationGraphWidget())
487 << tr("Can't visit widget : the visitor is null");
487 << tr("Can't visit widget : the visitor is null");
488 }
488 }
489 }
489 }
490
490
491 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
491 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
492 {
492 {
493 auto isSpectrogram = [](const auto &variable) {
493 auto isSpectrogram = [](const auto &variable) {
494 return std::dynamic_pointer_cast<SpectrogramSeries>(variable.dataSeries()) != nullptr;
494 return std::dynamic_pointer_cast<SpectrogramSeries>(variable.dataSeries()) != nullptr;
495 };
495 };
496
496
497 // - A spectrogram series can't be dropped on graph with existing plottables
497 // - A spectrogram series can't be dropped on graph with existing plottables
498 // - No data series can be dropped on graph with existing spectrogram series
498 // - No data series can be dropped on graph with existing spectrogram series
499 return isSpectrogram(variable)
499 return isSpectrogram(variable)
500 ? impl->m_VariableToPlotMultiMap.empty()
500 ? impl->m_VariableToPlotMultiMap.empty()
501 : std::none_of(
501 : std::none_of(
502 impl->m_VariableToPlotMultiMap.cbegin(), impl->m_VariableToPlotMultiMap.cend(),
502 impl->m_VariableToPlotMultiMap.cbegin(), impl->m_VariableToPlotMultiMap.cend(),
503 [isSpectrogram](const auto &entry) { return isSpectrogram(*entry.first); });
503 [isSpectrogram](const auto &entry) { return isSpectrogram(*entry.first); });
504 }
504 }
505
505
506 bool VisualizationGraphWidget::contains(const Variable &variable) const
506 bool VisualizationGraphWidget::contains(const Variable &variable) const
507 {
507 {
508 // Finds the variable among the keys of the map
508 // Finds the variable among the keys of the map
509 auto variablePtr = &variable;
509 auto variablePtr = &variable;
510 auto findVariable
510 auto findVariable
511 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
511 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
512
512
513 auto end = impl->m_VariableToPlotMultiMap.cend();
513 auto end = impl->m_VariableToPlotMultiMap.cend();
514 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
514 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
515 return it != end;
515 return it != end;
516 }
516 }
517
517
518 QString VisualizationGraphWidget::name() const
518 QString VisualizationGraphWidget::name() const
519 {
519 {
520 return impl->m_Name;
520 return impl->m_Name;
521 }
521 }
522
522
523 QMimeData *VisualizationGraphWidget::mimeData(const QPoint &position) const
523 QMimeData *VisualizationGraphWidget::mimeData(const QPoint &position) const
524 {
524 {
525 auto mimeData = new QMimeData;
525 auto mimeData = new QMimeData;
526
526
527 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(position, plot());
527 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(position, plot());
528 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
528 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
529 && selectionZoneItemUnderCursor) {
529 && selectionZoneItemUnderCursor) {
530 mimeData->setData(MIME_TYPE_TIME_RANGE, TimeController::mimeDataForTimeRange(
530 mimeData->setData(MIME_TYPE_TIME_RANGE, TimeController::mimeDataForTimeRange(
531 selectionZoneItemUnderCursor->range()));
531 selectionZoneItemUnderCursor->range()));
532 mimeData->setData(MIME_TYPE_SELECTION_ZONE, TimeController::mimeDataForTimeRange(
532 mimeData->setData(MIME_TYPE_SELECTION_ZONE, TimeController::mimeDataForTimeRange(
533 selectionZoneItemUnderCursor->range()));
533 selectionZoneItemUnderCursor->range()));
534 }
534 }
535 else {
535 else {
536 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
536 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
537
537
538 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
538 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
539 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
539 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
540 }
540 }
541
541
542 return mimeData;
542 return mimeData;
543 }
543 }
544
544
545 QPixmap VisualizationGraphWidget::customDragPixmap(const QPoint &dragPosition)
545 QPixmap VisualizationGraphWidget::customDragPixmap(const QPoint &dragPosition)
546 {
546 {
547 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(dragPosition, plot());
547 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(dragPosition, plot());
548 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
548 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
549 && selectionZoneItemUnderCursor) {
549 && selectionZoneItemUnderCursor) {
550
550
551 auto zoneTopLeft = selectionZoneItemUnderCursor->topLeft->pixelPosition();
551 auto zoneTopLeft = selectionZoneItemUnderCursor->topLeft->pixelPosition();
552 auto zoneBottomRight = selectionZoneItemUnderCursor->bottomRight->pixelPosition();
552 auto zoneBottomRight = selectionZoneItemUnderCursor->bottomRight->pixelPosition();
553
553
554 auto zoneSize = QSizeF{qAbs(zoneBottomRight.x() - zoneTopLeft.x()),
554 auto zoneSize = QSizeF{qAbs(zoneBottomRight.x() - zoneTopLeft.x()),
555 qAbs(zoneBottomRight.y() - zoneTopLeft.y())}
555 qAbs(zoneBottomRight.y() - zoneTopLeft.y())}
556 .toSize();
556 .toSize();
557
557
558 auto pixmap = QPixmap(zoneSize);
558 auto pixmap = QPixmap(zoneSize);
559 render(&pixmap, QPoint(), QRegion{QRect{zoneTopLeft.toPoint(), zoneSize}});
559 render(&pixmap, QPoint(), QRegion{QRect{zoneTopLeft.toPoint(), zoneSize}});
560
560
561 return pixmap;
561 return pixmap;
562 }
562 }
563
563
564 return QPixmap();
564 return QPixmap();
565 }
565 }
566
566
567 bool VisualizationGraphWidget::isDragAllowed() const
567 bool VisualizationGraphWidget::isDragAllowed() const
568 {
568 {
569 return true;
569 return true;
570 }
570 }
571
571
572 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
572 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
573 {
573 {
574 if (highlighted) {
574 if (highlighted) {
575 plot().setBackground(QBrush(QColor("#BBD5EE")));
575 plot().setBackground(QBrush(QColor("#BBD5EE")));
576 }
576 }
577 else {
577 else {
578 plot().setBackground(QBrush(Qt::white));
578 plot().setBackground(QBrush(Qt::white));
579 }
579 }
580
580
581 plot().update();
581 plot().update();
582 }
582 }
583
583
584 void VisualizationGraphWidget::addVerticalCursor(double time)
584 void VisualizationGraphWidget::addVerticalCursor(double time)
585 {
585 {
586 impl->m_VerticalCursor->setPosition(time);
586 impl->m_VerticalCursor->setPosition(time);
587 impl->m_VerticalCursor->setVisible(true);
587 impl->m_VerticalCursor->setVisible(true);
588
588
589 auto text
589 auto text
590 = DateUtils::dateTime(time).toString(CURSOR_LABELS_DATETIME_FORMAT).replace(' ', '\n');
590 = DateUtils::dateTime(time).toString(CURSOR_LABELS_DATETIME_FORMAT).replace(' ', '\n');
591 impl->m_VerticalCursor->setLabelText(text);
591 impl->m_VerticalCursor->setLabelText(text);
592 }
592 }
593
593
594 void VisualizationGraphWidget::addVerticalCursorAtViewportPosition(double position)
594 void VisualizationGraphWidget::addVerticalCursorAtViewportPosition(double position)
595 {
595 {
596 impl->m_VerticalCursor->setAbsolutePosition(position);
596 impl->m_VerticalCursor->setAbsolutePosition(position);
597 impl->m_VerticalCursor->setVisible(true);
597 impl->m_VerticalCursor->setVisible(true);
598
598
599 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
599 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
600 auto text
600 auto text
601 = DateUtils::dateTime(axis->pixelToCoord(position)).toString(CURSOR_LABELS_DATETIME_FORMAT);
601 = DateUtils::dateTime(axis->pixelToCoord(position)).toString(CURSOR_LABELS_DATETIME_FORMAT);
602 impl->m_VerticalCursor->setLabelText(text);
602 impl->m_VerticalCursor->setLabelText(text);
603 }
603 }
604
604
605 void VisualizationGraphWidget::removeVerticalCursor()
605 void VisualizationGraphWidget::removeVerticalCursor()
606 {
606 {
607 impl->m_VerticalCursor->setVisible(false);
607 impl->m_VerticalCursor->setVisible(false);
608 plot().replot(QCustomPlot::rpQueuedReplot);
608 plot().replot(QCustomPlot::rpQueuedReplot);
609 }
609 }
610
610
611 void VisualizationGraphWidget::addHorizontalCursor(double value)
611 void VisualizationGraphWidget::addHorizontalCursor(double value)
612 {
612 {
613 impl->m_HorizontalCursor->setPosition(value);
613 impl->m_HorizontalCursor->setPosition(value);
614 impl->m_HorizontalCursor->setVisible(true);
614 impl->m_HorizontalCursor->setVisible(true);
615 impl->m_HorizontalCursor->setLabelText(QString::number(value));
615 impl->m_HorizontalCursor->setLabelText(QString::number(value));
616 }
616 }
617
617
618 void VisualizationGraphWidget::addHorizontalCursorAtViewportPosition(double position)
618 void VisualizationGraphWidget::addHorizontalCursorAtViewportPosition(double position)
619 {
619 {
620 impl->m_HorizontalCursor->setAbsolutePosition(position);
620 impl->m_HorizontalCursor->setAbsolutePosition(position);
621 impl->m_HorizontalCursor->setVisible(true);
621 impl->m_HorizontalCursor->setVisible(true);
622
622
623 auto axis = plot().axisRect()->axis(QCPAxis::atLeft);
623 auto axis = plot().axisRect()->axis(QCPAxis::atLeft);
624 impl->m_HorizontalCursor->setLabelText(QString::number(axis->pixelToCoord(position)));
624 impl->m_HorizontalCursor->setLabelText(QString::number(axis->pixelToCoord(position)));
625 }
625 }
626
626
627 void VisualizationGraphWidget::removeHorizontalCursor()
627 void VisualizationGraphWidget::removeHorizontalCursor()
628 {
628 {
629 impl->m_HorizontalCursor->setVisible(false);
629 impl->m_HorizontalCursor->setVisible(false);
630 plot().replot(QCustomPlot::rpQueuedReplot);
630 plot().replot(QCustomPlot::rpQueuedReplot);
631 }
631 }
632
632
633 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
633 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
634 {
634 {
635 Q_UNUSED(event);
635 Q_UNUSED(event);
636
636
637 for (auto i : impl->m_SelectionZones) {
637 for (auto i : impl->m_SelectionZones) {
638 parentVisualizationWidget()->selectionZoneManager().setSelected(i, false);
638 parentVisualizationWidget()->selectionZoneManager().setSelected(i, false);
639 }
639 }
640
640
641 // Prevents that all variables will be removed from graph when it will be closed
641 // Prevents that all variables will be removed from graph when it will be closed
642 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
642 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
643 emit variableAboutToBeRemoved(variableEntry.first);
643 emit variableAboutToBeRemoved(variableEntry.first);
644 }
644 }
645 }
645 }
646
646
647 void VisualizationGraphWidget::enterEvent(QEvent *event)
647 void VisualizationGraphWidget::enterEvent(QEvent *event)
648 {
648 {
649 Q_UNUSED(event);
649 Q_UNUSED(event);
650 impl->m_RenderingDelegate->showGraphOverlay(true);
650 impl->m_RenderingDelegate->showGraphOverlay(true);
651 }
651 }
652
652
653 void VisualizationGraphWidget::leaveEvent(QEvent *event)
653 void VisualizationGraphWidget::leaveEvent(QEvent *event)
654 {
654 {
655 Q_UNUSED(event);
655 Q_UNUSED(event);
656 impl->m_RenderingDelegate->showGraphOverlay(false);
656 impl->m_RenderingDelegate->showGraphOverlay(false);
657
657
658 if (auto parentZone = parentZoneWidget()) {
658 if (auto parentZone = parentZoneWidget()) {
659 parentZone->notifyMouseLeaveGraph(this);
659 parentZone->notifyMouseLeaveGraph(this);
660 }
660 }
661 else {
661 else {
662 qCWarning(LOG_VisualizationGraphWidget()) << "leaveEvent: No parent zone widget";
662 qCWarning(LOG_VisualizationGraphWidget()) << "leaveEvent: No parent zone widget";
663 }
663 }
664
664
665 if (impl->m_HoveredZone) {
665 if (impl->m_HoveredZone) {
666 impl->m_HoveredZone->setHovered(false);
666 impl->m_HoveredZone->setHovered(false);
667 impl->m_HoveredZone = nullptr;
667 impl->m_HoveredZone = nullptr;
668 }
668 }
669 }
669 }
670
670
671 QCustomPlot &VisualizationGraphWidget::plot() const noexcept
671 QCustomPlot &VisualizationGraphWidget::plot() const noexcept
672 {
672 {
673 return *ui->widget;
673 return *ui->widget;
674 }
674 }
675
675
676 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
676 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
677 {
677 {
678 QMenu graphMenu{};
678 QMenu graphMenu{};
679
679
680 // Iterates on variables (unique keys)
680 // Iterates on variables (unique keys)
681 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
681 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
682 end = impl->m_VariableToPlotMultiMap.cend();
682 end = impl->m_VariableToPlotMultiMap.cend();
683 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
683 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
684 // 'Remove variable' action
684 // 'Remove variable' action
685 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
685 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
686 [ this, var = it->first ]() { removeVariable(var); });
686 [ this, var = it->first ]() { removeVariable(var); });
687 }
687 }
688
688
689 if (!impl->m_ZoomStack.isEmpty()) {
689 if (!impl->m_ZoomStack.isEmpty()) {
690 if (!graphMenu.isEmpty()) {
690 if (!graphMenu.isEmpty()) {
691 graphMenu.addSeparator();
691 graphMenu.addSeparator();
692 }
692 }
693
693
694 graphMenu.addAction(tr("Undo Zoom"), [this]() { undoZoom(); });
694 graphMenu.addAction(tr("Undo Zoom"), [this]() { undoZoom(); });
695 }
695 }
696
696
697 // Selection Zone Actions
697 // Selection Zone Actions
698 auto selectionZoneItem = impl->selectionZoneAt(pos, plot());
698 auto selectionZoneItem = impl->selectionZoneAt(pos, plot());
699 if (selectionZoneItem) {
699 if (selectionZoneItem) {
700 auto selectedItems = parentVisualizationWidget()->selectionZoneManager().selectedItems();
700 auto selectedItems = parentVisualizationWidget()->selectionZoneManager().selectedItems();
701 selectedItems.removeAll(selectionZoneItem);
701 selectedItems.removeAll(selectionZoneItem);
702 selectedItems.prepend(selectionZoneItem); // Put the current selection zone first
702 selectedItems.prepend(selectionZoneItem); // Put the current selection zone first
703
703
704 auto zoneActions = sqpApp->actionsGuiController().selectionZoneActions();
704 auto zoneActions = sqpApp->actionsGuiController().selectionZoneActions();
705 if (!zoneActions.isEmpty() && !graphMenu.isEmpty()) {
705 if (!zoneActions.isEmpty() && !graphMenu.isEmpty()) {
706 graphMenu.addSeparator();
706 graphMenu.addSeparator();
707 }
707 }
708
708
709 QHash<QString, QMenu *> subMenus;
709 QHash<QString, QMenu *> subMenus;
710 QHash<QString, bool> subMenusEnabled;
710 QHash<QString, bool> subMenusEnabled;
711 QHash<QString, FilteringAction *> filteredMenu;
711 QHash<QString, FilteringAction *> filteredMenu;
712
712
713 for (auto zoneAction : zoneActions) {
713 for (auto zoneAction : zoneActions) {
714
714
715 auto isEnabled = zoneAction->isEnabled(selectedItems);
715 auto isEnabled = zoneAction->isEnabled(selectedItems);
716
716
717 auto menu = &graphMenu;
717 auto menu = &graphMenu;
718 QString menuPath;
718 QString menuPath;
719 for (auto subMenuName : zoneAction->subMenuList()) {
719 for (auto subMenuName : zoneAction->subMenuList()) {
720 menuPath += '/';
720 menuPath += '/';
721 menuPath += subMenuName;
721 menuPath += subMenuName;
722
722
723 if (!subMenus.contains(menuPath)) {
723 if (!subMenus.contains(menuPath)) {
724 menu = menu->addMenu(subMenuName);
724 menu = menu->addMenu(subMenuName);
725 subMenus[menuPath] = menu;
725 subMenus[menuPath] = menu;
726 subMenusEnabled[menuPath] = isEnabled;
726 subMenusEnabled[menuPath] = isEnabled;
727 }
727 }
728 else {
728 else {
729 menu = subMenus.value(menuPath);
729 menu = subMenus.value(menuPath);
730 if (isEnabled) {
730 if (isEnabled) {
731 // The sub menu is enabled if at least one of its actions is enabled
731 // The sub menu is enabled if at least one of its actions is enabled
732 subMenusEnabled[menuPath] = true;
732 subMenusEnabled[menuPath] = true;
733 }
733 }
734 }
734 }
735 }
735 }
736
736
737 FilteringAction *filterAction = nullptr;
737 FilteringAction *filterAction = nullptr;
738 if (sqpApp->actionsGuiController().isMenuFiltered(zoneAction->subMenuList())) {
738 if (sqpApp->actionsGuiController().isMenuFiltered(zoneAction->subMenuList())) {
739 filterAction = filteredMenu.value(menuPath);
739 filterAction = filteredMenu.value(menuPath);
740 if (!filterAction) {
740 if (!filterAction) {
741 filterAction = new FilteringAction{this};
741 filterAction = new FilteringAction{this};
742 filteredMenu[menuPath] = filterAction;
742 filteredMenu[menuPath] = filterAction;
743 menu->addAction(filterAction);
743 menu->addAction(filterAction);
744 }
744 }
745 }
745 }
746
746
747 auto action = menu->addAction(zoneAction->name());
747 auto action = menu->addAction(zoneAction->name());
748 action->setEnabled(isEnabled);
748 action->setEnabled(isEnabled);
749 action->setShortcut(zoneAction->displayedShortcut());
749 action->setShortcut(zoneAction->displayedShortcut());
750 QObject::connect(action, &QAction::triggered,
750 QObject::connect(action, &QAction::triggered,
751 [zoneAction, selectedItems]() { zoneAction->execute(selectedItems); });
751 [zoneAction, selectedItems]() { zoneAction->execute(selectedItems); });
752
752
753 if (filterAction && zoneAction->isFilteringAllowed()) {
753 if (filterAction && zoneAction->isFilteringAllowed()) {
754 filterAction->addActionToFilter(action);
754 filterAction->addActionToFilter(action);
755 }
755 }
756 }
756 }
757
757
758 for (auto it = subMenus.cbegin(); it != subMenus.cend(); ++it) {
758 for (auto it = subMenus.cbegin(); it != subMenus.cend(); ++it) {
759 it.value()->setEnabled(subMenusEnabled[it.key()]);
759 it.value()->setEnabled(subMenusEnabled[it.key()]);
760 }
760 }
761 }
761 }
762
762
763 if (!graphMenu.isEmpty()) {
763 if (!graphMenu.isEmpty()) {
764 graphMenu.exec(QCursor::pos());
764 graphMenu.exec(QCursor::pos());
765 }
765 }
766 }
766 }
767
767
768 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
768 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
769 {
769 {
770 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
770 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
771 << QThread::currentThread()->objectName() << "DoAcqui"
771 << QThread::currentThread()->objectName() << "DoAcqui"
772 << impl->m_Flags.testFlag(GraphFlag::EnableAcquisition);
772 << impl->m_Flags.testFlag(GraphFlag::EnableAcquisition);
773
773
774 auto graphRange = SqpRange{t1.lower, t1.upper};
774 auto graphRange = SqpRange{t1.lower, t1.upper};
775 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
775 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
776
776
777 if (impl->m_Flags.testFlag(GraphFlag::EnableAcquisition)) {
777 if (impl->m_Flags.testFlag(GraphFlag::EnableAcquisition)) {
778 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
778 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
779
779
780 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
780 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
781 end = impl->m_VariableToPlotMultiMap.end();
781 end = impl->m_VariableToPlotMultiMap.end();
782 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
782 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
783 variableUnderGraphVector.push_back(it->first);
783 variableUnderGraphVector.push_back(it->first);
784 }
784 }
785 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
785 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
786 !impl->m_IsCalibration);
786 !impl->m_IsCalibration);
787 }
787 }
788
788
789 if (impl->m_Flags.testFlag(GraphFlag::EnableSynchronization) && !impl->m_IsCalibration) {
789 if (impl->m_Flags.testFlag(GraphFlag::EnableSynchronization) && !impl->m_IsCalibration) {
790 qCDebug(LOG_VisualizationGraphWidget())
790 qCDebug(LOG_VisualizationGraphWidget())
791 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
791 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
792 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
792 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
793 emit synchronize(graphRange, oldGraphRange);
793 emit synchronize(graphRange, oldGraphRange);
794 }
794 }
795
795
796 auto pos = mapFromGlobal(QCursor::pos());
796 auto pos = mapFromGlobal(QCursor::pos());
797 auto axisPos = impl->posToAxisPos(pos, plot());
797 auto axisPos = impl->posToAxisPos(pos, plot());
798 if (auto parentZone = parentZoneWidget()) {
798 if (auto parentZone = parentZoneWidget()) {
799 if (impl->pointIsInAxisRect(axisPos, plot())) {
799 if (impl->pointIsInAxisRect(axisPos, plot())) {
800 parentZone->notifyMouseMoveInGraph(pos, axisPos, this);
800 parentZone->notifyMouseMoveInGraph(pos, axisPos, this);
801 }
801 }
802 else {
802 else {
803 parentZone->notifyMouseLeaveGraph(this);
803 parentZone->notifyMouseLeaveGraph(this);
804 }
804 }
805 }
805 }
806 else {
806 else {
807 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
807 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
808 }
808 }
809
809
810 // Quits calibration
810 // Quits calibration
811 impl->m_IsCalibration = false;
811 impl->m_IsCalibration = false;
812 }
812 }
813
813
814 void VisualizationGraphWidget::onMouseDoubleClick(QMouseEvent *event) noexcept
814 void VisualizationGraphWidget::onMouseDoubleClick(QMouseEvent *event) noexcept
815 {
815 {
816 impl->m_RenderingDelegate->onMouseDoubleClick(event);
816 impl->m_RenderingDelegate->onMouseDoubleClick(event);
817 }
817 }
818
818
819 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
819 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
820 {
820 {
821 // Handles plot rendering when mouse is moving
821 // Handles plot rendering when mouse is moving
822 impl->m_RenderingDelegate->onMouseMove(event);
822 impl->m_RenderingDelegate->onMouseMove(event);
823
823
824 auto axisPos = impl->posToAxisPos(event->pos(), plot());
824 auto axisPos = impl->posToAxisPos(event->pos(), plot());
825
825
826 // Zoom box and zone drawing
826 // Zoom box and zone drawing
827 if (impl->m_DrawingZoomRect) {
827 if (impl->m_DrawingZoomRect) {
828 impl->m_DrawingZoomRect->bottomRight->setCoords(axisPos);
828 impl->m_DrawingZoomRect->bottomRight->setCoords(axisPos);
829 }
829 }
830 else if (impl->m_DrawingZone) {
830 else if (impl->m_DrawingZone) {
831 impl->m_DrawingZone->setEnd(axisPos.x());
831 impl->m_DrawingZone->setEnd(axisPos.x());
832 }
832 }
833
833
834 // Cursor
834 // Cursor
835 if (auto parentZone = parentZoneWidget()) {
835 if (auto parentZone = parentZoneWidget()) {
836 if (impl->pointIsInAxisRect(axisPos, plot())) {
836 if (impl->pointIsInAxisRect(axisPos, plot())) {
837 parentZone->notifyMouseMoveInGraph(event->pos(), axisPos, this);
837 parentZone->notifyMouseMoveInGraph(event->pos(), axisPos, this);
838 }
838 }
839 else {
839 else {
840 parentZone->notifyMouseLeaveGraph(this);
840 parentZone->notifyMouseLeaveGraph(this);
841 }
841 }
842 }
842 }
843 else {
843 else {
844 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
844 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
845 }
845 }
846
846
847 // Search for the selection zone under the mouse
847 // Search for the selection zone under the mouse
848 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
848 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
849 if (selectionZoneItemUnderCursor && !impl->m_DrawingZone
849 if (selectionZoneItemUnderCursor && !impl->m_DrawingZone
850 && sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones) {
850 && sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones) {
851
851
852 // Sets the appropriate cursor shape
852 // Sets the appropriate cursor shape
853 auto cursorShape = selectionZoneItemUnderCursor->curshorShapeForPosition(event->pos());
853 auto cursorShape = selectionZoneItemUnderCursor->curshorShapeForPosition(event->pos());
854 setCursor(cursorShape);
854 setCursor(cursorShape);
855
855
856 // Manages the hovered zone
856 // Manages the hovered zone
857 if (selectionZoneItemUnderCursor != impl->m_HoveredZone) {
857 if (selectionZoneItemUnderCursor != impl->m_HoveredZone) {
858 if (impl->m_HoveredZone) {
858 if (impl->m_HoveredZone) {
859 impl->m_HoveredZone->setHovered(false);
859 impl->m_HoveredZone->setHovered(false);
860 }
860 }
861 selectionZoneItemUnderCursor->setHovered(true);
861 selectionZoneItemUnderCursor->setHovered(true);
862 impl->m_HoveredZone = selectionZoneItemUnderCursor;
862 impl->m_HoveredZone = selectionZoneItemUnderCursor;
863 plot().replot(QCustomPlot::rpQueuedReplot);
863 plot().replot(QCustomPlot::rpQueuedReplot);
864 }
864 }
865 }
865 }
866 else {
866 else {
867 // There is no zone under the mouse or the interaction mode is not "selection zones"
867 // There is no zone under the mouse or the interaction mode is not "selection zones"
868 if (impl->m_HoveredZone) {
868 if (impl->m_HoveredZone) {
869 impl->m_HoveredZone->setHovered(false);
869 impl->m_HoveredZone->setHovered(false);
870 impl->m_HoveredZone = nullptr;
870 impl->m_HoveredZone = nullptr;
871 }
871 }
872
872
873 setCursor(Qt::ArrowCursor);
873 setCursor(Qt::ArrowCursor);
874 }
874 }
875
875
876 impl->m_HasMovedMouse = true;
876 impl->m_HasMovedMouse = true;
877 VisualizationDragWidget::mouseMoveEvent(event);
877 VisualizationDragWidget::mouseMoveEvent(event);
878 }
878 }
879
879
880 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
880 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
881 {
881 {
882 // Processes event only if the wheel occurs on axis rect
882 // Processes event only if the wheel occurs on axis rect
883 if (!dynamic_cast<QCPAxisRect *>(ui->widget->layoutElementAt(event->posF()))) {
883 if (!dynamic_cast<QCPAxisRect *>(ui->widget->layoutElementAt(event->posF()))) {
884 return;
884 return;
885 }
885 }
886
886
887 auto value = event->angleDelta().x() + event->angleDelta().y();
887 auto value = event->angleDelta().x() + event->angleDelta().y();
888 if (value != 0) {
888 if (value != 0) {
889
889
890 auto direction = value > 0 ? 1.0 : -1.0;
890 auto direction = value > 0 ? 1.0 : -1.0;
891 auto isZoomX = event->modifiers().testFlag(HORIZONTAL_ZOOM_MODIFIER);
891 auto isZoomX = event->modifiers().testFlag(HORIZONTAL_ZOOM_MODIFIER);
892 auto isZoomY = event->modifiers().testFlag(VERTICAL_ZOOM_MODIFIER);
892 auto isZoomY = event->modifiers().testFlag(VERTICAL_ZOOM_MODIFIER);
893 impl->m_IsCalibration = event->modifiers().testFlag(VERTICAL_PAN_MODIFIER);
893 impl->m_IsCalibration = event->modifiers().testFlag(VERTICAL_PAN_MODIFIER);
894
894
895 auto zoomOrientations = QFlags<Qt::Orientation>{};
895 auto zoomOrientations = QFlags<Qt::Orientation>{};
896 zoomOrientations.setFlag(Qt::Horizontal, isZoomX);
896 zoomOrientations.setFlag(Qt::Horizontal, isZoomX);
897 zoomOrientations.setFlag(Qt::Vertical, isZoomY);
897 zoomOrientations.setFlag(Qt::Vertical, isZoomY);
898
898
899 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
899 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
900
900
901 if (!isZoomX && !isZoomY) {
901 if (!isZoomX && !isZoomY) {
902 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
902 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
903 auto diff = direction * (axis->range().size() * (PAN_SPEED / 100.0));
903 auto diff = direction * (axis->range().size() * (PAN_SPEED / 100.0));
904
904
905 axis->setRange(axis->range() + diff);
905 axis->setRange(axis->range() + diff);
906
906
907 if (plot().noAntialiasingOnDrag()) {
907 if (plot().noAntialiasingOnDrag()) {
908 plot().setNotAntialiasedElements(QCP::aeAll);
908 plot().setNotAntialiasedElements(QCP::aeAll);
909 }
909 }
910
910
911 plot().replot(QCustomPlot::rpQueuedReplot);
911 plot().replot(QCustomPlot::rpQueuedReplot);
912 }
912 }
913 }
913 }
914 }
914 }
915
915
916 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
916 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
917 {
917 {
918 auto isDragDropClick = event->modifiers().testFlag(DRAG_DROP_MODIFIER);
918 auto isDragDropClick = event->modifiers().testFlag(DRAG_DROP_MODIFIER);
919 auto isSelectionZoneMode
919 auto isSelectionZoneMode
920 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
920 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
921 auto isLeftClick = event->buttons().testFlag(Qt::LeftButton);
921 auto isLeftClick = event->buttons().testFlag(Qt::LeftButton);
922
922
923 if (!isDragDropClick && isLeftClick) {
923 if (!isDragDropClick && isLeftClick) {
924 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::ZoomBox) {
924 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::ZoomBox) {
925 // Starts a zoom box
925 // Starts a zoom box
926 impl->startDrawingRect(event->pos(), plot());
926 impl->startDrawingRect(event->pos(), plot());
927 }
927 }
928 else if (isSelectionZoneMode && impl->m_DrawingZone == nullptr) {
928 else if (isSelectionZoneMode && impl->m_DrawingZone == nullptr) {
929 // Starts a new selection zone
929 // Starts a new selection zone
930 auto zoneAtPos = impl->selectionZoneAt(event->pos(), plot());
930 auto zoneAtPos = impl->selectionZoneAt(event->pos(), plot());
931 if (!zoneAtPos) {
931 if (!zoneAtPos) {
932 impl->startDrawingZone(event->pos(), this);
932 impl->startDrawingZone(event->pos(), this);
933 }
933 }
934 }
934 }
935 }
935 }
936
936
937 // Allows mouse panning only in default mode
937 // Allows mouse panning only in default mode
938 plot().setInteraction(QCP::iRangeDrag, sqpApp->plotsInteractionMode()
938 plot().setInteraction(QCP::iRangeDrag, sqpApp->plotsInteractionMode()
939 == SqpApplication::PlotsInteractionMode::None
939 == SqpApplication::PlotsInteractionMode::None
940 && !isDragDropClick);
940 && !isDragDropClick);
941
941
942 // Allows zone edition only in selection zone mode without drag&drop
942 // Allows zone edition only in selection zone mode without drag&drop
943 impl->setSelectionZonesEditionEnabled(isSelectionZoneMode && !isDragDropClick);
943 impl->setSelectionZonesEditionEnabled(isSelectionZoneMode && !isDragDropClick);
944
944
945 // Selection / Deselection
945 // Selection / Deselection
946 if (isSelectionZoneMode) {
946 if (isSelectionZoneMode) {
947 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
947 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
948 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
948 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
949
949
950
950
951 if (selectionZoneItemUnderCursor && !selectionZoneItemUnderCursor->selected()
951 if (selectionZoneItemUnderCursor && !selectionZoneItemUnderCursor->selected()
952 && !isMultiSelectionClick) {
952 && !isMultiSelectionClick) {
953 parentVisualizationWidget()->selectionZoneManager().select(
953 parentVisualizationWidget()->selectionZoneManager().select(
954 {selectionZoneItemUnderCursor});
954 {selectionZoneItemUnderCursor});
955 }
955 }
956 else if (!selectionZoneItemUnderCursor && !isMultiSelectionClick && isLeftClick) {
956 else if (!selectionZoneItemUnderCursor && !isMultiSelectionClick && isLeftClick) {
957 parentVisualizationWidget()->selectionZoneManager().clearSelection();
957 parentVisualizationWidget()->selectionZoneManager().clearSelection();
958 }
958 }
959 else {
959 else {
960 // No selection change
960 // No selection change
961 }
961 }
962
962
963 if (selectionZoneItemUnderCursor && isLeftClick) {
963 if (selectionZoneItemUnderCursor && isLeftClick) {
964 selectionZoneItemUnderCursor->setAssociatedEditedZones(
964 selectionZoneItemUnderCursor->setAssociatedEditedZones(
965 parentVisualizationWidget()->selectionZoneManager().selectedItems());
965 parentVisualizationWidget()->selectionZoneManager().selectedItems());
966 }
966 }
967 }
967 }
968
968
969
969
970 impl->m_HasMovedMouse = false;
970 impl->m_HasMovedMouse = false;
971 VisualizationDragWidget::mousePressEvent(event);
971 VisualizationDragWidget::mousePressEvent(event);
972 }
972 }
973
973
974 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
974 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
975 {
975 {
976 if (impl->m_DrawingZoomRect) {
976 if (impl->m_DrawingZoomRect) {
977
977
978 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
978 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
979 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
979 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
980
980
981 auto newAxisXRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().x(),
981 auto newAxisXRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().x(),
982 impl->m_DrawingZoomRect->bottomRight->coords().x()};
982 impl->m_DrawingZoomRect->bottomRight->coords().x()};
983
983
984 auto newAxisYRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().y(),
984 auto newAxisYRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().y(),
985 impl->m_DrawingZoomRect->bottomRight->coords().y()};
985 impl->m_DrawingZoomRect->bottomRight->coords().y()};
986
986
987 impl->removeDrawingRect(plot());
987 impl->removeDrawingRect(plot());
988
988
989 if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)
989 if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)
990 && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)) {
990 && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)) {
991 impl->m_ZoomStack.push(qMakePair(axisX->range(), axisY->range()));
991 impl->m_ZoomStack.push(qMakePair(axisX->range(), axisY->range()));
992 axisX->setRange(newAxisXRange);
992 axisX->setRange(newAxisXRange);
993 axisY->setRange(newAxisYRange);
993 axisY->setRange(newAxisYRange);
994
994
995 plot().replot(QCustomPlot::rpQueuedReplot);
995 plot().replot(QCustomPlot::rpQueuedReplot);
996 }
996 }
997 }
997 }
998
998
999 impl->endDrawingZone(this);
999 impl->endDrawingZone(this);
1000
1000
1001 // Selection / Deselection
1001 // Selection / Deselection
1002 auto isSelectionZoneMode
1002 auto isSelectionZoneMode
1003 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
1003 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
1004 if (isSelectionZoneMode) {
1004 if (isSelectionZoneMode) {
1005 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
1005 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
1006 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
1006 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
1007 if (selectionZoneItemUnderCursor && event->button() == Qt::LeftButton
1007 if (selectionZoneItemUnderCursor && event->button() == Qt::LeftButton
1008 && !impl->m_HasMovedMouse) {
1008 && !impl->m_HasMovedMouse) {
1009
1009
1010 auto zonesUnderCursor = impl->selectionZonesAt(event->pos(), plot());
1010 auto zonesUnderCursor = impl->selectionZonesAt(event->pos(), plot());
1011 if (zonesUnderCursor.count() > 1) {
1011 if (zonesUnderCursor.count() > 1) {
1012 // There are multiple zones under the mouse.
1012 // There are multiple zones under the mouse.
1013 // Performs the selection with a selection dialog.
1013 // Performs the selection with a selection dialog.
1014 VisualizationMultiZoneSelectionDialog dialog{this};
1014 VisualizationMultiZoneSelectionDialog dialog{this};
1015 dialog.setZones(zonesUnderCursor);
1015 dialog.setZones(zonesUnderCursor);
1016 dialog.move(mapToGlobal(event->pos() - QPoint(dialog.width() / 2, 20)));
1016 dialog.move(mapToGlobal(event->pos() - QPoint(dialog.width() / 2, 20)));
1017 dialog.activateWindow();
1017 dialog.activateWindow();
1018 dialog.raise();
1018 dialog.raise();
1019 if (dialog.exec() == QDialog::Accepted) {
1019 if (dialog.exec() == QDialog::Accepted) {
1020 auto selection = dialog.selectedZones();
1020 auto selection = dialog.selectedZones();
1021
1021
1022 if (!isMultiSelectionClick) {
1022 if (!isMultiSelectionClick) {
1023 parentVisualizationWidget()->selectionZoneManager().clearSelection();
1023 parentVisualizationWidget()->selectionZoneManager().clearSelection();
1024 }
1024 }
1025
1025
1026 for (auto it = selection.cbegin(); it != selection.cend(); ++it) {
1026 for (auto it = selection.cbegin(); it != selection.cend(); ++it) {
1027 auto zone = it.key();
1027 auto zone = it.key();
1028 auto isSelected = it.value();
1028 auto isSelected = it.value();
1029 parentVisualizationWidget()->selectionZoneManager().setSelected(zone,
1029 parentVisualizationWidget()->selectionZoneManager().setSelected(zone,
1030 isSelected);
1030 isSelected);
1031
1031
1032 if (isSelected) {
1032 if (isSelected) {
1033 // Puts the zone on top of the stack so it can be moved or resized
1033 // Puts the zone on top of the stack so it can be moved or resized
1034 impl->moveSelectionZoneOnTop(zone, plot());
1034 impl->moveSelectionZoneOnTop(zone, plot());
1035 }
1035 }
1036 }
1036 }
1037 }
1037 }
1038 }
1038 }
1039 else {
1039 else {
1040 if (!isMultiSelectionClick) {
1040 if (!isMultiSelectionClick) {
1041 parentVisualizationWidget()->selectionZoneManager().select(
1041 parentVisualizationWidget()->selectionZoneManager().select(
1042 {selectionZoneItemUnderCursor});
1042 {selectionZoneItemUnderCursor});
1043 impl->moveSelectionZoneOnTop(selectionZoneItemUnderCursor, plot());
1043 impl->moveSelectionZoneOnTop(selectionZoneItemUnderCursor, plot());
1044 }
1044 }
1045 else {
1045 else {
1046 parentVisualizationWidget()->selectionZoneManager().setSelected(
1046 parentVisualizationWidget()->selectionZoneManager().setSelected(
1047 selectionZoneItemUnderCursor, !selectionZoneItemUnderCursor->selected()
1047 selectionZoneItemUnderCursor, !selectionZoneItemUnderCursor->selected()
1048 || event->button() == Qt::RightButton);
1048 || event->button() == Qt::RightButton);
1049 }
1049 }
1050 }
1050 }
1051 }
1051 }
1052 else {
1052 else {
1053 // No selection change
1053 // No selection change
1054 }
1054 }
1055 }
1055 }
1056 }
1056 }
1057
1057
1058 void VisualizationGraphWidget::onDataCacheVariableUpdated()
1058 void VisualizationGraphWidget::onDataCacheVariableUpdated()
1059 {
1059 {
1060 auto graphRange = ui->widget->xAxis->range();
1060 auto graphRange = ui->widget->xAxis->range();
1061 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
1061 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
1062
1062
1063 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
1063 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
1064 auto variable = variableEntry.first;
1064 auto variable = variableEntry.first;
1065 qCDebug(LOG_VisualizationGraphWidget())
1065 qCDebug(LOG_VisualizationGraphWidget())
1066 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
1066 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
1067 qCDebug(LOG_VisualizationGraphWidget())
1067 qCDebug(LOG_VisualizationGraphWidget())
1068 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
1068 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
1069 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
1069 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
1070 impl->updateData(variableEntry.second, variable, variable->range());
1070 impl->updateData(variableEntry.second, variable, variable->range());
1071 }
1071 }
1072 }
1072 }
1073 }
1073 }
1074
1074
1075 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
1075 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
1076 const SqpRange &range)
1076 const SqpRange &range)
1077 {
1077 {
1078 auto it = impl->m_VariableToPlotMultiMap.find(variable);
1078 auto it = impl->m_VariableToPlotMultiMap.find(variable);
1079 if (it != impl->m_VariableToPlotMultiMap.end()) {
1079 if (it != impl->m_VariableToPlotMultiMap.end()) {
1080 impl->updateData(it->second, variable, range);
1080 impl->updateData(it->second, variable, range);
1081 }
1081 }
1082 }
1082 }
@@ -1,274 +1,275
1 #include "AmdaProvider.h"
1 #include "AmdaProvider.h"
2 #include "AmdaDefs.h"
2 #include "AmdaDefs.h"
3 #include "AmdaResultParser.h"
3 #include "AmdaResultParser.h"
4 #include "AmdaServer.h"
4 #include "AmdaServer.h"
5
5
6 #include <Common/DateUtils.h>
6 #include <Common/DateUtils.h>
7 #include <Data/DataProviderParameters.h>
7 #include <Data/DataProviderParameters.h>
8 #include <Network/NetworkController.h>
8 #include <Network/NetworkController.h>
9 #include <SqpApplication.h>
9 #include <SqpApplication.h>
10 #include <Variable/Variable.h>
10 #include <Variable/Variable.h>
11
11
12 #include <QNetworkAccessManager>
12 #include <QNetworkAccessManager>
13 #include <QNetworkReply>
13 #include <QNetworkReply>
14 #include <QTemporaryFile>
14 #include <QTemporaryFile>
15 #include <QThread>
15 #include <QThread>
16
16
17 Q_LOGGING_CATEGORY(LOG_AmdaProvider, "AmdaProvider")
17 Q_LOGGING_CATEGORY(LOG_AmdaProvider, "AmdaProvider")
18
18
19 namespace {
19 namespace {
20
20
21 /// URL format for a request on AMDA server. The parameters are as follows:
21 /// URL format for a request on AMDA server. The parameters are as follows:
22 /// - %1: server URL
22 /// - %1: server URL
23 /// - %2: start date
23 /// - %2: start date
24 /// - %3: end date
24 /// - %3: end date
25 /// - %4: parameter id
25 /// - %4: parameter id
26 /// AMDA V2: http://amdatest.irap.omp.eu/php/rest/
26 /// AMDA V2: http://amdatest.irap.omp.eu/php/rest/
27 const auto AMDA_URL_FORMAT = QStringLiteral(
27 const auto AMDA_URL_FORMAT = QStringLiteral(
28 "http://%1/php/rest/"
28 "http://%1/php/rest/"
29 "getParameter.php?startTime=%2&stopTime=%3&parameterID=%4&outputFormat=ASCII&"
29 "getParameter.php?startTime=%2&stopTime=%3&parameterID=%4&outputFormat=ASCII&"
30 "timeFormat=ISO8601&gzip=0");
30 "timeFormat=ISO8601&gzip=0");
31
31
32 /// Dates format passed in the URL (e.g 2013-09-23T09:00)
32 /// Dates format passed in the URL (e.g 2013-09-23T09:00)
33 const auto AMDA_TIME_FORMAT = QStringLiteral("yyyy-MM-ddThh:mm:ss");
33 const auto AMDA_TIME_FORMAT = QStringLiteral("yyyy-MM-ddThh:mm:ss");
34
34
35 /// Formats a time to a date that can be passed in URL
35 /// Formats a time to a date that can be passed in URL
36 QString dateFormat(double sqpRange) noexcept
36 QString dateFormat(double sqpRange) noexcept
37 {
37 {
38 auto dateTime = DateUtils::dateTime(sqpRange);
38 auto dateTime = DateUtils::dateTime(sqpRange);
39 return dateTime.toString(AMDA_TIME_FORMAT);
39 return dateTime.toString(AMDA_TIME_FORMAT);
40 }
40 }
41
41
42
42
43 } // namespace
43 } // namespace
44
44
45 AmdaProvider::AmdaProvider()
45 AmdaProvider::AmdaProvider()
46 {
46 {
47 qCDebug(LOG_AmdaProvider()) << tr("AmdaProvider::AmdaProvider") << QThread::currentThread();
47 qCDebug(LOG_AmdaProvider()) << tr("AmdaProvider::AmdaProvider") << QThread::currentThread();
48 if (auto app = sqpApp) {
48 if (auto app = sqpApp) {
49 auto &networkController = app->networkController();
49 auto &networkController = app->networkController();
50 connect(this, SIGNAL(requestConstructed(std::shared_ptr<QNetworkRequest>, QUuid,
50 connect(this, SIGNAL(requestConstructed(std::shared_ptr<QNetworkRequest>, QUuid,
51 std::function<void(QNetworkReply *, QUuid)>)),
51 std::function<void(QNetworkReply *, QUuid)>)),
52 &networkController,
52 &networkController,
53 SLOT(onProcessRequested(std::shared_ptr<QNetworkRequest>, QUuid,
53 SLOT(onProcessRequested(std::shared_ptr<QNetworkRequest>, QUuid,
54 std::function<void(QNetworkReply *, QUuid)>)));
54 std::function<void(QNetworkReply *, QUuid)>)));
55
55
56
56
57 connect(&sqpApp->networkController(),
57 connect(&sqpApp->networkController(),
58 SIGNAL(replyDownloadProgress(QUuid, std::shared_ptr<QNetworkRequest>, double)),
58 SIGNAL(replyDownloadProgress(QUuid, std::shared_ptr<QNetworkRequest>, double)),
59 this,
59 this,
60 SLOT(onReplyDownloadProgress(QUuid, std::shared_ptr<QNetworkRequest>, double)));
60 SLOT(onReplyDownloadProgress(QUuid, std::shared_ptr<QNetworkRequest>, double)));
61 }
61 }
62 }
62 }
63
63
64 std::shared_ptr<IDataProvider> AmdaProvider::clone() const
64 std::shared_ptr<IDataProvider> AmdaProvider::clone() const
65 {
65 {
66 // No copy is made in the clone
66 // No copy is made in the clone
67 return std::make_shared<AmdaProvider>();
67 return std::make_shared<AmdaProvider>();
68 }
68 }
69
69
70 void AmdaProvider::requestDataLoading(QUuid acqIdentifier, const DataProviderParameters &parameters)
70 void AmdaProvider::requestDataLoading(QUuid acqIdentifier, const DataProviderParameters &parameters)
71 {
71 {
72 // NOTE: Try to use multithread if possible
72 // NOTE: Try to use multithread if possible
73 const auto times = parameters.m_Times;
73 const auto times = parameters.m_Times;
74 const auto data = parameters.m_Data;
74 const auto data = parameters.m_Data;
75 for (const auto &dateTime : qAsConst(times)) {
75 for (const auto &dateTime : qAsConst(times)) {
76 qCDebug(LOG_AmdaProvider()) << tr("TORM AmdaProvider::requestDataLoading ") << acqIdentifier
76 qCDebug(LOG_AmdaProvider()) << tr("TORM AmdaProvider::requestDataLoading ") << acqIdentifier
77 << dateTime;
77 << dateTime;
78 this->retrieveData(acqIdentifier, dateTime, data);
78 this->retrieveData(acqIdentifier, dateTime, data);
79
79
80
80
81 // TORM when AMDA will support quick asynchrone request
81 // TORM when AMDA will support quick asynchrone request
82 QThread::msleep(1000);
82 QThread::msleep(1000);
83 }
83 }
84 }
84 }
85
85
86 void AmdaProvider::requestDataAborting(QUuid acqIdentifier)
86 void AmdaProvider::requestDataAborting(QUuid acqIdentifier)
87 {
87 {
88 if (auto app = sqpApp) {
88 if (auto app = sqpApp) {
89 auto &networkController = app->networkController();
89 auto &networkController = app->networkController();
90 networkController.onReplyCanceled(acqIdentifier);
90 networkController.onReplyCanceled(acqIdentifier);
91 }
91 }
92 }
92 }
93
93
94 void AmdaProvider::onReplyDownloadProgress(QUuid acqIdentifier,
94 void AmdaProvider::onReplyDownloadProgress(QUuid acqIdentifier,
95 std::shared_ptr<QNetworkRequest> networkRequest,
95 std::shared_ptr<QNetworkRequest> networkRequest,
96 double progress)
96 double progress)
97 {
97 {
98 qCDebug(LOG_AmdaProvider()) << tr("onReplyDownloadProgress") << acqIdentifier
98 qCDebug(LOG_AmdaProvider()) << tr("onReplyDownloadProgress") << acqIdentifier
99 << networkRequest.get() << progress;
99 << networkRequest.get() << progress;
100 auto acqIdToRequestProgressMapIt = m_AcqIdToRequestProgressMap.find(acqIdentifier);
100 auto acqIdToRequestProgressMapIt = m_AcqIdToRequestProgressMap.find(acqIdentifier);
101 if (acqIdToRequestProgressMapIt != m_AcqIdToRequestProgressMap.end()) {
101 if (acqIdToRequestProgressMapIt != m_AcqIdToRequestProgressMap.end()) {
102
102
103 // Update the progression for the current request
103 // Update the progression for the current request
104 auto requestPtr = networkRequest;
104 auto requestPtr = networkRequest;
105 auto findRequest = [requestPtr](const auto &entry) { return requestPtr == entry.first; };
105 auto findRequest = [requestPtr](const auto &entry) { return requestPtr == entry.first; };
106
106
107 auto &requestProgressMap = acqIdToRequestProgressMapIt->second;
107 auto &requestProgressMap = acqIdToRequestProgressMapIt->second;
108 auto requestProgressMapEnd = requestProgressMap.end();
108 auto requestProgressMapEnd = requestProgressMap.end();
109 auto requestProgressMapIt
109 auto requestProgressMapIt
110 = std::find_if(requestProgressMap.begin(), requestProgressMapEnd, findRequest);
110 = std::find_if(requestProgressMap.begin(), requestProgressMapEnd, findRequest);
111
111
112 if (requestProgressMapIt != requestProgressMapEnd) {
112 if (requestProgressMapIt != requestProgressMapEnd) {
113 requestProgressMapIt->second = progress;
113 requestProgressMapIt->second = progress;
114 }
114 }
115 else {
115 else {
116 // This case can happened when a progression is send after the request has been
116 // This case can happened when a progression is send after the request has been
117 // finished.
117 // finished.
118 // Generaly the case when aborting a request
118 // Generaly the case when aborting a request
119 qCDebug(LOG_AmdaProvider()) << tr("Can't retrieve Request in progress") << acqIdentifier
119 qCDebug(LOG_AmdaProvider()) << tr("Can't retrieve Request in progress") << acqIdentifier
120 << networkRequest.get() << progress;
120 << networkRequest.get() << progress;
121 }
121 }
122
122
123 // Compute the current final progress and notify it
123 // Compute the current final progress and notify it
124 double finalProgress = 0.0;
124 double finalProgress = 0.0;
125
125
126 auto fraq = requestProgressMap.size();
126 auto fraq = requestProgressMap.size();
127
127
128 for (auto requestProgress : requestProgressMap) {
128 for (auto requestProgress : requestProgressMap) {
129 finalProgress += requestProgress.second;
129 finalProgress += requestProgress.second;
130 qCDebug(LOG_AmdaProvider()) << tr("Current final progress without fraq:")
130 qCDebug(LOG_AmdaProvider()) << tr("Current final progress without fraq:")
131 << finalProgress << requestProgress.second;
131 << finalProgress << requestProgress.second;
132 }
132 }
133
133
134 if (fraq > 0) {
134 if (fraq > 0) {
135 finalProgress = finalProgress / fraq;
135 finalProgress = finalProgress / fraq;
136 }
136 }
137
137
138 qCDebug(LOG_AmdaProvider()) << tr("Current final progress: ") << fraq << finalProgress;
138 qCDebug(LOG_AmdaProvider()) << tr("final progress: ")
139 << QThread::currentThread()->objectName() << acqIdentifier
140 << fraq << finalProgress;
139 emit dataProvidedProgress(acqIdentifier, finalProgress);
141 emit dataProvidedProgress(acqIdentifier, finalProgress);
140 }
142 }
141 else {
143 else {
142 // This case can happened when a progression is send after the request has been finished.
144 // This case can happened when a progression is send after the request has been finished.
143 // Generaly the case when aborting a request
145 // Generaly the case when aborting a request
146 qCDebug(LOG_AmdaProvider()) << tr("Acquisition request not found: final progress: 100 : ")
147 << QThread::currentThread()->objectName() << acqIdentifier;
144 emit dataProvidedProgress(acqIdentifier, 100.0);
148 emit dataProvidedProgress(acqIdentifier, 100.0);
145 }
149 }
146 }
150 }
147
151
148 void AmdaProvider::retrieveData(QUuid token, const SqpRange &dateTime, const QVariantHash &data)
152 void AmdaProvider::retrieveData(QUuid token, const SqpRange &dateTime, const QVariantHash &data)
149 {
153 {
150 // Retrieves product ID from data: if the value is invalid, no request is made
154 // Retrieves product ID from data: if the value is invalid, no request is made
151 auto productId = data.value(AMDA_XML_ID_KEY).toString();
155 auto productId = data.value(AMDA_XML_ID_KEY).toString();
152 if (productId.isNull()) {
156 if (productId.isNull()) {
153 qCCritical(LOG_AmdaProvider()) << tr("Can't retrieve data: unknown product id");
157 qCCritical(LOG_AmdaProvider()) << tr("Can't retrieve data: unknown product id");
154 return;
158 return;
155 }
159 }
156
160
157 // Retrieves the data type that determines whether the expected format for the result file is
161 // Retrieves the data type that determines whether the expected format for the result file is
158 // scalar, vector...
162 // scalar, vector...
159 auto productValueType
163 auto productValueType
160 = DataSeriesTypeUtils::fromString(data.value(AMDA_DATA_TYPE_KEY).toString());
164 = DataSeriesTypeUtils::fromString(data.value(AMDA_DATA_TYPE_KEY).toString());
161
165
162 // /////////// //
166 // /////////// //
163 // Creates URL //
167 // Creates URL //
164 // /////////// //
168 // /////////// //
165
169
166 auto startDate = dateFormat(dateTime.m_TStart);
170 auto startDate = dateFormat(dateTime.m_TStart);
167 auto endDate = dateFormat(dateTime.m_TEnd);
171 auto endDate = dateFormat(dateTime.m_TEnd);
168
172
169 QVariantHash urlProperties{{AMDA_SERVER_KEY, data.value(AMDA_SERVER_KEY)}};
173 QVariantHash urlProperties{{AMDA_SERVER_KEY, data.value(AMDA_SERVER_KEY)}};
170 auto url = QUrl{QString{AMDA_URL_FORMAT}.arg(AmdaServer::instance().url(urlProperties),
174 auto url = QUrl{QString{AMDA_URL_FORMAT}.arg(AmdaServer::instance().url(urlProperties),
171 startDate, endDate, productId)};
175 startDate, endDate, productId)};
172 qCInfo(LOG_AmdaProvider()) << tr("TORM AmdaProvider::retrieveData url:") << url;
173 auto tempFile = std::make_shared<QTemporaryFile>();
176 auto tempFile = std::make_shared<QTemporaryFile>();
174
177
175 // LAMBDA
178 // LAMBDA
176 auto httpDownloadFinished = [this, dateTime, tempFile,
179 auto httpDownloadFinished = [this, dateTime, tempFile,
177 productValueType](QNetworkReply *reply, QUuid dataId) noexcept {
180 productValueType](QNetworkReply *reply, QUuid dataId) noexcept {
178
181
179 // Don't do anything if the reply was abort
182 // Don't do anything if the reply was abort
180 if (reply->error() == QNetworkReply::NoError) {
183 if (reply->error() == QNetworkReply::NoError) {
181
184
182 if (tempFile) {
185 if (tempFile) {
183 auto replyReadAll = reply->readAll();
186 auto replyReadAll = reply->readAll();
184 if (!replyReadAll.isEmpty()) {
187 if (!replyReadAll.isEmpty()) {
185 tempFile->write(replyReadAll);
188 tempFile->write(replyReadAll);
186 }
189 }
187 tempFile->close();
190 tempFile->close();
188
191
189 // Parse results file
192 // Parse results file
190 if (auto dataSeries
193 if (auto dataSeries
191 = AmdaResultParser::readTxt(tempFile->fileName(), productValueType)) {
194 = AmdaResultParser::readTxt(tempFile->fileName(), productValueType)) {
192 emit dataProvided(dataId, dataSeries, dateTime);
195 emit dataProvided(dataId, dataSeries, dateTime);
193 }
196 }
194 else {
197 else {
195 /// @todo ALX : debug
198 /// @todo ALX : debug
196 emit dataProvidedFailed(dataId);
199 emit dataProvidedFailed(dataId);
197 }
200 }
198 }
201 }
199 m_AcqIdToRequestProgressMap.erase(dataId);
202 m_AcqIdToRequestProgressMap.erase(dataId);
200 }
203 }
201 else {
204 else {
202 qCCritical(LOG_AmdaProvider()) << tr("httpDownloadFinished ERROR");
205 qCCritical(LOG_AmdaProvider()) << tr("httpDownloadFinished ERROR");
203 emit dataProvidedFailed(dataId);
206 emit dataProvidedFailed(dataId);
204 }
207 }
205
208
206 };
209 };
207 auto httpFinishedLambda
210 auto httpFinishedLambda
208 = [this, httpDownloadFinished, tempFile](QNetworkReply *reply, QUuid dataId) noexcept {
211 = [this, httpDownloadFinished, tempFile](QNetworkReply *reply, QUuid dataId) noexcept {
209
212
210 // Don't do anything if the reply was abort
213 // Don't do anything if the reply was abort
211 if (reply->error() == QNetworkReply::NoError) {
214 if (reply->error() == QNetworkReply::NoError) {
212 auto downloadFileUrl = QUrl{QString{reply->readAll()}.trimmed()};
215 auto downloadFileUrl = QUrl{QString{reply->readAll()}.trimmed()};
213
216
214 qCInfo(LOG_AmdaProvider())
217 qCDebug(LOG_AmdaProvider()) << tr("AmdaProvider::retrieveData downloadFileUrl:")
215 << tr("TORM AmdaProvider::retrieveData downloadFileUrl:") << downloadFileUrl;
218 << downloadFileUrl;
216 // Executes request for downloading file //
219 // Executes request for downloading file //
217
220
218 // Creates destination file
221 // Creates destination file
219 if (tempFile->open()) {
222 if (tempFile->open()) {
220 // Executes request and store the request for progression
223 // Executes request and store the request for progression
221 auto request = std::make_shared<QNetworkRequest>(downloadFileUrl);
224 auto request = std::make_shared<QNetworkRequest>(downloadFileUrl);
222 updateRequestProgress(dataId, request, 0.0);
225 updateRequestProgress(dataId, request, 0.0);
223 emit requestConstructed(request, dataId, httpDownloadFinished);
226 emit requestConstructed(request, dataId, httpDownloadFinished);
224 }
227 }
225 else {
228 else {
226 emit dataProvidedFailed(dataId);
229 emit dataProvidedFailed(dataId);
227 }
230 }
228 }
231 }
229 else {
232 else {
230 qCCritical(LOG_AmdaProvider()) << tr("httpFinishedLambda ERROR");
233 qCCritical(LOG_AmdaProvider()) << tr("httpFinishedLambda ERROR");
231 m_AcqIdToRequestProgressMap.erase(dataId);
234 m_AcqIdToRequestProgressMap.erase(dataId);
232 emit dataProvidedFailed(dataId);
235 emit dataProvidedFailed(dataId);
233 }
236 }
234 };
237 };
235
238
236 // //////////////// //
239 // //////////////// //
237 // Executes request //
240 // Executes request //
238 // //////////////// //
241 // //////////////// //
239
242
240 auto request = std::make_shared<QNetworkRequest>(url);
243 auto request = std::make_shared<QNetworkRequest>(url);
241 qCDebug(LOG_AmdaProvider()) << tr("First Request creation") << request.get();
242 updateRequestProgress(token, request, 0.0);
244 updateRequestProgress(token, request, 0.0);
243
245
244 emit requestConstructed(request, token, httpFinishedLambda);
246 emit requestConstructed(request, token, httpFinishedLambda);
245 }
247 }
246
248
247 void AmdaProvider::updateRequestProgress(QUuid acqIdentifier,
249 void AmdaProvider::updateRequestProgress(QUuid acqIdentifier,
248 std::shared_ptr<QNetworkRequest> request, double progress)
250 std::shared_ptr<QNetworkRequest> request, double progress)
249 {
251 {
250 qCDebug(LOG_AmdaProvider()) << tr("updateRequestProgress request") << request.get();
251 auto acqIdToRequestProgressMapIt = m_AcqIdToRequestProgressMap.find(acqIdentifier);
252 auto acqIdToRequestProgressMapIt = m_AcqIdToRequestProgressMap.find(acqIdentifier);
252 if (acqIdToRequestProgressMapIt != m_AcqIdToRequestProgressMap.end()) {
253 if (acqIdToRequestProgressMapIt != m_AcqIdToRequestProgressMap.end()) {
253 auto &requestProgressMap = acqIdToRequestProgressMapIt->second;
254 auto &requestProgressMap = acqIdToRequestProgressMapIt->second;
254 auto requestProgressMapIt = requestProgressMap.find(request);
255 auto requestProgressMapIt = requestProgressMap.find(request);
255 if (requestProgressMapIt != requestProgressMap.end()) {
256 if (requestProgressMapIt != requestProgressMap.end()) {
256 requestProgressMapIt->second = progress;
257 requestProgressMapIt->second = progress;
257 qCDebug(LOG_AmdaProvider()) << tr("updateRequestProgress new progress for request")
258 qCDebug(LOG_AmdaProvider()) << tr("updateRequestProgress new progress for request")
258 << acqIdentifier << request.get() << progress;
259 << acqIdentifier << request.get() << progress;
259 }
260 }
260 else {
261 else {
261 qCDebug(LOG_AmdaProvider()) << tr("updateRequestProgress new request") << acqIdentifier
262 qCDebug(LOG_AmdaProvider()) << tr("updateRequestProgress new request") << acqIdentifier
262 << request.get() << progress;
263 << request.get() << progress;
263 acqIdToRequestProgressMapIt->second.insert(std::make_pair(request, progress));
264 acqIdToRequestProgressMapIt->second.insert(std::make_pair(request, progress));
264 }
265 }
265 }
266 }
266 else {
267 else {
267 qCDebug(LOG_AmdaProvider()) << tr("updateRequestProgress new acqIdentifier")
268 qCDebug(LOG_AmdaProvider()) << tr("updateRequestProgress new acqIdentifier")
268 << acqIdentifier << request.get() << progress;
269 << acqIdentifier << request.get() << progress;
269 auto requestProgressMap = std::map<std::shared_ptr<QNetworkRequest>, double>{};
270 auto requestProgressMap = std::map<std::shared_ptr<QNetworkRequest>, double>{};
270 requestProgressMap.insert(std::make_pair(request, progress));
271 requestProgressMap.insert(std::make_pair(request, progress));
271 m_AcqIdToRequestProgressMap.insert(
272 m_AcqIdToRequestProgressMap.insert(
272 std::make_pair(acqIdentifier, std::move(requestProgressMap)));
273 std::make_pair(acqIdentifier, std::move(requestProgressMap)));
273 }
274 }
274 }
275 }
@@ -1,118 +1,119
1 #include "FuzzingDefs.h"
1 #include "FuzzingDefs.h"
2
2
3 const QString ACQUISITION_TIMEOUT_PROPERTY = QStringLiteral("acquisitionTimeout");
3 const QString ACQUISITION_TIMEOUT_PROPERTY = QStringLiteral("acquisitionTimeout");
4 const QString NB_MAX_OPERATIONS_PROPERTY = QStringLiteral("component");
4 const QString NB_MAX_OPERATIONS_PROPERTY = QStringLiteral("component");
5 const QString NB_MAX_SYNC_GROUPS_PROPERTY = QStringLiteral("nbSyncGroups");
5 const QString NB_MAX_SYNC_GROUPS_PROPERTY = QStringLiteral("nbSyncGroups");
6 const QString NB_MAX_VARIABLES_PROPERTY = QStringLiteral("nbMaxVariables");
6 const QString NB_MAX_VARIABLES_PROPERTY = QStringLiteral("nbMaxVariables");
7 const QString AVAILABLE_OPERATIONS_PROPERTY = QStringLiteral("availableOperations");
7 const QString AVAILABLE_OPERATIONS_PROPERTY = QStringLiteral("availableOperations");
8 const QString CACHE_TOLERANCE_PROPERTY = QStringLiteral("cacheTolerance");
8 const QString CACHE_TOLERANCE_PROPERTY = QStringLiteral("cacheTolerance");
9 const QString INITIAL_RANGE_PROPERTY = QStringLiteral("initialRange");
9 const QString INITIAL_RANGE_PROPERTY = QStringLiteral("initialRange");
10 const QString MAX_RANGE_PROPERTY = QStringLiteral("maxRange");
10 const QString MAX_RANGE_PROPERTY = QStringLiteral("maxRange");
11 const QString METADATA_POOL_PROPERTY = QStringLiteral("metadataPool");
11 const QString METADATA_POOL_PROPERTY = QStringLiteral("metadataPool");
12 const QString PROVIDER_PROPERTY = QStringLiteral("provider");
12 const QString PROVIDER_PROPERTY = QStringLiteral("provider");
13 const QString OPERATION_DELAY_BOUNDS_PROPERTY = QStringLiteral("operationDelays");
13 const QString OPERATION_DELAY_BOUNDS_PROPERTY = QStringLiteral("operationDelays");
14 const QString VALIDATORS_PROPERTY = QStringLiteral("validators");
14 const QString VALIDATORS_PROPERTY = QStringLiteral("validators");
15 const QString VALIDATION_FREQUENCY_BOUNDS_PROPERTY = QStringLiteral("validationFrequencyBounds");
15 const QString VALIDATION_FREQUENCY_BOUNDS_PROPERTY = QStringLiteral("validationFrequencyBounds");
16 const QString CUSTOM_OPERATIONS_PROPERTY = QStringLiteral("customOperations");
16
17
17 // //////////// //
18 // //////////// //
18 // FuzzingState //
19 // FuzzingState //
19 // //////////// //
20 // //////////// //
20
21
21 const SyncGroup &FuzzingState::syncGroup(SyncGroupId id) const
22 const SyncGroup &FuzzingState::syncGroup(SyncGroupId id) const
22 {
23 {
23 return m_SyncGroupsPool.at(id);
24 return m_SyncGroupsPool.at(id);
24 }
25 }
25
26
26 SyncGroup &FuzzingState::syncGroup(SyncGroupId id)
27 SyncGroup &FuzzingState::syncGroup(SyncGroupId id)
27 {
28 {
28 return m_SyncGroupsPool.at(id);
29 return m_SyncGroupsPool.at(id);
29 }
30 }
30
31
31 const VariableState &FuzzingState::variableState(VariableId id) const
32 const VariableState &FuzzingState::variableState(VariableId id) const
32 {
33 {
33 return m_VariablesPool.at(id);
34 return m_VariablesPool.at(id);
34 }
35 }
35
36
36 VariableState &FuzzingState::variableState(VariableId id)
37 VariableState &FuzzingState::variableState(VariableId id)
37 {
38 {
38 return m_VariablesPool.at(id);
39 return m_VariablesPool.at(id);
39 }
40 }
40
41
41 SyncGroupId FuzzingState::syncGroupId(VariableId variableId) const
42 SyncGroupId FuzzingState::syncGroupId(VariableId variableId) const
42 {
43 {
43 auto end = m_SyncGroupsPool.cend();
44 auto end = m_SyncGroupsPool.cend();
44 auto it
45 auto it
45 = std::find_if(m_SyncGroupsPool.cbegin(), end, [&variableId](const auto &syncGroupEntry) {
46 = std::find_if(m_SyncGroupsPool.cbegin(), end, [&variableId](const auto &syncGroupEntry) {
46 const auto &syncGroup = syncGroupEntry.second;
47 const auto &syncGroup = syncGroupEntry.second;
47 return syncGroup.m_Variables.find(variableId) != syncGroup.m_Variables.end();
48 return syncGroup.m_Variables.find(variableId) != syncGroup.m_Variables.end();
48 });
49 });
49
50
50 return it != end ? it->first : SyncGroupId{};
51 return it != end ? it->first : SyncGroupId{};
51 }
52 }
52
53
53 std::vector<SyncGroupId> FuzzingState::syncGroupsIds() const
54 std::vector<SyncGroupId> FuzzingState::syncGroupsIds() const
54 {
55 {
55 std::vector<SyncGroupId> result{};
56 std::vector<SyncGroupId> result{};
56
57
57 for (const auto &entry : m_SyncGroupsPool) {
58 for (const auto &entry : m_SyncGroupsPool) {
58 result.push_back(entry.first);
59 result.push_back(entry.first);
59 }
60 }
60
61
61 return result;
62 return result;
62 }
63 }
63
64
64 void FuzzingState::synchronizeVariable(VariableId variableId, SyncGroupId syncGroupId)
65 void FuzzingState::synchronizeVariable(VariableId variableId, SyncGroupId syncGroupId)
65 {
66 {
66 if (syncGroupId.isNull()) {
67 if (syncGroupId.isNull()) {
67 return;
68 return;
68 }
69 }
69
70
70 // Registers variable into sync group
71 // Registers variable into sync group
71 auto &syncGroup = m_SyncGroupsPool.at(syncGroupId);
72 auto &syncGroup = m_SyncGroupsPool.at(syncGroupId);
72 auto &variableState = m_VariablesPool.at(variableId);
73 auto &variableState = m_VariablesPool.at(variableId);
73 syncGroup.m_Variables.insert(variableId);
74 syncGroup.m_Variables.insert(variableId);
74 if (syncGroup.m_Variables.size() == 1) {
75 if (syncGroup.m_Variables.size() == 1) {
75 // If it's the first variable, sets the variable range as the sync group range
76 // If it's the first variable, sets the variable range as the sync group range
76 syncGroup.m_Range = variableState.m_Range;
77 syncGroup.m_Range = variableState.m_Range;
77 }
78 }
78 else {
79 else {
79 // If a variable is added to an existing group, sets its range to the group's range
80 // If a variable is added to an existing group, sets its range to the group's range
80 variableState.m_Range = syncGroup.m_Range;
81 variableState.m_Range = syncGroup.m_Range;
81 }
82 }
82 }
83 }
83
84
84 void FuzzingState::desynchronizeVariable(VariableId variableId, SyncGroupId syncGroupId)
85 void FuzzingState::desynchronizeVariable(VariableId variableId, SyncGroupId syncGroupId)
85 {
86 {
86 if (syncGroupId.isNull()) {
87 if (syncGroupId.isNull()) {
87 return;
88 return;
88 }
89 }
89
90
90 // Unregisters variable from sync group: if there is no more variable in the group, resets the
91 // Unregisters variable from sync group: if there is no more variable in the group, resets the
91 // range
92 // range
92 auto &syncGroup = m_SyncGroupsPool.at(syncGroupId);
93 auto &syncGroup = m_SyncGroupsPool.at(syncGroupId);
93 syncGroup.m_Variables.erase(variableId);
94 syncGroup.m_Variables.erase(variableId);
94 if (syncGroup.m_Variables.empty()) {
95 if (syncGroup.m_Variables.empty()) {
95 syncGroup.m_Range = INVALID_RANGE;
96 syncGroup.m_Range = INVALID_RANGE;
96 }
97 }
97 }
98 }
98
99
99 void FuzzingState::updateRanges(VariableId variableId, const SqpRange &newRange)
100 void FuzzingState::updateRanges(VariableId variableId, const SqpRange &newRange)
100 {
101 {
101 auto syncGroupId = this->syncGroupId(variableId);
102 auto syncGroupId = this->syncGroupId(variableId);
102
103
103 // Retrieves the variables to update:
104 // Retrieves the variables to update:
104 // - if the variable is synchronized to others, updates the range of the group and of all
105 // - if the variable is synchronized to others, updates the range of the group and of all
105 // synchronized variables
106 // synchronized variables
106 // - otherwise, updates only the variable
107 // - otherwise, updates only the variable
107 if (syncGroupId.isNull()) {
108 if (syncGroupId.isNull()) {
108 m_VariablesPool.at(variableId).m_Range = newRange;
109 m_VariablesPool.at(variableId).m_Range = newRange;
109 }
110 }
110 else {
111 else {
111 auto &syncGroup = m_SyncGroupsPool.at(syncGroupId);
112 auto &syncGroup = m_SyncGroupsPool.at(syncGroupId);
112 syncGroup.m_Range = newRange;
113 syncGroup.m_Range = newRange;
113
114
114 for (const auto &variableId : syncGroup.m_Variables) {
115 for (const auto &variableId : syncGroup.m_Variables) {
115 m_VariablesPool.at(variableId).m_Range = newRange;
116 m_VariablesPool.at(variableId).m_Range = newRange;
116 }
117 }
117 }
118 }
118 }
119 }
@@ -1,128 +1,131
1 #ifndef SCIQLOP_FUZZINGDEFS_H
1 #ifndef SCIQLOP_FUZZINGDEFS_H
2 #define SCIQLOP_FUZZINGDEFS_H
2 #define SCIQLOP_FUZZINGDEFS_H
3
3
4 #include <Data/SqpRange.h>
4 #include <Data/SqpRange.h>
5
5
6 #include <QString>
6 #include <QString>
7 #include <QUuid>
7 #include <QUuid>
8 #include <QVariantHash>
8 #include <QVariantHash>
9
9
10 #include <memory>
10 #include <memory>
11 #include <set>
11 #include <set>
12
12
13 // /////// //
13 // /////// //
14 // Aliases //
14 // Aliases //
15 // /////// //
15 // /////// //
16
16
17 using MetadataPool = std::vector<QVariantHash>;
17 using MetadataPool = std::vector<QVariantHash>;
18 Q_DECLARE_METATYPE(MetadataPool)
18 Q_DECLARE_METATYPE(MetadataPool)
19
19
20 using Properties = QVariantHash;
20 using Properties = QVariantHash;
21
21
22 // ///////// //
22 // ///////// //
23 // Constants //
23 // Constants //
24 // ///////// //
24 // ///////// //
25
25
26 /// Timeout set for data acquisition for an operation (in ms)
26 /// Timeout set for data acquisition for an operation (in ms)
27 extern const QString ACQUISITION_TIMEOUT_PROPERTY;
27 extern const QString ACQUISITION_TIMEOUT_PROPERTY;
28
28
29 /// Max number of operations to generate
29 /// Max number of operations to generate
30 extern const QString NB_MAX_OPERATIONS_PROPERTY;
30 extern const QString NB_MAX_OPERATIONS_PROPERTY;
31
31
32 /// Max number of sync groups to create through operations
32 /// Max number of sync groups to create through operations
33 extern const QString NB_MAX_SYNC_GROUPS_PROPERTY;
33 extern const QString NB_MAX_SYNC_GROUPS_PROPERTY;
34
34
35 /// Max number of variables to manipulate through operations
35 /// Max number of variables to manipulate through operations
36 extern const QString NB_MAX_VARIABLES_PROPERTY;
36 extern const QString NB_MAX_VARIABLES_PROPERTY;
37
37
38 /// Set of operations available for the test
38 /// Set of operations available for the test
39 extern const QString AVAILABLE_OPERATIONS_PROPERTY;
39 extern const QString AVAILABLE_OPERATIONS_PROPERTY;
40
40
41 /// Tolerance used for variable's cache (in ratio)
41 /// Tolerance used for variable's cache (in ratio)
42 extern const QString CACHE_TOLERANCE_PROPERTY;
42 extern const QString CACHE_TOLERANCE_PROPERTY;
43
43
44 /// Range with which the timecontroller is initialized
44 /// Range with which the timecontroller is initialized
45 extern const QString INITIAL_RANGE_PROPERTY;
45 extern const QString INITIAL_RANGE_PROPERTY;
46
46
47 /// Max range that an operation can reach
47 /// Max range that an operation can reach
48 extern const QString MAX_RANGE_PROPERTY;
48 extern const QString MAX_RANGE_PROPERTY;
49
49
50 /// Set of metadata that can be associated to a variable
50 /// Set of metadata that can be associated to a variable
51 extern const QString METADATA_POOL_PROPERTY;
51 extern const QString METADATA_POOL_PROPERTY;
52
52
53 /// Provider used to retrieve data
53 /// Provider used to retrieve data
54 extern const QString PROVIDER_PROPERTY;
54 extern const QString PROVIDER_PROPERTY;
55
55
56 /// Min/max times left for an operation to execute
56 /// Min/max times left for an operation to execute
57 extern const QString OPERATION_DELAY_BOUNDS_PROPERTY;
57 extern const QString OPERATION_DELAY_BOUNDS_PROPERTY;
58
58
59 /// Validators used to validate an operation
59 /// Validators used to validate an operation
60 extern const QString VALIDATORS_PROPERTY;
60 extern const QString VALIDATORS_PROPERTY;
61
61
62 /// Min/max number of operations to execute before calling validation of the current test's state
62 /// Min/max number of operations to execute before calling validation of the current test's state
63 extern const QString VALIDATION_FREQUENCY_BOUNDS_PROPERTY;
63 extern const QString VALIDATION_FREQUENCY_BOUNDS_PROPERTY;
64
64
65 /// Custom operations to execute instead of random operations
66 extern const QString CUSTOM_OPERATIONS_PROPERTY;
67
65 // /////// //
68 // /////// //
66 // Structs //
69 // Structs //
67 // /////// //
70 // /////// //
68
71
69 class Variable;
72 class Variable;
70 struct VariableState {
73 struct VariableState {
71 std::shared_ptr<Variable> m_Variable{nullptr};
74 std::shared_ptr<Variable> m_Variable{nullptr};
72 SqpRange m_Range{INVALID_RANGE};
75 SqpRange m_Range{INVALID_RANGE};
73 };
76 };
74
77
75 using VariableId = int;
78 using VariableId = int;
76 using VariablesPool = std::map<VariableId, VariableState>;
79 using VariablesPool = std::map<VariableId, VariableState>;
77
80
78 /**
81 /**
79 * Defines a synchronization group for a fuzzing state. A group reports the variables synchronized
82 * Defines a synchronization group for a fuzzing state. A group reports the variables synchronized
80 * with each other, and the current range of the group (i.e. range of the last synchronized variable
83 * with each other, and the current range of the group (i.e. range of the last synchronized variable
81 * that has been moved)
84 * that has been moved)
82 */
85 */
83 struct SyncGroup {
86 struct SyncGroup {
84 std::set<VariableId> m_Variables{};
87 std::set<VariableId> m_Variables{};
85 SqpRange m_Range{INVALID_RANGE};
88 SqpRange m_Range{INVALID_RANGE};
86 };
89 };
87
90
88 using SyncGroupId = QUuid;
91 using SyncGroupId = QUuid;
89 using SyncGroupsPool = std::map<SyncGroupId, SyncGroup>;
92 using SyncGroupsPool = std::map<SyncGroupId, SyncGroup>;
90
93
91 /**
94 /**
92 * Defines a current state during a fuzzing state. It contains all the variables manipulated during
95 * Defines a current state during a fuzzing state. It contains all the variables manipulated during
93 * the test, as well as the synchronization status of these variables.
96 * the test, as well as the synchronization status of these variables.
94 */
97 */
95 struct FuzzingState {
98 struct FuzzingState {
96 const SyncGroup &syncGroup(SyncGroupId id) const;
99 const SyncGroup &syncGroup(SyncGroupId id) const;
97 SyncGroup &syncGroup(SyncGroupId id);
100 SyncGroup &syncGroup(SyncGroupId id);
98
101
99 const VariableState &variableState(VariableId id) const;
102 const VariableState &variableState(VariableId id) const;
100 VariableState &variableState(VariableId id);
103 VariableState &variableState(VariableId id);
101
104
102 /// @return the identifier of the synchronization group in which the variable passed in
105 /// @return the identifier of the synchronization group in which the variable passed in
103 /// parameter is located. If the variable is not in any group, returns an invalid identifier
106 /// parameter is located. If the variable is not in any group, returns an invalid identifier
104 SyncGroupId syncGroupId(VariableId variableId) const;
107 SyncGroupId syncGroupId(VariableId variableId) const;
105
108
106 /// @return the set of synchronization group identifiers
109 /// @return the set of synchronization group identifiers
107 std::vector<SyncGroupId> syncGroupsIds() const;
110 std::vector<SyncGroupId> syncGroupsIds() const;
108
111
109 /// Updates fuzzing state according to a variable synchronization
112 /// Updates fuzzing state according to a variable synchronization
110 /// @param variableId the variable that is synchronized
113 /// @param variableId the variable that is synchronized
111 /// @param syncGroupId the synchronization group
114 /// @param syncGroupId the synchronization group
112 void synchronizeVariable(VariableId variableId, SyncGroupId syncGroupId);
115 void synchronizeVariable(VariableId variableId, SyncGroupId syncGroupId);
113
116
114 /// Updates fuzzing state according to a variable desynchronization
117 /// Updates fuzzing state according to a variable desynchronization
115 /// @param variableId the variable that is desynchronized
118 /// @param variableId the variable that is desynchronized
116 /// @param syncGroupId the synchronization group from which to remove the variable
119 /// @param syncGroupId the synchronization group from which to remove the variable
117 void desynchronizeVariable(VariableId variableId, SyncGroupId syncGroupId);
120 void desynchronizeVariable(VariableId variableId, SyncGroupId syncGroupId);
118
121
119 /// Updates the range of a variable and all variables to which it is synchronized
122 /// Updates the range of a variable and all variables to which it is synchronized
120 /// @param the variable for which to affect the range
123 /// @param the variable for which to affect the range
121 /// @param the range to affect
124 /// @param the range to affect
122 void updateRanges(VariableId variableId, const SqpRange &newRange);
125 void updateRanges(VariableId variableId, const SqpRange &newRange);
123
126
124 VariablesPool m_VariablesPool;
127 VariablesPool m_VariablesPool;
125 SyncGroupsPool m_SyncGroupsPool;
128 SyncGroupsPool m_SyncGroupsPool;
126 };
129 };
127
130
128 #endif // SCIQLOP_FUZZINGDEFS_H
131 #endif // SCIQLOP_FUZZINGDEFS_H
@@ -1,268 +1,268
1 #include "FuzzingOperations.h"
1 #include "FuzzingOperations.h"
2 #include "FuzzingUtils.h"
2 #include "FuzzingUtils.h"
3
3
4 #include <Data/IDataProvider.h>
4 #include <Data/IDataProvider.h>
5
5
6 #include <Variable/Variable.h>
6 #include <Variable/Variable.h>
7 #include <Variable/VariableController.h>
7 #include <Variable/VariableController.h>
8
8
9 #include <QUuid>
9 #include <QUuid>
10
10
11 #include <functional>
11 #include <functional>
12
12
13 Q_LOGGING_CATEGORY(LOG_FuzzingOperations, "FuzzingOperations")
13 Q_LOGGING_CATEGORY(LOG_FuzzingOperations, "FuzzingOperations")
14
14
15 namespace {
15 namespace {
16
16
17 struct CreateOperation : public IFuzzingOperation {
17 struct CreateOperation : public IFuzzingOperation {
18 bool canExecute(VariableId variableId, const FuzzingState &fuzzingState) const override
18 bool canExecute(VariableId variableId, const FuzzingState &fuzzingState) const override
19 {
19 {
20 // A variable can be created only if it doesn't exist yet
20 // A variable can be created only if it doesn't exist yet
21 return fuzzingState.variableState(variableId).m_Variable == nullptr;
21 return fuzzingState.variableState(variableId).m_Variable == nullptr;
22 }
22 }
23
23
24 void execute(VariableId variableId, FuzzingState &fuzzingState,
24 void execute(VariableId variableId, FuzzingState &fuzzingState,
25 VariableController &variableController,
25 VariableController &variableController,
26 const Properties &properties) const override
26 const Properties &properties) const override
27 {
27 {
28 // Retrieves metadata pool from properties, and choose one of the metadata entries to
28 // Retrieves metadata pool from properties, and choose one of the metadata entries to
29 // associate it with the variable
29 // associate it with the variable
30 auto metaDataPool = properties.value(METADATA_POOL_PROPERTY).value<MetadataPool>();
30 auto metaDataPool = properties.value(METADATA_POOL_PROPERTY).value<MetadataPool>();
31 auto variableMetadata = RandomGenerator::instance().randomChoice(metaDataPool);
31 auto variableMetadata = RandomGenerator::instance().randomChoice(metaDataPool);
32
32
33 // Retrieves provider
33 // Retrieves provider
34 auto variableProvider
34 auto variableProvider
35 = properties.value(PROVIDER_PROPERTY).value<std::shared_ptr<IDataProvider> >();
35 = properties.value(PROVIDER_PROPERTY).value<std::shared_ptr<IDataProvider> >();
36
36
37 auto variableName = QString{"Var_%1"}.arg(QUuid::createUuid().toString());
37 auto variableName = QString{"Var_%1"}.arg(QUuid::createUuid().toString());
38 qCInfo(LOG_FuzzingOperations()).noquote() << "Creating variable" << variableName
38 qCInfo(LOG_FuzzingOperations()).noquote() << "Creating variable" << variableName
39 << "(metadata:" << variableMetadata << ")...";
39 << "(metadata:" << variableMetadata << ")...";
40
40
41 auto newVariable
41 auto newVariable
42 = variableController.createVariable(variableName, variableMetadata, variableProvider);
42 = variableController.createVariable(variableName, variableMetadata, variableProvider);
43
43
44 // Updates variable's state
44 // Updates variable's state
45 auto &variableState = fuzzingState.variableState(variableId);
45 auto &variableState = fuzzingState.variableState(variableId);
46 variableState.m_Range = properties.value(INITIAL_RANGE_PROPERTY).value<SqpRange>();
46 variableState.m_Range = properties.value(INITIAL_RANGE_PROPERTY).value<SqpRange>();
47 std::swap(variableState.m_Variable, newVariable);
47 std::swap(variableState.m_Variable, newVariable);
48 }
48 }
49 };
49 };
50
50
51 struct DeleteOperation : public IFuzzingOperation {
51 struct DeleteOperation : public IFuzzingOperation {
52 bool canExecute(VariableId variableId, const FuzzingState &fuzzingState) const override
52 bool canExecute(VariableId variableId, const FuzzingState &fuzzingState) const override
53 {
53 {
54 // A variable can be delete only if it exists
54 // A variable can be delete only if it exists
55 return fuzzingState.variableState(variableId).m_Variable != nullptr;
55 return fuzzingState.variableState(variableId).m_Variable != nullptr;
56 }
56 }
57
57
58 void execute(VariableId variableId, FuzzingState &fuzzingState,
58 void execute(VariableId variableId, FuzzingState &fuzzingState,
59 VariableController &variableController, const Properties &) const override
59 VariableController &variableController, const Properties &) const override
60 {
60 {
61 auto &variableState = fuzzingState.variableState(variableId);
61 auto &variableState = fuzzingState.variableState(variableId);
62
62
63 qCInfo(LOG_FuzzingOperations()).noquote() << "Deleting variable"
63 qCInfo(LOG_FuzzingOperations()).noquote() << "Deleting variable"
64 << variableState.m_Variable->name() << "...";
64 << variableState.m_Variable->name() << "...";
65 variableController.deleteVariable(variableState.m_Variable);
65 variableController.deleteVariable(variableState.m_Variable);
66
66
67 // Updates variable's state
67 // Updates variable's state
68 variableState.m_Range = INVALID_RANGE;
68 variableState.m_Range = INVALID_RANGE;
69 variableState.m_Variable = nullptr;
69 variableState.m_Variable = nullptr;
70
70
71 // Desynchronizes the variable if it was in a sync group
71 // Desynchronizes the variable if it was in a sync group
72 auto syncGroupId = fuzzingState.syncGroupId(variableId);
72 auto syncGroupId = fuzzingState.syncGroupId(variableId);
73 fuzzingState.desynchronizeVariable(variableId, syncGroupId);
73 fuzzingState.desynchronizeVariable(variableId, syncGroupId);
74 }
74 }
75 };
75 };
76
76
77 /**
77 /**
78 * Defines a move operation through a range.
78 * Defines a move operation through a range.
79 *
79 *
80 * A move operation is determined by three functions:
80 * A move operation is determined by three functions:
81 * - Two 'move' functions, used to indicate in which direction the beginning and the end of a range
81 * - Two 'move' functions, used to indicate in which direction the beginning and the end of a range
82 * are going during the operation. These functions will be:
82 * are going during the operation. These functions will be:
83 * -- {<- / <-} for pan left
83 * -- {<- / <-} for pan left
84 * -- {-> / ->} for pan right
84 * -- {-> / ->} for pan right
85 * -- {-> / <-} for zoom in
85 * -- {-> / <-} for zoom in
86 * -- {<- / ->} for zoom out
86 * -- {<- / ->} for zoom out
87 * - One 'max move' functions, used to compute the max delta at which the operation can move a
87 * - One 'max move' functions, used to compute the max delta at which the operation can move a
88 * range, according to a max range. For exemple, for a range of {1, 5} and a max range of {0, 10},
88 * range, according to a max range. For exemple, for a range of {1, 5} and a max range of {0, 10},
89 * max deltas will be:
89 * max deltas will be:
90 * -- {0, 4} for pan left
90 * -- {0, 4} for pan left
91 * -- {6, 10} for pan right
91 * -- {6, 10} for pan right
92 * -- {3, 3} for zoom in
92 * -- {3, 3} for zoom in
93 * -- {0, 6} for zoom out (same spacing left and right)
93 * -- {0, 6} for zoom out (same spacing left and right)
94 */
94 */
95 struct MoveOperation : public IFuzzingOperation {
95 struct MoveOperation : public IFuzzingOperation {
96 using MoveFunction = std::function<double(double currentValue, double maxValue)>;
96 using MoveFunction = std::function<double(double currentValue, double maxValue)>;
97 using MaxMoveFunction = std::function<double(const SqpRange &range, const SqpRange &maxRange)>;
97 using MaxMoveFunction = std::function<double(const SqpRange &range, const SqpRange &maxRange)>;
98
98
99 explicit MoveOperation(MoveFunction rangeStartMoveFun, MoveFunction rangeEndMoveFun,
99 explicit MoveOperation(MoveFunction rangeStartMoveFun, MoveFunction rangeEndMoveFun,
100 MaxMoveFunction maxMoveFun,
100 MaxMoveFunction maxMoveFun,
101 const QString &label = QStringLiteral("Move operation"))
101 const QString &label = QStringLiteral("Move operation"))
102 : m_RangeStartMoveFun{std::move(rangeStartMoveFun)},
102 : m_RangeStartMoveFun{std::move(rangeStartMoveFun)},
103 m_RangeEndMoveFun{std::move(rangeEndMoveFun)},
103 m_RangeEndMoveFun{std::move(rangeEndMoveFun)},
104 m_MaxMoveFun{std::move(maxMoveFun)},
104 m_MaxMoveFun{std::move(maxMoveFun)},
105 m_Label{label}
105 m_Label{label}
106 {
106 {
107 }
107 }
108
108
109 bool canExecute(VariableId variableId, const FuzzingState &fuzzingState) const override
109 bool canExecute(VariableId variableId, const FuzzingState &fuzzingState) const override
110 {
110 {
111 return fuzzingState.variableState(variableId).m_Variable != nullptr;
111 return fuzzingState.variableState(variableId).m_Variable != nullptr;
112 }
112 }
113
113
114 void execute(VariableId variableId, FuzzingState &fuzzingState,
114 void execute(VariableId variableId, FuzzingState &fuzzingState,
115 VariableController &variableController,
115 VariableController &variableController,
116 const Properties &properties) const override
116 const Properties &properties) const override
117 {
117 {
118 auto &variableState = fuzzingState.variableState(variableId);
118 auto &variableState = fuzzingState.variableState(variableId);
119 auto variable = variableState.m_Variable;
119 auto variable = variableState.m_Variable;
120
120
121 // Gets the max range defined
121 // Gets the max range defined
122 auto maxRange = properties.value(MAX_RANGE_PROPERTY, QVariant::fromValue(INVALID_RANGE))
122 auto maxRange = properties.value(MAX_RANGE_PROPERTY, QVariant::fromValue(INVALID_RANGE))
123 .value<SqpRange>();
123 .value<SqpRange>();
124 auto variableRange = variableState.m_Range;
124 auto variableRange = variableState.m_Range;
125
125
126 if (maxRange == INVALID_RANGE || variableRange.m_TStart < maxRange.m_TStart
126 if (maxRange == INVALID_RANGE || variableRange.m_TStart < maxRange.m_TStart
127 || variableRange.m_TEnd > maxRange.m_TEnd) {
127 || variableRange.m_TEnd > maxRange.m_TEnd) {
128 qCWarning(LOG_FuzzingOperations()) << "Can't execute operation: invalid max range";
128 qCWarning(LOG_FuzzingOperations()) << "Can't execute operation: invalid max range";
129 return;
129 return;
130 }
130 }
131
131
132 // Computes the max delta at which the variable can move, up to the limits of the max range
132 // Computes the max delta at which the variable can move, up to the limits of the max range
133 auto deltaMax = m_MaxMoveFun(variableRange, maxRange);
133 auto deltaMax = m_MaxMoveFun(variableRange, maxRange);
134
134
135 // Generates random delta that will be used to move variable
135 // Generates random delta that will be used to move variable
136 auto delta = RandomGenerator::instance().generateDouble(0, deltaMax);
136 auto delta = RandomGenerator::instance().generateDouble(0, deltaMax);
137
137
138 // Moves variable to its new range
138 // Moves variable to its new range
139 auto isSynchronized = !fuzzingState.syncGroupId(variableId).isNull();
139 auto isSynchronized = !fuzzingState.syncGroupId(variableId).isNull();
140 auto newVariableRange = SqpRange{m_RangeStartMoveFun(variableRange.m_TStart, delta),
140 auto newVariableRange = SqpRange{m_RangeStartMoveFun(variableRange.m_TStart, delta),
141 m_RangeEndMoveFun(variableRange.m_TEnd, delta)};
141 m_RangeEndMoveFun(variableRange.m_TEnd, delta)};
142 qCInfo(LOG_FuzzingOperations()).noquote() << "Performing" << m_Label << "on"
142 qCInfo(LOG_FuzzingOperations()).noquote() << "Performing" << m_Label << "on"
143 << variable->name() << "(from" << variableRange
143 << variable->name() << "(from" << variableRange
144 << "to" << newVariableRange << ")...";
144 << "to" << newVariableRange << ")...";
145 variableController.onRequestDataLoading({variable}, newVariableRange, isSynchronized);
145 variableController.onRequestDataLoading({variable}, newVariableRange, isSynchronized);
146
146
147 // Updates state
147 // Updates state
148 fuzzingState.updateRanges(variableId, newVariableRange);
148 fuzzingState.updateRanges(variableId, newVariableRange);
149 }
149 }
150
150
151 MoveFunction m_RangeStartMoveFun;
151 MoveFunction m_RangeStartMoveFun;
152 MoveFunction m_RangeEndMoveFun;
152 MoveFunction m_RangeEndMoveFun;
153 MaxMoveFunction m_MaxMoveFun;
153 MaxMoveFunction m_MaxMoveFun;
154 QString m_Label;
154 QString m_Label;
155 };
155 };
156
156
157 struct SynchronizeOperation : public IFuzzingOperation {
157 struct SynchronizeOperation : public IFuzzingOperation {
158 bool canExecute(VariableId variableId, const FuzzingState &fuzzingState) const override
158 bool canExecute(VariableId variableId, const FuzzingState &fuzzingState) const override
159 {
159 {
160 auto variable = fuzzingState.variableState(variableId).m_Variable;
160 auto variable = fuzzingState.variableState(variableId).m_Variable;
161 return variable != nullptr && !fuzzingState.m_SyncGroupsPool.empty()
161 return variable != nullptr && !fuzzingState.m_SyncGroupsPool.empty()
162 && fuzzingState.syncGroupId(variableId).isNull();
162 && fuzzingState.syncGroupId(variableId).isNull();
163 }
163 }
164
164
165 void execute(VariableId variableId, FuzzingState &fuzzingState,
165 void execute(VariableId variableId, FuzzingState &fuzzingState,
166 VariableController &variableController, const Properties &) const override
166 VariableController &variableController, const Properties &) const override
167 {
167 {
168 auto &variableState = fuzzingState.variableState(variableId);
168 auto &variableState = fuzzingState.variableState(variableId);
169
169
170 // Chooses a random synchronization group and adds the variable into sync group
170 // Chooses a random synchronization group and adds the variable into sync group
171 auto syncGroupId = RandomGenerator::instance().randomChoice(fuzzingState.syncGroupsIds());
171 auto syncGroupId = RandomGenerator::instance().randomChoice(fuzzingState.syncGroupsIds());
172 qCInfo(LOG_FuzzingOperations()).noquote() << "Adding" << variableState.m_Variable->name()
172 qCInfo(LOG_FuzzingOperations()).noquote() << "Adding" << variableState.m_Variable->name()
173 << "into synchronization group" << syncGroupId
173 << "into synchronization group" << syncGroupId
174 << "...";
174 << "...";
175 variableController.onAddSynchronized(variableState.m_Variable, syncGroupId);
175 variableController.onAddSynchronized(variableState.m_Variable, syncGroupId);
176
176
177 // Updates state
177 // Updates state
178 fuzzingState.synchronizeVariable(variableId, syncGroupId);
178 fuzzingState.synchronizeVariable(variableId, syncGroupId);
179
179
180 variableController.onRequestDataLoading({variableState.m_Variable}, variableState.m_Range,
180 variableController.onRequestDataLoading({variableState.m_Variable}, variableState.m_Range,
181 false);
181 true);
182 }
182 }
183 };
183 };
184
184
185 struct DesynchronizeOperation : public IFuzzingOperation {
185 struct DesynchronizeOperation : public IFuzzingOperation {
186 bool canExecute(VariableId variableId, const FuzzingState &fuzzingState) const override
186 bool canExecute(VariableId variableId, const FuzzingState &fuzzingState) const override
187 {
187 {
188 auto variable = fuzzingState.variableState(variableId).m_Variable;
188 auto variable = fuzzingState.variableState(variableId).m_Variable;
189 return variable != nullptr && !fuzzingState.syncGroupId(variableId).isNull();
189 return variable != nullptr && !fuzzingState.syncGroupId(variableId).isNull();
190 }
190 }
191
191
192 void execute(VariableId variableId, FuzzingState &fuzzingState,
192 void execute(VariableId variableId, FuzzingState &fuzzingState,
193 VariableController &variableController, const Properties &) const override
193 VariableController &variableController, const Properties &) const override
194 {
194 {
195 auto &variableState = fuzzingState.variableState(variableId);
195 auto &variableState = fuzzingState.variableState(variableId);
196
196
197 // Gets the sync group of the variable
197 // Gets the sync group of the variable
198 auto syncGroupId = fuzzingState.syncGroupId(variableId);
198 auto syncGroupId = fuzzingState.syncGroupId(variableId);
199
199
200 qCInfo(LOG_FuzzingOperations()).noquote() << "Removing" << variableState.m_Variable->name()
200 qCInfo(LOG_FuzzingOperations()).noquote() << "Removing" << variableState.m_Variable->name()
201 << "from synchronization group" << syncGroupId
201 << "from synchronization group" << syncGroupId
202 << "...";
202 << "...";
203 variableController.desynchronize(variableState.m_Variable, syncGroupId);
203 variableController.desynchronize(variableState.m_Variable, syncGroupId);
204
204
205 // Updates state
205 // Updates state
206 fuzzingState.desynchronizeVariable(variableId, syncGroupId);
206 fuzzingState.desynchronizeVariable(variableId, syncGroupId);
207 }
207 }
208 };
208 };
209
209
210 struct UnknownOperation : public IFuzzingOperation {
210 struct UnknownOperation : public IFuzzingOperation {
211 bool canExecute(VariableId, const FuzzingState &) const override { return false; }
211 bool canExecute(VariableId, const FuzzingState &) const override { return false; }
212
212
213 void execute(VariableId, FuzzingState &, VariableController &,
213 void execute(VariableId, FuzzingState &, VariableController &,
214 const Properties &) const override
214 const Properties &) const override
215 {
215 {
216 }
216 }
217 };
217 };
218
218
219 } // namespace
219 } // namespace
220
220
221 std::unique_ptr<IFuzzingOperation> FuzzingOperationFactory::create(FuzzingOperationType type)
221 std::unique_ptr<IFuzzingOperation> FuzzingOperationFactory::create(FuzzingOperationType type)
222 {
222 {
223 switch (type) {
223 switch (type) {
224 case FuzzingOperationType::CREATE:
224 case FuzzingOperationType::CREATE:
225 return std::make_unique<CreateOperation>();
225 return std::make_unique<CreateOperation>();
226 case FuzzingOperationType::DELETE:
226 case FuzzingOperationType::DELETE:
227 return std::make_unique<DeleteOperation>();
227 return std::make_unique<DeleteOperation>();
228 case FuzzingOperationType::PAN_LEFT:
228 case FuzzingOperationType::PAN_LEFT:
229 return std::make_unique<MoveOperation>(
229 return std::make_unique<MoveOperation>(
230 std::minus<double>(), std::minus<double>(),
230 std::minus<double>(), std::minus<double>(),
231 [](const SqpRange &range, const SqpRange &maxRange) {
231 [](const SqpRange &range, const SqpRange &maxRange) {
232 return range.m_TStart - maxRange.m_TStart;
232 return range.m_TStart - maxRange.m_TStart;
233 },
233 },
234 QStringLiteral("Pan left operation"));
234 QStringLiteral("Pan left operation"));
235 case FuzzingOperationType::PAN_RIGHT:
235 case FuzzingOperationType::PAN_RIGHT:
236 return std::make_unique<MoveOperation>(
236 return std::make_unique<MoveOperation>(
237 std::plus<double>(), std::plus<double>(),
237 std::plus<double>(), std::plus<double>(),
238 [](const SqpRange &range, const SqpRange &maxRange) {
238 [](const SqpRange &range, const SqpRange &maxRange) {
239 return maxRange.m_TEnd - range.m_TEnd;
239 return maxRange.m_TEnd - range.m_TEnd;
240 },
240 },
241 QStringLiteral("Pan right operation"));
241 QStringLiteral("Pan right operation"));
242 case FuzzingOperationType::ZOOM_IN:
242 case FuzzingOperationType::ZOOM_IN:
243 return std::make_unique<MoveOperation>(
243 return std::make_unique<MoveOperation>(
244 std::plus<double>(), std::minus<double>(),
244 std::plus<double>(), std::minus<double>(),
245 [](const SqpRange &range, const SqpRange &maxRange) {
245 [](const SqpRange &range, const SqpRange &maxRange) {
246 Q_UNUSED(maxRange)
246 Q_UNUSED(maxRange)
247 return range.m_TEnd - (range.m_TStart + range.m_TEnd) / 2.;
247 return range.m_TEnd - (range.m_TStart + range.m_TEnd) / 2.;
248 },
248 },
249 QStringLiteral("Zoom in operation"));
249 QStringLiteral("Zoom in operation"));
250 case FuzzingOperationType::ZOOM_OUT:
250 case FuzzingOperationType::ZOOM_OUT:
251 return std::make_unique<MoveOperation>(
251 return std::make_unique<MoveOperation>(
252 std::minus<double>(), std::plus<double>(),
252 std::minus<double>(), std::plus<double>(),
253 [](const SqpRange &range, const SqpRange &maxRange) {
253 [](const SqpRange &range, const SqpRange &maxRange) {
254 return std::min(range.m_TStart - maxRange.m_TStart,
254 return std::min(range.m_TStart - maxRange.m_TStart,
255 maxRange.m_TEnd - range.m_TEnd);
255 maxRange.m_TEnd - range.m_TEnd);
256 },
256 },
257 QStringLiteral("Zoom out operation"));
257 QStringLiteral("Zoom out operation"));
258 case FuzzingOperationType::SYNCHRONIZE:
258 case FuzzingOperationType::SYNCHRONIZE:
259 return std::make_unique<SynchronizeOperation>();
259 return std::make_unique<SynchronizeOperation>();
260 case FuzzingOperationType::DESYNCHRONIZE:
260 case FuzzingOperationType::DESYNCHRONIZE:
261 return std::make_unique<DesynchronizeOperation>();
261 return std::make_unique<DesynchronizeOperation>();
262 default:
262 default:
263 // Default case returns unknown operation
263 // Default case returns unknown operation
264 break;
264 break;
265 }
265 }
266
266
267 return std::make_unique<UnknownOperation>();
267 return std::make_unique<UnknownOperation>();
268 }
268 }
@@ -1,395 +1,560
1 #include "FuzzingDefs.h"
1 #include "FuzzingDefs.h"
2 #include "FuzzingOperations.h"
2 #include "FuzzingOperations.h"
3 #include "FuzzingUtils.h"
3 #include "FuzzingUtils.h"
4 #include "FuzzingValidators.h"
4 #include "FuzzingValidators.h"
5
5
6 #include "AmdaProvider.h"
6 #include "AmdaProvider.h"
7
7
8 #include <Common/SignalWaiter.h>
8 #include <Common/SignalWaiter.h>
9 #include <Network/NetworkController.h>
9 #include <Network/NetworkController.h>
10 #include <Settings/SqpSettingsDefs.h>
10 #include <Settings/SqpSettingsDefs.h>
11 #include <SqpApplication.h>
11 #include <SqpApplication.h>
12 #include <Time/TimeController.h>
12 #include <Time/TimeController.h>
13 #include <Variable/Variable.h>
13 #include <Variable/Variable.h>
14 #include <Variable/VariableController.h>
14 #include <Variable/VariableController.h>
15
15
16 #include <QLoggingCategory>
16 #include <QLoggingCategory>
17 #include <QObject>
17 #include <QObject>
18 #include <QtTest>
18 #include <QtTest>
19
19
20 #include <memory>
20 #include <memory>
21
21
22 Q_LOGGING_CATEGORY(LOG_TestAmdaFuzzing, "TestAmdaFuzzing")
22 Q_LOGGING_CATEGORY(LOG_TestAmdaFuzzing, "TestAmdaFuzzing")
23
23
24 /**
24 /**
25 * Macro used to generate a getter for a property in @sa FuzzingTest. The macro generates a static
25 * Macro used to generate a getter for a property in @sa FuzzingTest. The macro generates a static
26 * attribute that is initialized by searching in properties the property and use a default value if
26 * attribute that is initialized by searching in properties the property and use a default value if
27 * it's not present. Macro arguments are:
27 * it's not present. Macro arguments are:
28 * - GETTER_NAME : name of the getter
28 * - GETTER_NAME : name of the getter
29 * - PROPERTY_NAME: used to generate constants for property's name ({PROPERTY_NAME}_PROPERTY) and
29 * - PROPERTY_NAME: used to generate constants for property's name ({PROPERTY_NAME}_PROPERTY) and
30 * default value ({PROPERTY_NAME}_DEFAULT_VALUE)
30 * default value ({PROPERTY_NAME}_DEFAULT_VALUE)
31 * - TYPE : return type of the getter
31 * - TYPE : return type of the getter
32 */
32 */
33 // clang-format off
33 // clang-format off
34 #define DECLARE_PROPERTY_GETTER(GETTER_NAME, PROPERTY_NAME, TYPE) \
34 #define DECLARE_PROPERTY_GETTER(GETTER_NAME, PROPERTY_NAME, TYPE) \
35 TYPE GETTER_NAME() const \
35 TYPE GETTER_NAME() const \
36 { \
36 { \
37 static auto result = m_Properties.value(PROPERTY_NAME##_PROPERTY, PROPERTY_NAME##_DEFAULT_VALUE).value<TYPE>(); \
37 static auto result = m_Properties.value(PROPERTY_NAME##_PROPERTY, PROPERTY_NAME##_DEFAULT_VALUE).value<TYPE>(); \
38 return result; \
38 return result; \
39 } \
39 } \
40 // clang-format on
40 // clang-format on
41
41
42 namespace {
42 namespace {
43
43
44 // /////// //
44 // /////// //
45 // Aliases //
45 // Aliases //
46 // /////// //
46 // /////// //
47
47
48 using IntPair = std::pair<int, int>;
48 using IntPair = std::pair<int, int>;
49 using Weight = double;
49 using Weight = double;
50 using Weights = std::vector<Weight>;
50 using Weights = std::vector<Weight>;
51
51
52 struct OperationProperty {
52 struct OperationProperty {
53 Weight m_Weight{1.};
53 Weight m_Weight{1.};
54 bool m_WaitAcquisition{false};
54 bool m_WaitAcquisition{false};
55 };
55 };
56
56
57 using VariableOperation = std::pair<VariableId, std::shared_ptr<IFuzzingOperation> >;
57 using VariableOperation = std::pair<VariableId, std::shared_ptr<IFuzzingOperation> >;
58 using VariablesOperations = std::vector<VariableOperation>;
58 using VariablesOperations = std::vector<VariableOperation>;
59
59
60 struct CustomVariableOperation {
61 VariableOperation m_VariableOperation{};
62 bool m_WaitAcquisition{false};
63 };
64 using CustomVariablesOperations = std::vector<CustomVariableOperation>;
65
60 using OperationsTypes = std::map<FuzzingOperationType, OperationProperty>;
66 using OperationsTypes = std::map<FuzzingOperationType, OperationProperty>;
61 using OperationsPool = std::map<std::shared_ptr<IFuzzingOperation>, OperationProperty>;
67 using OperationsPool = std::map<std::shared_ptr<IFuzzingOperation>, OperationProperty>;
62
68
63 using Validators = std::vector<std::shared_ptr<IFuzzingValidator> >;
69 using Validators = std::vector<std::shared_ptr<IFuzzingValidator> >;
64
70
65 // ///////// //
71 // ///////// //
66 // Constants //
72 // Constants //
67 // ///////// //
73 // ///////// //
68
74
69 // Defaults values used when the associated properties have not been set for the test
75 // Defaults values used when the associated properties have not been set for the test
70 const auto ACQUISITION_TIMEOUT_DEFAULT_VALUE = 30000;
76 const auto ACQUISITION_TIMEOUT_DEFAULT_VALUE = 100000;
71 const auto NB_MAX_OPERATIONS_DEFAULT_VALUE = 100;
77 const auto NB_MAX_OPERATIONS_DEFAULT_VALUE = 160;
72 const auto NB_MAX_SYNC_GROUPS_DEFAULT_VALUE = 1;
78 const auto NB_MAX_SYNC_GROUPS_DEFAULT_VALUE = 8;
73 const auto NB_MAX_VARIABLES_DEFAULT_VALUE = 1;
79 const auto NB_MAX_VARIABLES_DEFAULT_VALUE = 30;
74 const auto AVAILABLE_OPERATIONS_DEFAULT_VALUE = QVariant::fromValue(
80 const auto AVAILABLE_OPERATIONS_DEFAULT_VALUE = QVariant::fromValue(
75 OperationsTypes{{FuzzingOperationType::CREATE, {1., true}},
81 OperationsTypes{{FuzzingOperationType::CREATE, {40000., true}},
76 {FuzzingOperationType::DELETE, {0.1}}, // Delete operation is less frequent
82 {FuzzingOperationType::DELETE, {0.0}}, // Delete operation is less frequent
77 {FuzzingOperationType::PAN_LEFT, {1.}},
83 {FuzzingOperationType::PAN_LEFT, {1.}},
78 {FuzzingOperationType::PAN_RIGHT, {1.}},
84 {FuzzingOperationType::PAN_RIGHT, {1.}},
79 {FuzzingOperationType::ZOOM_IN, {1.}},
85 {FuzzingOperationType::ZOOM_IN, {1.}},
80 {FuzzingOperationType::ZOOM_OUT, {1.}},
86 {FuzzingOperationType::ZOOM_OUT, {1.}},
81 {FuzzingOperationType::SYNCHRONIZE, {0.8}},
87 {FuzzingOperationType::SYNCHRONIZE, {500.0}},
82 {FuzzingOperationType::DESYNCHRONIZE, {0.4}}});
88 {FuzzingOperationType::DESYNCHRONIZE, {0.0}}});
83 const auto CACHE_TOLERANCE_DEFAULT_VALUE = 0.2;
89 const auto CACHE_TOLERANCE_DEFAULT_VALUE = 0.2;
84
90
85 /// Min/max delays between each operation (in ms)
91 /// Min/max delays between each operation (in ms)
86 const auto OPERATION_DELAY_BOUNDS_DEFAULT_VALUE = QVariant::fromValue(std::make_pair(100, 3000));
92 const auto OPERATION_DELAY_BOUNDS_DEFAULT_VALUE = QVariant::fromValue(std::make_pair(20, 3000));
87
93
88 /// Validators for the tests (executed in the order in which they're defined)
94 /// Validators for the tests (executed in the order in which they're defined)
89 const auto VALIDATORS_DEFAULT_VALUE = QVariant::fromValue(
95 const auto VALIDATORS_DEFAULT_VALUE = QVariant::fromValue(
90 ValidatorsTypes{{FuzzingValidatorType::RANGE, FuzzingValidatorType::DATA}});
96 ValidatorsTypes{{FuzzingValidatorType::RANGE, FuzzingValidatorType::DATA}});
91
97
92 /// Min/max number of operations to execute before calling validation
98 /// Min/max number of operations to execute before calling validation
93 const auto VALIDATION_FREQUENCY_BOUNDS_DEFAULT_VALUE = QVariant::fromValue(std::make_pair(1, 10));
99 const auto VALIDATION_FREQUENCY_BOUNDS_DEFAULT_VALUE = QVariant::fromValue(std::make_pair(2, 10));
100
101
102 // /////// //////
103 // CUSTOM CASE //
104 // /////// //////
105
106 auto op = [](auto type){
107 return FuzzingOperationFactory::create(type);
108 };
109
110
111 const QVariant CUSTOM_CASE_ONE =QVariant::fromValue(CustomVariablesOperations{{{0, op(FuzzingOperationType::CREATE)}, true},
112 {{0, op(FuzzingOperationType::SYNCHRONIZE)}},
113 {{1, op(FuzzingOperationType::CREATE)}, true},
114 {{1, op(FuzzingOperationType::SYNCHRONIZE)}},
115 {{0, op(FuzzingOperationType::PAN_LEFT)}},
116 {{1, op(FuzzingOperationType::PAN_RIGHT)}},
117 {{0, op(FuzzingOperationType::PAN_LEFT)}},
118 {{1, op(FuzzingOperationType::PAN_RIGHT)}},
119 {{0, op(FuzzingOperationType::PAN_LEFT)}},
120 {{1, op(FuzzingOperationType::PAN_RIGHT)}},
121 {{0, op(FuzzingOperationType::PAN_LEFT)}},
122 {{1, op(FuzzingOperationType::PAN_RIGHT)}},
123 {{0, op(FuzzingOperationType::PAN_LEFT)}},
124 {{1, op(FuzzingOperationType::PAN_RIGHT)}},
125 {{0, op(FuzzingOperationType::PAN_RIGHT)}},
126 {{1, op(FuzzingOperationType::PAN_LEFT)}},
127 {{0, op(FuzzingOperationType::PAN_RIGHT)}},
128 {{1, op(FuzzingOperationType::PAN_RIGHT)}},
129 {{0, op(FuzzingOperationType::PAN_LEFT)}},
130 {{1, op(FuzzingOperationType::PAN_RIGHT)}},
131 {{0, op(FuzzingOperationType::PAN_LEFT)}},
132 {{1, op(FuzzingOperationType::PAN_RIGHT)}},
133 {{0, op(FuzzingOperationType::PAN_LEFT)}},
134 {{1, op(FuzzingOperationType::PAN_RIGHT)}},
135 {{0, op(FuzzingOperationType::PAN_LEFT)}},
136 {{1, op(FuzzingOperationType::PAN_RIGHT)}},
137 {{0, op(FuzzingOperationType::PAN_LEFT)}},
138 {{1, op(FuzzingOperationType::PAN_LEFT)}},
139 {{0, op(FuzzingOperationType::PAN_LEFT)}},
140 {{1, op(FuzzingOperationType::PAN_LEFT)}},
141 {{0, op(FuzzingOperationType::PAN_RIGHT)}},
142 {{1, op(FuzzingOperationType::PAN_LEFT)}},
143 {{0, op(FuzzingOperationType::PAN_RIGHT)}},
144 {{1, op(FuzzingOperationType::PAN_RIGHT)}},
145 {{0, op(FuzzingOperationType::PAN_LEFT)}},
146 {{1, op(FuzzingOperationType::PAN_RIGHT)}},
147 {{0, op(FuzzingOperationType::PAN_LEFT)}},
148 {{1, op(FuzzingOperationType::PAN_RIGHT)}},
149 {{0, op(FuzzingOperationType::PAN_LEFT)}},
150 {{1, op(FuzzingOperationType::PAN_RIGHT)}},
151 {{0, op(FuzzingOperationType::PAN_LEFT)}},
152 {{1, op(FuzzingOperationType::PAN_RIGHT)}},
153 {{0, op(FuzzingOperationType::PAN_LEFT)}},
154 {{1, op(FuzzingOperationType::PAN_RIGHT)}},
155 {{0, op(FuzzingOperationType::PAN_LEFT)}},
156 {{1, op(FuzzingOperationType::PAN_RIGHT)}},
157 {{0, op(FuzzingOperationType::PAN_RIGHT)}},
158 {{1, op(FuzzingOperationType::PAN_LEFT)}},
159 {{0, op(FuzzingOperationType::PAN_RIGHT)}},
160 {{1, op(FuzzingOperationType::PAN_RIGHT)}},
161 {{0, op(FuzzingOperationType::PAN_LEFT)}},
162 {{1, op(FuzzingOperationType::PAN_RIGHT)}},
163 {{0, op(FuzzingOperationType::PAN_LEFT)}},
164 {{1, op(FuzzingOperationType::PAN_RIGHT)}},
165 {{0, op(FuzzingOperationType::PAN_RIGHT)}},
166 {{1, op(FuzzingOperationType::PAN_RIGHT)}},
167 {{0, op(FuzzingOperationType::PAN_LEFT)}},
168 {{1, op(FuzzingOperationType::PAN_RIGHT)}},
169 {{0, op(FuzzingOperationType::PAN_LEFT)}},
170 {{1, op(FuzzingOperationType::PAN_RIGHT)}},
171 {{0, op(FuzzingOperationType::PAN_LEFT)}},
172 {{1, op(FuzzingOperationType::PAN_RIGHT)}},
173 {{0, op(FuzzingOperationType::PAN_RIGHT)}},
174 {{1, op(FuzzingOperationType::PAN_LEFT)}},
175 {{0, op(FuzzingOperationType::PAN_RIGHT)}},
176 {{1, op(FuzzingOperationType::PAN_RIGHT)}},
177 {{0, op(FuzzingOperationType::PAN_LEFT)}},
178 {{1, op(FuzzingOperationType::PAN_RIGHT)}},
179 {{0, op(FuzzingOperationType::PAN_LEFT)}},
180 {{1, op(FuzzingOperationType::PAN_RIGHT)}},
181 {{0, op(FuzzingOperationType::PAN_LEFT)}},
182 {{1, op(FuzzingOperationType::PAN_RIGHT)}},
183 {{0, op(FuzzingOperationType::PAN_LEFT)}},
184 {{1, op(FuzzingOperationType::PAN_RIGHT)}},
185 {{0, op(FuzzingOperationType::PAN_LEFT)}},
186 {{1, op(FuzzingOperationType::PAN_RIGHT)}},
187 {{0, op(FuzzingOperationType::PAN_LEFT)}},
188 {{1, op(FuzzingOperationType::PAN_RIGHT)}},
189 {{0, op(FuzzingOperationType::PAN_RIGHT)}},
190 {{1, op(FuzzingOperationType::PAN_LEFT)}},
191 {{0, op(FuzzingOperationType::PAN_RIGHT)}},
192 {{1, op(FuzzingOperationType::PAN_RIGHT)}},
193 {{0, op(FuzzingOperationType::PAN_RIGHT)}},
194 {{1, op(FuzzingOperationType::PAN_RIGHT)}},
195 {{0, op(FuzzingOperationType::PAN_LEFT)}},
196 {{1, op(FuzzingOperationType::PAN_RIGHT)}},
197 {{0, op(FuzzingOperationType::PAN_LEFT)}},
198 {{1, op(FuzzingOperationType::PAN_RIGHT)}},
199 {{0, op(FuzzingOperationType::PAN_LEFT)}},
200 {{1, op(FuzzingOperationType::PAN_RIGHT)}},
201 {{0, op(FuzzingOperationType::PAN_LEFT)}},
202 {{1, op(FuzzingOperationType::PAN_RIGHT)}},
203 {{0, op(FuzzingOperationType::PAN_LEFT)}},
204 {{1, op(FuzzingOperationType::PAN_RIGHT)}},
205 {{0, op(FuzzingOperationType::PAN_RIGHT)}},
206 {{1, op(FuzzingOperationType::PAN_LEFT)}},
207 {{0, op(FuzzingOperationType::PAN_RIGHT)}},
208 {{1, op(FuzzingOperationType::PAN_RIGHT)}},
209 {{0, op(FuzzingOperationType::PAN_LEFT)}},
210 {{1, op(FuzzingOperationType::PAN_RIGHT)}},
211 });
212
213 const QVariant CUSTOM_CASE_TWO =QVariant::fromValue(CustomVariablesOperations{{{0, op(FuzzingOperationType::CREATE)}, true},
214 {{0, op(FuzzingOperationType::SYNCHRONIZE)}},
215 {{1, op(FuzzingOperationType::CREATE)}, true},
216 {{1, op(FuzzingOperationType::SYNCHRONIZE)}},
217 {{1, op(FuzzingOperationType::ZOOM_OUT)}},
218 {{1, op(FuzzingOperationType::ZOOM_IN)}},
219 });
94
220
95 // /////// //
221 // /////// //
96 // Methods //
222 // Methods //
97 // /////// //
223 // /////// //
98
224
99 /// Goes through the variables pool and operations pool to determine the set of {variable/operation}
225 /// Goes through the variables pool and operations pool to determine the set of {variable/operation}
100 /// pairs that are valid (i.e. operation that can be executed on variable)
226 /// pairs that are valid (i.e. operation that can be executed on variable)
101 std::pair<VariablesOperations, Weights> availableOperations(const FuzzingState &fuzzingState,
227 std::pair<VariablesOperations, Weights> availableOperations(const FuzzingState &fuzzingState,
102 const OperationsPool &operationsPool)
228 const OperationsPool &operationsPool)
103 {
229 {
104 VariablesOperations result{};
230 VariablesOperations result{};
105 Weights weights{};
231 Weights weights{};
106
232
107 for (const auto &variablesPoolEntry : fuzzingState.m_VariablesPool) {
233 for (const auto &variablesPoolEntry : fuzzingState.m_VariablesPool) {
108 auto variableId = variablesPoolEntry.first;
234 auto variableId = variablesPoolEntry.first;
109
235
110 for (const auto &operationsPoolEntry : operationsPool) {
236 for (const auto &operationsPoolEntry : operationsPool) {
111 auto operation = operationsPoolEntry.first;
237 auto operation = operationsPoolEntry.first;
112 auto operationProperty = operationsPoolEntry.second;
238 auto operationProperty = operationsPoolEntry.second;
113
239
114 // A pair is valid if the current operation can be executed on the current variable
240 // A pair is valid if the current operation can be executed on the current variable
115 if (operation->canExecute(variableId, fuzzingState)) {
241 if (operation->canExecute(variableId, fuzzingState)) {
116 result.push_back({variableId, operation});
242 result.push_back({variableId, operation});
117 weights.push_back(operationProperty.m_Weight);
243 weights.push_back(operationProperty.m_Weight);
118 }
244 }
119 }
245 }
120 }
246 }
121
247
122 return {result, weights};
248 return {result, weights};
123 }
249 }
124
250
125 OperationsPool createOperationsPool(const OperationsTypes &types)
251 OperationsPool createOperationsPool(const OperationsTypes &types)
126 {
252 {
127 OperationsPool result{};
253 OperationsPool result{};
128
254
129 std::transform(
255 std::transform(
130 types.cbegin(), types.cend(), std::inserter(result, result.end()), [](const auto &type) {
256 types.cbegin(), types.cend(), std::inserter(result, result.end()), [](const auto &type) {
131 return std::make_pair(FuzzingOperationFactory::create(type.first), type.second);
257 return std::make_pair(FuzzingOperationFactory::create(type.first), type.second);
132 });
258 });
133
259
134 return result;
260 return result;
135 }
261 }
136
262
137 Validators createValidators(const ValidatorsTypes &types)
263 Validators createValidators(const ValidatorsTypes &types)
138 {
264 {
139 Validators result{};
265 Validators result{};
140
266
141 std::transform(types.cbegin(), types.cend(), std::inserter(result, result.end()),
267 std::transform(types.cbegin(), types.cend(), std::inserter(result, result.end()),
142 [](const auto &type) { return FuzzingValidatorFactory::create(type); });
268 [](const auto &type) { return FuzzingValidatorFactory::create(type); });
143
269
144 return result;
270 return result;
145 }
271 }
146
272
147 /**
273 /**
148 * Validates all the variables' states passed in parameter, according to a set of validators
274 * Validates all the variables' states passed in parameter, according to a set of validators
149 * @param variablesPool the variables' states
275 * @param variablesPool the variables' states
150 * @param validators the validators used for validation
276 * @param validators the validators used for validation
151 */
277 */
152 void validate(const VariablesPool &variablesPool, const Validators &validators)
278 void validate(const VariablesPool &variablesPool, const Validators &validators)
153 {
279 {
154 for (const auto &variablesPoolEntry : variablesPool) {
280 for (const auto &variablesPoolEntry : variablesPool) {
155 auto variableId = variablesPoolEntry.first;
281 auto variableId = variablesPoolEntry.first;
156 const auto &variableState = variablesPoolEntry.second;
282 const auto &variableState = variablesPoolEntry.second;
157
283
158 auto variableMessage = variableState.m_Variable ? variableState.m_Variable->name()
284 auto variableMessage = variableState.m_Variable ? variableState.m_Variable->name()
159 : QStringLiteral("null variable");
285 : QStringLiteral("null variable");
160 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Validating state of variable at index"
286 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Validating state of variable at index"
161 << variableId << "(" << variableMessage << ")...";
287 << variableId << "(" << variableMessage << ")...";
162
288
163 for (const auto &validator : validators) {
289 for (const auto &validator : validators) {
164 validator->validate(VariableState{variableState});
290 validator->validate(VariableState{variableState});
165 }
291 }
166
292
167 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Validation completed.";
293 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Validation completed.";
168 }
294 }
169 }
295 }
170
296
171 /**
297 /**
172 * Class to run random tests
298 * Class to run random tests
173 */
299 */
174 class FuzzingTest {
300 class FuzzingTest {
175 public:
301 public:
176 explicit FuzzingTest(VariableController &variableController, Properties properties)
302 explicit FuzzingTest(VariableController &variableController, Properties properties)
177 : m_VariableController{variableController},
303 : m_VariableController{variableController},
178 m_Properties{std::move(properties)},
304 m_Properties{std::move(properties)},
179 m_FuzzingState{}
305 m_FuzzingState{}
180 {
306 {
181 // Inits variables pool: at init, all variables are null
307 // Inits variables pool: at init, all variables are null
182 for (auto variableId = 0; variableId < nbMaxVariables(); ++variableId) {
308 for (auto variableId = 0; variableId < nbMaxVariables(); ++variableId) {
183 m_FuzzingState.m_VariablesPool[variableId] = VariableState{};
309 m_FuzzingState.m_VariablesPool[variableId] = VariableState{};
184 }
310 }
185
311
186 // Inits sync groups and registers them into the variable controller
312 // Inits sync groups and registers them into the variable controller
187 for (auto i = 0; i < nbMaxSyncGroups(); ++i) {
313 for (auto i = 0; i < nbMaxSyncGroups(); ++i) {
188 auto syncGroupId = SyncGroupId::createUuid();
314 auto syncGroupId = SyncGroupId::createUuid();
189 variableController.onAddSynchronizationGroupId(syncGroupId);
315 variableController.onAddSynchronizationGroupId(syncGroupId);
190 m_FuzzingState.m_SyncGroupsPool[syncGroupId] = SyncGroup{};
316 m_FuzzingState.m_SyncGroupsPool[syncGroupId] = SyncGroup{};
191 }
317 }
192 }
318 }
193
319
194 void execute()
320 void execute()
195 {
321 {
196 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Running" << nbMaxOperations() << "operations on"
197 << nbMaxVariables() << "variable(s)...";
198
199
322
200 // Inits the count of the number of operations before the next validation
323 // Inits the count of the number of operations before the next validation
201 int nextValidationCounter = 0;
324 int nextValidationCounter = 0;
202 auto updateValidationCounter = [this, &nextValidationCounter]() {
325 auto updateValidationCounter = [this, &nextValidationCounter]() {
203 nextValidationCounter = RandomGenerator::instance().generateInt(
326 nextValidationCounter = RandomGenerator::instance().generateInt(
204 validationFrequencies().first, validationFrequencies().second);
327 validationFrequencies().first, validationFrequencies().second);
205 qCInfo(LOG_TestAmdaFuzzing()).noquote()
328 qCInfo(LOG_TestAmdaFuzzing()).noquote()
206 << "Next validation in " << nextValidationCounter << "operation(s)...";
329 << "Next validation in " << nextValidationCounter << "operation(s)...";
207 };
330 };
208 updateValidationCounter();
331 updateValidationCounter();
209
332
333 // Get custom operations
334 auto customOperations = m_Properties.value(CUSTOM_OPERATIONS_PROPERTY).value<CustomVariablesOperations>();
335 auto isCustomTest = !customOperations.empty();
336
337 auto nbOperations = isCustomTest ? customOperations.size() : nbMaxOperations();
338
339 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Running" << nbOperations << "operations on"
340 << nbMaxVariables() << "variable(s)...";
341
210 auto canExecute = true;
342 auto canExecute = true;
211 for (auto i = 0; i < nbMaxOperations() && canExecute; ++i) {
343 for (auto i = 0; i < nbOperations && canExecute; ++i) {
212 // Retrieves all operations that can be executed in the current context
344 VariableOperation variableOperation{};
213 VariablesOperations variableOperations{};
345 auto forceWait = false;
214 Weights weights{};
346
215 std::tie(variableOperations, weights)
347 if(isCustomTest){
216 = availableOperations(m_FuzzingState, operationsPool());
348 auto customOperation = customOperations.front();
217
349 variableOperation = customOperation.m_VariableOperation;
218 canExecute = !variableOperations.empty();
350 customOperations.erase(customOperations.begin());
219 if (canExecute) {
351
220 --nextValidationCounter;
352 canExecute = variableOperation.second->canExecute(variableOperation.first, m_FuzzingState);
353 forceWait = customOperation.m_WaitAcquisition;
354 } else {
355 // Retrieves all operations that can be executed in the current context
356 VariablesOperations variableOperations{};
357 Weights weights{};
358 std::tie(variableOperations, weights)
359 = availableOperations(m_FuzzingState, operationsPool());
221
360
222 // Of the operations available, chooses a random operation and executes it
361 // Of the operations available, chooses a random operation and executes it
223 auto variableOperation
362 variableOperation
224 = RandomGenerator::instance().randomChoice(variableOperations, weights);
363 = RandomGenerator::instance().randomChoice(variableOperations, weights);
364 canExecute = !variableOperations.empty();
365 forceWait = operationsPool().at(variableOperation.second).m_WaitAcquisition;
366 }
367
368 if (canExecute) {
369 --nextValidationCounter;
225
370
226 auto variableId = variableOperation.first;
371 auto variableId = variableOperation.first;
227 auto fuzzingOperation = variableOperation.second;
372 auto fuzzingOperation = variableOperation.second;
228
373
229 auto waitAcquisition = nextValidationCounter == 0
374 auto waitAcquisition = nextValidationCounter == 0
230 || operationsPool().at(fuzzingOperation).m_WaitAcquisition;
375 || forceWait;
231
376
377 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Operation :" << i +1 << " on"
378 << nbOperations;
232 fuzzingOperation->execute(variableId, m_FuzzingState, m_VariableController,
379 fuzzingOperation->execute(variableId, m_FuzzingState, m_VariableController,
233 m_Properties);
380 m_Properties);
234
381
235 if (waitAcquisition) {
382 if (waitAcquisition) {
236 qCDebug(LOG_TestAmdaFuzzing()) << "Waiting for acquisition to finish...";
383 qCDebug(LOG_TestAmdaFuzzing()) << "Waiting for acquisition to finish...";
237 SignalWaiter{m_VariableController, SIGNAL(acquisitionFinished())}.wait(
384 SignalWaiter{m_VariableController, SIGNAL(acquisitionFinished())}.wait(
238 acquisitionTimeout());
385 acquisitionTimeout());
239
386
240 // Validates variables
387 // Validates variables
241 if (nextValidationCounter == 0) {
388 if (nextValidationCounter == 0) {
242 validate(m_FuzzingState.m_VariablesPool, validators());
389 validate(m_FuzzingState.m_VariablesPool, validators());
243 updateValidationCounter();
390 updateValidationCounter();
244 }
391 }
245 }
392 }
246 else {
393 else {
247 // Delays the next operation with a randomly generated time
394 // Delays the next operation with a randomly generated time
248 auto delay = RandomGenerator::instance().generateInt(operationDelays().first,
395 auto delay = RandomGenerator::instance().generateInt(operationDelays().first,
249 operationDelays().second);
396 operationDelays().second);
250 qCDebug(LOG_TestAmdaFuzzing())
397 qCDebug(LOG_TestAmdaFuzzing())
251 << "Waiting " << delay << "ms before the next operation...";
398 << "Waiting " << delay << "ms before the next operation...";
252 QTest::qWait(delay);
399 QTest::qWait(delay);
253 }
400 }
254 }
401 }
255 else {
402 else {
256 qCInfo(LOG_TestAmdaFuzzing()).noquote()
403 qCInfo(LOG_TestAmdaFuzzing()).noquote()
257 << "No more operations are available, the execution of the test will stop...";
404 << "No more operations are available, the execution of the test will stop...";
258 }
405 }
259 }
406 }
260
407
261 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Execution of the test completed.";
408 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Execution of the test completed.";
262 }
409 }
263
410
264 private:
411 private:
265 OperationsPool operationsPool() const
412 OperationsPool operationsPool() const
266 {
413 {
267 static auto result = createOperationsPool(
414 static auto result = createOperationsPool(
268 m_Properties.value(AVAILABLE_OPERATIONS_PROPERTY, AVAILABLE_OPERATIONS_DEFAULT_VALUE)
415 m_Properties.value(AVAILABLE_OPERATIONS_PROPERTY, AVAILABLE_OPERATIONS_DEFAULT_VALUE)
269 .value<OperationsTypes>());
416 .value<OperationsTypes>());
270 return result;
417 return result;
271 }
418 }
272
419
273 Validators validators() const
420 Validators validators() const
274 {
421 {
275 static auto result
422 static auto result
276 = createValidators(m_Properties.value(VALIDATORS_PROPERTY, VALIDATORS_DEFAULT_VALUE)
423 = createValidators(m_Properties.value(VALIDATORS_PROPERTY, VALIDATORS_DEFAULT_VALUE)
277 .value<ValidatorsTypes>());
424 .value<ValidatorsTypes>());
278 return result;
425 return result;
279 }
426 }
280
427
281 DECLARE_PROPERTY_GETTER(nbMaxOperations, NB_MAX_OPERATIONS, int)
428 DECLARE_PROPERTY_GETTER(nbMaxOperations, NB_MAX_OPERATIONS, int)
282 DECLARE_PROPERTY_GETTER(nbMaxSyncGroups, NB_MAX_SYNC_GROUPS, int)
429 DECLARE_PROPERTY_GETTER(nbMaxSyncGroups, NB_MAX_SYNC_GROUPS, int)
283 DECLARE_PROPERTY_GETTER(nbMaxVariables, NB_MAX_VARIABLES, int)
430 DECLARE_PROPERTY_GETTER(nbMaxVariables, NB_MAX_VARIABLES, int)
284 DECLARE_PROPERTY_GETTER(operationDelays, OPERATION_DELAY_BOUNDS, IntPair)
431 DECLARE_PROPERTY_GETTER(operationDelays, OPERATION_DELAY_BOUNDS, IntPair)
285 DECLARE_PROPERTY_GETTER(validationFrequencies, VALIDATION_FREQUENCY_BOUNDS, IntPair)
432 DECLARE_PROPERTY_GETTER(validationFrequencies, VALIDATION_FREQUENCY_BOUNDS, IntPair)
286 DECLARE_PROPERTY_GETTER(acquisitionTimeout, ACQUISITION_TIMEOUT, int)
433 DECLARE_PROPERTY_GETTER(acquisitionTimeout, ACQUISITION_TIMEOUT, int)
287
434
288 VariableController &m_VariableController;
435 VariableController &m_VariableController;
289 Properties m_Properties;
436 Properties m_Properties;
290 FuzzingState m_FuzzingState;
437 FuzzingState m_FuzzingState;
291 };
438 };
292
439
293 } // namespace
440 } // namespace
294
441
295 Q_DECLARE_METATYPE(OperationsTypes)
442 Q_DECLARE_METATYPE(OperationsTypes)
443 Q_DECLARE_METATYPE(CustomVariablesOperations)
296
444
297 class TestAmdaFuzzing : public QObject {
445 class TestAmdaFuzzing : public QObject {
298 Q_OBJECT
446 Q_OBJECT
299
447
300 private slots:
448 private slots:
301 /// Input data for @sa testFuzzing()
449 /// Input data for @sa testFuzzing()
302 void testFuzzing_data();
450 void testFuzzing_data();
303 void testFuzzing();
451 void testFuzzing();
304 };
452 };
305
453
306 void TestAmdaFuzzing::testFuzzing_data()
454 void TestAmdaFuzzing::testFuzzing_data()
307 {
455 {
308 // Note: Comment this line to run fuzzing tests
456 // Note: Comment this line to run fuzzing tests
309 QSKIP("Fuzzing tests are disabled by default");
457 // QSKIP("Fuzzing tests are disabled by default");
310
458
311 // ////////////// //
459 // ////////////// //
312 // Test structure //
460 // Test structure //
313 // ////////////// //
461 // ////////////// //
314
462
315 QTest::addColumn<Properties>("properties"); // Properties for random test
463 QTest::addColumn<Properties>("properties"); // Properties for random test
316
464
317 // ////////// //
465 // ////////// //
318 // Test cases //
466 // Test cases //
319 // ////////// //
467 // ////////// //
320
468
321 auto maxRange = SqpRange::fromDateTime({2017, 1, 1}, {0, 0}, {2017, 1, 5}, {0, 0});
469 auto maxRange = SqpRange::fromDateTime({2017, 1, 5}, {8, 0}, {2017, 1, 5}, {16, 0});
322 MetadataPool metadataPool{{{"dataType", "vector"}, {"xml:id", "imf"}}};
470 MetadataPool metadataPool{{{"dataType", "vector"}, {"xml:id", "c1_b"}}};
323
471
324 // Note: we don't use auto here as we want to pass std::shared_ptr<IDataProvider> as is in the
472 // Note: we don't use auto here as we want to pass std::shared_ptr<IDataProvider> as is in the
325 // QVariant
473 // QVariant
326 std::shared_ptr<IDataProvider> provider = std::make_shared<AmdaProvider>();
474 std::shared_ptr<IDataProvider> provider = std::make_shared<AmdaProvider>();
327
475
476
477 // Case Custom one : Only lot of pan on two variables synchronized
478 // QTest::newRow("fuzzingTestPan") << Properties{
479 // {MAX_RANGE_PROPERTY, QVariant::fromValue(maxRange)},
480 // {METADATA_POOL_PROPERTY, QVariant::fromValue(metadataPool)},
481 // {PROVIDER_PROPERTY, QVariant::fromValue(provider)},
482 // {CUSTOM_OPERATIONS_PROPERTY, CUSTOM_CASE_ONE}};
483
484 // QTest::newRow("fuzzingTestZoom") << Properties{
485 // {MAX_RANGE_PROPERTY, QVariant::fromValue(maxRange)},
486 // {METADATA_POOL_PROPERTY, QVariant::fromValue(metadataPool)},
487 // {PROVIDER_PROPERTY, QVariant::fromValue(provider)},
488 // {CUSTOM_OPERATIONS_PROPERTY, CUSTOM_CASE_TWO}};
489
490
491 //// Fuzzing
328 QTest::newRow("fuzzingTest") << Properties{
492 QTest::newRow("fuzzingTest") << Properties{
329 {MAX_RANGE_PROPERTY, QVariant::fromValue(maxRange)},
493 {MAX_RANGE_PROPERTY, QVariant::fromValue(maxRange)},
330 {METADATA_POOL_PROPERTY, QVariant::fromValue(metadataPool)},
494 {METADATA_POOL_PROPERTY, QVariant::fromValue(metadataPool)},
331 {PROVIDER_PROPERTY, QVariant::fromValue(provider)}};
495 {PROVIDER_PROPERTY, QVariant::fromValue(provider)}};
496
332 }
497 }
333
498
334 void TestAmdaFuzzing::testFuzzing()
499 void TestAmdaFuzzing::testFuzzing()
335 {
500 {
336 QFETCH(Properties, properties);
501 QFETCH(Properties, properties);
337
502
338 // Sets cache property
503 // Sets cache property
339 QSettings settings{};
504 QSettings settings{};
340 auto cacheTolerance = properties.value(CACHE_TOLERANCE_PROPERTY, CACHE_TOLERANCE_DEFAULT_VALUE);
505 auto cacheTolerance = properties.value(CACHE_TOLERANCE_PROPERTY, CACHE_TOLERANCE_DEFAULT_VALUE);
341 settings.setValue(GENERAL_TOLERANCE_AT_INIT_KEY, cacheTolerance);
506 settings.setValue(GENERAL_TOLERANCE_AT_INIT_KEY, cacheTolerance);
342 settings.setValue(GENERAL_TOLERANCE_AT_UPDATE_KEY, cacheTolerance);
507 settings.setValue(GENERAL_TOLERANCE_AT_UPDATE_KEY, cacheTolerance);
343
508
344 auto &variableController = sqpApp->variableController();
509 auto &variableController = sqpApp->variableController();
345 auto &timeController = sqpApp->timeController();
510 auto &timeController = sqpApp->timeController();
346
511
347 // Generates random initial range (bounded to max range)
512 // Generates random initial range (bounded to max range)
348 auto maxRange = properties.value(MAX_RANGE_PROPERTY, QVariant::fromValue(INVALID_RANGE))
513 auto maxRange = properties.value(MAX_RANGE_PROPERTY, QVariant::fromValue(INVALID_RANGE))
349 .value<SqpRange>();
514 .value<SqpRange>();
350
515
351 QVERIFY(maxRange != INVALID_RANGE);
516 QVERIFY(maxRange != INVALID_RANGE);
352
517
353 auto initialRangeStart
518 auto initialRangeStart
354 = RandomGenerator::instance().generateDouble(maxRange.m_TStart, maxRange.m_TEnd);
519 = RandomGenerator::instance().generateDouble(maxRange.m_TStart, maxRange.m_TEnd);
355 auto initialRangeEnd
520 auto initialRangeEnd
356 = RandomGenerator::instance().generateDouble(maxRange.m_TStart, maxRange.m_TEnd);
521 = RandomGenerator::instance().generateDouble(maxRange.m_TStart, maxRange.m_TEnd);
357 if (initialRangeStart > initialRangeEnd) {
522 if (initialRangeStart > initialRangeEnd) {
358 std::swap(initialRangeStart, initialRangeEnd);
523 std::swap(initialRangeStart, initialRangeEnd);
359 }
524 }
360
525
361 // Sets initial range on time controller
526 // Sets initial range on time controller
362 SqpRange initialRange{initialRangeStart, initialRangeEnd};
527 SqpRange initialRange{initialRangeStart, initialRangeEnd};
363 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Setting initial range to" << initialRange << "...";
528 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Setting initial range to" << initialRange << "...";
364 timeController.onTimeToUpdate(initialRange);
529 timeController.onTimeToUpdate(initialRange);
365 properties.insert(INITIAL_RANGE_PROPERTY, QVariant::fromValue(initialRange));
530 properties.insert(INITIAL_RANGE_PROPERTY, QVariant::fromValue(initialRange));
366
531
367 FuzzingTest test{variableController, properties};
532 FuzzingTest test{variableController, properties};
368 test.execute();
533 test.execute();
369 }
534 }
370
535
371 int main(int argc, char *argv[])
536 int main(int argc, char *argv[])
372 {
537 {
373 // Increases the test function timeout (which is 5 minutes by default) to 12 hours
538 // Increases the test function timeout (which is 5 minutes by default) to 12 hours
374 // https://stackoverflow.com/questions/42655932/setting-timeout-to-qt-test
539 // https://stackoverflow.com/questions/42655932/setting-timeout-to-qt-test
375 qputenv("QTEST_FUNCTION_TIMEOUT", QByteArray::number(12*60*60*1000));
540 qputenv("QTEST_FUNCTION_TIMEOUT", QByteArray::number(12*60*60*1000));
376
541
377 QLoggingCategory::setFilterRules(
542 QLoggingCategory::setFilterRules(
378 "*.warning=false\n"
543 "*.warning=false\n"
379 "*.info=false\n"
544 "*.info=false\n"
380 "*.debug=false\n"
545 "*.debug=false\n"
381 "FuzzingOperations.info=true\n"
546 "FuzzingOperations.info=true\n"
382 "FuzzingValidators.info=true\n"
547 "FuzzingValidators.info=true\n"
383 "TestAmdaFuzzing.info=true\n");
548 "TestAmdaFuzzing.info=true\n");
384
549
385 SqpApplication app{argc, argv};
550 SqpApplication app{argc, argv};
386 SqpApplication::setOrganizationName("LPP");
551 SqpApplication::setOrganizationName("LPP");
387 SqpApplication::setOrganizationDomain("lpp.fr");
552 SqpApplication::setOrganizationDomain("lpp.fr");
388 SqpApplication::setApplicationName("SciQLop-TestFuzzing");
553 SqpApplication::setApplicationName("SciQLop-TestFuzzing");
389 app.setAttribute(Qt::AA_Use96Dpi, true);
554 app.setAttribute(Qt::AA_Use96Dpi, true);
390 TestAmdaFuzzing testObject{};
555 TestAmdaFuzzing testObject{};
391 QTEST_SET_MAIN_SOURCE_PATH
556 QTEST_SET_MAIN_SOURCE_PATH
392 return QTest::qExec(&testObject, argc, argv);
557 return QTest::qExec(&testObject, argc, argv);
393 }
558 }
394
559
395 #include "TestAmdaFuzzing.moc"
560 #include "TestAmdaFuzzing.moc"
General Comments 0
You need to be logged in to leave comments. Login now