##// END OF EJS Templates
The dataSeries of a variable is now shared istead of uniq to avoid...
perrinel -
r542:4e7b3226237d
parent child
Show More
@@ -1,211 +1,211
1 1 #include "Variable/Variable.h"
2 2
3 3 #include <Data/IDataSeries.h>
4 4 #include <Data/SqpRange.h>
5 5
6 6 #include <QMutex>
7 7 #include <QReadWriteLock>
8 8 #include <QThread>
9 9
10 10 Q_LOGGING_CATEGORY(LOG_Variable, "Variable")
11 11
12 12 struct Variable::VariablePrivate {
13 13 explicit VariablePrivate(const QString &name, const SqpRange &dateTime,
14 14 const QVariantHash &metadata)
15 15 : m_Name{name}, m_Range{dateTime}, m_Metadata{metadata}, m_DataSeries{nullptr}
16 16 {
17 17 }
18 18
19 19 void lockRead() { m_Lock.lockForRead(); }
20 20 void lockWrite() { m_Lock.lockForWrite(); }
21 21 void unlock() { m_Lock.unlock(); }
22 22
23 23 QString m_Name;
24 24
25 25 SqpRange m_Range;
26 26 SqpRange m_CacheRange;
27 27 QVariantHash m_Metadata;
28 std::unique_ptr<IDataSeries> m_DataSeries;
28 std::shared_ptr<IDataSeries> m_DataSeries;
29 29
30 30 QReadWriteLock m_Lock;
31 31 };
32 32
33 33 Variable::Variable(const QString &name, const SqpRange &dateTime, const QVariantHash &metadata)
34 34 : impl{spimpl::make_unique_impl<VariablePrivate>(name, dateTime, metadata)}
35 35 {
36 36 }
37 37
38 38 QString Variable::name() const noexcept
39 39 {
40 40 impl->lockRead();
41 41 auto name = impl->m_Name;
42 42 impl->unlock();
43 43 return name;
44 44 }
45 45
46 46 SqpRange Variable::range() const noexcept
47 47 {
48 48 impl->lockRead();
49 49 auto range = impl->m_Range;
50 50 impl->unlock();
51 51 return range;
52 52 }
53 53
54 54 void Variable::setRange(const SqpRange &range) noexcept
55 55 {
56 56 impl->lockWrite();
57 57 impl->m_Range = range;
58 58 impl->unlock();
59 59 }
60 60
61 61 SqpRange Variable::cacheRange() const noexcept
62 62 {
63 63 impl->lockRead();
64 64 auto cacheRange = impl->m_CacheRange;
65 65 impl->unlock();
66 66 return cacheRange;
67 67 }
68 68
69 69 void Variable::setCacheRange(const SqpRange &cacheRange) noexcept
70 70 {
71 71 impl->lockWrite();
72 72 impl->m_CacheRange = cacheRange;
73 73 impl->unlock();
74 74 }
75 75
76 76 void Variable::setDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept
77 77 {
78 qCInfo(LOG_Variable()) << "Variable::setDataSeries" << QThread::currentThread()->objectName();
78 qCDebug(LOG_Variable()) << "TORM Variable::setDataSeries"
79 << QThread::currentThread()->objectName();
79 80 if (!dataSeries) {
80 81 /// @todo ALX : log
81 82 return;
82 83 }
83 84 impl->lockWrite();
84 85 impl->m_DataSeries = dataSeries->clone();
85 86 impl->unlock();
86 87 }
87 88
88 89 void Variable::mergeDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept
89 90 {
90 qCDebug(LOG_Variable()) << "Variable::mergeDataSeries"
91 qCDebug(LOG_Variable()) << "TORM Variable::mergeDataSeries"
91 92 << QThread::currentThread()->objectName();
92 93 if (!dataSeries) {
93 94 /// @todo ALX : log
94 95 return;
95 96 }
96 97
97 98 // Add or merge the data
98 99 // Inits the data series of the variable
99 100 impl->lockWrite();
100 101 if (!impl->m_DataSeries) {
101 102 impl->m_DataSeries = dataSeries->clone();
102 103 }
103 104 else {
104 105 impl->m_DataSeries->merge(dataSeries.get());
105 106 }
106 107 impl->unlock();
107 108
108 109 // sub the data
109 110 auto subData = this->dataSeries()->subData(this->cacheRange());
110 qCCritical(LOG_Variable()) << "TORM: Variable::mergeDataSeries sub" << subData->range();
111 qCDebug(LOG_Variable()) << "TORM: Variable::mergeDataSeries sub" << subData->range();
111 112 this->setDataSeries(subData);
112 qCCritical(LOG_Variable()) << "TORM: Variable::mergeDataSeries set"
113 << this->dataSeries()->range();
113 qCDebug(LOG_Variable()) << "TORM: Variable::mergeDataSeries set" << this->dataSeries()->range();
114 114 }
115 115
116 IDataSeries *Variable::dataSeries() const noexcept
116 std::shared_ptr<IDataSeries> Variable::dataSeries() const noexcept
117 117 {
118 118 impl->lockRead();
119 auto dataSeries = impl->m_DataSeries.get();
119 auto dataSeries = impl->m_DataSeries;
120 120 impl->unlock();
121 121
122 122 return dataSeries;
123 123 }
124 124
125 125 QVariantHash Variable::metadata() const noexcept
126 126 {
127 127 impl->lockRead();
128 128 auto metadata = impl->m_Metadata;
129 129 impl->unlock();
130 130 return metadata;
131 131 }
132 132
133 133 bool Variable::contains(const SqpRange &range) const noexcept
134 134 {
135 135 impl->lockRead();
136 136 auto res = impl->m_Range.contains(range);
137 137 impl->unlock();
138 138 return res;
139 139 }
140 140
141 141 bool Variable::intersect(const SqpRange &range) const noexcept
142 142 {
143 143
144 144 impl->lockRead();
145 145 auto res = impl->m_Range.intersect(range);
146 146 impl->unlock();
147 147 return res;
148 148 }
149 149
150 150 bool Variable::isInside(const SqpRange &range) const noexcept
151 151 {
152 152 impl->lockRead();
153 153 auto res = range.contains(SqpRange{impl->m_Range.m_TStart, impl->m_Range.m_TEnd});
154 154 impl->unlock();
155 155 return res;
156 156 }
157 157
158 158 bool Variable::cacheContains(const SqpRange &range) const noexcept
159 159 {
160 160 impl->lockRead();
161 161 auto res = impl->m_CacheRange.contains(range);
162 162 impl->unlock();
163 163 return res;
164 164 }
165 165
166 166 bool Variable::cacheIntersect(const SqpRange &range) const noexcept
167 167 {
168 168 impl->lockRead();
169 169 auto res = impl->m_CacheRange.intersect(range);
170 170 impl->unlock();
171 171 return res;
172 172 }
173 173
174 174 bool Variable::cacheIsInside(const SqpRange &range) const noexcept
175 175 {
176 176 impl->lockRead();
177 177 auto res = range.contains(SqpRange{impl->m_CacheRange.m_TStart, impl->m_CacheRange.m_TEnd});
178 178 impl->unlock();
179 179 return res;
180 180 }
181 181
182 182
183 183 QVector<SqpRange> Variable::provideNotInCacheRangeList(const SqpRange &range) const noexcept
184 184 {
185 185 auto notInCache = QVector<SqpRange>{};
186 186
187 187 if (!this->cacheContains(range)) {
188 188 if (range.m_TEnd <= impl->m_CacheRange.m_TStart
189 189 || range.m_TStart >= impl->m_CacheRange.m_TEnd) {
190 190 notInCache << range;
191 191 }
192 192 else if (range.m_TStart < impl->m_CacheRange.m_TStart
193 193 && range.m_TEnd <= impl->m_CacheRange.m_TEnd) {
194 194 notInCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TStart};
195 195 }
196 196 else if (range.m_TStart < impl->m_CacheRange.m_TStart
197 197 && range.m_TEnd > impl->m_CacheRange.m_TEnd) {
198 198 notInCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TStart}
199 199 << SqpRange{impl->m_CacheRange.m_TEnd, range.m_TEnd};
200 200 }
201 201 else if (range.m_TStart < impl->m_CacheRange.m_TEnd) {
202 202 notInCache << SqpRange{impl->m_CacheRange.m_TEnd, range.m_TEnd};
203 203 }
204 204 else {
205 205 qCCritical(LOG_Variable()) << tr("Detection of unknown case.")
206 206 << QThread::currentThread();
207 207 }
208 208 }
209 209
210 210 return notInCache;
211 211 }
@@ -1,225 +1,225
1 1 #include "Variable/VariableAcquisitionWorker.h"
2 2
3 3 #include "Variable/Variable.h"
4 4
5 5 #include <Data/AcquisitionRequest.h>
6 6 #include <Data/SqpRange.h>
7 7
8 8 #include <unordered_map>
9 9 #include <utility>
10 10
11 11 #include <QMutex>
12 12 #include <QReadWriteLock>
13 13 #include <QThread>
14 14
15 15 Q_LOGGING_CATEGORY(LOG_VariableAcquisitionWorker, "VariableAcquisitionWorker")
16 16
17 17 struct VariableAcquisitionWorker::VariableAcquisitionWorkerPrivate {
18 18
19 19 explicit VariableAcquisitionWorkerPrivate() : m_Lock{QReadWriteLock::Recursive} {}
20 20
21 21 void lockRead() { m_Lock.lockForRead(); }
22 22 void lockWrite() { m_Lock.lockForWrite(); }
23 23 void unlock() { m_Lock.unlock(); }
24 24
25 25 void removeVariableRequest(QUuid vIdentifier);
26 26
27 27 QMutex m_WorkingMutex;
28 28 QReadWriteLock m_Lock;
29 29
30 30 std::map<QUuid, QVector<AcquisitionDataPacket> > m_AcqIdentifierToAcqDataPacketVectorMap;
31 31 std::map<QUuid, AcquisitionRequest> m_AcqIdentifierToAcqRequestMap;
32 32 std::map<QUuid, std::pair<QUuid, QUuid> > m_VIdentifierToCurrrentAcqIdNextIdPairMap;
33 33 };
34 34
35 35
36 36 VariableAcquisitionWorker::VariableAcquisitionWorker(QObject *parent)
37 37 : QObject{parent}, impl{spimpl::make_unique_impl<VariableAcquisitionWorkerPrivate>()}
38 38 {
39 39 }
40 40
41 41 VariableAcquisitionWorker::~VariableAcquisitionWorker()
42 42 {
43 43 qCInfo(LOG_VariableAcquisitionWorker()) << tr("VariableAcquisitionWorker destruction")
44 44 << QThread::currentThread();
45 45 this->waitForFinish();
46 46 }
47 47
48 48
49 49 void VariableAcquisitionWorker::pushVariableRequest(QUuid vIdentifier, SqpRange rangeRequested,
50 50 SqpRange cacheRangeRequested,
51 51 DataProviderParameters parameters,
52 52 std::shared_ptr<IDataProvider> provider)
53 53 {
54 qCDebug(LOG_VariableAcquisitionWorker())
54 qCInfo(LOG_VariableAcquisitionWorker())
55 55 << tr("TORM VariableAcquisitionWorker::pushVariableRequest ") << cacheRangeRequested;
56 56
57 57 // Request creation
58 58 auto acqRequest = AcquisitionRequest{};
59 59 acqRequest.m_vIdentifier = vIdentifier;
60 60 acqRequest.m_DataProviderParameters = parameters;
61 61 acqRequest.m_RangeRequested = rangeRequested;
62 62 acqRequest.m_CacheRangeRequested = cacheRangeRequested;
63 63 acqRequest.m_Size = parameters.m_Times.size();
64 64 acqRequest.m_Provider = provider;
65 65
66 66 // Register request
67 67 impl->lockWrite();
68 68 impl->m_AcqIdentifierToAcqRequestMap.insert(
69 69 std::make_pair(acqRequest.m_AcqIdentifier, acqRequest));
70 70
71 71 auto it = impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.find(vIdentifier);
72 72 if (it != impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.cend()) {
73 73 // A current request already exists, we can replace the next one
74 74 it->second.second = acqRequest.m_AcqIdentifier;
75 75 impl->unlock();
76 76 }
77 77 else {
78 78 // First request for the variable, it must be stored and executed
79 79 impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.insert(
80 80 std::make_pair(vIdentifier, std::make_pair(acqRequest.m_AcqIdentifier, QUuid())));
81 81 impl->unlock();
82 82
83 83 QMetaObject::invokeMethod(this, "onExecuteRequest", Qt::QueuedConnection,
84 84 Q_ARG(QUuid, acqRequest.m_AcqIdentifier));
85 85 }
86 86 }
87 87
88 88 void VariableAcquisitionWorker::abortProgressRequested(QUuid vIdentifier)
89 89 {
90 90 // TODO
91 91 }
92 92
93 93 void VariableAcquisitionWorker::onVariableRetrieveDataInProgress(QUuid acqIdentifier,
94 94 double progress)
95 95 {
96 96 // TODO
97 97 }
98 98
99 99 void VariableAcquisitionWorker::onVariableDataAcquired(QUuid acqIdentifier,
100 100 std::shared_ptr<IDataSeries> dataSeries,
101 101 SqpRange dataRangeAcquired)
102 102 {
103 103 qCDebug(LOG_VariableAcquisitionWorker()) << tr("onVariableDataAcquired on range ")
104 104 << acqIdentifier << dataRangeAcquired;
105 105 impl->lockWrite();
106 106 auto aIdToARit = impl->m_AcqIdentifierToAcqRequestMap.find(acqIdentifier);
107 107 if (aIdToARit != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
108 108 // Store the result
109 109 auto dataPacket = AcquisitionDataPacket{};
110 110 dataPacket.m_Range = dataRangeAcquired;
111 111 dataPacket.m_DateSeries = dataSeries;
112 112
113 113 auto aIdToADPVit = impl->m_AcqIdentifierToAcqDataPacketVectorMap.find(acqIdentifier);
114 114 if (aIdToADPVit != impl->m_AcqIdentifierToAcqDataPacketVectorMap.cend()) {
115 115 // A current request result already exists, we can update it
116 116 aIdToADPVit->second.push_back(dataPacket);
117 117 }
118 118 else {
119 119 // First request result for the variable, it must be stored
120 120 impl->m_AcqIdentifierToAcqDataPacketVectorMap.insert(
121 121 std::make_pair(acqIdentifier, QVector<AcquisitionDataPacket>() << dataPacket));
122 122 }
123 123
124 124
125 125 // Decrement the counter of the request
126 126 auto &acqRequest = aIdToARit->second;
127 127 acqRequest.m_Size = acqRequest.m_Size - 1;
128 128
129 129 // if the counter is 0, we can return data then run the next request if it exists and
130 130 // removed the finished request
131 131 if (acqRequest.m_Size == 0) {
132 132 // Return the data
133 133 aIdToADPVit = impl->m_AcqIdentifierToAcqDataPacketVectorMap.find(acqIdentifier);
134 134 if (aIdToADPVit != impl->m_AcqIdentifierToAcqDataPacketVectorMap.cend()) {
135 135 emit dataProvided(acqRequest.m_vIdentifier, acqRequest.m_RangeRequested,
136 136 acqRequest.m_CacheRangeRequested, aIdToADPVit->second);
137 137 }
138 138
139 139 // Execute the next one
140 140 auto it
141 141 = impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.find(acqRequest.m_vIdentifier);
142 142
143 143 if (it != impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.cend()) {
144 144 if (it->second.second.isNull()) {
145 145 // There is no next request, we can remove the varibale request
146 146 impl->removeVariableRequest(acqRequest.m_vIdentifier);
147 147 }
148 148 else {
149 149 auto acqIdentifierToRemove = it->second.first;
150 150 // Move the next request to the current request
151 151 it->second.first = it->second.second;
152 152 it->second.second = QUuid();
153 153 // Remove AcquisitionRequest and results;
154 154 impl->m_AcqIdentifierToAcqRequestMap.erase(acqIdentifierToRemove);
155 155 impl->m_AcqIdentifierToAcqDataPacketVectorMap.erase(acqIdentifierToRemove);
156 156 // Execute the current request
157 157 QMetaObject::invokeMethod(this, "onExecuteRequest", Qt::QueuedConnection,
158 158 Q_ARG(QUuid, it->second.first));
159 159 }
160 160 }
161 161 else {
162 162 qCCritical(LOG_VariableAcquisitionWorker())
163 163 << tr("Impossible to execute the acquisition on an unfound variable ");
164 164 }
165 165 }
166 166 }
167 167 else {
168 168 qCCritical(LOG_VariableAcquisitionWorker())
169 169 << tr("Impossible to retrieve AcquisitionRequest for the incoming data");
170 170 }
171 171 impl->unlock();
172 172 }
173 173
174 174 void VariableAcquisitionWorker::onExecuteRequest(QUuid acqIdentifier)
175 175 {
176 qCDebug(LOG_VariableAcquisitionWorker()) << tr("onExecuteRequest") << QThread::currentThread();
176 qCInfo(LOG_VariableAcquisitionWorker()) << tr("onExecuteRequest") << QThread::currentThread();
177 177 impl->lockRead();
178 178 auto it = impl->m_AcqIdentifierToAcqRequestMap.find(acqIdentifier);
179 179 if (it != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
180 180 auto request = it->second;
181 181 impl->unlock();
182 182 request.m_Provider->requestDataLoading(acqIdentifier, request.m_DataProviderParameters);
183 183 }
184 184 else {
185 185 impl->unlock();
186 186 // TODO log no acqIdentifier recognized
187 187 }
188 188 }
189 189
190 190 void VariableAcquisitionWorker::initialize()
191 191 {
192 192 qCDebug(LOG_VariableAcquisitionWorker()) << tr("VariableAcquisitionWorker init")
193 193 << QThread::currentThread();
194 194 impl->m_WorkingMutex.lock();
195 195 qCDebug(LOG_VariableAcquisitionWorker()) << tr("VariableAcquisitionWorker init END");
196 196 }
197 197
198 198 void VariableAcquisitionWorker::finalize()
199 199 {
200 200 impl->m_WorkingMutex.unlock();
201 201 }
202 202
203 203 void VariableAcquisitionWorker::waitForFinish()
204 204 {
205 205 QMutexLocker locker{&impl->m_WorkingMutex};
206 206 }
207 207
208 208 void VariableAcquisitionWorker::VariableAcquisitionWorkerPrivate::removeVariableRequest(
209 209 QUuid vIdentifier)
210 210 {
211 211 lockWrite();
212 212 auto it = m_VIdentifierToCurrrentAcqIdNextIdPairMap.find(vIdentifier);
213 213
214 214 if (it != m_VIdentifierToCurrrentAcqIdNextIdPairMap.cend()) {
215 215 // A current request already exists, we can replace the next one
216 216
217 217 m_AcqIdentifierToAcqRequestMap.erase(it->second.first);
218 218 m_AcqIdentifierToAcqDataPacketVectorMap.erase(it->second.first);
219 219
220 220 m_AcqIdentifierToAcqRequestMap.erase(it->second.second);
221 221 m_AcqIdentifierToAcqDataPacketVectorMap.erase(it->second.second);
222 222 }
223 223 m_VIdentifierToCurrrentAcqIdNextIdPairMap.erase(vIdentifier);
224 224 unlock();
225 225 }
@@ -1,543 +1,543
1 1 #include <Variable/Variable.h>
2 2 #include <Variable/VariableAcquisitionWorker.h>
3 3 #include <Variable/VariableCacheController.h>
4 4 #include <Variable/VariableCacheStrategy.h>
5 5 #include <Variable/VariableController.h>
6 6 #include <Variable/VariableModel.h>
7 7 #include <Variable/VariableSynchronizationGroup.h>
8 8
9 9 #include <Data/DataProviderParameters.h>
10 10 #include <Data/IDataProvider.h>
11 11 #include <Data/IDataSeries.h>
12 12 #include <Time/TimeController.h>
13 13
14 14 #include <QMutex>
15 15 #include <QThread>
16 16 #include <QUuid>
17 17 #include <QtCore/QItemSelectionModel>
18 18
19 19 #include <set>
20 20 #include <unordered_map>
21 21
22 22 Q_LOGGING_CATEGORY(LOG_VariableController, "VariableController")
23 23
24 24 namespace {
25 25
26 26 SqpRange computeSynchroRangeRequested(const SqpRange &varRange, const SqpRange &grapheRange,
27 27 const SqpRange &oldGraphRange)
28 28 {
29 29 auto zoomType = VariableController::getZoomType(grapheRange, oldGraphRange);
30 30
31 31 auto varRangeRequested = varRange;
32 32 switch (zoomType) {
33 33 case AcquisitionZoomType::ZoomIn: {
34 34 auto deltaLeft = grapheRange.m_TStart - oldGraphRange.m_TStart;
35 35 auto deltaRight = oldGraphRange.m_TEnd - grapheRange.m_TEnd;
36 36 varRangeRequested.m_TStart += deltaLeft;
37 37 varRangeRequested.m_TEnd -= deltaRight;
38 38 break;
39 39 }
40 40
41 41 case AcquisitionZoomType::ZoomOut: {
42 42 auto deltaLeft = oldGraphRange.m_TStart - grapheRange.m_TStart;
43 43 auto deltaRight = grapheRange.m_TEnd - oldGraphRange.m_TEnd;
44 44 varRangeRequested.m_TStart -= deltaLeft;
45 45 varRangeRequested.m_TEnd += deltaRight;
46 46 break;
47 47 }
48 48 case AcquisitionZoomType::PanRight: {
49 49 auto deltaRight = grapheRange.m_TEnd - oldGraphRange.m_TEnd;
50 50 varRangeRequested.m_TStart += deltaRight;
51 51 varRangeRequested.m_TEnd += deltaRight;
52 52 break;
53 53 }
54 54 case AcquisitionZoomType::PanLeft: {
55 55 auto deltaLeft = oldGraphRange.m_TStart - grapheRange.m_TStart;
56 56 varRangeRequested.m_TStart -= deltaLeft;
57 57 varRangeRequested.m_TEnd -= deltaLeft;
58 58 break;
59 59 }
60 60 case AcquisitionZoomType::Unknown: {
61 61 qCCritical(LOG_VariableController())
62 62 << VariableController::tr("Impossible to synchronize: zoom type unknown");
63 63 break;
64 64 }
65 65 default:
66 66 qCCritical(LOG_VariableController()) << VariableController::tr(
67 67 "Impossible to synchronize: zoom type not take into account");
68 68 // No action
69 69 break;
70 70 }
71 71
72 72 return varRangeRequested;
73 73 }
74 74 }
75 75
76 76 struct VariableController::VariableControllerPrivate {
77 77 explicit VariableControllerPrivate(VariableController *parent)
78 78 : m_WorkingMutex{},
79 79 m_VariableModel{new VariableModel{parent}},
80 80 m_VariableSelectionModel{new QItemSelectionModel{m_VariableModel, parent}},
81 81 m_VariableCacheController{std::make_unique<VariableCacheController>()},
82 82 m_VariableCacheStrategy{std::make_unique<VariableCacheStrategy>()},
83 83 m_VariableAcquisitionWorker{std::make_unique<VariableAcquisitionWorker>()}
84 84 {
85 85
86 86 m_VariableAcquisitionWorker->moveToThread(&m_VariableAcquisitionWorkerThread);
87 87 m_VariableAcquisitionWorkerThread.setObjectName("VariableAcquisitionWorkerThread");
88 88 }
89 89
90 90
91 91 virtual ~VariableControllerPrivate()
92 92 {
93 93 qCDebug(LOG_VariableController()) << tr("VariableControllerPrivate destruction");
94 94 m_VariableAcquisitionWorkerThread.quit();
95 95 m_VariableAcquisitionWorkerThread.wait();
96 96 }
97 97
98 98
99 99 void processRequest(std::shared_ptr<Variable> var, const SqpRange &rangeRequested);
100 100
101 101 QVector<SqpRange> provideNotInCacheDateTimeList(std::shared_ptr<Variable> variable,
102 102 const SqpRange &dateTime);
103 103
104 104 std::shared_ptr<Variable> findVariable(QUuid vIdentifier);
105 105 std::shared_ptr<IDataSeries>
106 106 retrieveDataSeries(const QVector<AcquisitionDataPacket> acqDataPacketVector);
107 107
108 108 void registerProvider(std::shared_ptr<IDataProvider> provider);
109 109
110 110 QMutex m_WorkingMutex;
111 111 /// Variable model. The VariableController has the ownership
112 112 VariableModel *m_VariableModel;
113 113 QItemSelectionModel *m_VariableSelectionModel;
114 114
115 115
116 116 TimeController *m_TimeController{nullptr};
117 117 std::unique_ptr<VariableCacheController> m_VariableCacheController;
118 118 std::unique_ptr<VariableCacheStrategy> m_VariableCacheStrategy;
119 119 std::unique_ptr<VariableAcquisitionWorker> m_VariableAcquisitionWorker;
120 120 QThread m_VariableAcquisitionWorkerThread;
121 121
122 122 std::unordered_map<std::shared_ptr<Variable>, std::shared_ptr<IDataProvider> >
123 123 m_VariableToProviderMap;
124 124 std::unordered_map<std::shared_ptr<Variable>, QUuid> m_VariableToIdentifierMap;
125 125 std::map<QUuid, std::shared_ptr<VariableSynchronizationGroup> >
126 126 m_GroupIdToVariableSynchronizationGroupMap;
127 127 std::map<QUuid, QUuid> m_VariableIdGroupIdMap;
128 128 std::set<std::shared_ptr<IDataProvider> > m_ProviderSet;
129 129 };
130 130
131 131
132 132 VariableController::VariableController(QObject *parent)
133 133 : QObject{parent}, impl{spimpl::make_unique_impl<VariableControllerPrivate>(this)}
134 134 {
135 135 qCDebug(LOG_VariableController()) << tr("VariableController construction")
136 136 << QThread::currentThread();
137 137
138 138 connect(impl->m_VariableModel, &VariableModel::abortProgessRequested, this,
139 139 &VariableController::onAbortProgressRequested);
140 140
141 141 connect(impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::dataProvided, this,
142 142 &VariableController::onDataProvided);
143 143 connect(impl->m_VariableAcquisitionWorker.get(),
144 144 &VariableAcquisitionWorker::variableRequestInProgress, this,
145 145 &VariableController::onVariableRetrieveDataInProgress);
146 146
147 147 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::started,
148 148 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::initialize);
149 149 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::finished,
150 150 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::finalize);
151 151
152 152
153 153 impl->m_VariableAcquisitionWorkerThread.start();
154 154 }
155 155
156 156 VariableController::~VariableController()
157 157 {
158 158 qCDebug(LOG_VariableController()) << tr("VariableController destruction")
159 159 << QThread::currentThread();
160 160 this->waitForFinish();
161 161 }
162 162
163 163 VariableModel *VariableController::variableModel() noexcept
164 164 {
165 165 return impl->m_VariableModel;
166 166 }
167 167
168 168 QItemSelectionModel *VariableController::variableSelectionModel() noexcept
169 169 {
170 170 return impl->m_VariableSelectionModel;
171 171 }
172 172
173 173 void VariableController::setTimeController(TimeController *timeController) noexcept
174 174 {
175 175 impl->m_TimeController = timeController;
176 176 }
177 177
178 178 void VariableController::deleteVariable(std::shared_ptr<Variable> variable) noexcept
179 179 {
180 180 if (!variable) {
181 181 qCCritical(LOG_VariableController()) << "Can't delete variable: variable is null";
182 182 return;
183 183 }
184 184
185 185 // Spreads in SciQlop that the variable will be deleted, so that potential receivers can
186 186 // make some treatments before the deletion
187 187 emit variableAboutToBeDeleted(variable);
188 188
189 189 // Deletes identifier
190 190 impl->m_VariableToIdentifierMap.erase(variable);
191 191
192 192 // Deletes provider
193 193 auto nbProvidersDeleted = impl->m_VariableToProviderMap.erase(variable);
194 194 qCDebug(LOG_VariableController())
195 195 << tr("Number of providers deleted for variable %1: %2")
196 196 .arg(variable->name(), QString::number(nbProvidersDeleted));
197 197
198 198 // Clears cache
199 199 impl->m_VariableCacheController->clear(variable);
200 200
201 201 // Deletes from model
202 202 impl->m_VariableModel->deleteVariable(variable);
203 203 }
204 204
205 205 void VariableController::deleteVariables(
206 206 const QVector<std::shared_ptr<Variable> > &variables) noexcept
207 207 {
208 208 for (auto variable : qAsConst(variables)) {
209 209 deleteVariable(variable);
210 210 }
211 211 }
212 212
213 213 void VariableController::abortProgress(std::shared_ptr<Variable> variable)
214 214 {
215 215 }
216 216
217 217 void VariableController::createVariable(const QString &name, const QVariantHash &metadata,
218 218 std::shared_ptr<IDataProvider> provider) noexcept
219 219 {
220 220
221 221 if (!impl->m_TimeController) {
222 222 qCCritical(LOG_VariableController())
223 223 << tr("Impossible to create variable: The time controller is null");
224 224 return;
225 225 }
226 226
227 227 auto range = impl->m_TimeController->dateTime();
228 228
229 229 if (auto newVariable = impl->m_VariableModel->createVariable(name, range, metadata)) {
230 230 auto identifier = QUuid::createUuid();
231 231
232 232 // store the provider
233 233 impl->registerProvider(provider);
234 234
235 235 // Associate the provider
236 236 impl->m_VariableToProviderMap[newVariable] = provider;
237 237 impl->m_VariableToIdentifierMap[newVariable] = identifier;
238 238
239 239
240 240 impl->processRequest(newVariable, range);
241 241 }
242 242 }
243 243
244 244 void VariableController::onDateTimeOnSelection(const SqpRange &dateTime)
245 245 {
246 246 // TODO check synchronisation
247 247 qCDebug(LOG_VariableController()) << "VariableController::onDateTimeOnSelection"
248 248 << QThread::currentThread()->objectName();
249 249 auto selectedRows = impl->m_VariableSelectionModel->selectedRows();
250 250
251 251 for (const auto &selectedRow : qAsConst(selectedRows)) {
252 252 if (auto selectedVariable = impl->m_VariableModel->variable(selectedRow.row())) {
253 253 selectedVariable->setRange(dateTime);
254 254 impl->processRequest(selectedVariable, dateTime);
255 255
256 256 // notify that rescale operation has to be done
257 257 emit rangeChanged(selectedVariable, dateTime);
258 258 }
259 259 }
260 260 }
261 261
262 262 void VariableController::onDataProvided(QUuid vIdentifier, const SqpRange &rangeRequested,
263 263 const SqpRange &cacheRangeRequested,
264 264 QVector<AcquisitionDataPacket> dataAcquired)
265 265 {
266 266 auto var = impl->findVariable(vIdentifier);
267 267 if (var != nullptr) {
268 268 var->setRange(rangeRequested);
269 269 var->setCacheRange(cacheRangeRequested);
270 270 qCDebug(LOG_VariableController()) << tr("1: onDataProvided") << rangeRequested;
271 271 qCDebug(LOG_VariableController()) << tr("2: onDataProvided") << cacheRangeRequested;
272 272
273 273 auto retrievedDataSeries = impl->retrieveDataSeries(dataAcquired);
274 274 qCDebug(LOG_VariableController()) << tr("3: onDataProvided")
275 275 << retrievedDataSeries->range();
276 276 var->mergeDataSeries(retrievedDataSeries);
277 qCDebug(LOG_VariableController()) << tr("4: onDataProvided");
277 278 emit var->updated();
278 279 }
279 280 else {
280 281 qCCritical(LOG_VariableController()) << tr("Impossible to provide data to a null variable");
281 282 }
282 283 }
283 284
284 285 void VariableController::onVariableRetrieveDataInProgress(QUuid identifier, double progress)
285 286 {
286 287 auto var = impl->findVariable(identifier);
287 288 if (var != nullptr) {
288 289 impl->m_VariableModel->setDataProgress(var, progress);
289 290 }
290 291 else {
291 292 qCCritical(LOG_VariableController())
292 293 << tr("Impossible to notify progression of a null variable");
293 294 }
294 295 }
295 296
296 297 void VariableController::onAbortProgressRequested(std::shared_ptr<Variable> variable)
297 298 {
298 299 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAbortProgressRequested"
299 300 << QThread::currentThread()->objectName();
300 301
301 302 auto it = impl->m_VariableToIdentifierMap.find(variable);
302 303 if (it != impl->m_VariableToIdentifierMap.cend()) {
303 304 impl->m_VariableToProviderMap.at(variable)->requestDataAborting(it->second);
304 305 }
305 306 else {
306 307 qCWarning(LOG_VariableController())
307 308 << tr("Aborting progression of inexistant variable detected !!!")
308 309 << QThread::currentThread()->objectName();
309 310 }
310 311 }
311 312
312 313 void VariableController::onAddSynchronizationGroupId(QUuid synchronizationGroupId)
313 314 {
314 315 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronizationGroupId"
315 316 << QThread::currentThread()->objectName()
316 317 << synchronizationGroupId;
317 318 auto vSynchroGroup = std::make_shared<VariableSynchronizationGroup>();
318 319 impl->m_GroupIdToVariableSynchronizationGroupMap.insert(
319 320 std::make_pair(synchronizationGroupId, vSynchroGroup));
320 321 }
321 322
322 323 void VariableController::onRemoveSynchronizationGroupId(QUuid synchronizationGroupId)
323 324 {
324 325 impl->m_GroupIdToVariableSynchronizationGroupMap.erase(synchronizationGroupId);
325 326 }
326 327
327 328 void VariableController::onAddSynchronized(std::shared_ptr<Variable> variable,
328 329 QUuid synchronizationGroupId)
329 330
330 331 {
331 332 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronized"
332 333 << synchronizationGroupId;
333 334 auto vToVIdit = impl->m_VariableToIdentifierMap.find(variable);
334 335 if (vToVIdit != impl->m_VariableToIdentifierMap.cend()) {
335 336 auto itSynchroGroup
336 337 = impl->m_GroupIdToVariableSynchronizationGroupMap.find(synchronizationGroupId);
337 338 if (itSynchroGroup != impl->m_GroupIdToVariableSynchronizationGroupMap.cend()) {
338 339 impl->m_VariableIdGroupIdMap.insert(
339 340 std::make_pair(vToVIdit->second, synchronizationGroupId));
340 341 itSynchroGroup->second->addVariableId(vToVIdit->second);
341 342 }
342 343 else {
343 344 qCCritical(LOG_VariableController())
344 345 << tr("Impossible to synchronize a variable with an unknown sycnhronization group")
345 346 << variable->name();
346 347 }
347 348 }
348 349 else {
349 350 qCCritical(LOG_VariableController())
350 351 << tr("Impossible to synchronize a variable with no identifier") << variable->name();
351 352 }
352 353 }
353 354
354 355
355 356 void VariableController::onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables,
356 357 const SqpRange &range, const SqpRange &oldRange,
357 358 bool synchronise)
358 359 {
359 360 // NOTE: oldRange isn't really necessary since oldRange == variable->range().
360 361
361 qCDebug(LOG_VariableController()) << "VariableController::onRequestDataLoading"
362 qCInfo(LOG_VariableController()) << "VariableController::onRequestDataLoading"
362 363 << QThread::currentThread()->objectName();
363 364 // we want to load data of the variable for the dateTime.
364 365 // First we check if the cache contains some of them.
365 366 // For the other, we ask the provider to give them.
366 367
367 368 foreach (auto var, variables) {
368 369 qCDebug(LOG_VariableController()) << "processRequest for" << var->name();
369 370 impl->processRequest(var, range);
370 371 }
371 372
372 373 if (synchronise) {
373 374 // Get the group ids
374 375 qCDebug(LOG_VariableController())
375 376 << "VariableController::onRequestDataLoading for synchro var ENABLE";
376 377 auto groupIds = std::set<QUuid>();
377 378 foreach (auto var, variables) {
378 379 auto varToVarIdIt = impl->m_VariableToIdentifierMap.find(var);
379 380 if (varToVarIdIt != impl->m_VariableToIdentifierMap.cend()) {
380 381 auto vId = varToVarIdIt->second;
381 382 auto varIdToGroupIdIt = impl->m_VariableIdGroupIdMap.find(vId);
382 383 if (varIdToGroupIdIt != impl->m_VariableIdGroupIdMap.cend()) {
383 384 auto gId = varIdToGroupIdIt->second;
384 385 if (groupIds.find(gId) == groupIds.cend()) {
385 386 qCDebug(LOG_VariableController()) << "Synchro detect group " << gId;
386 387 groupIds.insert(gId);
387 388 }
388 389 }
389 390 }
390 391 }
391 392
392 393 // We assume here all group ids exist
393 394 foreach (auto gId, groupIds) {
394 395 auto vSynchronizationGroup = impl->m_GroupIdToVariableSynchronizationGroupMap.at(gId);
395 396 auto vSyncIds = vSynchronizationGroup->getIds();
396 397 qCDebug(LOG_VariableController()) << "Var in synchro group ";
397 398 for (auto vId : vSyncIds) {
398 399 auto var = impl->findVariable(vId);
399 400
400 401 // Don't process already processed var
401 402 if (!variables.contains(var)) {
402 403 if (var != nullptr) {
403 404 qCDebug(LOG_VariableController()) << "processRequest synchro for"
404 405 << var->name();
405 406 auto vSyncRangeRequested
406 407 = computeSynchroRangeRequested(var->range(), range, oldRange);
407 408 impl->processRequest(var, vSyncRangeRequested);
408 409 }
409 410 else {
410 411 qCCritical(LOG_VariableController())
411 412
412 413 << tr("Impossible to synchronize a null variable");
413 414 }
414 415 }
415 416 }
416 417 }
417 418 }
418 419 }
419 420
420 421
421 422 void VariableController::initialize()
422 423 {
423 424 qCDebug(LOG_VariableController()) << tr("VariableController init") << QThread::currentThread();
424 425 impl->m_WorkingMutex.lock();
425 426 qCDebug(LOG_VariableController()) << tr("VariableController init END");
426 427 }
427 428
428 429 void VariableController::finalize()
429 430 {
430 431 impl->m_WorkingMutex.unlock();
431 432 }
432 433
433 434 void VariableController::waitForFinish()
434 435 {
435 436 QMutexLocker locker{&impl->m_WorkingMutex};
436 437 }
437 438
438 439 AcquisitionZoomType VariableController::getZoomType(const SqpRange &range, const SqpRange &oldRange)
439 440 {
440 441 // t1.m_TStart <= t2.m_TStart && t2.m_TEnd <= t1.m_TEnd
441 442 auto zoomType = AcquisitionZoomType::Unknown;
442 443 if (range.m_TStart <= oldRange.m_TStart && oldRange.m_TEnd <= range.m_TEnd) {
443 444 zoomType = AcquisitionZoomType::ZoomOut;
444 445 }
445 446 else if (range.m_TStart > oldRange.m_TStart && range.m_TEnd > oldRange.m_TEnd) {
446 447 zoomType = AcquisitionZoomType::PanRight;
447 448 }
448 449 else if (range.m_TStart < oldRange.m_TStart && range.m_TEnd < oldRange.m_TEnd) {
449 450 zoomType = AcquisitionZoomType::PanLeft;
450 451 }
451 452 else if (range.m_TStart > oldRange.m_TStart && oldRange.m_TEnd > range.m_TEnd) {
452 453 zoomType = AcquisitionZoomType::ZoomIn;
453 454 }
454 455 else {
455 456 qCCritical(LOG_VariableController()) << "getZoomType: Unknown type detected";
456 457 }
457 458 return zoomType;
458 459 }
459 460
460 461 void VariableController::VariableControllerPrivate::processRequest(std::shared_ptr<Variable> var,
461 462 const SqpRange &rangeRequested)
462 463 {
463 464
464 465 auto varRangesRequested
465 466 = m_VariableCacheStrategy->computeCacheRange(var->range(), rangeRequested);
466 467 auto notInCacheRangeList = var->provideNotInCacheRangeList(varRangesRequested.second);
467 468
468 469 if (!notInCacheRangeList.empty()) {
469 // Display part of data which are already there
470 // Ask the provider for each data on the dateTimeListNotInCache
471 470 auto identifier = m_VariableToIdentifierMap.at(var);
472 471 auto varProvider = m_VariableToProviderMap.at(var);
473 472 if (varProvider != nullptr) {
474 473 m_VariableAcquisitionWorker->pushVariableRequest(
475 474 identifier, varRangesRequested.first, varRangesRequested.second,
476 475 DataProviderParameters{std::move(notInCacheRangeList), var->metadata()},
477 476 varProvider);
478 477 }
479 478 else {
480 479 qCCritical(LOG_VariableController())
481 480 << "Impossible to provide data with a null provider";
482 481 }
483 482 }
484 483 else {
485 484 var->setRange(rangeRequested);
486 485 var->setCacheRange(varRangesRequested.second);
487 486 var->setDataSeries(var->dataSeries()->subData(varRangesRequested.second));
488 487 emit var->updated();
489 488 }
490 489 }
491 490
492 491 std::shared_ptr<Variable>
493 492 VariableController::VariableControllerPrivate::findVariable(QUuid vIdentifier)
494 493 {
495 494 std::shared_ptr<Variable> var;
496 495 auto findReply = [vIdentifier](const auto &entry) { return vIdentifier == entry.second; };
497 496
498 497 auto end = m_VariableToIdentifierMap.cend();
499 498 auto it = std::find_if(m_VariableToIdentifierMap.cbegin(), end, findReply);
500 499 if (it != end) {
501 500 var = it->first;
502 501 }
503 502 else {
504 503 qCCritical(LOG_VariableController())
505 504 << tr("Impossible to find the variable with the identifier: ") << vIdentifier;
506 505 }
507 506
508 507 return var;
509 508 }
510 509
511 510 std::shared_ptr<IDataSeries> VariableController::VariableControllerPrivate::retrieveDataSeries(
512 511 const QVector<AcquisitionDataPacket> acqDataPacketVector)
513 512 {
514 qCInfo(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size")
513 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size")
515 514 << acqDataPacketVector.size();
516 515 std::shared_ptr<IDataSeries> dataSeries;
517 516 if (!acqDataPacketVector.isEmpty()) {
518 517 dataSeries = acqDataPacketVector[0].m_DateSeries;
519 518 for (int i = 1; i < acqDataPacketVector.size(); ++i) {
520 519 dataSeries->merge(acqDataPacketVector[i].m_DateSeries.get());
521 520 }
522 521 }
523
522 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size END")
523 << acqDataPacketVector.size();
524 524 return dataSeries;
525 525 }
526 526
527 527 void VariableController::VariableControllerPrivate::registerProvider(
528 528 std::shared_ptr<IDataProvider> provider)
529 529 {
530 530 if (m_ProviderSet.find(provider) == m_ProviderSet.end()) {
531 qCInfo(LOG_VariableController()) << tr("Registering of a new provider")
531 qCDebug(LOG_VariableController()) << tr("Registering of a new provider")
532 532 << provider->objectName();
533 533 m_ProviderSet.insert(provider);
534 534 connect(provider.get(), &IDataProvider::dataProvided, m_VariableAcquisitionWorker.get(),
535 535 &VariableAcquisitionWorker::onVariableDataAcquired);
536 536 connect(provider.get(), &IDataProvider::dataProvidedProgress,
537 537 m_VariableAcquisitionWorker.get(),
538 538 &VariableAcquisitionWorker::onVariableRetrieveDataInProgress);
539 539 }
540 540 else {
541 541 qCDebug(LOG_VariableController()) << tr("Cannot register provider, it already exists ");
542 542 }
543 543 }
@@ -1,38 +1,38
1 1 #ifndef SCIQLOP_VISUALIZATIONGRAPHHELPER_H
2 2 #define SCIQLOP_VISUALIZATIONGRAPHHELPER_H
3 3
4 4 #include <Data/SqpRange.h>
5 5
6 6 #include <QLoggingCategory>
7 7 #include <QVector>
8 8
9 9 #include <memory>
10 10
11 11 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationGraphHelper)
12 12
13 13 class IDataSeries;
14 14 class QCPAbstractPlottable;
15 15 class QCustomPlot;
16 16 class Variable;
17 17
18 18 /**
19 19 * @brief The VisualizationGraphHelper class aims to create the QCustomPlot components relative to a
20 20 * variable, depending on the data series of this variable
21 21 */
22 22 struct VisualizationGraphHelper {
23 23 /**
24 24 * Creates (if possible) the QCustomPlot components relative to the variable passed in
25 25 * parameter, and adds these to the plot passed in parameter.
26 26 * @param variable the variable for which to create the components
27 27 * @param plot the plot in which to add the created components. It takes ownership of these
28 28 * components.
29 29 * @return the list of the components created
30 30 */
31 31 static QVector<QCPAbstractPlottable *> create(std::shared_ptr<Variable> variable,
32 32 QCustomPlot &plot) noexcept;
33 33
34 static void updateData(QVector<QCPAbstractPlottable *> plotableVect, IDataSeries *dataSeries,
35 const SqpRange &dateTime);
34 static void updateData(QVector<QCPAbstractPlottable *> plotableVect,
35 std::shared_ptr<IDataSeries> dataSeries, const SqpRange &dateTime);
36 36 };
37 37
38 38 #endif // SCIQLOP_VISUALIZATIONGRAPHHELPER_H
@@ -1,162 +1,163
1 1 #include "Visualization/VisualizationGraphHelper.h"
2 2 #include "Visualization/qcustomplot.h"
3 3
4 4 #include <Data/ScalarSeries.h>
5 5
6 6 #include <Variable/Variable.h>
7 7
8 8 Q_LOGGING_CATEGORY(LOG_VisualizationGraphHelper, "VisualizationGraphHelper")
9 9
10 10 namespace {
11 11
12 12 class SqpDataContainer : public QCPGraphDataContainer {
13 13 public:
14 14 void appendGraphData(const QCPGraphData &data) { mData.append(data); }
15 15 };
16 16
17 17
18 18 /// Format for datetimes on a axis
19 19 const auto DATETIME_TICKER_FORMAT = QStringLiteral("yyyy/MM/dd \nhh:mm:ss");
20 20
21 21 /// Generates the appropriate ticker for an axis, depending on whether the axis displays time or
22 22 /// non-time data
23 23 QSharedPointer<QCPAxisTicker> axisTicker(bool isTimeAxis)
24 24 {
25 25 if (isTimeAxis) {
26 26 auto dateTicker = QSharedPointer<QCPAxisTickerDateTime>::create();
27 27 dateTicker->setDateTimeFormat(DATETIME_TICKER_FORMAT);
28 28 dateTicker->setDateTimeSpec(Qt::UTC);
29 29
30 30 return dateTicker;
31 31 }
32 32 else {
33 33 // default ticker
34 34 return QSharedPointer<QCPAxisTicker>::create();
35 35 }
36 36 }
37 37
38 void updateScalarData(QCPAbstractPlottable *component, ScalarSeries &scalarSeries,
38 void updateScalarData(QCPAbstractPlottable *component, std::shared_ptr<ScalarSeries> scalarSeries,
39 39 const SqpRange &dateTime)
40 40 {
41 41 qCDebug(LOG_VisualizationGraphHelper()) << "TORM: updateScalarData"
42 42 << QThread::currentThread()->objectName();
43 43 if (auto qcpGraph = dynamic_cast<QCPGraph *>(component)) {
44 scalarSeries.lockRead();
44 scalarSeries->lockRead();
45 45 {
46 const auto &xData = scalarSeries.xAxisData()->cdata();
47 const auto &valuesData = scalarSeries.valuesData()->cdata();
46 const auto &xData = scalarSeries->xAxisData()->cdata();
47 const auto &valuesData = scalarSeries->valuesData()->cdata();
48 48
49 49 auto xDataBegin = xData.cbegin();
50 50 auto xDataEnd = xData.cend();
51 51
52 qCInfo(LOG_VisualizationGraphHelper()) << "TORM: Current points in cache"
52 qCInfo(LOG_VisualizationGraphHelper()) << "TODEBUG: Current points in cache"
53 53 << xData.count();
54 54
55 55 auto sqpDataContainer = QSharedPointer<SqpDataContainer>::create();
56 56 qcpGraph->setData(sqpDataContainer);
57 57
58 58 auto lowerIt = std::lower_bound(xDataBegin, xDataEnd, dateTime.m_TStart);
59 59 auto upperIt = std::upper_bound(xDataBegin, xDataEnd, dateTime.m_TEnd);
60 60 auto distance = std::distance(xDataBegin, lowerIt);
61 61
62 62 auto valuesDataIt = valuesData.cbegin() + distance;
63 63 for (auto xAxisDataIt = lowerIt; xAxisDataIt != upperIt;
64 64 ++xAxisDataIt, ++valuesDataIt) {
65 65 sqpDataContainer->appendGraphData(QCPGraphData(*xAxisDataIt, *valuesDataIt));
66 66 }
67 67
68 qCInfo(LOG_VisualizationGraphHelper()) << "TORM: Current points displayed"
68 qCInfo(LOG_VisualizationGraphHelper()) << "TODEBUG: Current points displayed"
69 69 << sqpDataContainer->size();
70 70 }
71 scalarSeries.unlock();
71 scalarSeries->unlock();
72 72
73 73
74 74 // Display all data
75 75 component->parentPlot()->replot();
76 76 }
77 77 else {
78 78 /// @todo DEBUG
79 79 }
80 80 }
81 81
82 QCPAbstractPlottable *createScalarSeriesComponent(ScalarSeries &scalarSeries, QCustomPlot &plot,
83 const SqpRange &dateTime)
82 QCPAbstractPlottable *createScalarSeriesComponent(std::shared_ptr<ScalarSeries> scalarSeries,
83 QCustomPlot &plot, const SqpRange &dateTime)
84 84 {
85 85 auto component = plot.addGraph();
86 86
87 87 if (component) {
88 88 // // Graph data
89 component->setData(scalarSeries.xAxisData()->data(), scalarSeries.valuesData()->data(),
89 component->setData(scalarSeries->xAxisData()->data(), scalarSeries->valuesData()->data(),
90 90 true);
91 91
92 92 updateScalarData(component, scalarSeries, dateTime);
93 93
94 94 // Axes properties
95 95 /// @todo : for the moment, no control is performed on the axes: the units and the tickers
96 96 /// are fixed for the default x-axis and y-axis of the plot, and according to the new graph
97 97
98 98 auto setAxisProperties = [](auto axis, const auto &unit) {
99 99 // label (unit name)
100 100 axis->setLabel(unit.m_Name);
101 101
102 102 // ticker (depending on the type of unit)
103 103 axis->setTicker(axisTicker(unit.m_TimeUnit));
104 104 };
105 setAxisProperties(plot.xAxis, scalarSeries.xAxisUnit());
106 setAxisProperties(plot.yAxis, scalarSeries.valuesUnit());
105 setAxisProperties(plot.xAxis, scalarSeries->xAxisUnit());
106 setAxisProperties(plot.yAxis, scalarSeries->valuesUnit());
107 107
108 108 // Display all data
109 109 component->rescaleAxes();
110 110 plot.replot();
111 111 }
112 112 else {
113 113 qCDebug(LOG_VisualizationGraphHelper())
114 114 << QObject::tr("Can't create graph for the scalar series");
115 115 }
116 116
117 117 return component;
118 118 }
119 119
120 120 } // namespace
121 121
122 122 QVector<QCPAbstractPlottable *> VisualizationGraphHelper::create(std::shared_ptr<Variable> variable,
123 123 QCustomPlot &plot) noexcept
124 124 {
125 125 auto result = QVector<QCPAbstractPlottable *>{};
126 126
127 127 if (variable) {
128 128 // Gets the data series of the variable to call the creation of the right components
129 129 // according to its type
130 if (auto scalarSeries = dynamic_cast<ScalarSeries *>(variable->dataSeries())) {
131 result.append(createScalarSeriesComponent(*scalarSeries, plot, variable->range()));
130 if (auto scalarSeries = std::dynamic_pointer_cast<ScalarSeries>(variable->dataSeries())) {
131 result.append(createScalarSeriesComponent(scalarSeries, plot, variable->range()));
132 132 }
133 133 else {
134 134 qCDebug(LOG_VisualizationGraphHelper())
135 135 << QObject::tr("Can't create graph plottables : unmanaged data series type");
136 136 }
137 137 }
138 138 else {
139 139 qCDebug(LOG_VisualizationGraphHelper())
140 140 << QObject::tr("Can't create graph plottables : the variable is null");
141 141 }
142 142
143 143 return result;
144 144 }
145 145
146 146 void VisualizationGraphHelper::updateData(QVector<QCPAbstractPlottable *> plotableVect,
147 IDataSeries *dataSeries, const SqpRange &dateTime)
147 std::shared_ptr<IDataSeries> dataSeries,
148 const SqpRange &dateTime)
148 149 {
149 if (auto scalarSeries = dynamic_cast<ScalarSeries *>(dataSeries)) {
150 if (auto scalarSeries = std::dynamic_pointer_cast<ScalarSeries>(dataSeries)) {
150 151 if (plotableVect.size() == 1) {
151 updateScalarData(plotableVect.at(0), *scalarSeries, dateTime);
152 updateScalarData(plotableVect.at(0), scalarSeries, dateTime);
152 153 }
153 154 else {
154 155 qCCritical(LOG_VisualizationGraphHelper()) << QObject::tr(
155 156 "Can't update Data of a scalarSeries because there is not only one component "
156 157 "associated");
157 158 }
158 159 }
159 160 else {
160 161 /// @todo DEBUG
161 162 }
162 163 }
@@ -1,307 +1,307
1 1 #include "Visualization/VisualizationGraphWidget.h"
2 2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 3 #include "Visualization/VisualizationGraphHelper.h"
4 4 #include "Visualization/VisualizationGraphRenderingDelegate.h"
5 5 #include "ui_VisualizationGraphWidget.h"
6 6
7 7 #include <Data/ArrayData.h>
8 8 #include <Data/IDataSeries.h>
9 9 #include <Settings/SqpSettingsDefs.h>
10 10 #include <SqpApplication.h>
11 11 #include <Variable/Variable.h>
12 12 #include <Variable/VariableController.h>
13 13
14 14 #include <unordered_map>
15 15
16 16 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
17 17
18 18 namespace {
19 19
20 20 /// Key pressed to enable zoom on horizontal axis
21 21 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::NoModifier;
22 22
23 23 /// Key pressed to enable zoom on vertical axis
24 24 const auto VERTICAL_ZOOM_MODIFIER = Qt::ControlModifier;
25 25
26 26 } // namespace
27 27
28 28 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
29 29
30 30 explicit VisualizationGraphWidgetPrivate()
31 31 : m_DoAcquisition{true}, m_IsCalibration{false}, m_RenderingDelegate{nullptr}
32 32 {
33 33 }
34 34
35 35 // 1 variable -> n qcpplot
36 36 std::multimap<std::shared_ptr<Variable>, QCPAbstractPlottable *> m_VariableToPlotMultiMap;
37 37 bool m_DoAcquisition;
38 38 bool m_IsCalibration;
39 39 QCPItemTracer *m_TextTracer;
40 40 /// Delegate used to attach rendering features to the plot
41 41 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
42 42 };
43 43
44 44 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
45 45 : QWidget{parent},
46 46 ui{new Ui::VisualizationGraphWidget},
47 47 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>()}
48 48 {
49 49 ui->setupUi(this);
50 50
51 51 // The delegate must be initialized after the ui as it uses the plot
52 52 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*ui->widget);
53 53
54 54 ui->graphNameLabel->setText(name);
55 55
56 56 // 'Close' options : widget is deleted when closed
57 57 setAttribute(Qt::WA_DeleteOnClose);
58 58 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationGraphWidget::close);
59 59 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
60 60
61 61 // Set qcpplot properties :
62 62 // - Drag (on x-axis) and zoom are enabled
63 63 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
64 64 ui->widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);
65 65 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal);
66 66
67 67 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
68 68 connect(ui->widget, &QCustomPlot::mouseRelease, this,
69 69 &VisualizationGraphWidget::onMouseRelease);
70 70 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
71 71 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
72 72 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
73 73 &QCPAxis::rangeChanged),
74 74 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
75 75
76 76 // Activates menu when right clicking on the graph
77 77 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
78 78 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
79 79 &VisualizationGraphWidget::onGraphMenuRequested);
80 80
81 81 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
82 82 &VariableController::onRequestDataLoading);
83 83 }
84 84
85 85
86 86 VisualizationGraphWidget::~VisualizationGraphWidget()
87 87 {
88 88 delete ui;
89 89 }
90 90
91 91 void VisualizationGraphWidget::enableAcquisition(bool enable)
92 92 {
93 93 impl->m_DoAcquisition = enable;
94 94 }
95 95
96 96 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable)
97 97 {
98 98 auto calibrationState = impl->m_IsCalibration;
99 99 impl->m_IsCalibration = true;
100 100 // Uses delegate to create the qcpplot components according to the variable
101 101 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
102 102 impl->m_IsCalibration = calibrationState;
103 103
104 104 for (auto createdPlottable : qAsConst(createdPlottables)) {
105 105 impl->m_VariableToPlotMultiMap.insert({variable, createdPlottable});
106 106 }
107 107
108 108 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
109 109
110 110 emit variableAdded(variable);
111 111 }
112 112 void VisualizationGraphWidget::addVariableUsingGraph(std::shared_ptr<Variable> variable)
113 113 {
114 114 // Uses delegate to create the qcpplot components according to the variable
115 115 this->addVariable(variable);
116 116
117 117 // Request range for the variable
118 118 auto graphRange = ui->widget->xAxis->range();
119 119
120 120 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable,
121 121 SqpRange{graphRange.lower, graphRange.upper}, variable->range(), false);
122 122 }
123 123
124 124 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
125 125 {
126 126 // Each component associated to the variable :
127 127 // - is removed from qcpplot (which deletes it)
128 128 // - is no longer referenced in the map
129 129 auto componentsIt = impl->m_VariableToPlotMultiMap.equal_range(variable);
130 130 for (auto it = componentsIt.first; it != componentsIt.second;) {
131 131 ui->widget->removePlottable(it->second);
132 132 it = impl->m_VariableToPlotMultiMap.erase(it);
133 133 }
134 134
135 135 // Updates graph
136 136 ui->widget->replot();
137 137 }
138 138
139 139 void VisualizationGraphWidget::setRange(std::shared_ptr<Variable> variable, const SqpRange &range)
140 140 {
141 141 // Note: in case of different axes that depends on variable, we could start with a code like
142 142 // that:
143 143 // auto componentsIt = impl->m_VariableToPlotMultiMap.equal_range(variable);
144 144 // for (auto it = componentsIt.first; it != componentsIt.second;) {
145 145 // }
146 146 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
147 147 ui->widget->replot();
148 148 }
149 149
150 150 SqpRange VisualizationGraphWidget::graphRange() const noexcept
151 151 {
152 152 auto grapheRange = ui->widget->xAxis->range();
153 153 return SqpRange{grapheRange.lower, grapheRange.upper};
154 154 }
155 155
156 156 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
157 157 {
158 158 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
159 159 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
160 160 ui->widget->replot();
161 161 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
162 162 }
163 163
164 164 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
165 165 {
166 166 if (visitor) {
167 167 visitor->visit(this);
168 168 }
169 169 else {
170 170 qCCritical(LOG_VisualizationGraphWidget())
171 171 << tr("Can't visit widget : the visitor is null");
172 172 }
173 173 }
174 174
175 175 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
176 176 {
177 177 /// @todo : for the moment, a graph can always accomodate a variable
178 178 Q_UNUSED(variable);
179 179 return true;
180 180 }
181 181
182 182 bool VisualizationGraphWidget::contains(const Variable &variable) const
183 183 {
184 184 // Finds the variable among the keys of the map
185 185 auto variablePtr = &variable;
186 186 auto findVariable
187 187 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
188 188
189 189 auto end = impl->m_VariableToPlotMultiMap.cend();
190 190 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
191 191 return it != end;
192 192 }
193 193
194 194 QString VisualizationGraphWidget::name() const
195 195 {
196 196 return ui->graphNameLabel->text();
197 197 }
198 198
199 199 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
200 200 {
201 201 QMenu graphMenu{};
202 202
203 203 // Iterates on variables (unique keys)
204 204 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
205 205 end = impl->m_VariableToPlotMultiMap.cend();
206 206 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
207 207 // 'Remove variable' action
208 208 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
209 209 [ this, var = it->first ]() { removeVariable(var); });
210 210 }
211 211
212 212 if (!graphMenu.isEmpty()) {
213 213 graphMenu.exec(mapToGlobal(pos));
214 214 }
215 215 }
216 216
217 217 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
218 218 {
219 219 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
220 220 << QThread::currentThread()->objectName() << "DoAcqui"
221 221 << impl->m_DoAcquisition;
222 222
223 223 auto graphRange = SqpRange{t1.lower, t1.upper};
224 224 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
225 225
226 226 if (impl->m_DoAcquisition) {
227 227 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
228 228
229 229 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
230 230 end = impl->m_VariableToPlotMultiMap.end();
231 231 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
232 232 variableUnderGraphVector.push_back(it->first);
233 233 }
234 234 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange, oldGraphRange,
235 235 !impl->m_IsCalibration);
236 236
237 237 if (!impl->m_IsCalibration) {
238 qCInfo(LOG_VisualizationGraphWidget())
238 qCDebug(LOG_VisualizationGraphWidget())
239 239 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
240 240 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
241 241 emit synchronize(graphRange, oldGraphRange);
242 242 }
243 243 }
244 244 }
245 245
246 246 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
247 247 {
248 248 // Handles plot rendering when mouse is moving
249 249 impl->m_RenderingDelegate->onMouseMove(event);
250 250 }
251 251
252 252 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
253 253 {
254 254 auto zoomOrientations = QFlags<Qt::Orientation>{};
255 255
256 256 // Lambda that enables a zoom orientation if the key modifier related to this orientation
257 257 // has
258 258 // been pressed
259 259 auto enableOrientation
260 260 = [&zoomOrientations, event](const auto &orientation, const auto &modifier) {
261 261 auto orientationEnabled = event->modifiers().testFlag(modifier);
262 262 zoomOrientations.setFlag(orientation, orientationEnabled);
263 263 };
264 264 enableOrientation(Qt::Vertical, VERTICAL_ZOOM_MODIFIER);
265 265 enableOrientation(Qt::Horizontal, HORIZONTAL_ZOOM_MODIFIER);
266 266
267 267 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
268 268 }
269 269
270 270 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
271 271 {
272 272 impl->m_IsCalibration = event->modifiers().testFlag(Qt::ControlModifier);
273 273 }
274 274
275 275 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
276 276 {
277 277 impl->m_IsCalibration = false;
278 278 }
279 279
280 280 void VisualizationGraphWidget::onDataCacheVariableUpdated()
281 281 {
282 282 // NOTE:
283 283 // We don't want to call the method for each component of a variable unitarily, but for
284 284 // all
285 285 // its components at once (eg its three components in the case of a vector).
286 286
287 287 // The unordered_multimap does not do this easily, so the question is whether to:
288 288 // - use an ordered_multimap and the algos of std to group the values by key
289 289 // - use a map (unique keys) and store as values directly the list of components
290 290
291 291 auto grapheRange = ui->widget->xAxis->range();
292 292 auto dateTime = SqpRange{grapheRange.lower, grapheRange.upper};
293 293
294 294 for (auto it = impl->m_VariableToPlotMultiMap.cbegin();
295 295 it != impl->m_VariableToPlotMultiMap.cend(); ++it) {
296 296 auto variable = it->first;
297 297 qCDebug(LOG_VisualizationGraphWidget())
298 298 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
299 299 qCDebug(LOG_VisualizationGraphWidget())
300 300 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
301 301 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
302 302
303 303 VisualizationGraphHelper::updateData(QVector<QCPAbstractPlottable *>{} << it->second,
304 304 variable->dataSeries(), variable->range());
305 305 }
306 306 }
307 307 }
@@ -1,102 +1,103
1 1 #include "CosinusProvider.h"
2 2
3 3 #include <Data/DataProviderParameters.h>
4 4 #include <Data/ScalarSeries.h>
5 5
6 6 #include <cmath>
7 7
8 8 #include <QFuture>
9 9 #include <QThread>
10 10 #include <QtConcurrent/QtConcurrent>
11 11
12 12 Q_LOGGING_CATEGORY(LOG_CosinusProvider, "CosinusProvider")
13 13
14 14 std::shared_ptr<IDataSeries> CosinusProvider::retrieveData(QUuid acqIdentifier,
15 15 const SqpRange &dataRangeRequested)
16 16 {
17 17 // TODO: Add Mutex
18 18 auto dataIndex = 0;
19 19
20 20 // Gets the timerange from the parameters
21 21 double freq = 100.0;
22 22 double start = std::ceil(dataRangeRequested.m_TStart * freq); // 100 htz
23 23 double end = std::floor(dataRangeRequested.m_TEnd * freq); // 100 htz
24 24
25 25 // We assure that timerange is valid
26 26 if (end < start) {
27 27 std::swap(start, end);
28 28 }
29 29
30 30 // Generates scalar series containing cosinus values (one value per second)
31 31 auto dataCount = end - start;
32 32
33 33 auto xAxisData = QVector<double>{};
34 34 xAxisData.resize(dataCount);
35 35
36 36 auto valuesData = QVector<double>{};
37 37 valuesData.resize(dataCount);
38 38
39 39 int progress = 0;
40 40 auto progressEnd = dataCount;
41 41 for (auto time = start; time < end; ++time, ++dataIndex) {
42 42 auto it = m_VariableToEnableProvider.find(acqIdentifier);
43 43 if (it != m_VariableToEnableProvider.end() && it.value()) {
44 44 const auto timeOnFreq = time / freq;
45 45
46 46 xAxisData.replace(dataIndex, timeOnFreq);
47 47 valuesData.replace(dataIndex, std::cos(timeOnFreq));
48 48
49 49 // progression
50 50 int currentProgress = (time - start) * 100.0 / progressEnd;
51 51 if (currentProgress != progress) {
52 52 progress = currentProgress;
53 53
54 54 emit dataProvidedProgress(acqIdentifier, progress);
55 55 }
56 56 }
57 57 else {
58 58 if (!it.value()) {
59 59 qCDebug(LOG_CosinusProvider())
60 60 << "CosinusProvider::retrieveData: ARRET De l'acquisition detectΓ©"
61 61 << end - time;
62 62 }
63 63 }
64 64 }
65 65 emit dataProvidedProgress(acqIdentifier, 0.0);
66 66
67 67 return std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData),
68 68 Unit{QStringLiteral("t"), true}, Unit{});
69 69 }
70 70
71 71 void CosinusProvider::requestDataLoading(QUuid acqIdentifier,
72 72 const DataProviderParameters &parameters)
73 73 {
74 74 // TODO: Add Mutex
75 75 m_VariableToEnableProvider[acqIdentifier] = true;
76 76 qCDebug(LOG_CosinusProvider()) << "CosinusProvider::requestDataLoading"
77 77 << QThread::currentThread()->objectName();
78 78 // NOTE: Try to use multithread if possible
79 79 const auto times = parameters.m_Times;
80 80
81 81 for (const auto &dateTime : qAsConst(times)) {
82 82 if (m_VariableToEnableProvider[acqIdentifier]) {
83 83 auto scalarSeries = this->retrieveData(acqIdentifier, dateTime);
84 qCCritical(LOG_CosinusProvider()) << "CosinusProvider::dataProvided";
84 85 emit dataProvided(acqIdentifier, scalarSeries, dateTime);
85 86 }
86 87 }
87 88 }
88 89
89 90 void CosinusProvider::requestDataAborting(QUuid acqIdentifier)
90 91 {
91 92 // TODO: Add Mutex
92 93 qCDebug(LOG_CosinusProvider()) << "CosinusProvider::requestDataAborting" << acqIdentifier
93 94 << QThread::currentThread()->objectName();
94 95 auto it = m_VariableToEnableProvider.find(acqIdentifier);
95 96 if (it != m_VariableToEnableProvider.end()) {
96 97 it.value() = false;
97 98 }
98 99 else {
99 100 qCWarning(LOG_CosinusProvider())
100 101 << tr("Aborting progression of inexistant identifier detected !!!");
101 102 }
102 103 }
General Comments 0
You need to be logged in to leave comments. Login now