##// END OF EJS Templates
Merge branch 'feature/AcqFixes' into develop
Alexandre Leroux -
r1329:73d2a50d0c6d merge
parent child
Show More
@@ -1,1069 +1,1102
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>
140 void desynchronize(VariableIterator variableIt, const QUuid &syncGroupId);
141
139 QMutex m_WorkingMutex;
142 QMutex m_WorkingMutex;
140 /// Variable model. The VariableController has the ownership
143 /// Variable model. The VariableController has the ownership
141 VariableModel *m_VariableModel;
144 VariableModel *m_VariableModel;
142 QItemSelectionModel *m_VariableSelectionModel;
145 QItemSelectionModel *m_VariableSelectionModel;
143
146
144
147
145 TimeController *m_TimeController{nullptr};
148 TimeController *m_TimeController{nullptr};
146 std::unique_ptr<VariableCacheStrategy> m_VariableCacheStrategy;
149 std::unique_ptr<VariableCacheStrategy> m_VariableCacheStrategy;
147 std::unique_ptr<VariableAcquisitionWorker> m_VariableAcquisitionWorker;
150 std::unique_ptr<VariableAcquisitionWorker> m_VariableAcquisitionWorker;
148 QThread m_VariableAcquisitionWorkerThread;
151 QThread m_VariableAcquisitionWorkerThread;
149
152
150 std::unordered_map<std::shared_ptr<Variable>, std::shared_ptr<IDataProvider> >
153 std::unordered_map<std::shared_ptr<Variable>, std::shared_ptr<IDataProvider> >
151 m_VariableToProviderMap;
154 m_VariableToProviderMap;
152 std::unordered_map<std::shared_ptr<Variable>, QUuid> m_VariableToIdentifierMap;
155 std::unordered_map<std::shared_ptr<Variable>, QUuid> m_VariableToIdentifierMap;
153 std::map<QUuid, std::shared_ptr<VariableSynchronizationGroup> >
156 std::map<QUuid, std::shared_ptr<VariableSynchronizationGroup> >
154 m_GroupIdToVariableSynchronizationGroupMap;
157 m_GroupIdToVariableSynchronizationGroupMap;
155 std::map<QUuid, QUuid> m_VariableIdGroupIdMap;
158 std::map<QUuid, QUuid> m_VariableIdGroupIdMap;
156 std::set<std::shared_ptr<IDataProvider> > m_ProviderSet;
159 std::set<std::shared_ptr<IDataProvider> > m_ProviderSet;
157
160
158 std::map<QUuid, std::list<QUuid> > m_VarGroupIdToVarIds;
161 std::map<QUuid, std::list<QUuid> > m_VarGroupIdToVarIds;
159 std::map<QUuid, std::unique_ptr<VariableRequestHandler> > m_VarIdToVarRequestHandler;
162 std::map<QUuid, std::unique_ptr<VariableRequestHandler> > m_VarIdToVarRequestHandler;
160
163
161 VariableController *q;
164 VariableController *q;
162 };
165 };
163
166
164
167
165 VariableController::VariableController(QObject *parent)
168 VariableController::VariableController(QObject *parent)
166 : QObject{parent}, impl{spimpl::make_unique_impl<VariableControllerPrivate>(this)}
169 : QObject{parent}, impl{spimpl::make_unique_impl<VariableControllerPrivate>(this)}
167 {
170 {
168 qCDebug(LOG_VariableController()) << tr("VariableController construction")
171 qCDebug(LOG_VariableController()) << tr("VariableController construction")
169 << QThread::currentThread();
172 << QThread::currentThread();
170
173
171 connect(impl->m_VariableModel, &VariableModel::abortProgessRequested, this,
174 connect(impl->m_VariableModel, &VariableModel::abortProgessRequested, this,
172 &VariableController::onAbortProgressRequested);
175 &VariableController::onAbortProgressRequested);
173
176
174 connect(impl->m_VariableAcquisitionWorker.get(),
177 connect(impl->m_VariableAcquisitionWorker.get(),
175 &VariableAcquisitionWorker::variableCanceledRequested, this,
178 &VariableAcquisitionWorker::variableCanceledRequested, this,
176 &VariableController::onAbortAcquisitionRequested);
179 &VariableController::onAbortAcquisitionRequested);
177
180
178 connect(impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::dataProvided, this,
181 connect(impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::dataProvided, this,
179 &VariableController::onDataProvided);
182 &VariableController::onDataProvided);
180 connect(impl->m_VariableAcquisitionWorker.get(),
183 connect(impl->m_VariableAcquisitionWorker.get(),
181 &VariableAcquisitionWorker::variableRequestInProgress, this,
184 &VariableAcquisitionWorker::variableRequestInProgress, this,
182 &VariableController::onVariableRetrieveDataInProgress);
185 &VariableController::onVariableRetrieveDataInProgress);
183
186
184
187
185 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::started,
188 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::started,
186 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::initialize);
189 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::initialize);
187 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::finished,
190 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::finished,
188 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::finalize);
191 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::finalize);
189
192
190 connect(impl->m_VariableModel, &VariableModel::requestVariableRangeUpdate, this,
193 connect(impl->m_VariableModel, &VariableModel::requestVariableRangeUpdate, this,
191 &VariableController::onUpdateDateTime);
194 &VariableController::onUpdateDateTime);
192
195
193 impl->m_VariableAcquisitionWorkerThread.start();
196 impl->m_VariableAcquisitionWorkerThread.start();
194 }
197 }
195
198
196 VariableController::~VariableController()
199 VariableController::~VariableController()
197 {
200 {
198 qCDebug(LOG_VariableController()) << tr("VariableController destruction")
201 qCDebug(LOG_VariableController()) << tr("VariableController destruction")
199 << QThread::currentThread();
202 << QThread::currentThread();
200 this->waitForFinish();
203 this->waitForFinish();
201 }
204 }
202
205
203 VariableModel *VariableController::variableModel() noexcept
206 VariableModel *VariableController::variableModel() noexcept
204 {
207 {
205 return impl->m_VariableModel;
208 return impl->m_VariableModel;
206 }
209 }
207
210
208 QItemSelectionModel *VariableController::variableSelectionModel() noexcept
211 QItemSelectionModel *VariableController::variableSelectionModel() noexcept
209 {
212 {
210 return impl->m_VariableSelectionModel;
213 return impl->m_VariableSelectionModel;
211 }
214 }
212
215
213 void VariableController::setTimeController(TimeController *timeController) noexcept
216 void VariableController::setTimeController(TimeController *timeController) noexcept
214 {
217 {
215 impl->m_TimeController = timeController;
218 impl->m_TimeController = timeController;
216 }
219 }
217
220
218 std::shared_ptr<Variable>
221 std::shared_ptr<Variable>
219 VariableController::cloneVariable(std::shared_ptr<Variable> variable) noexcept
222 VariableController::cloneVariable(std::shared_ptr<Variable> variable) noexcept
220 {
223 {
221 if (impl->m_VariableModel->containsVariable(variable)) {
224 if (impl->m_VariableModel->containsVariable(variable)) {
222 // Clones variable
225 // Clones variable
223 auto duplicate = variable->clone();
226 auto duplicate = variable->clone();
224
227
225 // Adds clone to model
228 // Adds clone to model
226 impl->m_VariableModel->addVariable(duplicate);
229 impl->m_VariableModel->addVariable(duplicate);
227
230
228 // Generates clone identifier
231 // Generates clone identifier
229 impl->m_VariableToIdentifierMap[duplicate] = QUuid::createUuid();
232 impl->m_VariableToIdentifierMap[duplicate] = QUuid::createUuid();
230
233
231 // Registers provider
234 // Registers provider
232 auto variableProvider = impl->m_VariableToProviderMap.at(variable);
235 auto variableProvider = impl->m_VariableToProviderMap.at(variable);
233 auto duplicateProvider = variableProvider != nullptr ? variableProvider->clone() : nullptr;
236 auto duplicateProvider = variableProvider != nullptr ? variableProvider->clone() : nullptr;
234
237
235 impl->m_VariableToProviderMap[duplicate] = duplicateProvider;
238 impl->m_VariableToProviderMap[duplicate] = duplicateProvider;
236 if (duplicateProvider) {
239 if (duplicateProvider) {
237 impl->registerProvider(duplicateProvider);
240 impl->registerProvider(duplicateProvider);
238 }
241 }
239
242
240 return duplicate;
243 return duplicate;
241 }
244 }
242 else {
245 else {
243 qCCritical(LOG_VariableController())
246 qCCritical(LOG_VariableController())
244 << 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")
245 .arg(variable->name());
248 .arg(variable->name());
246 return nullptr;
249 return nullptr;
247 }
250 }
248 }
251 }
249
252
250 void VariableController::deleteVariable(std::shared_ptr<Variable> variable) noexcept
253 void VariableController::deleteVariable(std::shared_ptr<Variable> variable) noexcept
251 {
254 {
252 if (!variable) {
255 if (!variable) {
253 qCCritical(LOG_VariableController()) << "Can't delete variable: variable is null";
256 qCCritical(LOG_VariableController()) << "Can't delete variable: variable is null";
254 return;
257 return;
255 }
258 }
256
259
257 // 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
258 // make some treatments before the deletion
261 // make some treatments before the deletion
259 emit variableAboutToBeDeleted(variable);
262 emit variableAboutToBeDeleted(variable);
260
263
264 auto variableIt = impl->m_VariableToIdentifierMap.find(variable);
265 Q_ASSERT(variableIt != impl->m_VariableToIdentifierMap.cend());
266
267 auto variableId = variableIt->second;
268
269 // Removes variable's handler
270 impl->m_VarIdToVarRequestHandler.erase(variableId);
271
272 // Desynchronizes variable (if the variable is in a sync group)
273 auto syncGroupIt = impl->m_VariableIdGroupIdMap.find(variableId);
274 if (syncGroupIt != impl->m_VariableIdGroupIdMap.cend()) {
275 impl->desynchronize(variableIt, syncGroupIt->second);
276 }
277
261 // Deletes identifier
278 // Deletes identifier
262 impl->m_VariableToIdentifierMap.erase(variable);
279 impl->m_VariableToIdentifierMap.erase(variableIt);
263
280
264 // Deletes provider
281 // Deletes provider
265 auto nbProvidersDeleted = impl->m_VariableToProviderMap.erase(variable);
282 auto nbProvidersDeleted = impl->m_VariableToProviderMap.erase(variable);
266 qCDebug(LOG_VariableController())
283 qCDebug(LOG_VariableController())
267 << tr("Number of providers deleted for variable %1: %2")
284 << tr("Number of providers deleted for variable %1: %2")
268 .arg(variable->name(), QString::number(nbProvidersDeleted));
285 .arg(variable->name(), QString::number(nbProvidersDeleted));
269
286
270
287
271 // Deletes from model
288 // Deletes from model
272 impl->m_VariableModel->deleteVariable(variable);
289 impl->m_VariableModel->deleteVariable(variable);
273 }
290 }
274
291
275 void VariableController::deleteVariables(
292 void VariableController::deleteVariables(
276 const QVector<std::shared_ptr<Variable> > &variables) noexcept
293 const QVector<std::shared_ptr<Variable> > &variables) noexcept
277 {
294 {
278 for (auto variable : qAsConst(variables)) {
295 for (auto variable : qAsConst(variables)) {
279 deleteVariable(variable);
296 deleteVariable(variable);
280 }
297 }
281 }
298 }
282
299
283 QByteArray
300 QByteArray
284 VariableController::mimeDataForVariables(const QList<std::shared_ptr<Variable> > &variables) const
301 VariableController::mimeDataForVariables(const QList<std::shared_ptr<Variable> > &variables) const
285 {
302 {
286 auto encodedData = QByteArray{};
303 auto encodedData = QByteArray{};
287
304
288 QVariantList ids;
305 QVariantList ids;
289 for (auto &var : variables) {
306 for (auto &var : variables) {
290 auto itVar = impl->m_VariableToIdentifierMap.find(var);
307 auto itVar = impl->m_VariableToIdentifierMap.find(var);
291 if (itVar == impl->m_VariableToIdentifierMap.cend()) {
308 if (itVar == impl->m_VariableToIdentifierMap.cend()) {
292 qCCritical(LOG_VariableController())
309 qCCritical(LOG_VariableController())
293 << tr("Impossible to find the data for an unknown variable.");
310 << tr("Impossible to find the data for an unknown variable.");
294 }
311 }
295
312
296 ids << itVar->second.toByteArray();
313 ids << itVar->second.toByteArray();
297 }
314 }
298
315
299 QDataStream stream{&encodedData, QIODevice::WriteOnly};
316 QDataStream stream{&encodedData, QIODevice::WriteOnly};
300 stream << ids;
317 stream << ids;
301
318
302 return encodedData;
319 return encodedData;
303 }
320 }
304
321
305 QList<std::shared_ptr<Variable> >
322 QList<std::shared_ptr<Variable> >
306 VariableController::variablesForMimeData(const QByteArray &mimeData) const
323 VariableController::variablesForMimeData(const QByteArray &mimeData) const
307 {
324 {
308 auto variables = QList<std::shared_ptr<Variable> >{};
325 auto variables = QList<std::shared_ptr<Variable> >{};
309 QDataStream stream{mimeData};
326 QDataStream stream{mimeData};
310
327
311 QVariantList ids;
328 QVariantList ids;
312 stream >> ids;
329 stream >> ids;
313
330
314 for (auto id : ids) {
331 for (auto id : ids) {
315 auto uuid = QUuid{id.toByteArray()};
332 auto uuid = QUuid{id.toByteArray()};
316 auto var = impl->findVariable(uuid);
333 auto var = impl->findVariable(uuid);
317 variables << var;
334 variables << var;
318 }
335 }
319
336
320 return variables;
337 return variables;
321 }
338 }
322
339
323 std::shared_ptr<Variable>
340 std::shared_ptr<Variable>
324 VariableController::createVariable(const QString &name, const QVariantHash &metadata,
341 VariableController::createVariable(const QString &name, const QVariantHash &metadata,
325 std::shared_ptr<IDataProvider> provider) noexcept
342 std::shared_ptr<IDataProvider> provider) noexcept
326 {
343 {
327 if (!impl->m_TimeController) {
344 if (!impl->m_TimeController) {
328 qCCritical(LOG_VariableController())
345 qCCritical(LOG_VariableController())
329 << tr("Impossible to create variable: The time controller is null");
346 << tr("Impossible to create variable: The time controller is null");
330 return nullptr;
347 return nullptr;
331 }
348 }
332
349
333 auto range = impl->m_TimeController->dateTime();
350 auto range = impl->m_TimeController->dateTime();
334
351
335 if (auto newVariable = impl->m_VariableModel->createVariable(name, metadata)) {
352 if (auto newVariable = impl->m_VariableModel->createVariable(name, metadata)) {
336 auto varId = QUuid::createUuid();
353 auto varId = QUuid::createUuid();
337
354
338 // Create the handler
355 // Create the handler
339 auto varRequestHandler = std::make_unique<VariableRequestHandler>();
356 auto varRequestHandler = std::make_unique<VariableRequestHandler>();
340 varRequestHandler->m_VarId = varId;
357 varRequestHandler->m_VarId = varId;
341
358
342 impl->m_VarIdToVarRequestHandler.insert(
359 impl->m_VarIdToVarRequestHandler.insert(
343 std::make_pair(varId, std::move(varRequestHandler)));
360 std::make_pair(varId, std::move(varRequestHandler)));
344
361
345 // store the provider
362 // store the provider
346 impl->registerProvider(provider);
363 impl->registerProvider(provider);
347
364
348 // Associate the provider
365 // Associate the provider
349 impl->m_VariableToProviderMap[newVariable] = provider;
366 impl->m_VariableToProviderMap[newVariable] = provider;
350 impl->m_VariableToIdentifierMap[newVariable] = varId;
367 impl->m_VariableToIdentifierMap[newVariable] = varId;
351
368
352 this->onRequestDataLoading(QVector<std::shared_ptr<Variable> >{newVariable}, range, false);
369 this->onRequestDataLoading(QVector<std::shared_ptr<Variable> >{newVariable}, range, false);
353
370
354 // auto varRequestId = QUuid::createUuid();
371 // auto varRequestId = QUuid::createUuid();
355 // qCInfo(LOG_VariableController()) << "createVariable: " << varId << varRequestId;
372 // qCInfo(LOG_VariableController()) << "createVariable: " << varId << varRequestId;
356 // impl->processRequest(newVariable, range, varRequestId);
373 // impl->processRequest(newVariable, range, varRequestId);
357 // impl->updateVariableRequest(varRequestId);
374 // impl->updateVariableRequest(varRequestId);
358
375
359 return newVariable;
376 return newVariable;
360 }
377 }
361
378
362 qCCritical(LOG_VariableController()) << tr("Impossible to create variable");
379 qCCritical(LOG_VariableController()) << tr("Impossible to create variable");
363 return nullptr;
380 return nullptr;
364 }
381 }
365
382
366 void VariableController::onDateTimeOnSelection(const SqpRange &dateTime)
383 void VariableController::onDateTimeOnSelection(const SqpRange &dateTime)
367 {
384 {
368 // NOTE: Even if acquisition request is aborting, the graphe range will be changed
385 // NOTE: Even if acquisition request is aborting, the graphe range will be changed
369 qCDebug(LOG_VariableController()) << "VariableController::onDateTimeOnSelection"
386 qCDebug(LOG_VariableController()) << "VariableController::onDateTimeOnSelection"
370 << QThread::currentThread()->objectName();
387 << QThread::currentThread()->objectName();
371 auto selectedRows = impl->m_VariableSelectionModel->selectedRows();
388 auto selectedRows = impl->m_VariableSelectionModel->selectedRows();
372
389
373 // NOTE we only permit the time modification for one variable
390 // NOTE we only permit the time modification for one variable
374 // DEPRECATED
391 // DEPRECATED
375 // auto variables = QVector<std::shared_ptr<Variable> >{};
392 // auto variables = QVector<std::shared_ptr<Variable> >{};
376 // for (const auto &selectedRow : qAsConst(selectedRows)) {
393 // for (const auto &selectedRow : qAsConst(selectedRows)) {
377 // if (auto selectedVariable =
394 // if (auto selectedVariable =
378 // impl->m_VariableModel->variable(selectedRow.row())) {
395 // impl->m_VariableModel->variable(selectedRow.row())) {
379 // variables << selectedVariable;
396 // variables << selectedVariable;
380
397
381 // // notify that rescale operation has to be done
398 // // notify that rescale operation has to be done
382 // emit rangeChanged(selectedVariable, dateTime);
399 // emit rangeChanged(selectedVariable, dateTime);
383 // }
400 // }
384 // }
401 // }
385 // if (!variables.isEmpty()) {
402 // if (!variables.isEmpty()) {
386 // this->onRequestDataLoading(variables, dateTime, synchro);
403 // this->onRequestDataLoading(variables, dateTime, synchro);
387 // }
404 // }
388 if (selectedRows.size() == 1) {
405 if (selectedRows.size() == 1) {
389
406
390 if (auto selectedVariable
407 if (auto selectedVariable
391 = impl->m_VariableModel->variable(qAsConst(selectedRows).first().row())) {
408 = impl->m_VariableModel->variable(qAsConst(selectedRows).first().row())) {
392
409
393 onUpdateDateTime(selectedVariable, dateTime);
410 onUpdateDateTime(selectedVariable, dateTime);
394 }
411 }
395 }
412 }
396 else if (selectedRows.size() > 1) {
413 else if (selectedRows.size() > 1) {
397 qCCritical(LOG_VariableController())
414 qCCritical(LOG_VariableController())
398 << tr("Impossible to set time for more than 1 variable in the same time");
415 << tr("Impossible to set time for more than 1 variable in the same time");
399 }
416 }
400 else {
417 else {
401 qCWarning(LOG_VariableController())
418 qCWarning(LOG_VariableController())
402 << tr("There is no variable selected to set the time one");
419 << tr("There is no variable selected to set the time one");
403 }
420 }
404 }
421 }
405
422
406 void VariableController::onUpdateDateTime(std::shared_ptr<Variable> variable,
423 void VariableController::onUpdateDateTime(std::shared_ptr<Variable> variable,
407 const SqpRange &dateTime)
424 const SqpRange &dateTime)
408 {
425 {
409 auto itVar = impl->m_VariableToIdentifierMap.find(variable);
426 auto itVar = impl->m_VariableToIdentifierMap.find(variable);
410 if (itVar == impl->m_VariableToIdentifierMap.cend()) {
427 if (itVar == impl->m_VariableToIdentifierMap.cend()) {
411 qCCritical(LOG_VariableController())
428 qCCritical(LOG_VariableController())
412 << tr("Impossible to onDateTimeOnSelection request for unknown variable");
429 << tr("Impossible to onDateTimeOnSelection request for unknown variable");
413 return;
430 return;
414 }
431 }
415
432
416 // notify that rescale operation has to be done
433 // notify that rescale operation has to be done
417 emit rangeChanged(variable, dateTime);
434 emit rangeChanged(variable, dateTime);
418
435
419 auto synchro
436 auto synchro
420 = impl->m_VariableIdGroupIdMap.find(itVar->second) != impl->m_VariableIdGroupIdMap.cend();
437 = impl->m_VariableIdGroupIdMap.find(itVar->second) != impl->m_VariableIdGroupIdMap.cend();
421
438
422 this->onRequestDataLoading(QVector<std::shared_ptr<Variable> >{variable}, dateTime, synchro);
439 this->onRequestDataLoading(QVector<std::shared_ptr<Variable> >{variable}, dateTime, synchro);
423 }
440 }
424
441
425 void VariableController::onDataProvided(QUuid vIdentifier, const SqpRange &rangeRequested,
442 void VariableController::onDataProvided(QUuid vIdentifier, const SqpRange &rangeRequested,
426 const SqpRange &cacheRangeRequested,
443 const SqpRange &cacheRangeRequested,
427 QVector<AcquisitionDataPacket> dataAcquired)
444 QVector<AcquisitionDataPacket> dataAcquired)
428 {
445 {
429 qCDebug(LOG_VariableController()) << tr("onDataProvided") << QThread::currentThread();
446 qCDebug(LOG_VariableController()) << tr("onDataProvided") << QThread::currentThread();
430 auto retrievedDataSeries = impl->retrieveDataSeries(dataAcquired);
447 auto retrievedDataSeries = impl->retrieveDataSeries(dataAcquired);
431 auto varRequestId = impl->acceptVariableRequest(vIdentifier, retrievedDataSeries);
448 auto varRequestId = impl->acceptVariableRequest(vIdentifier, retrievedDataSeries);
432 if (!varRequestId.isNull()) {
449 if (!varRequestId.isNull()) {
433 impl->updateVariables(varRequestId);
450 impl->updateVariables(varRequestId);
434 }
451 }
435 }
452 }
436
453
437 void VariableController::onVariableRetrieveDataInProgress(QUuid identifier, double progress)
454 void VariableController::onVariableRetrieveDataInProgress(QUuid identifier, double progress)
438 {
455 {
439 qCDebug(LOG_VariableController())
456 qCDebug(LOG_VariableController())
440 << "TORM: variableController::onVariableRetrieveDataInProgress"
457 << "TORM: variableController::onVariableRetrieveDataInProgress"
441 << QThread::currentThread()->objectName() << progress;
458 << QThread::currentThread()->objectName() << progress;
442 if (auto var = impl->findVariable(identifier)) {
459 if (auto var = impl->findVariable(identifier)) {
443 impl->m_VariableModel->setDataProgress(var, progress);
460 impl->m_VariableModel->setDataProgress(var, progress);
444 }
461 }
445 else {
462 else {
446 qCCritical(LOG_VariableController())
463 qCCritical(LOG_VariableController())
447 << tr("Impossible to notify progression of a null variable");
464 << tr("Impossible to notify progression of a null variable");
448 }
465 }
449 }
466 }
450
467
451 void VariableController::onAbortProgressRequested(std::shared_ptr<Variable> variable)
468 void VariableController::onAbortProgressRequested(std::shared_ptr<Variable> variable)
452 {
469 {
453 qCDebug(LOG_VariableController()) << "TORM: variableController::onAbortProgressRequested"
470 qCDebug(LOG_VariableController()) << "TORM: variableController::onAbortProgressRequested"
454 << QThread::currentThread()->objectName() << variable->name();
471 << QThread::currentThread()->objectName() << variable->name();
455
472
456 auto itVar = impl->m_VariableToIdentifierMap.find(variable);
473 auto itVar = impl->m_VariableToIdentifierMap.find(variable);
457 if (itVar == impl->m_VariableToIdentifierMap.cend()) {
474 if (itVar == impl->m_VariableToIdentifierMap.cend()) {
458 qCCritical(LOG_VariableController())
475 qCCritical(LOG_VariableController())
459 << tr("Impossible to onAbortProgressRequested request for unknown variable");
476 << tr("Impossible to onAbortProgressRequested request for unknown variable");
460 return;
477 return;
461 }
478 }
462
479
463 auto varId = itVar->second;
480 auto varId = itVar->second;
464
481
465 auto itVarHandler = impl->m_VarIdToVarRequestHandler.find(varId);
482 auto itVarHandler = impl->m_VarIdToVarRequestHandler.find(varId);
466 if (itVarHandler == impl->m_VarIdToVarRequestHandler.cend()) {
483 if (itVarHandler == impl->m_VarIdToVarRequestHandler.cend()) {
467 qCCritical(LOG_VariableController())
484 qCCritical(LOG_VariableController())
468 << tr("Impossible to onAbortProgressRequested for variable with unknown handler");
485 << tr("Impossible to onAbortProgressRequested for variable with unknown handler");
469 return;
486 return;
470 }
487 }
471
488
472 auto varHandler = itVarHandler->second.get();
489 auto varHandler = itVarHandler->second.get();
473
490
474 // case where a variable has a running request
491 // case where a variable has a running request
475 if (varHandler->m_State != VariableRequestHandlerState::OFF) {
492 if (varHandler->m_State != VariableRequestHandlerState::OFF) {
476 impl->cancelVariableRequest(varHandler->m_RunningVarRequest.m_VariableGroupId);
493 impl->cancelVariableRequest(varHandler->m_RunningVarRequest.m_VariableGroupId);
477 }
494 }
478 }
495 }
479
496
480 void VariableController::onAbortAcquisitionRequested(QUuid vIdentifier)
497 void VariableController::onAbortAcquisitionRequested(QUuid vIdentifier)
481 {
498 {
482 qCDebug(LOG_VariableController()) << "TORM: variableController::onAbortAcquisitionRequested"
499 qCDebug(LOG_VariableController()) << "TORM: variableController::onAbortAcquisitionRequested"
483 << QThread::currentThread()->objectName() << vIdentifier;
500 << QThread::currentThread()->objectName() << vIdentifier;
484
501
485 if (auto var = impl->findVariable(vIdentifier)) {
502 if (auto var = impl->findVariable(vIdentifier)) {
486 this->onAbortProgressRequested(var);
503 this->onAbortProgressRequested(var);
487 }
504 }
488 else {
505 else {
489 qCCritical(LOG_VariableController())
506 qCCritical(LOG_VariableController())
490 << tr("Impossible to abort Acquisition Requestof a null variable");
507 << tr("Impossible to abort Acquisition Requestof a null variable");
491 }
508 }
492 }
509 }
493
510
494 void VariableController::onAddSynchronizationGroupId(QUuid synchronizationGroupId)
511 void VariableController::onAddSynchronizationGroupId(QUuid synchronizationGroupId)
495 {
512 {
496 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronizationGroupId"
513 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronizationGroupId"
497 << QThread::currentThread()->objectName()
514 << QThread::currentThread()->objectName()
498 << synchronizationGroupId;
515 << synchronizationGroupId;
499 auto vSynchroGroup = std::make_shared<VariableSynchronizationGroup>();
516 auto vSynchroGroup = std::make_shared<VariableSynchronizationGroup>();
500 impl->m_GroupIdToVariableSynchronizationGroupMap.insert(
517 impl->m_GroupIdToVariableSynchronizationGroupMap.insert(
501 std::make_pair(synchronizationGroupId, vSynchroGroup));
518 std::make_pair(synchronizationGroupId, vSynchroGroup));
502 }
519 }
503
520
504 void VariableController::onRemoveSynchronizationGroupId(QUuid synchronizationGroupId)
521 void VariableController::onRemoveSynchronizationGroupId(QUuid synchronizationGroupId)
505 {
522 {
506 impl->m_GroupIdToVariableSynchronizationGroupMap.erase(synchronizationGroupId);
523 impl->m_GroupIdToVariableSynchronizationGroupMap.erase(synchronizationGroupId);
507 }
524 }
508
525
509 void VariableController::onAddSynchronized(std::shared_ptr<Variable> variable,
526 void VariableController::onAddSynchronized(std::shared_ptr<Variable> variable,
510 QUuid synchronizationGroupId)
527 QUuid synchronizationGroupId)
511
528
512 {
529 {
513 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronized"
530 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronized"
514 << synchronizationGroupId;
531 << synchronizationGroupId;
515 auto varToVarIdIt = impl->m_VariableToIdentifierMap.find(variable);
532 auto varToVarIdIt = impl->m_VariableToIdentifierMap.find(variable);
516 if (varToVarIdIt != impl->m_VariableToIdentifierMap.cend()) {
533 if (varToVarIdIt != impl->m_VariableToIdentifierMap.cend()) {
517 auto groupIdToVSGIt
534 auto groupIdToVSGIt
518 = impl->m_GroupIdToVariableSynchronizationGroupMap.find(synchronizationGroupId);
535 = impl->m_GroupIdToVariableSynchronizationGroupMap.find(synchronizationGroupId);
519 if (groupIdToVSGIt != impl->m_GroupIdToVariableSynchronizationGroupMap.cend()) {
536 if (groupIdToVSGIt != impl->m_GroupIdToVariableSynchronizationGroupMap.cend()) {
520 impl->m_VariableIdGroupIdMap.insert(
537 impl->m_VariableIdGroupIdMap.insert(
521 std::make_pair(varToVarIdIt->second, synchronizationGroupId));
538 std::make_pair(varToVarIdIt->second, synchronizationGroupId));
522 groupIdToVSGIt->second->addVariableId(varToVarIdIt->second);
539 groupIdToVSGIt->second->addVariableId(varToVarIdIt->second);
523 }
540 }
524 else {
541 else {
525 qCCritical(LOG_VariableController())
542 qCCritical(LOG_VariableController())
526 << tr("Impossible to synchronize a variable with an unknown sycnhronization group")
543 << tr("Impossible to synchronize a variable with an unknown sycnhronization group")
527 << variable->name();
544 << variable->name();
528 }
545 }
529 }
546 }
530 else {
547 else {
531 qCCritical(LOG_VariableController())
548 qCCritical(LOG_VariableController())
532 << tr("Impossible to synchronize a variable with no identifier") << variable->name();
549 << tr("Impossible to synchronize a variable with no identifier") << variable->name();
533 }
550 }
534 }
551 }
535
552
536 void VariableController::desynchronize(std::shared_ptr<Variable> variable,
553 void VariableController::desynchronize(std::shared_ptr<Variable> variable,
537 QUuid synchronizationGroupId)
554 QUuid synchronizationGroupId)
538 {
555 {
539 // Gets variable id
556 // Gets variable id
540 auto variableIt = impl->m_VariableToIdentifierMap.find(variable);
557 auto variableIt = impl->m_VariableToIdentifierMap.find(variable);
541 if (variableIt == impl->m_VariableToIdentifierMap.cend()) {
558 if (variableIt == impl->m_VariableToIdentifierMap.cend()) {
542 qCCritical(LOG_VariableController())
559 qCCritical(LOG_VariableController())
543 << tr("Can't desynchronize variable %1: variable identifier not found")
560 << tr("Can't desynchronize variable %1: variable identifier not found")
544 .arg(variable->name());
561 .arg(variable->name());
545 return;
562 return;
546 }
563 }
547
564
548 // Gets synchronization group
565 impl->desynchronize(variableIt, synchronizationGroupId);
549 auto groupIt = impl->m_GroupIdToVariableSynchronizationGroupMap.find(synchronizationGroupId);
550 if (groupIt == impl->m_GroupIdToVariableSynchronizationGroupMap.cend()) {
551 qCCritical(LOG_VariableController())
552 << tr("Can't desynchronize variable %1: unknown synchronization group")
553 .arg(variable->name());
554 return;
555 }
556
557 auto variableId = variableIt->second;
558
559 // Removes variable from synchronization group
560 auto synchronizationGroup = groupIt->second;
561 synchronizationGroup->removeVariableId(variableId);
562
563 // Removes link between variable and synchronization group
564 impl->m_VariableIdGroupIdMap.erase(variableId);
565 }
566 }
566
567
567 void VariableController::onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables,
568 void VariableController::onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables,
568 const SqpRange &range, bool synchronise)
569 const SqpRange &range, bool synchronise)
569 {
570 {
570 // variables is assumed synchronized
571 // variables is assumed synchronized
571 // TODO: Asser variables synchronization
572 // TODO: Asser variables synchronization
572 // we want to load data of the variable for the dateTime.
573 // we want to load data of the variable for the dateTime.
573 if (variables.isEmpty()) {
574 if (variables.isEmpty()) {
574 return;
575 return;
575 }
576 }
576
577
577 auto varRequestId = QUuid::createUuid();
578 auto varRequestId = QUuid::createUuid();
578 qCDebug(LOG_VariableController()) << "VariableController::onRequestDataLoading"
579 qCDebug(LOG_VariableController()) << "VariableController::onRequestDataLoading"
579 << QThread::currentThread()->objectName() << varRequestId
580 << QThread::currentThread()->objectName() << varRequestId
580 << range << synchronise;
581 << range << synchronise;
581
582
582 if (!synchronise) {
583 if (!synchronise) {
583 auto varIds = std::list<QUuid>{};
584 auto varIds = std::list<QUuid>{};
584 for (const auto &var : variables) {
585 for (const auto &var : variables) {
585 auto vId = impl->m_VariableToIdentifierMap.at(var);
586 auto vId = impl->m_VariableToIdentifierMap.at(var);
586 varIds.push_back(vId);
587 varIds.push_back(vId);
587 }
588 }
588 impl->m_VarGroupIdToVarIds.insert(std::make_pair(varRequestId, varIds));
589 impl->m_VarGroupIdToVarIds.insert(std::make_pair(varRequestId, varIds));
589 for (const auto &var : variables) {
590 for (const auto &var : variables) {
590 qCDebug(LOG_VariableController()) << "processRequest for" << var->name() << varRequestId
591 qCDebug(LOG_VariableController()) << "processRequest for" << var->name() << varRequestId
591 << varIds.size();
592 << varIds.size();
592 impl->processRequest(var, range, varRequestId);
593 impl->processRequest(var, range, varRequestId);
593 }
594 }
594 }
595 }
595 else {
596 else {
596 auto vId = impl->m_VariableToIdentifierMap.at(variables.first());
597 auto vId = impl->m_VariableToIdentifierMap.at(variables.first());
597 auto varIdToGroupIdIt = impl->m_VariableIdGroupIdMap.find(vId);
598 auto varIdToGroupIdIt = impl->m_VariableIdGroupIdMap.find(vId);
598 if (varIdToGroupIdIt != impl->m_VariableIdGroupIdMap.cend()) {
599 if (varIdToGroupIdIt != impl->m_VariableIdGroupIdMap.cend()) {
599 auto groupId = varIdToGroupIdIt->second;
600 auto groupId = varIdToGroupIdIt->second;
600
601
601 auto vSynchronizationGroup
602 auto vSynchronizationGroup
602 = impl->m_GroupIdToVariableSynchronizationGroupMap.at(groupId);
603 = impl->m_GroupIdToVariableSynchronizationGroupMap.at(groupId);
603 auto vSyncIds = vSynchronizationGroup->getIds();
604 auto vSyncIds = vSynchronizationGroup->getIds();
604
605
605 auto varIds = std::list<QUuid>{};
606 auto varIds = std::list<QUuid>{};
606 for (auto vId : vSyncIds) {
607 for (auto vId : vSyncIds) {
607 varIds.push_back(vId);
608 varIds.push_back(vId);
608 }
609 }
609 impl->m_VarGroupIdToVarIds.insert(std::make_pair(varRequestId, varIds));
610 impl->m_VarGroupIdToVarIds.insert(std::make_pair(varRequestId, varIds));
610
611
611 for (auto vId : vSyncIds) {
612 for (auto vId : vSyncIds) {
612 auto var = impl->findVariable(vId);
613 auto var = impl->findVariable(vId);
613
614
614 // Don't process already processed var
615 // Don't process already processed var
615 if (var != nullptr) {
616 if (var != nullptr) {
616 qCDebug(LOG_VariableController()) << "processRequest synchro for" << var->name()
617 qCDebug(LOG_VariableController()) << "processRequest synchro for" << var->name()
617 << varRequestId;
618 << varRequestId;
618 auto vSyncRangeRequested
619 auto vSyncRangeRequested
619 = variables.contains(var)
620 = variables.contains(var)
620 ? range
621 ? range
621 : computeSynchroRangeRequested(var->range(), range,
622 : computeSynchroRangeRequested(var->range(), range,
622 variables.first()->range());
623 variables.first()->range());
623 qCDebug(LOG_VariableController()) << "synchro RR" << vSyncRangeRequested;
624 qCDebug(LOG_VariableController()) << "synchro RR" << vSyncRangeRequested;
624 impl->processRequest(var, vSyncRangeRequested, varRequestId);
625 impl->processRequest(var, vSyncRangeRequested, varRequestId);
625 }
626 }
626 else {
627 else {
627 qCCritical(LOG_VariableController())
628 qCCritical(LOG_VariableController())
628
629
629 << tr("Impossible to synchronize a null variable");
630 << tr("Impossible to synchronize a null variable");
630 }
631 }
631 }
632 }
632 }
633 }
633 }
634 }
634
635
635 impl->updateVariables(varRequestId);
636 impl->updateVariables(varRequestId);
636 }
637 }
637
638
638
639
639 void VariableController::initialize()
640 void VariableController::initialize()
640 {
641 {
641 qCDebug(LOG_VariableController()) << tr("VariableController init") << QThread::currentThread();
642 qCDebug(LOG_VariableController()) << tr("VariableController init") << QThread::currentThread();
642 impl->m_WorkingMutex.lock();
643 impl->m_WorkingMutex.lock();
643 qCDebug(LOG_VariableController()) << tr("VariableController init END");
644 qCDebug(LOG_VariableController()) << tr("VariableController init END");
644 }
645 }
645
646
646 void VariableController::finalize()
647 void VariableController::finalize()
647 {
648 {
648 impl->m_WorkingMutex.unlock();
649 impl->m_WorkingMutex.unlock();
649 }
650 }
650
651
651 void VariableController::waitForFinish()
652 void VariableController::waitForFinish()
652 {
653 {
653 QMutexLocker locker{&impl->m_WorkingMutex};
654 QMutexLocker locker{&impl->m_WorkingMutex};
654 }
655 }
655
656
656 AcquisitionZoomType VariableController::getZoomType(const SqpRange &range, const SqpRange &oldRange)
657 AcquisitionZoomType VariableController::getZoomType(const SqpRange &range, const SqpRange &oldRange)
657 {
658 {
658 // t1.m_TStart <= t2.m_TStart && t2.m_TEnd <= t1.m_TEnd
659 // t1.m_TStart <= t2.m_TStart && t2.m_TEnd <= t1.m_TEnd
659 auto zoomType = AcquisitionZoomType::Unknown;
660 auto zoomType = AcquisitionZoomType::Unknown;
660 if (range.m_TStart <= oldRange.m_TStart && oldRange.m_TEnd <= range.m_TEnd) {
661 if (range.m_TStart <= oldRange.m_TStart && oldRange.m_TEnd <= range.m_TEnd) {
661 qCDebug(LOG_VariableController()) << "zoomtype: ZoomOut";
662 qCDebug(LOG_VariableController()) << "zoomtype: ZoomOut";
662 zoomType = AcquisitionZoomType::ZoomOut;
663 zoomType = AcquisitionZoomType::ZoomOut;
663 }
664 }
664 else if (range.m_TStart > oldRange.m_TStart && range.m_TEnd > oldRange.m_TEnd) {
665 else if (range.m_TStart > oldRange.m_TStart && range.m_TEnd > oldRange.m_TEnd) {
665 qCDebug(LOG_VariableController()) << "zoomtype: PanRight";
666 qCDebug(LOG_VariableController()) << "zoomtype: PanRight";
666 zoomType = AcquisitionZoomType::PanRight;
667 zoomType = AcquisitionZoomType::PanRight;
667 }
668 }
668 else if (range.m_TStart < oldRange.m_TStart && range.m_TEnd < oldRange.m_TEnd) {
669 else if (range.m_TStart < oldRange.m_TStart && range.m_TEnd < oldRange.m_TEnd) {
669 qCDebug(LOG_VariableController()) << "zoomtype: PanLeft";
670 qCDebug(LOG_VariableController()) << "zoomtype: PanLeft";
670 zoomType = AcquisitionZoomType::PanLeft;
671 zoomType = AcquisitionZoomType::PanLeft;
671 }
672 }
672 else if (range.m_TStart >= oldRange.m_TStart && oldRange.m_TEnd >= range.m_TEnd) {
673 else if (range.m_TStart >= oldRange.m_TStart && oldRange.m_TEnd >= range.m_TEnd) {
673 qCDebug(LOG_VariableController()) << "zoomtype: ZoomIn";
674 qCDebug(LOG_VariableController()) << "zoomtype: ZoomIn";
674 zoomType = AcquisitionZoomType::ZoomIn;
675 zoomType = AcquisitionZoomType::ZoomIn;
675 }
676 }
676 else {
677 else {
677 qCDebug(LOG_VariableController()) << "getZoomType: Unknown type detected";
678 qCDebug(LOG_VariableController()) << "getZoomType: Unknown type detected";
678 }
679 }
679 return zoomType;
680 return zoomType;
680 }
681 }
681
682
682 void VariableController::VariableControllerPrivate::processRequest(std::shared_ptr<Variable> var,
683 void VariableController::VariableControllerPrivate::processRequest(std::shared_ptr<Variable> var,
683 const SqpRange &rangeRequested,
684 const SqpRange &rangeRequested,
684 QUuid varRequestId)
685 QUuid varRequestId)
685 {
686 {
686 auto itVar = m_VariableToIdentifierMap.find(var);
687 auto itVar = m_VariableToIdentifierMap.find(var);
687 if (itVar == m_VariableToIdentifierMap.cend()) {
688 if (itVar == m_VariableToIdentifierMap.cend()) {
688 qCCritical(LOG_VariableController())
689 qCCritical(LOG_VariableController())
689 << tr("Impossible to process request for unknown variable");
690 << tr("Impossible to process request for unknown variable");
690 return;
691 return;
691 }
692 }
692
693
693 auto varId = itVar->second;
694 auto varId = itVar->second;
694
695
695 auto itVarHandler = m_VarIdToVarRequestHandler.find(varId);
696 auto itVarHandler = m_VarIdToVarRequestHandler.find(varId);
696 if (itVarHandler == m_VarIdToVarRequestHandler.cend()) {
697 if (itVarHandler == m_VarIdToVarRequestHandler.cend()) {
697 qCCritical(LOG_VariableController())
698 qCCritical(LOG_VariableController())
698 << tr("Impossible to process request for variable with unknown handler");
699 << tr("Impossible to process request for variable with unknown handler");
699 return;
700 return;
700 }
701 }
701
702
702 auto oldRange = var->range();
703 auto oldRange = var->range();
703
704
704 auto varHandler = itVarHandler->second.get();
705 auto varHandler = itVarHandler->second.get();
705
706
706 if (varHandler->m_State != VariableRequestHandlerState::OFF) {
707 if (varHandler->m_State != VariableRequestHandlerState::OFF) {
707 oldRange = varHandler->m_RunningVarRequest.m_RangeRequested;
708 oldRange = varHandler->m_RunningVarRequest.m_RangeRequested;
708 }
709 }
709
710
710 auto varRequest = VariableRequest{};
711 auto varRequest = VariableRequest{};
711 varRequest.m_VariableGroupId = varRequestId;
712 varRequest.m_VariableGroupId = varRequestId;
712 auto varStrategyRangesRequested
713 auto varStrategyRangesRequested
713 = m_VariableCacheStrategy->computeRange(oldRange, rangeRequested);
714 = m_VariableCacheStrategy->computeRange(oldRange, rangeRequested);
714 varRequest.m_RangeRequested = varStrategyRangesRequested.first;
715 varRequest.m_RangeRequested = varStrategyRangesRequested.first;
715 varRequest.m_CacheRangeRequested = varStrategyRangesRequested.second;
716 varRequest.m_CacheRangeRequested = varStrategyRangesRequested.second;
716
717
717 switch (varHandler->m_State) {
718 switch (varHandler->m_State) {
718 case VariableRequestHandlerState::OFF: {
719 case VariableRequestHandlerState::OFF: {
719 qCDebug(LOG_VariableController()) << tr("Process Request OFF")
720 qCDebug(LOG_VariableController()) << tr("Process Request OFF")
720 << varRequest.m_RangeRequested
721 << varRequest.m_RangeRequested
721 << varRequest.m_CacheRangeRequested;
722 << varRequest.m_CacheRangeRequested;
722 varHandler->m_RunningVarRequest = varRequest;
723 varHandler->m_RunningVarRequest = varRequest;
723 varHandler->m_State = VariableRequestHandlerState::RUNNING;
724 varHandler->m_State = VariableRequestHandlerState::RUNNING;
724 executeVarRequest(var, varRequest);
725 executeVarRequest(var, varRequest);
725 break;
726 break;
726 }
727 }
727 case VariableRequestHandlerState::RUNNING: {
728 case VariableRequestHandlerState::RUNNING: {
728 qCDebug(LOG_VariableController()) << tr("Process Request RUNNING")
729 qCDebug(LOG_VariableController()) << tr("Process Request RUNNING")
729 << varRequest.m_RangeRequested
730 << varRequest.m_RangeRequested
730 << varRequest.m_CacheRangeRequested;
731 << varRequest.m_CacheRangeRequested;
731 varHandler->m_State = VariableRequestHandlerState::PENDING;
732 varHandler->m_State = VariableRequestHandlerState::PENDING;
732 varHandler->m_PendingVarRequest = varRequest;
733 varHandler->m_PendingVarRequest = varRequest;
733 break;
734 break;
734 }
735 }
735 case VariableRequestHandlerState::PENDING: {
736 case VariableRequestHandlerState::PENDING: {
736 qCDebug(LOG_VariableController()) << tr("Process Request PENDING")
737 qCDebug(LOG_VariableController()) << tr("Process Request PENDING")
737 << varRequest.m_RangeRequested
738 << varRequest.m_RangeRequested
738 << varRequest.m_CacheRangeRequested;
739 << varRequest.m_CacheRangeRequested;
739 auto variableGroupIdToCancel = varHandler->m_PendingVarRequest.m_VariableGroupId;
740 auto variableGroupIdToCancel = varHandler->m_PendingVarRequest.m_VariableGroupId;
740 cancelVariableRequest(variableGroupIdToCancel);
741 cancelVariableRequest(variableGroupIdToCancel);
741 // Cancel variable can make state downgrade
742 // Cancel variable can make state downgrade
742 varHandler->m_State = VariableRequestHandlerState::PENDING;
743 varHandler->m_State = VariableRequestHandlerState::PENDING;
743 varHandler->m_PendingVarRequest = varRequest;
744 varHandler->m_PendingVarRequest = varRequest;
744
745
745 break;
746 break;
746 }
747 }
747 default:
748 default:
748 qCCritical(LOG_VariableController())
749 qCCritical(LOG_VariableController())
749 << QObject::tr("Unknown VariableRequestHandlerState");
750 << QObject::tr("Unknown VariableRequestHandlerState");
750 }
751 }
751 }
752 }
752
753
753 std::shared_ptr<Variable>
754 std::shared_ptr<Variable>
754 VariableController::VariableControllerPrivate::findVariable(QUuid vIdentifier)
755 VariableController::VariableControllerPrivate::findVariable(QUuid vIdentifier)
755 {
756 {
756 std::shared_ptr<Variable> var;
757 std::shared_ptr<Variable> var;
757 auto findReply = [vIdentifier](const auto &entry) { return vIdentifier == entry.second; };
758 auto findReply = [vIdentifier](const auto &entry) { return vIdentifier == entry.second; };
758
759
759 auto end = m_VariableToIdentifierMap.cend();
760 auto end = m_VariableToIdentifierMap.cend();
760 auto it = std::find_if(m_VariableToIdentifierMap.cbegin(), end, findReply);
761 auto it = std::find_if(m_VariableToIdentifierMap.cbegin(), end, findReply);
761 if (it != end) {
762 if (it != end) {
762 var = it->first;
763 var = it->first;
763 }
764 }
764 else {
765 else {
765 qCCritical(LOG_VariableController())
766 qCCritical(LOG_VariableController())
766 << tr("Impossible to find the variable with the identifier: ") << vIdentifier;
767 << tr("Impossible to find the variable with the identifier: ") << vIdentifier;
767 }
768 }
768
769
769 return var;
770 return var;
770 }
771 }
771
772
772 std::shared_ptr<IDataSeries> VariableController::VariableControllerPrivate::retrieveDataSeries(
773 std::shared_ptr<IDataSeries> VariableController::VariableControllerPrivate::retrieveDataSeries(
773 const QVector<AcquisitionDataPacket> acqDataPacketVector)
774 const QVector<AcquisitionDataPacket> acqDataPacketVector)
774 {
775 {
775 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size")
776 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size")
776 << acqDataPacketVector.size();
777 << acqDataPacketVector.size();
777 std::shared_ptr<IDataSeries> dataSeries;
778 std::shared_ptr<IDataSeries> dataSeries;
778 if (!acqDataPacketVector.isEmpty()) {
779 if (!acqDataPacketVector.isEmpty()) {
779 dataSeries = acqDataPacketVector[0].m_DateSeries;
780 dataSeries = acqDataPacketVector[0].m_DateSeries;
780 for (int i = 1; i < acqDataPacketVector.size(); ++i) {
781 for (int i = 1; i < acqDataPacketVector.size(); ++i) {
781 dataSeries->merge(acqDataPacketVector[i].m_DateSeries.get());
782 dataSeries->merge(acqDataPacketVector[i].m_DateSeries.get());
782 }
783 }
783 }
784 }
784 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size END")
785 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size END")
785 << acqDataPacketVector.size();
786 << acqDataPacketVector.size();
786 return dataSeries;
787 return dataSeries;
787 }
788 }
788
789
789 void VariableController::VariableControllerPrivate::registerProvider(
790 void VariableController::VariableControllerPrivate::registerProvider(
790 std::shared_ptr<IDataProvider> provider)
791 std::shared_ptr<IDataProvider> provider)
791 {
792 {
792 if (m_ProviderSet.find(provider) == m_ProviderSet.end()) {
793 if (m_ProviderSet.find(provider) == m_ProviderSet.end()) {
793 qCDebug(LOG_VariableController()) << tr("Registering of a new provider")
794 qCDebug(LOG_VariableController()) << tr("Registering of a new provider")
794 << provider->objectName();
795 << provider->objectName();
795 m_ProviderSet.insert(provider);
796 m_ProviderSet.insert(provider);
796 connect(provider.get(), &IDataProvider::dataProvided, m_VariableAcquisitionWorker.get(),
797 connect(provider.get(), &IDataProvider::dataProvided, m_VariableAcquisitionWorker.get(),
797 &VariableAcquisitionWorker::onVariableDataAcquired);
798 &VariableAcquisitionWorker::onVariableDataAcquired);
798 connect(provider.get(), &IDataProvider::dataProvidedProgress,
799 connect(provider.get(), &IDataProvider::dataProvidedProgress,
799 m_VariableAcquisitionWorker.get(),
800 m_VariableAcquisitionWorker.get(),
800 &VariableAcquisitionWorker::onVariableRetrieveDataInProgress);
801 &VariableAcquisitionWorker::onVariableRetrieveDataInProgress);
801 connect(provider.get(), &IDataProvider::dataProvidedFailed,
802 connect(provider.get(), &IDataProvider::dataProvidedFailed,
802 m_VariableAcquisitionWorker.get(),
803 m_VariableAcquisitionWorker.get(),
803 &VariableAcquisitionWorker::onVariableAcquisitionFailed);
804 &VariableAcquisitionWorker::onVariableAcquisitionFailed);
804 }
805 }
805 else {
806 else {
806 qCDebug(LOG_VariableController()) << tr("Cannot register provider, it already exists ");
807 qCDebug(LOG_VariableController()) << tr("Cannot register provider, it already exists ");
807 }
808 }
808 }
809 }
809
810
810 QUuid VariableController::VariableControllerPrivate::acceptVariableRequest(
811 QUuid VariableController::VariableControllerPrivate::acceptVariableRequest(
811 QUuid varId, std::shared_ptr<IDataSeries> dataSeries)
812 QUuid varId, std::shared_ptr<IDataSeries> dataSeries)
812 {
813 {
813 auto itVarHandler = m_VarIdToVarRequestHandler.find(varId);
814 auto itVarHandler = m_VarIdToVarRequestHandler.find(varId);
814 if (itVarHandler == m_VarIdToVarRequestHandler.cend()) {
815 if (itVarHandler == m_VarIdToVarRequestHandler.cend()) {
815 return QUuid();
816 return QUuid();
816 }
817 }
817
818
818 auto varHandler = itVarHandler->second.get();
819 auto varHandler = itVarHandler->second.get();
819 if (varHandler->m_State == VariableRequestHandlerState::OFF) {
820 if (varHandler->m_State == VariableRequestHandlerState::OFF) {
820 qCCritical(LOG_VariableController())
821 qCCritical(LOG_VariableController())
821 << tr("acceptVariableRequest impossible on a variable with OFF state");
822 << tr("acceptVariableRequest impossible on a variable with OFF state");
822 }
823 }
823
824
824 varHandler->m_RunningVarRequest.m_DataSeries = dataSeries;
825 varHandler->m_RunningVarRequest.m_DataSeries = dataSeries;
825 varHandler->m_CanUpdate = true;
826 varHandler->m_CanUpdate = true;
826
827
827 // Element traitΓ©, on a dΓ©jΓ  toutes les donnΓ©es necessaires
828 // Element traitΓ©, on a dΓ©jΓ  toutes les donnΓ©es necessaires
828 auto varGroupId = varHandler->m_RunningVarRequest.m_VariableGroupId;
829 auto varGroupId = varHandler->m_RunningVarRequest.m_VariableGroupId;
829 qCDebug(LOG_VariableController()) << "Variable::acceptVariableRequest" << varGroupId
830 qCDebug(LOG_VariableController()) << "Variable::acceptVariableRequest" << varGroupId
830 << m_VarGroupIdToVarIds.size();
831 << m_VarGroupIdToVarIds.size();
831
832
832 return varHandler->m_RunningVarRequest.m_VariableGroupId;
833 return varHandler->m_RunningVarRequest.m_VariableGroupId;
833 }
834 }
834
835
835 void VariableController::VariableControllerPrivate::updateVariables(QUuid varRequestId)
836 void VariableController::VariableControllerPrivate::updateVariables(QUuid varRequestId)
836 {
837 {
837 qCDebug(LOG_VariableController()) << "VariableControllerPrivate::updateVariables"
838 qCDebug(LOG_VariableController()) << "VariableControllerPrivate::updateVariables"
838 << QThread::currentThread()->objectName() << varRequestId;
839 << QThread::currentThread()->objectName() << varRequestId;
839
840
840 auto varGroupIdToVarIdsIt = m_VarGroupIdToVarIds.find(varRequestId);
841 auto varGroupIdToVarIdsIt = m_VarGroupIdToVarIds.find(varRequestId);
841 if (varGroupIdToVarIdsIt == m_VarGroupIdToVarIds.end()) {
842 if (varGroupIdToVarIdsIt == m_VarGroupIdToVarIds.end()) {
842 qCWarning(LOG_VariableController())
843 qCWarning(LOG_VariableController())
843 << tr("Impossible to updateVariables of unknown variables") << varRequestId;
844 << tr("Impossible to updateVariables of unknown variables") << varRequestId;
844 return;
845 return;
845 }
846 }
846
847
847 auto &varIds = varGroupIdToVarIdsIt->second;
848 auto &varIds = varGroupIdToVarIdsIt->second;
848 auto varIdsEnd = varIds.end();
849 auto varIdsEnd = varIds.end();
849 bool processVariableUpdate = true;
850 bool processVariableUpdate = true;
850 qCDebug(LOG_VariableController()) << "VariableControllerPrivate::updateVariables"
851 qCDebug(LOG_VariableController()) << "VariableControllerPrivate::updateVariables"
851 << varRequestId << varIds.size();
852 << varRequestId << varIds.size();
852 for (auto varIdsIt = varIds.begin(); (varIdsIt != varIdsEnd) && processVariableUpdate;
853 for (auto varIdsIt = varIds.begin(); (varIdsIt != varIdsEnd) && processVariableUpdate;
853 ++varIdsIt) {
854 ++varIdsIt) {
854 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
855 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
855 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
856 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
856 processVariableUpdate &= itVarHandler->second->m_CanUpdate;
857 processVariableUpdate &= itVarHandler->second->m_CanUpdate;
857 }
858 }
858 }
859 }
859
860
860 if (processVariableUpdate) {
861 if (processVariableUpdate) {
861 qCDebug(LOG_VariableController()) << "Final update OK for the var request" << varIds.size();
862 qCDebug(LOG_VariableController()) << "Final update OK for the var request" << varIds.size();
862 for (auto varIdsIt = varIds.begin(); varIdsIt != varIdsEnd; ++varIdsIt) {
863 for (auto varIdsIt = varIds.begin(); varIdsIt != varIdsEnd; ++varIdsIt) {
863 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
864 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
864 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
865 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
865 if (auto var = findVariable(*varIdsIt)) {
866 if (auto var = findVariable(*varIdsIt)) {
866 auto &varRequest = itVarHandler->second->m_RunningVarRequest;
867 auto &varRequest = itVarHandler->second->m_RunningVarRequest;
867 var->setRange(varRequest.m_RangeRequested);
868 var->setRange(varRequest.m_RangeRequested);
868 var->setCacheRange(varRequest.m_CacheRangeRequested);
869 var->setCacheRange(varRequest.m_CacheRangeRequested);
869 qCDebug(LOG_VariableController()) << tr("1: onDataProvided")
870 qCDebug(LOG_VariableController()) << tr("1: onDataProvided")
870 << varRequest.m_RangeRequested
871 << varRequest.m_RangeRequested
871 << varRequest.m_CacheRangeRequested;
872 << varRequest.m_CacheRangeRequested;
872 qCDebug(LOG_VariableController()) << tr("2: onDataProvided var points before")
873 qCDebug(LOG_VariableController()) << tr("2: onDataProvided var points before")
873 << var->nbPoints()
874 << var->nbPoints()
874 << varRequest.m_DataSeries->nbPoints();
875 << varRequest.m_DataSeries->nbPoints();
875 var->mergeDataSeries(varRequest.m_DataSeries);
876 var->mergeDataSeries(varRequest.m_DataSeries);
876 qCDebug(LOG_VariableController()) << tr("3: onDataProvided var points after")
877 qCDebug(LOG_VariableController()) << tr("3: onDataProvided var points after")
877 << var->nbPoints();
878 << var->nbPoints();
878
879
879 emit var->updated();
880 emit var->updated();
880 qCDebug(LOG_VariableController()) << tr("Update OK");
881 qCDebug(LOG_VariableController()) << tr("Update OK");
881 }
882 }
882 else {
883 else {
883 qCCritical(LOG_VariableController())
884 qCCritical(LOG_VariableController())
884 << tr("Impossible to update data to a null variable");
885 << tr("Impossible to update data to a null variable");
885 }
886 }
886 }
887 }
887 }
888 }
888 updateVariableRequest(varRequestId);
889 updateVariableRequest(varRequestId);
889
890
890 // cleaning varRequestId
891 // cleaning varRequestId
891 qCDebug(LOG_VariableController()) << tr("m_VarGroupIdToVarIds erase") << varRequestId;
892 qCDebug(LOG_VariableController()) << tr("m_VarGroupIdToVarIds erase") << varRequestId;
892 m_VarGroupIdToVarIds.erase(varRequestId);
893 m_VarGroupIdToVarIds.erase(varRequestId);
893 if (m_VarGroupIdToVarIds.empty()) {
894 if (m_VarGroupIdToVarIds.empty()) {
894 emit q->acquisitionFinished();
895 emit q->acquisitionFinished();
895 }
896 }
896 }
897 }
897 }
898 }
898
899
899
900
900 void VariableController::VariableControllerPrivate::updateVariableRequest(QUuid varRequestId)
901 void VariableController::VariableControllerPrivate::updateVariableRequest(QUuid varRequestId)
901 {
902 {
902 auto varGroupIdToVarIdsIt = m_VarGroupIdToVarIds.find(varRequestId);
903 auto varGroupIdToVarIdsIt = m_VarGroupIdToVarIds.find(varRequestId);
903 if (varGroupIdToVarIdsIt == m_VarGroupIdToVarIds.end()) {
904 if (varGroupIdToVarIdsIt == m_VarGroupIdToVarIds.end()) {
904 qCCritical(LOG_VariableController()) << QObject::tr(
905 qCCritical(LOG_VariableController()) << QObject::tr(
905 "Impossible to updateVariableRequest since varGroupdId isn't here anymore");
906 "Impossible to updateVariableRequest since varGroupdId isn't here anymore");
906
907
907 return;
908 return;
908 }
909 }
909
910
910 auto &varIds = varGroupIdToVarIdsIt->second;
911 auto &varIds = varGroupIdToVarIdsIt->second;
911 auto varIdsEnd = varIds.end();
912 auto varIdsEnd = varIds.end();
912 for (auto varIdsIt = varIds.begin(); (varIdsIt != varIdsEnd); ++varIdsIt) {
913 for (auto varIdsIt = varIds.begin(); (varIdsIt != varIdsEnd); ++varIdsIt) {
913 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
914 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
914 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
915 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
915
916
916 auto varHandler = itVarHandler->second.get();
917 auto varHandler = itVarHandler->second.get();
917 varHandler->m_CanUpdate = false;
918 varHandler->m_CanUpdate = false;
918
919
919
920
920 switch (varHandler->m_State) {
921 switch (varHandler->m_State) {
921 case VariableRequestHandlerState::OFF: {
922 case VariableRequestHandlerState::OFF: {
922 qCCritical(LOG_VariableController())
923 qCCritical(LOG_VariableController())
923 << QObject::tr("Impossible to update a variable with handler in OFF state");
924 << QObject::tr("Impossible to update a variable with handler in OFF state");
924 } break;
925 } break;
925 case VariableRequestHandlerState::RUNNING: {
926 case VariableRequestHandlerState::RUNNING: {
926 varHandler->m_State = VariableRequestHandlerState::OFF;
927 varHandler->m_State = VariableRequestHandlerState::OFF;
927 varHandler->m_RunningVarRequest = VariableRequest{};
928 varHandler->m_RunningVarRequest = VariableRequest{};
928 break;
929 break;
929 }
930 }
930 case VariableRequestHandlerState::PENDING: {
931 case VariableRequestHandlerState::PENDING: {
931 varHandler->m_State = VariableRequestHandlerState::RUNNING;
932 varHandler->m_State = VariableRequestHandlerState::RUNNING;
932 varHandler->m_RunningVarRequest = varHandler->m_PendingVarRequest;
933 varHandler->m_RunningVarRequest = varHandler->m_PendingVarRequest;
933 varHandler->m_PendingVarRequest = VariableRequest{};
934 varHandler->m_PendingVarRequest = VariableRequest{};
934 auto var = findVariable(itVarHandler->first);
935 auto var = findVariable(itVarHandler->first);
935 executeVarRequest(var, varHandler->m_RunningVarRequest);
936 executeVarRequest(var, varHandler->m_RunningVarRequest);
937 updateVariables(varHandler->m_RunningVarRequest.m_VariableGroupId);
936 break;
938 break;
937 }
939 }
938 default:
940 default:
939 qCCritical(LOG_VariableController())
941 qCCritical(LOG_VariableController())
940 << QObject::tr("Unknown VariableRequestHandlerState");
942 << QObject::tr("Unknown VariableRequestHandlerState");
941 }
943 }
942 }
944 }
943 }
945 }
944 }
946 }
945
947
946
948
947 void VariableController::VariableControllerPrivate::cancelVariableRequest(QUuid varRequestId)
949 void VariableController::VariableControllerPrivate::cancelVariableRequest(QUuid varRequestId)
948 {
950 {
949 qCDebug(LOG_VariableController()) << tr("cancelVariableRequest") << varRequestId;
951 qCDebug(LOG_VariableController()) << tr("cancelVariableRequest") << varRequestId;
950
952
951 auto varGroupIdToVarIdsIt = m_VarGroupIdToVarIds.find(varRequestId);
953 auto varGroupIdToVarIdsIt = m_VarGroupIdToVarIds.find(varRequestId);
952 if (varGroupIdToVarIdsIt == m_VarGroupIdToVarIds.end()) {
954 if (varGroupIdToVarIdsIt == m_VarGroupIdToVarIds.end()) {
953 qCCritical(LOG_VariableController())
955 qCCritical(LOG_VariableController())
954 << tr("Impossible to cancelVariableRequest for unknown varGroupdId") << varRequestId;
956 << tr("Impossible to cancelVariableRequest for unknown varGroupdId") << varRequestId;
955 return;
957 return;
956 }
958 }
957
959
958 auto &varIds = varGroupIdToVarIdsIt->second;
960 auto &varIds = varGroupIdToVarIdsIt->second;
959 auto varIdsEnd = varIds.end();
961 auto varIdsEnd = varIds.end();
960 for (auto varIdsIt = varIds.begin(); (varIdsIt != varIdsEnd); ++varIdsIt) {
962 for (auto varIdsIt = varIds.begin(); (varIdsIt != varIdsEnd); ++varIdsIt) {
961 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
963 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
962 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
964 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
963
965
964 auto varHandler = itVarHandler->second.get();
966 auto varHandler = itVarHandler->second.get();
965 varHandler->m_VarId = QUuid{};
967 varHandler->m_VarId = QUuid{};
966 switch (varHandler->m_State) {
968 switch (varHandler->m_State) {
967 case VariableRequestHandlerState::OFF: {
969 case VariableRequestHandlerState::OFF: {
968 qCWarning(LOG_VariableController())
970 qCWarning(LOG_VariableController())
969 << QObject::tr("Impossible to cancel a variable with no running request");
971 << QObject::tr("Impossible to cancel a variable with no running request");
970 break;
972 break;
971 }
973 }
972 case VariableRequestHandlerState::RUNNING: {
974 case VariableRequestHandlerState::RUNNING: {
973
975
974 if (varHandler->m_RunningVarRequest.m_VariableGroupId == varRequestId) {
976 if (varHandler->m_RunningVarRequest.m_VariableGroupId == varRequestId) {
975 auto var = findVariable(itVarHandler->first);
977 auto var = findVariable(itVarHandler->first);
976 auto varProvider = m_VariableToProviderMap.at(var);
978 auto varProvider = m_VariableToProviderMap.at(var);
977 if (varProvider != nullptr) {
979 if (varProvider != nullptr) {
978 m_VariableAcquisitionWorker->abortProgressRequested(
980 m_VariableAcquisitionWorker->abortProgressRequested(
979 itVarHandler->first);
981 itVarHandler->first);
980 }
982 }
981 m_VariableModel->setDataProgress(var, 0.0);
983 m_VariableModel->setDataProgress(var, 0.0);
982 varHandler->m_CanUpdate = false;
984 varHandler->m_CanUpdate = false;
983 varHandler->m_State = VariableRequestHandlerState::OFF;
985 varHandler->m_State = VariableRequestHandlerState::OFF;
984 varHandler->m_RunningVarRequest = VariableRequest{};
986 varHandler->m_RunningVarRequest = VariableRequest{};
985 }
987 }
986 else {
988 else {
987 // TODO: log Impossible to cancel the running variable request beacause its
989 // TODO: log Impossible to cancel the running variable request beacause its
988 // varRequestId isn't not the canceled one
990 // varRequestId isn't not the canceled one
989 }
991 }
990 break;
992 break;
991 }
993 }
992 case VariableRequestHandlerState::PENDING: {
994 case VariableRequestHandlerState::PENDING: {
993 if (varHandler->m_RunningVarRequest.m_VariableGroupId == varRequestId) {
995 if (varHandler->m_RunningVarRequest.m_VariableGroupId == varRequestId) {
994 auto var = findVariable(itVarHandler->first);
996 auto var = findVariable(itVarHandler->first);
995 auto varProvider = m_VariableToProviderMap.at(var);
997 auto varProvider = m_VariableToProviderMap.at(var);
996 if (varProvider != nullptr) {
998 if (varProvider != nullptr) {
997 m_VariableAcquisitionWorker->abortProgressRequested(
999 m_VariableAcquisitionWorker->abortProgressRequested(
998 itVarHandler->first);
1000 itVarHandler->first);
999 }
1001 }
1000 m_VariableModel->setDataProgress(var, 0.0);
1002 m_VariableModel->setDataProgress(var, 0.0);
1001 varHandler->m_CanUpdate = false;
1003 varHandler->m_CanUpdate = false;
1002 varHandler->m_State = VariableRequestHandlerState::RUNNING;
1004 varHandler->m_State = VariableRequestHandlerState::RUNNING;
1003 varHandler->m_RunningVarRequest = varHandler->m_PendingVarRequest;
1005 varHandler->m_RunningVarRequest = varHandler->m_PendingVarRequest;
1004 varHandler->m_PendingVarRequest = VariableRequest{};
1006 varHandler->m_PendingVarRequest = VariableRequest{};
1005 executeVarRequest(var, varHandler->m_RunningVarRequest);
1007 executeVarRequest(var, varHandler->m_RunningVarRequest);
1006 }
1008 }
1007 else if (varHandler->m_PendingVarRequest.m_VariableGroupId == varRequestId) {
1009 else if (varHandler->m_PendingVarRequest.m_VariableGroupId == varRequestId) {
1008 varHandler->m_State = VariableRequestHandlerState::RUNNING;
1010 varHandler->m_State = VariableRequestHandlerState::RUNNING;
1009 varHandler->m_PendingVarRequest = VariableRequest{};
1011 varHandler->m_PendingVarRequest = VariableRequest{};
1010 }
1012 }
1011 else {
1013 else {
1012 // TODO: log Impossible to cancel the variable request beacause its
1014 // TODO: log Impossible to cancel the variable request beacause its
1013 // varRequestId isn't not the canceled one
1015 // varRequestId isn't not the canceled one
1014 }
1016 }
1015 break;
1017 break;
1016 }
1018 }
1017 default:
1019 default:
1018 qCCritical(LOG_VariableController())
1020 qCCritical(LOG_VariableController())
1019 << QObject::tr("Unknown VariableRequestHandlerState");
1021 << QObject::tr("Unknown VariableRequestHandlerState");
1020 }
1022 }
1021 }
1023 }
1022 }
1024 }
1023 qCDebug(LOG_VariableController()) << tr("cancelVariableRequest: erase") << varRequestId;
1025 qCDebug(LOG_VariableController()) << tr("cancelVariableRequest: erase") << varRequestId;
1024 m_VarGroupIdToVarIds.erase(varRequestId);
1026 m_VarGroupIdToVarIds.erase(varRequestId);
1025 if (m_VarGroupIdToVarIds.empty()) {
1027 if (m_VarGroupIdToVarIds.empty()) {
1026 emit q->acquisitionFinished();
1028 emit q->acquisitionFinished();
1027 }
1029 }
1028 }
1030 }
1029
1031
1030 void VariableController::VariableControllerPrivate::executeVarRequest(std::shared_ptr<Variable> var,
1032 void VariableController::VariableControllerPrivate::executeVarRequest(std::shared_ptr<Variable> var,
1031 VariableRequest &varRequest)
1033 VariableRequest &varRequest)
1032 {
1034 {
1033 qCDebug(LOG_VariableController()) << tr("TORM: executeVarRequest");
1035 qCDebug(LOG_VariableController()) << tr("TORM: executeVarRequest");
1034
1036
1035 auto varId = m_VariableToIdentifierMap.at(var);
1037 auto varIdIt = m_VariableToIdentifierMap.find(var);
1038 if (varIdIt == m_VariableToIdentifierMap.cend()) {
1039 qCWarning(LOG_VariableController()) << tr(
1040 "Can't execute request of a variable that is not registered (may has been deleted)");
1041 return;
1042 }
1043
1044 auto varId = varIdIt->second;
1036
1045
1037 auto varCacheRange = var->cacheRange();
1046 auto varCacheRange = var->cacheRange();
1038 auto varCacheRangeRequested = varRequest.m_CacheRangeRequested;
1047 auto varCacheRangeRequested = varRequest.m_CacheRangeRequested;
1039 auto notInCacheRangeList
1048 auto notInCacheRangeList
1040 = Variable::provideNotInCacheRangeList(varCacheRange, varCacheRangeRequested);
1049 = Variable::provideNotInCacheRangeList(varCacheRange, varCacheRangeRequested);
1041 auto inCacheRangeList
1050 auto inCacheRangeList
1042 = Variable::provideInCacheRangeList(varCacheRange, varCacheRangeRequested);
1051 = Variable::provideInCacheRangeList(varCacheRange, varCacheRangeRequested);
1043
1052
1044 if (!notInCacheRangeList.empty()) {
1053 if (!notInCacheRangeList.empty()) {
1045
1054
1046 auto varProvider = m_VariableToProviderMap.at(var);
1055 auto varProvider = m_VariableToProviderMap.at(var);
1047 if (varProvider != nullptr) {
1056 if (varProvider != nullptr) {
1048 qCDebug(LOG_VariableController()) << "executeVarRequest " << varRequest.m_RangeRequested
1057 qCDebug(LOG_VariableController()) << "executeVarRequest " << varRequest.m_RangeRequested
1049 << varRequest.m_CacheRangeRequested;
1058 << varRequest.m_CacheRangeRequested;
1050 m_VariableAcquisitionWorker->pushVariableRequest(
1059 m_VariableAcquisitionWorker->pushVariableRequest(
1051 varRequest.m_VariableGroupId, varId, varRequest.m_RangeRequested,
1060 varRequest.m_VariableGroupId, varId, varRequest.m_RangeRequested,
1052 varRequest.m_CacheRangeRequested,
1061 varRequest.m_CacheRangeRequested,
1053 DataProviderParameters{std::move(notInCacheRangeList), var->metadata()},
1062 DataProviderParameters{std::move(notInCacheRangeList), var->metadata()},
1054 varProvider);
1063 varProvider);
1055 }
1064 }
1056 else {
1065 else {
1057 qCCritical(LOG_VariableController())
1066 qCCritical(LOG_VariableController())
1058 << "Impossible to provide data with a null provider";
1067 << "Impossible to provide data with a null provider";
1059 }
1068 }
1060
1069
1061 if (!inCacheRangeList.empty()) {
1070 if (!inCacheRangeList.empty()) {
1062 emit q->updateVarDisplaying(var, inCacheRangeList.first());
1071 emit q->updateVarDisplaying(var, inCacheRangeList.first());
1063 }
1072 }
1064 }
1073 }
1065 else {
1074 else {
1066 acceptVariableRequest(varId,
1075 acceptVariableRequest(varId,
1067 var->dataSeries()->subDataSeries(varRequest.m_CacheRangeRequested));
1076 var->dataSeries()->subDataSeries(varRequest.m_CacheRangeRequested));
1068 }
1077 }
1069 }
1078 }
1079
1080 template <typename VariableIterator>
1081 void VariableController::VariableControllerPrivate::desynchronize(VariableIterator variableIt,
1082 const QUuid &syncGroupId)
1083 {
1084 const auto &variable = variableIt->first;
1085 const auto &variableId = variableIt->second;
1086
1087 // Gets synchronization group
1088 auto groupIt = m_GroupIdToVariableSynchronizationGroupMap.find(syncGroupId);
1089 if (groupIt == m_GroupIdToVariableSynchronizationGroupMap.cend()) {
1090 qCCritical(LOG_VariableController())
1091 << tr("Can't desynchronize variable %1: unknown synchronization group")
1092 .arg(variable->name());
1093 return;
1094 }
1095
1096 // Removes variable from synchronization group
1097 auto synchronizationGroup = groupIt->second;
1098 synchronizationGroup->removeVariableId(variableId);
1099
1100 // Removes link between variable and synchronization group
1101 m_VariableIdGroupIdMap.erase(variableId);
1102 }
@@ -1,141 +1,155
1 #ifndef SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
1 #ifndef SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
2 #define SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
2 #define SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
3
3
4 #include "Visualization/IVisualizationWidget.h"
4 #include "Visualization/IVisualizationWidget.h"
5 #include "Visualization/VisualizationDragWidget.h"
5 #include "Visualization/VisualizationDragWidget.h"
6
6
7 #include <QLoggingCategory>
7 #include <QLoggingCategory>
8 #include <QWidget>
8 #include <QWidget>
9
9
10 #include <memory>
10 #include <memory>
11
11
12 #include <Common/spimpl.h>
12 #include <Common/spimpl.h>
13
13
14 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationGraphWidget)
14 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationGraphWidget)
15
15
16 class QCPRange;
16 class QCPRange;
17 class QCustomPlot;
17 class QCustomPlot;
18 class SqpRange;
18 class SqpRange;
19 class Variable;
19 class Variable;
20 class VisualizationWidget;
20 class VisualizationWidget;
21 class VisualizationZoneWidget;
21 class VisualizationZoneWidget;
22 class VisualizationSelectionZoneItem;
22 class VisualizationSelectionZoneItem;
23
23
24 namespace Ui {
24 namespace Ui {
25 class VisualizationGraphWidget;
25 class VisualizationGraphWidget;
26 } // namespace Ui
26 } // namespace Ui
27
27
28 /// Defines options that can be associated with the graph
29 enum GraphFlag {
30 DisableAll = 0x0, ///< Disables acquisition and synchronization
31 EnableAcquisition = 0x1, ///< When this flag is set, the change of the graph's range leads to
32 /// the acquisition of data
33 EnableSynchronization = 0x2, ///< When this flag is set, the change of the graph's range causes
34 /// the call to the synchronization of the graphs contained in the
35 /// same zone of this graph
36 EnableAll = ~DisableAll ///< Enables acquisition and synchronization
37 };
38
39 Q_DECLARE_FLAGS(GraphFlags, GraphFlag)
40 Q_DECLARE_OPERATORS_FOR_FLAGS(GraphFlags)
41
28 class VisualizationGraphWidget : public VisualizationDragWidget, public IVisualizationWidget {
42 class VisualizationGraphWidget : public VisualizationDragWidget, public IVisualizationWidget {
29 Q_OBJECT
43 Q_OBJECT
30
44
31 friend class QCustomPlotSynchronizer;
45 friend class QCustomPlotSynchronizer;
32 friend class VisualizationGraphRenderingDelegate;
46 friend class VisualizationGraphRenderingDelegate;
33
47
34 public:
48 public:
35 explicit VisualizationGraphWidget(const QString &name = {}, QWidget *parent = 0);
49 explicit VisualizationGraphWidget(const QString &name = {}, QWidget *parent = 0);
36 virtual ~VisualizationGraphWidget();
50 virtual ~VisualizationGraphWidget();
37
51
38 /// Returns the VisualizationZoneWidget which contains the graph or nullptr
52 /// Returns the VisualizationZoneWidget which contains the graph or nullptr
39 VisualizationZoneWidget *parentZoneWidget() const noexcept;
53 VisualizationZoneWidget *parentZoneWidget() const noexcept;
40
54
41 /// Returns the main VisualizationWidget which contains the graph or nullptr
55 /// Returns the main VisualizationWidget which contains the graph or nullptr
42 VisualizationWidget *parentVisualizationWidget() const;
56 VisualizationWidget *parentVisualizationWidget() const;
43
57
44 /// If acquisition isn't enable, requestDataLoading signal cannot be emit
58 /// Sets graph options
45 void enableAcquisition(bool enable);
59 void setFlags(GraphFlags flags);
46
60
47 void addVariable(std::shared_ptr<Variable> variable, SqpRange range);
61 void addVariable(std::shared_ptr<Variable> variable, SqpRange range);
48
62
49 /// Removes a variable from the graph
63 /// Removes a variable from the graph
50 void removeVariable(std::shared_ptr<Variable> variable) noexcept;
64 void removeVariable(std::shared_ptr<Variable> variable) noexcept;
51
65
52 /// Returns the list of all variables used in the graph
66 /// Returns the list of all variables used in the graph
53 QList<std::shared_ptr<Variable> > variables() const;
67 QList<std::shared_ptr<Variable> > variables() const;
54
68
55 /// Sets the y-axis range based on the data of a variable
69 /// Sets the y-axis range based on the data of a variable
56 void setYRange(std::shared_ptr<Variable> variable);
70 void setYRange(std::shared_ptr<Variable> variable);
57 SqpRange graphRange() const noexcept;
71 SqpRange graphRange() const noexcept;
58 void setGraphRange(const SqpRange &range);
72 void setGraphRange(const SqpRange &range);
59
73
60 // Zones
74 // Zones
61 /// Returns the ranges of all the selection zones on the graph
75 /// Returns the ranges of all the selection zones on the graph
62 QVector<SqpRange> selectionZoneRanges() const;
76 QVector<SqpRange> selectionZoneRanges() const;
63 /// Adds new selection zones in the graph
77 /// Adds new selection zones in the graph
64 void addSelectionZones(const QVector<SqpRange> &ranges);
78 void addSelectionZones(const QVector<SqpRange> &ranges);
65 /// Removes the specified selection zone
79 /// Removes the specified selection zone
66 void removeSelectionZone(VisualizationSelectionZoneItem *selectionZone);
80 void removeSelectionZone(VisualizationSelectionZoneItem *selectionZone);
67
81
68 /// Undo the last zoom done with a zoom box
82 /// Undo the last zoom done with a zoom box
69 void undoZoom();
83 void undoZoom();
70
84
71 // IVisualizationWidget interface
85 // IVisualizationWidget interface
72 void accept(IVisualizationWidgetVisitor *visitor) override;
86 void accept(IVisualizationWidgetVisitor *visitor) override;
73 bool canDrop(const Variable &variable) const override;
87 bool canDrop(const Variable &variable) const override;
74 bool contains(const Variable &variable) const override;
88 bool contains(const Variable &variable) const override;
75 QString name() const override;
89 QString name() const override;
76
90
77 // VisualisationDragWidget
91 // VisualisationDragWidget
78 QMimeData *mimeData(const QPoint &position) const override;
92 QMimeData *mimeData(const QPoint &position) const override;
79 QPixmap customDragPixmap(const QPoint &dragPosition) override;
93 QPixmap customDragPixmap(const QPoint &dragPosition) override;
80 bool isDragAllowed() const override;
94 bool isDragAllowed() const override;
81 void highlightForMerge(bool highlighted) override;
95 void highlightForMerge(bool highlighted) override;
82
96
83 // Cursors
97 // Cursors
84 /// Adds or moves the vertical cursor at the specified value on the x-axis
98 /// Adds or moves the vertical cursor at the specified value on the x-axis
85 void addVerticalCursor(double time);
99 void addVerticalCursor(double time);
86 /// Adds or moves the vertical cursor at the specified value on the x-axis
100 /// Adds or moves the vertical cursor at the specified value on the x-axis
87 void addVerticalCursorAtViewportPosition(double position);
101 void addVerticalCursorAtViewportPosition(double position);
88 void removeVerticalCursor();
102 void removeVerticalCursor();
89 /// Adds or moves the vertical cursor at the specified value on the y-axis
103 /// Adds or moves the vertical cursor at the specified value on the y-axis
90 void addHorizontalCursor(double value);
104 void addHorizontalCursor(double value);
91 /// Adds or moves the vertical cursor at the specified value on the y-axis
105 /// Adds or moves the vertical cursor at the specified value on the y-axis
92 void addHorizontalCursorAtViewportPosition(double position);
106 void addHorizontalCursorAtViewportPosition(double position);
93 void removeHorizontalCursor();
107 void removeHorizontalCursor();
94
108
95 signals:
109 signals:
96 void synchronize(const SqpRange &range, const SqpRange &oldRange);
110 void synchronize(const SqpRange &range, const SqpRange &oldRange);
97 void requestDataLoading(QVector<std::shared_ptr<Variable> > variable, const SqpRange &range,
111 void requestDataLoading(QVector<std::shared_ptr<Variable> > variable, const SqpRange &range,
98 bool synchronise);
112 bool synchronise);
99
113
100 /// Signal emitted when the variable is about to be removed from the graph
114 /// Signal emitted when the variable is about to be removed from the graph
101 void variableAboutToBeRemoved(std::shared_ptr<Variable> var);
115 void variableAboutToBeRemoved(std::shared_ptr<Variable> var);
102 /// Signal emitted when the variable has been added to the graph
116 /// Signal emitted when the variable has been added to the graph
103 void variableAdded(std::shared_ptr<Variable> var);
117 void variableAdded(std::shared_ptr<Variable> var);
104
118
105 protected:
119 protected:
106 void closeEvent(QCloseEvent *event) override;
120 void closeEvent(QCloseEvent *event) override;
107 void enterEvent(QEvent *event) override;
121 void enterEvent(QEvent *event) override;
108 void leaveEvent(QEvent *event) override;
122 void leaveEvent(QEvent *event) override;
109
123
110 QCustomPlot &plot() const noexcept;
124 QCustomPlot &plot() const noexcept;
111
125
112 private:
126 private:
113 Ui::VisualizationGraphWidget *ui;
127 Ui::VisualizationGraphWidget *ui;
114
128
115 class VisualizationGraphWidgetPrivate;
129 class VisualizationGraphWidgetPrivate;
116 spimpl::unique_impl_ptr<VisualizationGraphWidgetPrivate> impl;
130 spimpl::unique_impl_ptr<VisualizationGraphWidgetPrivate> impl;
117
131
118 private slots:
132 private slots:
119 /// Slot called when right clicking on the graph (displays a menu)
133 /// Slot called when right clicking on the graph (displays a menu)
120 void onGraphMenuRequested(const QPoint &pos) noexcept;
134 void onGraphMenuRequested(const QPoint &pos) noexcept;
121
135
122 /// Rescale the X axe to range parameter
136 /// Rescale the X axe to range parameter
123 void onRangeChanged(const QCPRange &t1, const QCPRange &t2);
137 void onRangeChanged(const QCPRange &t1, const QCPRange &t2);
124
138
125 /// Slot called when a mouse double click was made
139 /// Slot called when a mouse double click was made
126 void onMouseDoubleClick(QMouseEvent *event) noexcept;
140 void onMouseDoubleClick(QMouseEvent *event) noexcept;
127 /// Slot called when a mouse move was made
141 /// Slot called when a mouse move was made
128 void onMouseMove(QMouseEvent *event) noexcept;
142 void onMouseMove(QMouseEvent *event) noexcept;
129 /// Slot called when a mouse wheel was made, to perform some processing before the zoom is done
143 /// Slot called when a mouse wheel was made, to perform some processing before the zoom is done
130 void onMouseWheel(QWheelEvent *event) noexcept;
144 void onMouseWheel(QWheelEvent *event) noexcept;
131 /// Slot called when a mouse press was made, to activate the calibration of a graph
145 /// Slot called when a mouse press was made, to activate the calibration of a graph
132 void onMousePress(QMouseEvent *event) noexcept;
146 void onMousePress(QMouseEvent *event) noexcept;
133 /// Slot called when a mouse release was made, to deactivate the calibration of a graph
147 /// Slot called when a mouse release was made, to deactivate the calibration of a graph
134 void onMouseRelease(QMouseEvent *event) noexcept;
148 void onMouseRelease(QMouseEvent *event) noexcept;
135
149
136 void onDataCacheVariableUpdated();
150 void onDataCacheVariableUpdated();
137
151
138 void onUpdateVarDisplaying(std::shared_ptr<Variable> variable, const SqpRange &range);
152 void onUpdateVarDisplaying(std::shared_ptr<Variable> variable, const SqpRange &range);
139 };
153 };
140
154
141 #endif // SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
155 #endif // SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
@@ -1,1003 +1,1004
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 <Common/MimeTypesDef.h>
15 #include <Common/MimeTypesDef.h>
16 #include <Data/ArrayData.h>
16 #include <Data/ArrayData.h>
17 #include <Data/IDataSeries.h>
17 #include <Data/IDataSeries.h>
18 #include <Data/SpectrogramSeries.h>
18 #include <Data/SpectrogramSeries.h>
19 #include <DragAndDrop/DragDropGuiController.h>
19 #include <DragAndDrop/DragDropGuiController.h>
20 #include <Settings/SqpSettingsDefs.h>
20 #include <Settings/SqpSettingsDefs.h>
21 #include <SqpApplication.h>
21 #include <SqpApplication.h>
22 #include <Time/TimeController.h>
22 #include <Time/TimeController.h>
23 #include <Variable/Variable.h>
23 #include <Variable/Variable.h>
24 #include <Variable/VariableController.h>
24 #include <Variable/VariableController.h>
25
25
26 #include <unordered_map>
26 #include <unordered_map>
27
27
28 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
28 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
29
29
30 namespace {
30 namespace {
31
31
32 /// Key pressed to enable drag&drop in all modes
32 /// Key pressed to enable drag&drop in all modes
33 const auto DRAG_DROP_MODIFIER = Qt::AltModifier;
33 const auto DRAG_DROP_MODIFIER = Qt::AltModifier;
34
34
35 /// Key pressed to enable zoom on horizontal axis
35 /// Key pressed to enable zoom on horizontal axis
36 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::ControlModifier;
36 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::ControlModifier;
37
37
38 /// Key pressed to enable zoom on vertical axis
38 /// Key pressed to enable zoom on vertical axis
39 const auto VERTICAL_ZOOM_MODIFIER = Qt::ShiftModifier;
39 const auto VERTICAL_ZOOM_MODIFIER = Qt::ShiftModifier;
40
40
41 /// Speed of a step of a wheel event for a pan, in percentage of the axis range
41 /// Speed of a step of a wheel event for a pan, in percentage of the axis range
42 const auto PAN_SPEED = 5;
42 const auto PAN_SPEED = 5;
43
43
44 /// Key pressed to enable a calibration pan
44 /// Key pressed to enable a calibration pan
45 const auto VERTICAL_PAN_MODIFIER = Qt::AltModifier;
45 const auto VERTICAL_PAN_MODIFIER = Qt::AltModifier;
46
46
47 /// Key pressed to enable multi selection of selection zones
47 /// Key pressed to enable multi selection of selection zones
48 const auto MULTI_ZONE_SELECTION_MODIFIER = Qt::ControlModifier;
48 const auto MULTI_ZONE_SELECTION_MODIFIER = Qt::ControlModifier;
49
49
50 /// Minimum size for the zoom box, in percentage of the axis range
50 /// Minimum size for the zoom box, in percentage of the axis range
51 const auto ZOOM_BOX_MIN_SIZE = 0.8;
51 const auto ZOOM_BOX_MIN_SIZE = 0.8;
52
52
53 /// Format of the dates appearing in the label of a cursor
53 /// Format of the dates appearing in the label of a cursor
54 const auto CURSOR_LABELS_DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd\nhh:mm:ss:zzz");
54 const auto CURSOR_LABELS_DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd\nhh:mm:ss:zzz");
55
55
56 } // namespace
56 } // namespace
57
57
58 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
58 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
59
59
60 explicit VisualizationGraphWidgetPrivate(const QString &name)
60 explicit VisualizationGraphWidgetPrivate(const QString &name)
61 : m_Name{name},
61 : m_Name{name},
62 m_DoAcquisition{true},
62 m_Flags{GraphFlag::EnableAll},
63 m_IsCalibration{false},
63 m_IsCalibration{false},
64 m_RenderingDelegate{nullptr}
64 m_RenderingDelegate{nullptr}
65 {
65 {
66 }
66 }
67
67
68 void updateData(PlottablesMap &plottables, std::shared_ptr<IDataSeries> dataSeries,
68 void updateData(PlottablesMap &plottables, std::shared_ptr<IDataSeries> dataSeries,
69 const SqpRange &range)
69 const SqpRange &range)
70 {
70 {
71 VisualizationGraphHelper::updateData(plottables, dataSeries, range);
71 VisualizationGraphHelper::updateData(plottables, dataSeries, range);
72
72
73 // Prevents that data has changed to update rendering
73 // Prevents that data has changed to update rendering
74 m_RenderingDelegate->onPlotUpdated();
74 m_RenderingDelegate->onPlotUpdated();
75 }
75 }
76
76
77 QString m_Name;
77 QString m_Name;
78 // 1 variable -> n qcpplot
78 // 1 variable -> n qcpplot
79 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
79 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
80 bool m_DoAcquisition;
80 GraphFlags m_Flags;
81 bool m_IsCalibration;
81 bool m_IsCalibration;
82 /// Delegate used to attach rendering features to the plot
82 /// Delegate used to attach rendering features to the plot
83 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
83 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
84
84
85 QCPItemRect *m_DrawingZoomRect = nullptr;
85 QCPItemRect *m_DrawingZoomRect = nullptr;
86 QStack<QPair<QCPRange, QCPRange> > m_ZoomStack;
86 QStack<QPair<QCPRange, QCPRange> > m_ZoomStack;
87
87
88 std::unique_ptr<VisualizationCursorItem> m_HorizontalCursor = nullptr;
88 std::unique_ptr<VisualizationCursorItem> m_HorizontalCursor = nullptr;
89 std::unique_ptr<VisualizationCursorItem> m_VerticalCursor = nullptr;
89 std::unique_ptr<VisualizationCursorItem> m_VerticalCursor = nullptr;
90
90
91 VisualizationSelectionZoneItem *m_DrawingZone = nullptr;
91 VisualizationSelectionZoneItem *m_DrawingZone = nullptr;
92 VisualizationSelectionZoneItem *m_HoveredZone = nullptr;
92 VisualizationSelectionZoneItem *m_HoveredZone = nullptr;
93 QVector<VisualizationSelectionZoneItem *> m_SelectionZones;
93 QVector<VisualizationSelectionZoneItem *> m_SelectionZones;
94
94
95 bool m_HasMovedMouse = false; // Indicates if the mouse moved in a releaseMouse even
95 bool m_HasMovedMouse = false; // Indicates if the mouse moved in a releaseMouse even
96
96
97 void startDrawingRect(const QPoint &pos, QCustomPlot &plot)
97 void startDrawingRect(const QPoint &pos, QCustomPlot &plot)
98 {
98 {
99 removeDrawingRect(plot);
99 removeDrawingRect(plot);
100
100
101 auto axisPos = posToAxisPos(pos, plot);
101 auto axisPos = posToAxisPos(pos, plot);
102
102
103 m_DrawingZoomRect = new QCPItemRect{&plot};
103 m_DrawingZoomRect = new QCPItemRect{&plot};
104 QPen p;
104 QPen p;
105 p.setWidth(2);
105 p.setWidth(2);
106 m_DrawingZoomRect->setPen(p);
106 m_DrawingZoomRect->setPen(p);
107
107
108 m_DrawingZoomRect->topLeft->setCoords(axisPos);
108 m_DrawingZoomRect->topLeft->setCoords(axisPos);
109 m_DrawingZoomRect->bottomRight->setCoords(axisPos);
109 m_DrawingZoomRect->bottomRight->setCoords(axisPos);
110 }
110 }
111
111
112 void removeDrawingRect(QCustomPlot &plot)
112 void removeDrawingRect(QCustomPlot &plot)
113 {
113 {
114 if (m_DrawingZoomRect) {
114 if (m_DrawingZoomRect) {
115 plot.removeItem(m_DrawingZoomRect); // the item is deleted by QCustomPlot
115 plot.removeItem(m_DrawingZoomRect); // the item is deleted by QCustomPlot
116 m_DrawingZoomRect = nullptr;
116 m_DrawingZoomRect = nullptr;
117 plot.replot(QCustomPlot::rpQueuedReplot);
117 plot.replot(QCustomPlot::rpQueuedReplot);
118 }
118 }
119 }
119 }
120
120
121 void startDrawingZone(const QPoint &pos, VisualizationGraphWidget *graph)
121 void startDrawingZone(const QPoint &pos, VisualizationGraphWidget *graph)
122 {
122 {
123 endDrawingZone(graph);
123 endDrawingZone(graph);
124
124
125 auto axisPos = posToAxisPos(pos, graph->plot());
125 auto axisPos = posToAxisPos(pos, graph->plot());
126
126
127 m_DrawingZone = new VisualizationSelectionZoneItem{&graph->plot()};
127 m_DrawingZone = new VisualizationSelectionZoneItem{&graph->plot()};
128 m_DrawingZone->setRange(axisPos.x(), axisPos.x());
128 m_DrawingZone->setRange(axisPos.x(), axisPos.x());
129 m_DrawingZone->setEditionEnabled(false);
129 m_DrawingZone->setEditionEnabled(false);
130 }
130 }
131
131
132 void endDrawingZone(VisualizationGraphWidget *graph)
132 void endDrawingZone(VisualizationGraphWidget *graph)
133 {
133 {
134 if (m_DrawingZone) {
134 if (m_DrawingZone) {
135 auto drawingZoneRange = m_DrawingZone->range();
135 auto drawingZoneRange = m_DrawingZone->range();
136 if (qAbs(drawingZoneRange.m_TEnd - drawingZoneRange.m_TStart) > 0) {
136 if (qAbs(drawingZoneRange.m_TEnd - drawingZoneRange.m_TStart) > 0) {
137 m_DrawingZone->setEditionEnabled(true);
137 m_DrawingZone->setEditionEnabled(true);
138 addSelectionZone(m_DrawingZone);
138 addSelectionZone(m_DrawingZone);
139 }
139 }
140 else {
140 else {
141 graph->plot().removeItem(m_DrawingZone); // the item is deleted by QCustomPlot
141 graph->plot().removeItem(m_DrawingZone); // the item is deleted by QCustomPlot
142 }
142 }
143
143
144 graph->plot().replot(QCustomPlot::rpQueuedReplot);
144 graph->plot().replot(QCustomPlot::rpQueuedReplot);
145 m_DrawingZone = nullptr;
145 m_DrawingZone = nullptr;
146 }
146 }
147 }
147 }
148
148
149 void setSelectionZonesEditionEnabled(bool value)
149 void setSelectionZonesEditionEnabled(bool value)
150 {
150 {
151 for (auto s : m_SelectionZones) {
151 for (auto s : m_SelectionZones) {
152 s->setEditionEnabled(value);
152 s->setEditionEnabled(value);
153 }
153 }
154 }
154 }
155
155
156 void addSelectionZone(VisualizationSelectionZoneItem *zone) { m_SelectionZones << zone; }
156 void addSelectionZone(VisualizationSelectionZoneItem *zone) { m_SelectionZones << zone; }
157
157
158 VisualizationSelectionZoneItem *selectionZoneAt(const QPoint &pos,
158 VisualizationSelectionZoneItem *selectionZoneAt(const QPoint &pos,
159 const QCustomPlot &plot) const
159 const QCustomPlot &plot) const
160 {
160 {
161 VisualizationSelectionZoneItem *selectionZoneItemUnderCursor = nullptr;
161 VisualizationSelectionZoneItem *selectionZoneItemUnderCursor = nullptr;
162 auto minDistanceToZone = -1;
162 auto minDistanceToZone = -1;
163 for (auto zone : m_SelectionZones) {
163 for (auto zone : m_SelectionZones) {
164 auto distanceToZone = zone->selectTest(pos, false);
164 auto distanceToZone = zone->selectTest(pos, false);
165 if ((minDistanceToZone < 0 || distanceToZone <= minDistanceToZone)
165 if ((minDistanceToZone < 0 || distanceToZone <= minDistanceToZone)
166 && distanceToZone >= 0 && distanceToZone < plot.selectionTolerance()) {
166 && distanceToZone >= 0 && distanceToZone < plot.selectionTolerance()) {
167 selectionZoneItemUnderCursor = zone;
167 selectionZoneItemUnderCursor = zone;
168 }
168 }
169 }
169 }
170
170
171 return selectionZoneItemUnderCursor;
171 return selectionZoneItemUnderCursor;
172 }
172 }
173
173
174 QVector<VisualizationSelectionZoneItem *> selectionZonesAt(const QPoint &pos,
174 QVector<VisualizationSelectionZoneItem *> selectionZonesAt(const QPoint &pos,
175 const QCustomPlot &plot) const
175 const QCustomPlot &plot) const
176 {
176 {
177 QVector<VisualizationSelectionZoneItem *> zones;
177 QVector<VisualizationSelectionZoneItem *> zones;
178 for (auto zone : m_SelectionZones) {
178 for (auto zone : m_SelectionZones) {
179 auto distanceToZone = zone->selectTest(pos, false);
179 auto distanceToZone = zone->selectTest(pos, false);
180 if (distanceToZone >= 0 && distanceToZone < plot.selectionTolerance()) {
180 if (distanceToZone >= 0 && distanceToZone < plot.selectionTolerance()) {
181 zones << zone;
181 zones << zone;
182 }
182 }
183 }
183 }
184
184
185 return zones;
185 return zones;
186 }
186 }
187
187
188 void moveSelectionZoneOnTop(VisualizationSelectionZoneItem *zone, QCustomPlot &plot)
188 void moveSelectionZoneOnTop(VisualizationSelectionZoneItem *zone, QCustomPlot &plot)
189 {
189 {
190 if (!m_SelectionZones.isEmpty() && m_SelectionZones.last() != zone) {
190 if (!m_SelectionZones.isEmpty() && m_SelectionZones.last() != zone) {
191 zone->moveToTop();
191 zone->moveToTop();
192 m_SelectionZones.removeAll(zone);
192 m_SelectionZones.removeAll(zone);
193 m_SelectionZones.append(zone);
193 m_SelectionZones.append(zone);
194 }
194 }
195 }
195 }
196
196
197 QPointF posToAxisPos(const QPoint &pos, QCustomPlot &plot) const
197 QPointF posToAxisPos(const QPoint &pos, QCustomPlot &plot) const
198 {
198 {
199 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
199 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
200 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
200 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
201 return QPointF{axisX->pixelToCoord(pos.x()), axisY->pixelToCoord(pos.y())};
201 return QPointF{axisX->pixelToCoord(pos.x()), axisY->pixelToCoord(pos.y())};
202 }
202 }
203
203
204 bool pointIsInAxisRect(const QPointF &axisPoint, QCustomPlot &plot) const
204 bool pointIsInAxisRect(const QPointF &axisPoint, QCustomPlot &plot) const
205 {
205 {
206 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
206 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
207 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
207 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
208 return axisX->range().contains(axisPoint.x()) && axisY->range().contains(axisPoint.y());
208 return axisX->range().contains(axisPoint.x()) && axisY->range().contains(axisPoint.y());
209 }
209 }
210 };
210 };
211
211
212 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
212 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
213 : VisualizationDragWidget{parent},
213 : VisualizationDragWidget{parent},
214 ui{new Ui::VisualizationGraphWidget},
214 ui{new Ui::VisualizationGraphWidget},
215 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
215 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
216 {
216 {
217 ui->setupUi(this);
217 ui->setupUi(this);
218
218
219 // 'Close' options : widget is deleted when closed
219 // 'Close' options : widget is deleted when closed
220 setAttribute(Qt::WA_DeleteOnClose);
220 setAttribute(Qt::WA_DeleteOnClose);
221
221
222 // Set qcpplot properties :
222 // Set qcpplot properties :
223 // - zoom is enabled
223 // - zoom is enabled
224 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
224 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
225 ui->widget->setInteractions(QCP::iRangeZoom);
225 ui->widget->setInteractions(QCP::iRangeZoom);
226 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal | Qt::Vertical);
226 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal | Qt::Vertical);
227
227
228 // The delegate must be initialized after the ui as it uses the plot
228 // The delegate must be initialized after the ui as it uses the plot
229 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
229 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
230
230
231 // Init the cursors
231 // Init the cursors
232 impl->m_HorizontalCursor = std::make_unique<VisualizationCursorItem>(&plot());
232 impl->m_HorizontalCursor = std::make_unique<VisualizationCursorItem>(&plot());
233 impl->m_HorizontalCursor->setOrientation(Qt::Horizontal);
233 impl->m_HorizontalCursor->setOrientation(Qt::Horizontal);
234 impl->m_VerticalCursor = std::make_unique<VisualizationCursorItem>(&plot());
234 impl->m_VerticalCursor = std::make_unique<VisualizationCursorItem>(&plot());
235 impl->m_VerticalCursor->setOrientation(Qt::Vertical);
235 impl->m_VerticalCursor->setOrientation(Qt::Vertical);
236
236
237 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
237 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
238 connect(ui->widget, &QCustomPlot::mouseRelease, this,
238 connect(ui->widget, &QCustomPlot::mouseRelease, this,
239 &VisualizationGraphWidget::onMouseRelease);
239 &VisualizationGraphWidget::onMouseRelease);
240 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
240 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
241 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
241 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
242 connect(ui->widget, &QCustomPlot::mouseDoubleClick, this,
242 connect(ui->widget, &QCustomPlot::mouseDoubleClick, this,
243 &VisualizationGraphWidget::onMouseDoubleClick);
243 &VisualizationGraphWidget::onMouseDoubleClick);
244 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
244 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
245 &QCPAxis::rangeChanged),
245 &QCPAxis::rangeChanged),
246 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
246 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
247
247
248 // Activates menu when right clicking on the graph
248 // Activates menu when right clicking on the graph
249 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
249 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
250 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
250 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
251 &VisualizationGraphWidget::onGraphMenuRequested);
251 &VisualizationGraphWidget::onGraphMenuRequested);
252
252
253 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
253 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
254 &VariableController::onRequestDataLoading);
254 &VariableController::onRequestDataLoading);
255
255
256 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
256 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
257 &VisualizationGraphWidget::onUpdateVarDisplaying);
257 &VisualizationGraphWidget::onUpdateVarDisplaying);
258
258
259 #ifdef Q_OS_MAC
259 #ifdef Q_OS_MAC
260 plot().setPlottingHint(QCP::phFastPolylines, true);
260 plot().setPlottingHint(QCP::phFastPolylines, true);
261 #endif
261 #endif
262 }
262 }
263
263
264
264
265 VisualizationGraphWidget::~VisualizationGraphWidget()
265 VisualizationGraphWidget::~VisualizationGraphWidget()
266 {
266 {
267 delete ui;
267 delete ui;
268 }
268 }
269
269
270 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
270 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
271 {
271 {
272 auto parent = parentWidget();
272 auto parent = parentWidget();
273 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
273 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
274 parent = parent->parentWidget();
274 parent = parent->parentWidget();
275 }
275 }
276
276
277 return qobject_cast<VisualizationZoneWidget *>(parent);
277 return qobject_cast<VisualizationZoneWidget *>(parent);
278 }
278 }
279
279
280 VisualizationWidget *VisualizationGraphWidget::parentVisualizationWidget() const
280 VisualizationWidget *VisualizationGraphWidget::parentVisualizationWidget() const
281 {
281 {
282 auto parent = parentWidget();
282 auto parent = parentWidget();
283 while (parent != nullptr && !qobject_cast<VisualizationWidget *>(parent)) {
283 while (parent != nullptr && !qobject_cast<VisualizationWidget *>(parent)) {
284 parent = parent->parentWidget();
284 parent = parent->parentWidget();
285 }
285 }
286
286
287 return qobject_cast<VisualizationWidget *>(parent);
287 return qobject_cast<VisualizationWidget *>(parent);
288 }
288 }
289
289
290 void VisualizationGraphWidget::enableAcquisition(bool enable)
290 void VisualizationGraphWidget::setFlags(GraphFlags flags)
291 {
291 {
292 impl->m_DoAcquisition = enable;
292 impl->m_Flags = std::move(flags);
293 }
293 }
294
294
295 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
295 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
296 {
296 {
297 // Uses delegate to create the qcpplot components according to the variable
297 // Uses delegate to create the qcpplot components according to the variable
298 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
298 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
299
299
300 if (auto dataSeries = variable->dataSeries()) {
300 if (auto dataSeries = variable->dataSeries()) {
301 // Set axes properties according to the units of the data series
301 // Set axes properties according to the units of the data series
302 impl->m_RenderingDelegate->setAxesProperties(dataSeries);
302 impl->m_RenderingDelegate->setAxesProperties(dataSeries);
303
303
304 // Sets rendering properties for the new plottables
304 // Sets rendering properties for the new plottables
305 // Warning: this method must be called after setAxesProperties(), as it can access to some
305 // Warning: this method must be called after setAxesProperties(), as it can access to some
306 // axes properties that have to be initialized
306 // axes properties that have to be initialized
307 impl->m_RenderingDelegate->setPlottablesProperties(dataSeries, createdPlottables);
307 impl->m_RenderingDelegate->setPlottablesProperties(dataSeries, createdPlottables);
308 }
308 }
309
309
310 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
310 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
311
311
312 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
312 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
313
313
314 this->enableAcquisition(false);
314 this->setFlags(GraphFlag::DisableAll);
315 this->setGraphRange(range);
315 this->setGraphRange(range);
316 this->enableAcquisition(true);
316 this->setFlags(GraphFlag::EnableAll);
317
317
318 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable, range, false);
318 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable, range, false);
319
319
320 emit variableAdded(variable);
320 emit variableAdded(variable);
321 }
321 }
322
322
323 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
323 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
324 {
324 {
325 // Each component associated to the variable :
325 // Each component associated to the variable :
326 // - is removed from qcpplot (which deletes it)
326 // - is removed from qcpplot (which deletes it)
327 // - is no longer referenced in the map
327 // - is no longer referenced in the map
328 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
328 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
329 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
329 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
330 emit variableAboutToBeRemoved(variable);
330 emit variableAboutToBeRemoved(variable);
331
331
332 auto &plottablesMap = variableIt->second;
332 auto &plottablesMap = variableIt->second;
333
333
334 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
334 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
335 plottableIt != plottableEnd;) {
335 plottableIt != plottableEnd;) {
336 ui->widget->removePlottable(plottableIt->second);
336 ui->widget->removePlottable(plottableIt->second);
337 plottableIt = plottablesMap.erase(plottableIt);
337 plottableIt = plottablesMap.erase(plottableIt);
338 }
338 }
339
339
340 impl->m_VariableToPlotMultiMap.erase(variableIt);
340 impl->m_VariableToPlotMultiMap.erase(variableIt);
341 }
341 }
342
342
343 // Updates graph
343 // Updates graph
344 ui->widget->replot();
344 ui->widget->replot();
345 }
345 }
346
346
347 QList<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
347 QList<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
348 {
348 {
349 auto variables = QList<std::shared_ptr<Variable> >{};
349 auto variables = QList<std::shared_ptr<Variable> >{};
350 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
350 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
351 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
351 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
352 variables << it->first;
352 variables << it->first;
353 }
353 }
354
354
355 return variables;
355 return variables;
356 }
356 }
357
357
358 void VisualizationGraphWidget::setYRange(std::shared_ptr<Variable> variable)
358 void VisualizationGraphWidget::setYRange(std::shared_ptr<Variable> variable)
359 {
359 {
360 if (!variable) {
360 if (!variable) {
361 qCCritical(LOG_VisualizationGraphWidget()) << "Can't set y-axis range: variable is null";
361 qCCritical(LOG_VisualizationGraphWidget()) << "Can't set y-axis range: variable is null";
362 return;
362 return;
363 }
363 }
364
364
365 VisualizationGraphHelper::setYAxisRange(variable, *ui->widget);
365 VisualizationGraphHelper::setYAxisRange(variable, *ui->widget);
366 }
366 }
367
367
368 SqpRange VisualizationGraphWidget::graphRange() const noexcept
368 SqpRange VisualizationGraphWidget::graphRange() const noexcept
369 {
369 {
370 auto graphRange = ui->widget->xAxis->range();
370 auto graphRange = ui->widget->xAxis->range();
371 return SqpRange{graphRange.lower, graphRange.upper};
371 return SqpRange{graphRange.lower, graphRange.upper};
372 }
372 }
373
373
374 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
374 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
375 {
375 {
376 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
376 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
377 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
377 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
378 ui->widget->replot();
378 ui->widget->replot();
379 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
379 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
380 }
380 }
381
381
382 QVector<SqpRange> VisualizationGraphWidget::selectionZoneRanges() const
382 QVector<SqpRange> VisualizationGraphWidget::selectionZoneRanges() const
383 {
383 {
384 QVector<SqpRange> ranges;
384 QVector<SqpRange> ranges;
385 for (auto zone : impl->m_SelectionZones) {
385 for (auto zone : impl->m_SelectionZones) {
386 ranges << zone->range();
386 ranges << zone->range();
387 }
387 }
388
388
389 return ranges;
389 return ranges;
390 }
390 }
391
391
392 void VisualizationGraphWidget::addSelectionZones(const QVector<SqpRange> &ranges)
392 void VisualizationGraphWidget::addSelectionZones(const QVector<SqpRange> &ranges)
393 {
393 {
394 for (const auto &range : ranges) {
394 for (const auto &range : ranges) {
395 // note: ownership is transfered to QCustomPlot
395 // note: ownership is transfered to QCustomPlot
396 auto zone = new VisualizationSelectionZoneItem(&plot());
396 auto zone = new VisualizationSelectionZoneItem(&plot());
397 zone->setRange(range.m_TStart, range.m_TEnd);
397 zone->setRange(range.m_TStart, range.m_TEnd);
398 impl->addSelectionZone(zone);
398 impl->addSelectionZone(zone);
399 }
399 }
400
400
401 plot().replot(QCustomPlot::rpQueuedReplot);
401 plot().replot(QCustomPlot::rpQueuedReplot);
402 }
402 }
403
403
404 void VisualizationGraphWidget::removeSelectionZone(VisualizationSelectionZoneItem *selectionZone)
404 void VisualizationGraphWidget::removeSelectionZone(VisualizationSelectionZoneItem *selectionZone)
405 {
405 {
406 parentVisualizationWidget()->selectionZoneManager().setSelected(selectionZone, false);
406 parentVisualizationWidget()->selectionZoneManager().setSelected(selectionZone, false);
407
407
408 if (impl->m_HoveredZone == selectionZone) {
408 if (impl->m_HoveredZone == selectionZone) {
409 impl->m_HoveredZone = nullptr;
409 impl->m_HoveredZone = nullptr;
410 setCursor(Qt::ArrowCursor);
410 setCursor(Qt::ArrowCursor);
411 }
411 }
412
412
413 impl->m_SelectionZones.removeAll(selectionZone);
413 impl->m_SelectionZones.removeAll(selectionZone);
414 plot().removeItem(selectionZone);
414 plot().removeItem(selectionZone);
415 plot().replot(QCustomPlot::rpQueuedReplot);
415 plot().replot(QCustomPlot::rpQueuedReplot);
416 }
416 }
417
417
418 void VisualizationGraphWidget::undoZoom()
418 void VisualizationGraphWidget::undoZoom()
419 {
419 {
420 auto zoom = impl->m_ZoomStack.pop();
420 auto zoom = impl->m_ZoomStack.pop();
421 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
421 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
422 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
422 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
423
423
424 axisX->setRange(zoom.first);
424 axisX->setRange(zoom.first);
425 axisY->setRange(zoom.second);
425 axisY->setRange(zoom.second);
426
426
427 plot().replot(QCustomPlot::rpQueuedReplot);
427 plot().replot(QCustomPlot::rpQueuedReplot);
428 }
428 }
429
429
430 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
430 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
431 {
431 {
432 if (visitor) {
432 if (visitor) {
433 visitor->visit(this);
433 visitor->visit(this);
434 }
434 }
435 else {
435 else {
436 qCCritical(LOG_VisualizationGraphWidget())
436 qCCritical(LOG_VisualizationGraphWidget())
437 << tr("Can't visit widget : the visitor is null");
437 << tr("Can't visit widget : the visitor is null");
438 }
438 }
439 }
439 }
440
440
441 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
441 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
442 {
442 {
443 auto isSpectrogram = [](const auto &variable) {
443 auto isSpectrogram = [](const auto &variable) {
444 return std::dynamic_pointer_cast<SpectrogramSeries>(variable.dataSeries()) != nullptr;
444 return std::dynamic_pointer_cast<SpectrogramSeries>(variable.dataSeries()) != nullptr;
445 };
445 };
446
446
447 // - A spectrogram series can't be dropped on graph with existing plottables
447 // - A spectrogram series can't be dropped on graph with existing plottables
448 // - No data series can be dropped on graph with existing spectrogram series
448 // - No data series can be dropped on graph with existing spectrogram series
449 return isSpectrogram(variable)
449 return isSpectrogram(variable)
450 ? impl->m_VariableToPlotMultiMap.empty()
450 ? impl->m_VariableToPlotMultiMap.empty()
451 : std::none_of(
451 : std::none_of(
452 impl->m_VariableToPlotMultiMap.cbegin(), impl->m_VariableToPlotMultiMap.cend(),
452 impl->m_VariableToPlotMultiMap.cbegin(), impl->m_VariableToPlotMultiMap.cend(),
453 [isSpectrogram](const auto &entry) { return isSpectrogram(*entry.first); });
453 [isSpectrogram](const auto &entry) { return isSpectrogram(*entry.first); });
454 }
454 }
455
455
456 bool VisualizationGraphWidget::contains(const Variable &variable) const
456 bool VisualizationGraphWidget::contains(const Variable &variable) const
457 {
457 {
458 // Finds the variable among the keys of the map
458 // Finds the variable among the keys of the map
459 auto variablePtr = &variable;
459 auto variablePtr = &variable;
460 auto findVariable
460 auto findVariable
461 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
461 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
462
462
463 auto end = impl->m_VariableToPlotMultiMap.cend();
463 auto end = impl->m_VariableToPlotMultiMap.cend();
464 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
464 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
465 return it != end;
465 return it != end;
466 }
466 }
467
467
468 QString VisualizationGraphWidget::name() const
468 QString VisualizationGraphWidget::name() const
469 {
469 {
470 return impl->m_Name;
470 return impl->m_Name;
471 }
471 }
472
472
473 QMimeData *VisualizationGraphWidget::mimeData(const QPoint &position) const
473 QMimeData *VisualizationGraphWidget::mimeData(const QPoint &position) const
474 {
474 {
475 auto mimeData = new QMimeData;
475 auto mimeData = new QMimeData;
476
476
477 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(position, plot());
477 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(position, plot());
478 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
478 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
479 && selectionZoneItemUnderCursor) {
479 && selectionZoneItemUnderCursor) {
480 mimeData->setData(MIME_TYPE_TIME_RANGE, TimeController::mimeDataForTimeRange(
480 mimeData->setData(MIME_TYPE_TIME_RANGE, TimeController::mimeDataForTimeRange(
481 selectionZoneItemUnderCursor->range()));
481 selectionZoneItemUnderCursor->range()));
482 mimeData->setData(MIME_TYPE_SELECTION_ZONE, TimeController::mimeDataForTimeRange(
482 mimeData->setData(MIME_TYPE_SELECTION_ZONE, TimeController::mimeDataForTimeRange(
483 selectionZoneItemUnderCursor->range()));
483 selectionZoneItemUnderCursor->range()));
484 }
484 }
485 else {
485 else {
486 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
486 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
487
487
488 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
488 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
489 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
489 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
490 }
490 }
491
491
492 return mimeData;
492 return mimeData;
493 }
493 }
494
494
495 QPixmap VisualizationGraphWidget::customDragPixmap(const QPoint &dragPosition)
495 QPixmap VisualizationGraphWidget::customDragPixmap(const QPoint &dragPosition)
496 {
496 {
497 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(dragPosition, plot());
497 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(dragPosition, plot());
498 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
498 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
499 && selectionZoneItemUnderCursor) {
499 && selectionZoneItemUnderCursor) {
500
500
501 auto zoneTopLeft = selectionZoneItemUnderCursor->topLeft->pixelPosition();
501 auto zoneTopLeft = selectionZoneItemUnderCursor->topLeft->pixelPosition();
502 auto zoneBottomRight = selectionZoneItemUnderCursor->bottomRight->pixelPosition();
502 auto zoneBottomRight = selectionZoneItemUnderCursor->bottomRight->pixelPosition();
503
503
504 auto zoneSize = QSizeF{qAbs(zoneBottomRight.x() - zoneTopLeft.x()),
504 auto zoneSize = QSizeF{qAbs(zoneBottomRight.x() - zoneTopLeft.x()),
505 qAbs(zoneBottomRight.y() - zoneTopLeft.y())}
505 qAbs(zoneBottomRight.y() - zoneTopLeft.y())}
506 .toSize();
506 .toSize();
507
507
508 auto pixmap = QPixmap(zoneSize);
508 auto pixmap = QPixmap(zoneSize);
509 render(&pixmap, QPoint(), QRegion{QRect{zoneTopLeft.toPoint(), zoneSize}});
509 render(&pixmap, QPoint(), QRegion{QRect{zoneTopLeft.toPoint(), zoneSize}});
510
510
511 return pixmap;
511 return pixmap;
512 }
512 }
513
513
514 return QPixmap();
514 return QPixmap();
515 }
515 }
516
516
517 bool VisualizationGraphWidget::isDragAllowed() const
517 bool VisualizationGraphWidget::isDragAllowed() const
518 {
518 {
519 return true;
519 return true;
520 }
520 }
521
521
522 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
522 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
523 {
523 {
524 if (highlighted) {
524 if (highlighted) {
525 plot().setBackground(QBrush(QColor("#BBD5EE")));
525 plot().setBackground(QBrush(QColor("#BBD5EE")));
526 }
526 }
527 else {
527 else {
528 plot().setBackground(QBrush(Qt::white));
528 plot().setBackground(QBrush(Qt::white));
529 }
529 }
530
530
531 plot().update();
531 plot().update();
532 }
532 }
533
533
534 void VisualizationGraphWidget::addVerticalCursor(double time)
534 void VisualizationGraphWidget::addVerticalCursor(double time)
535 {
535 {
536 impl->m_VerticalCursor->setPosition(time);
536 impl->m_VerticalCursor->setPosition(time);
537 impl->m_VerticalCursor->setVisible(true);
537 impl->m_VerticalCursor->setVisible(true);
538
538
539 auto text
539 auto text
540 = DateUtils::dateTime(time).toString(CURSOR_LABELS_DATETIME_FORMAT).replace(' ', '\n');
540 = DateUtils::dateTime(time).toString(CURSOR_LABELS_DATETIME_FORMAT).replace(' ', '\n');
541 impl->m_VerticalCursor->setLabelText(text);
541 impl->m_VerticalCursor->setLabelText(text);
542 }
542 }
543
543
544 void VisualizationGraphWidget::addVerticalCursorAtViewportPosition(double position)
544 void VisualizationGraphWidget::addVerticalCursorAtViewportPosition(double position)
545 {
545 {
546 impl->m_VerticalCursor->setAbsolutePosition(position);
546 impl->m_VerticalCursor->setAbsolutePosition(position);
547 impl->m_VerticalCursor->setVisible(true);
547 impl->m_VerticalCursor->setVisible(true);
548
548
549 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
549 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
550 auto text
550 auto text
551 = DateUtils::dateTime(axis->pixelToCoord(position)).toString(CURSOR_LABELS_DATETIME_FORMAT);
551 = DateUtils::dateTime(axis->pixelToCoord(position)).toString(CURSOR_LABELS_DATETIME_FORMAT);
552 impl->m_VerticalCursor->setLabelText(text);
552 impl->m_VerticalCursor->setLabelText(text);
553 }
553 }
554
554
555 void VisualizationGraphWidget::removeVerticalCursor()
555 void VisualizationGraphWidget::removeVerticalCursor()
556 {
556 {
557 impl->m_VerticalCursor->setVisible(false);
557 impl->m_VerticalCursor->setVisible(false);
558 plot().replot(QCustomPlot::rpQueuedReplot);
558 plot().replot(QCustomPlot::rpQueuedReplot);
559 }
559 }
560
560
561 void VisualizationGraphWidget::addHorizontalCursor(double value)
561 void VisualizationGraphWidget::addHorizontalCursor(double value)
562 {
562 {
563 impl->m_HorizontalCursor->setPosition(value);
563 impl->m_HorizontalCursor->setPosition(value);
564 impl->m_HorizontalCursor->setVisible(true);
564 impl->m_HorizontalCursor->setVisible(true);
565 impl->m_HorizontalCursor->setLabelText(QString::number(value));
565 impl->m_HorizontalCursor->setLabelText(QString::number(value));
566 }
566 }
567
567
568 void VisualizationGraphWidget::addHorizontalCursorAtViewportPosition(double position)
568 void VisualizationGraphWidget::addHorizontalCursorAtViewportPosition(double position)
569 {
569 {
570 impl->m_HorizontalCursor->setAbsolutePosition(position);
570 impl->m_HorizontalCursor->setAbsolutePosition(position);
571 impl->m_HorizontalCursor->setVisible(true);
571 impl->m_HorizontalCursor->setVisible(true);
572
572
573 auto axis = plot().axisRect()->axis(QCPAxis::atLeft);
573 auto axis = plot().axisRect()->axis(QCPAxis::atLeft);
574 impl->m_HorizontalCursor->setLabelText(QString::number(axis->pixelToCoord(position)));
574 impl->m_HorizontalCursor->setLabelText(QString::number(axis->pixelToCoord(position)));
575 }
575 }
576
576
577 void VisualizationGraphWidget::removeHorizontalCursor()
577 void VisualizationGraphWidget::removeHorizontalCursor()
578 {
578 {
579 impl->m_HorizontalCursor->setVisible(false);
579 impl->m_HorizontalCursor->setVisible(false);
580 plot().replot(QCustomPlot::rpQueuedReplot);
580 plot().replot(QCustomPlot::rpQueuedReplot);
581 }
581 }
582
582
583 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
583 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
584 {
584 {
585 Q_UNUSED(event);
585 Q_UNUSED(event);
586
586
587 // Prevents that all variables will be removed from graph when it will be closed
587 // Prevents that all variables will be removed from graph when it will be closed
588 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
588 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
589 emit variableAboutToBeRemoved(variableEntry.first);
589 emit variableAboutToBeRemoved(variableEntry.first);
590 }
590 }
591 }
591 }
592
592
593 void VisualizationGraphWidget::enterEvent(QEvent *event)
593 void VisualizationGraphWidget::enterEvent(QEvent *event)
594 {
594 {
595 Q_UNUSED(event);
595 Q_UNUSED(event);
596 impl->m_RenderingDelegate->showGraphOverlay(true);
596 impl->m_RenderingDelegate->showGraphOverlay(true);
597 }
597 }
598
598
599 void VisualizationGraphWidget::leaveEvent(QEvent *event)
599 void VisualizationGraphWidget::leaveEvent(QEvent *event)
600 {
600 {
601 Q_UNUSED(event);
601 Q_UNUSED(event);
602 impl->m_RenderingDelegate->showGraphOverlay(false);
602 impl->m_RenderingDelegate->showGraphOverlay(false);
603
603
604 if (auto parentZone = parentZoneWidget()) {
604 if (auto parentZone = parentZoneWidget()) {
605 parentZone->notifyMouseLeaveGraph(this);
605 parentZone->notifyMouseLeaveGraph(this);
606 }
606 }
607 else {
607 else {
608 qCWarning(LOG_VisualizationGraphWidget()) << "leaveEvent: No parent zone widget";
608 qCWarning(LOG_VisualizationGraphWidget()) << "leaveEvent: No parent zone widget";
609 }
609 }
610
610
611 if (impl->m_HoveredZone) {
611 if (impl->m_HoveredZone) {
612 impl->m_HoveredZone->setHovered(false);
612 impl->m_HoveredZone->setHovered(false);
613 impl->m_HoveredZone = nullptr;
613 impl->m_HoveredZone = nullptr;
614 }
614 }
615 }
615 }
616
616
617 QCustomPlot &VisualizationGraphWidget::plot() const noexcept
617 QCustomPlot &VisualizationGraphWidget::plot() const noexcept
618 {
618 {
619 return *ui->widget;
619 return *ui->widget;
620 }
620 }
621
621
622 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
622 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
623 {
623 {
624 QMenu graphMenu{};
624 QMenu graphMenu{};
625
625
626 // Iterates on variables (unique keys)
626 // Iterates on variables (unique keys)
627 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
627 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
628 end = impl->m_VariableToPlotMultiMap.cend();
628 end = impl->m_VariableToPlotMultiMap.cend();
629 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
629 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
630 // 'Remove variable' action
630 // 'Remove variable' action
631 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
631 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
632 [ this, var = it->first ]() { removeVariable(var); });
632 [ this, var = it->first ]() { removeVariable(var); });
633 }
633 }
634
634
635 if (!impl->m_ZoomStack.isEmpty()) {
635 if (!impl->m_ZoomStack.isEmpty()) {
636 if (!graphMenu.isEmpty()) {
636 if (!graphMenu.isEmpty()) {
637 graphMenu.addSeparator();
637 graphMenu.addSeparator();
638 }
638 }
639
639
640 graphMenu.addAction(tr("Undo Zoom"), [this]() { undoZoom(); });
640 graphMenu.addAction(tr("Undo Zoom"), [this]() { undoZoom(); });
641 }
641 }
642
642
643 // Selection Zone Actions
643 // Selection Zone Actions
644 auto selectionZoneItem = impl->selectionZoneAt(pos, plot());
644 auto selectionZoneItem = impl->selectionZoneAt(pos, plot());
645 if (selectionZoneItem) {
645 if (selectionZoneItem) {
646 auto selectedItems = parentVisualizationWidget()->selectionZoneManager().selectedItems();
646 auto selectedItems = parentVisualizationWidget()->selectionZoneManager().selectedItems();
647 selectedItems.removeAll(selectionZoneItem);
647 selectedItems.removeAll(selectionZoneItem);
648 selectedItems.prepend(selectionZoneItem); // Put the current selection zone first
648 selectedItems.prepend(selectionZoneItem); // Put the current selection zone first
649
649
650 auto zoneActions = sqpApp->actionsGuiController().selectionZoneActions();
650 auto zoneActions = sqpApp->actionsGuiController().selectionZoneActions();
651 if (!zoneActions.isEmpty() && !graphMenu.isEmpty()) {
651 if (!zoneActions.isEmpty() && !graphMenu.isEmpty()) {
652 graphMenu.addSeparator();
652 graphMenu.addSeparator();
653 }
653 }
654
654
655 QHash<QString, QMenu *> subMenus;
655 QHash<QString, QMenu *> subMenus;
656 QHash<QString, bool> subMenusEnabled;
656 QHash<QString, bool> subMenusEnabled;
657
657
658 for (auto zoneAction : zoneActions) {
658 for (auto zoneAction : zoneActions) {
659
659
660 auto isEnabled = zoneAction->isEnabled(selectedItems);
660 auto isEnabled = zoneAction->isEnabled(selectedItems);
661
661
662 auto menu = &graphMenu;
662 auto menu = &graphMenu;
663 for (auto subMenuName : zoneAction->subMenuList()) {
663 for (auto subMenuName : zoneAction->subMenuList()) {
664 if (!subMenus.contains(subMenuName)) {
664 if (!subMenus.contains(subMenuName)) {
665 menu = menu->addMenu(subMenuName);
665 menu = menu->addMenu(subMenuName);
666 subMenus[subMenuName] = menu;
666 subMenus[subMenuName] = menu;
667 subMenusEnabled[subMenuName] = isEnabled;
667 subMenusEnabled[subMenuName] = isEnabled;
668 }
668 }
669 else {
669 else {
670 menu = subMenus.value(subMenuName);
670 menu = subMenus.value(subMenuName);
671 if (isEnabled) {
671 if (isEnabled) {
672 // The sub menu is enabled if at least one of its actions is enabled
672 // The sub menu is enabled if at least one of its actions is enabled
673 subMenusEnabled[subMenuName] = true;
673 subMenusEnabled[subMenuName] = true;
674 }
674 }
675 }
675 }
676 }
676 }
677
677
678 auto action = menu->addAction(zoneAction->name());
678 auto action = menu->addAction(zoneAction->name());
679 action->setEnabled(isEnabled);
679 action->setEnabled(isEnabled);
680 action->setShortcut(zoneAction->displayedShortcut());
680 action->setShortcut(zoneAction->displayedShortcut());
681 QObject::connect(action, &QAction::triggered,
681 QObject::connect(action, &QAction::triggered,
682 [zoneAction, selectedItems]() { zoneAction->execute(selectedItems); });
682 [zoneAction, selectedItems]() { zoneAction->execute(selectedItems); });
683 }
683 }
684
684
685 for (auto it = subMenus.cbegin(); it != subMenus.cend(); ++it) {
685 for (auto it = subMenus.cbegin(); it != subMenus.cend(); ++it) {
686 it.value()->setEnabled(subMenusEnabled[it.key()]);
686 it.value()->setEnabled(subMenusEnabled[it.key()]);
687 }
687 }
688 }
688 }
689
689
690 if (!graphMenu.isEmpty()) {
690 if (!graphMenu.isEmpty()) {
691 graphMenu.exec(QCursor::pos());
691 graphMenu.exec(QCursor::pos());
692 }
692 }
693 }
693 }
694
694
695 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
695 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
696 {
696 {
697 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
697 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
698 << QThread::currentThread()->objectName() << "DoAcqui"
698 << QThread::currentThread()->objectName() << "DoAcqui"
699 << impl->m_DoAcquisition;
699 << impl->m_Flags.testFlag(GraphFlag::EnableAcquisition);
700
700
701 auto graphRange = SqpRange{t1.lower, t1.upper};
701 auto graphRange = SqpRange{t1.lower, t1.upper};
702 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
702 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
703
703
704 if (impl->m_DoAcquisition) {
704 if (impl->m_Flags.testFlag(GraphFlag::EnableAcquisition)) {
705 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
705 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
706
706
707 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
707 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
708 end = impl->m_VariableToPlotMultiMap.end();
708 end = impl->m_VariableToPlotMultiMap.end();
709 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
709 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
710 variableUnderGraphVector.push_back(it->first);
710 variableUnderGraphVector.push_back(it->first);
711 }
711 }
712 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
712 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
713 !impl->m_IsCalibration);
713 !impl->m_IsCalibration);
714 }
714
715
715 if (!impl->m_IsCalibration) {
716 if (impl->m_Flags.testFlag(GraphFlag::EnableSynchronization) && !impl->m_IsCalibration) {
716 qCDebug(LOG_VisualizationGraphWidget())
717 qCDebug(LOG_VisualizationGraphWidget())
717 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
718 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
718 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
719 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
719 emit synchronize(graphRange, oldGraphRange);
720 emit synchronize(graphRange, oldGraphRange);
720 }
721 }
721 }
722
722
723 auto pos = mapFromGlobal(QCursor::pos());
723 auto pos = mapFromGlobal(QCursor::pos());
724 auto axisPos = impl->posToAxisPos(pos, plot());
724 auto axisPos = impl->posToAxisPos(pos, plot());
725 if (auto parentZone = parentZoneWidget()) {
725 if (auto parentZone = parentZoneWidget()) {
726 if (impl->pointIsInAxisRect(axisPos, plot())) {
726 if (impl->pointIsInAxisRect(axisPos, plot())) {
727 parentZone->notifyMouseMoveInGraph(pos, axisPos, this);
727 parentZone->notifyMouseMoveInGraph(pos, axisPos, this);
728 }
728 }
729 else {
729 else {
730 parentZone->notifyMouseLeaveGraph(this);
730 parentZone->notifyMouseLeaveGraph(this);
731 }
731 }
732 }
732 }
733 else {
733 else {
734 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
734 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
735 }
735 }
736
737 // Quits calibration
738 impl->m_IsCalibration = false;
736 }
739 }
737
740
738 void VisualizationGraphWidget::onMouseDoubleClick(QMouseEvent *event) noexcept
741 void VisualizationGraphWidget::onMouseDoubleClick(QMouseEvent *event) noexcept
739 {
742 {
740 impl->m_RenderingDelegate->onMouseDoubleClick(event);
743 impl->m_RenderingDelegate->onMouseDoubleClick(event);
741 }
744 }
742
745
743 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
746 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
744 {
747 {
745 // Handles plot rendering when mouse is moving
748 // Handles plot rendering when mouse is moving
746 impl->m_RenderingDelegate->onMouseMove(event);
749 impl->m_RenderingDelegate->onMouseMove(event);
747
750
748 auto axisPos = impl->posToAxisPos(event->pos(), plot());
751 auto axisPos = impl->posToAxisPos(event->pos(), plot());
749
752
750 // Zoom box and zone drawing
753 // Zoom box and zone drawing
751 if (impl->m_DrawingZoomRect) {
754 if (impl->m_DrawingZoomRect) {
752 impl->m_DrawingZoomRect->bottomRight->setCoords(axisPos);
755 impl->m_DrawingZoomRect->bottomRight->setCoords(axisPos);
753 }
756 }
754 else if (impl->m_DrawingZone) {
757 else if (impl->m_DrawingZone) {
755 impl->m_DrawingZone->setEnd(axisPos.x());
758 impl->m_DrawingZone->setEnd(axisPos.x());
756 }
759 }
757
760
758 // Cursor
761 // Cursor
759 if (auto parentZone = parentZoneWidget()) {
762 if (auto parentZone = parentZoneWidget()) {
760 if (impl->pointIsInAxisRect(axisPos, plot())) {
763 if (impl->pointIsInAxisRect(axisPos, plot())) {
761 parentZone->notifyMouseMoveInGraph(event->pos(), axisPos, this);
764 parentZone->notifyMouseMoveInGraph(event->pos(), axisPos, this);
762 }
765 }
763 else {
766 else {
764 parentZone->notifyMouseLeaveGraph(this);
767 parentZone->notifyMouseLeaveGraph(this);
765 }
768 }
766 }
769 }
767 else {
770 else {
768 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
771 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
769 }
772 }
770
773
771 // Search for the selection zone under the mouse
774 // Search for the selection zone under the mouse
772 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
775 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
773 if (selectionZoneItemUnderCursor && !impl->m_DrawingZone
776 if (selectionZoneItemUnderCursor && !impl->m_DrawingZone
774 && sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones) {
777 && sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones) {
775
778
776 // Sets the appropriate cursor shape
779 // Sets the appropriate cursor shape
777 auto cursorShape = selectionZoneItemUnderCursor->curshorShapeForPosition(event->pos());
780 auto cursorShape = selectionZoneItemUnderCursor->curshorShapeForPosition(event->pos());
778 setCursor(cursorShape);
781 setCursor(cursorShape);
779
782
780 // Manages the hovered zone
783 // Manages the hovered zone
781 if (selectionZoneItemUnderCursor != impl->m_HoveredZone) {
784 if (selectionZoneItemUnderCursor != impl->m_HoveredZone) {
782 if (impl->m_HoveredZone) {
785 if (impl->m_HoveredZone) {
783 impl->m_HoveredZone->setHovered(false);
786 impl->m_HoveredZone->setHovered(false);
784 }
787 }
785 selectionZoneItemUnderCursor->setHovered(true);
788 selectionZoneItemUnderCursor->setHovered(true);
786 impl->m_HoveredZone = selectionZoneItemUnderCursor;
789 impl->m_HoveredZone = selectionZoneItemUnderCursor;
787 plot().replot(QCustomPlot::rpQueuedReplot);
790 plot().replot(QCustomPlot::rpQueuedReplot);
788 }
791 }
789 }
792 }
790 else {
793 else {
791 // There is no zone under the mouse or the interaction mode is not "selection zones"
794 // There is no zone under the mouse or the interaction mode is not "selection zones"
792 if (impl->m_HoveredZone) {
795 if (impl->m_HoveredZone) {
793 impl->m_HoveredZone->setHovered(false);
796 impl->m_HoveredZone->setHovered(false);
794 impl->m_HoveredZone = nullptr;
797 impl->m_HoveredZone = nullptr;
795 }
798 }
796
799
797 setCursor(Qt::ArrowCursor);
800 setCursor(Qt::ArrowCursor);
798 }
801 }
799
802
800 impl->m_HasMovedMouse = true;
803 impl->m_HasMovedMouse = true;
801 VisualizationDragWidget::mouseMoveEvent(event);
804 VisualizationDragWidget::mouseMoveEvent(event);
802 }
805 }
803
806
804 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
807 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
805 {
808 {
806 auto value = event->angleDelta().x() + event->angleDelta().y();
809 auto value = event->angleDelta().x() + event->angleDelta().y();
807 if (value != 0) {
810 if (value != 0) {
808
811
809 auto direction = value > 0 ? 1.0 : -1.0;
812 auto direction = value > 0 ? 1.0 : -1.0;
810 auto isZoomX = event->modifiers().testFlag(HORIZONTAL_ZOOM_MODIFIER);
813 auto isZoomX = event->modifiers().testFlag(HORIZONTAL_ZOOM_MODIFIER);
811 auto isZoomY = event->modifiers().testFlag(VERTICAL_ZOOM_MODIFIER);
814 auto isZoomY = event->modifiers().testFlag(VERTICAL_ZOOM_MODIFIER);
812 impl->m_IsCalibration = event->modifiers().testFlag(VERTICAL_PAN_MODIFIER);
815 impl->m_IsCalibration = event->modifiers().testFlag(VERTICAL_PAN_MODIFIER);
813
816
814 auto zoomOrientations = QFlags<Qt::Orientation>{};
817 auto zoomOrientations = QFlags<Qt::Orientation>{};
815 zoomOrientations.setFlag(Qt::Horizontal, isZoomX);
818 zoomOrientations.setFlag(Qt::Horizontal, isZoomX);
816 zoomOrientations.setFlag(Qt::Vertical, isZoomY);
819 zoomOrientations.setFlag(Qt::Vertical, isZoomY);
817
820
818 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
821 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
819
822
820 if (!isZoomX && !isZoomY) {
823 if (!isZoomX && !isZoomY) {
821 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
824 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
822 auto diff = direction * (axis->range().size() * (PAN_SPEED / 100.0));
825 auto diff = direction * (axis->range().size() * (PAN_SPEED / 100.0));
823
826
824 axis->setRange(axis->range() + diff);
827 axis->setRange(axis->range() + diff);
825
828
826 if (plot().noAntialiasingOnDrag()) {
829 if (plot().noAntialiasingOnDrag()) {
827 plot().setNotAntialiasedElements(QCP::aeAll);
830 plot().setNotAntialiasedElements(QCP::aeAll);
828 }
831 }
829
832
830 plot().replot(QCustomPlot::rpQueuedReplot);
833 plot().replot(QCustomPlot::rpQueuedReplot);
831 }
834 }
832 }
835 }
833 }
836 }
834
837
835 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
838 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
836 {
839 {
837 auto isDragDropClick = event->modifiers().testFlag(DRAG_DROP_MODIFIER);
840 auto isDragDropClick = event->modifiers().testFlag(DRAG_DROP_MODIFIER);
838 auto isSelectionZoneMode
841 auto isSelectionZoneMode
839 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
842 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
840 auto isLeftClick = event->buttons().testFlag(Qt::LeftButton);
843 auto isLeftClick = event->buttons().testFlag(Qt::LeftButton);
841
844
842 if (!isDragDropClick && isLeftClick) {
845 if (!isDragDropClick && isLeftClick) {
843 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::ZoomBox) {
846 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::ZoomBox) {
844 // Starts a zoom box
847 // Starts a zoom box
845 impl->startDrawingRect(event->pos(), plot());
848 impl->startDrawingRect(event->pos(), plot());
846 }
849 }
847 else if (isSelectionZoneMode && impl->m_DrawingZone == nullptr) {
850 else if (isSelectionZoneMode && impl->m_DrawingZone == nullptr) {
848 // Starts a new selection zone
851 // Starts a new selection zone
849 auto zoneAtPos = impl->selectionZoneAt(event->pos(), plot());
852 auto zoneAtPos = impl->selectionZoneAt(event->pos(), plot());
850 if (!zoneAtPos) {
853 if (!zoneAtPos) {
851 impl->startDrawingZone(event->pos(), this);
854 impl->startDrawingZone(event->pos(), this);
852 }
855 }
853 }
856 }
854 }
857 }
855
858
856 // Allows mouse panning only in default mode
859 // Allows mouse panning only in default mode
857 plot().setInteraction(QCP::iRangeDrag, sqpApp->plotsInteractionMode()
860 plot().setInteraction(QCP::iRangeDrag, sqpApp->plotsInteractionMode()
858 == SqpApplication::PlotsInteractionMode::None
861 == SqpApplication::PlotsInteractionMode::None
859 && !isDragDropClick);
862 && !isDragDropClick);
860
863
861 // Allows zone edition only in selection zone mode without drag&drop
864 // Allows zone edition only in selection zone mode without drag&drop
862 impl->setSelectionZonesEditionEnabled(isSelectionZoneMode && !isDragDropClick);
865 impl->setSelectionZonesEditionEnabled(isSelectionZoneMode && !isDragDropClick);
863
866
864 // Selection / Deselection
867 // Selection / Deselection
865 if (isSelectionZoneMode) {
868 if (isSelectionZoneMode) {
866 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
869 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
867 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
870 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
868
871
869
872
870 if (selectionZoneItemUnderCursor && !selectionZoneItemUnderCursor->selected()
873 if (selectionZoneItemUnderCursor && !selectionZoneItemUnderCursor->selected()
871 && !isMultiSelectionClick) {
874 && !isMultiSelectionClick) {
872 parentVisualizationWidget()->selectionZoneManager().select(
875 parentVisualizationWidget()->selectionZoneManager().select(
873 {selectionZoneItemUnderCursor});
876 {selectionZoneItemUnderCursor});
874 }
877 }
875 else if (!selectionZoneItemUnderCursor && !isMultiSelectionClick && isLeftClick) {
878 else if (!selectionZoneItemUnderCursor && !isMultiSelectionClick && isLeftClick) {
876 parentVisualizationWidget()->selectionZoneManager().clearSelection();
879 parentVisualizationWidget()->selectionZoneManager().clearSelection();
877 }
880 }
878 else {
881 else {
879 // No selection change
882 // No selection change
880 }
883 }
881
884
882 if (selectionZoneItemUnderCursor && isLeftClick) {
885 if (selectionZoneItemUnderCursor && isLeftClick) {
883 selectionZoneItemUnderCursor->setAssociatedEditedZones(
886 selectionZoneItemUnderCursor->setAssociatedEditedZones(
884 parentVisualizationWidget()->selectionZoneManager().selectedItems());
887 parentVisualizationWidget()->selectionZoneManager().selectedItems());
885 }
888 }
886 }
889 }
887
890
888
891
889 impl->m_HasMovedMouse = false;
892 impl->m_HasMovedMouse = false;
890 VisualizationDragWidget::mousePressEvent(event);
893 VisualizationDragWidget::mousePressEvent(event);
891 }
894 }
892
895
893 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
896 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
894 {
897 {
895 if (impl->m_DrawingZoomRect) {
898 if (impl->m_DrawingZoomRect) {
896
899
897 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
900 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
898 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
901 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
899
902
900 auto newAxisXRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().x(),
903 auto newAxisXRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().x(),
901 impl->m_DrawingZoomRect->bottomRight->coords().x()};
904 impl->m_DrawingZoomRect->bottomRight->coords().x()};
902
905
903 auto newAxisYRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().y(),
906 auto newAxisYRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().y(),
904 impl->m_DrawingZoomRect->bottomRight->coords().y()};
907 impl->m_DrawingZoomRect->bottomRight->coords().y()};
905
908
906 impl->removeDrawingRect(plot());
909 impl->removeDrawingRect(plot());
907
910
908 if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)
911 if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)
909 && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)) {
912 && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)) {
910 impl->m_ZoomStack.push(qMakePair(axisX->range(), axisY->range()));
913 impl->m_ZoomStack.push(qMakePair(axisX->range(), axisY->range()));
911 axisX->setRange(newAxisXRange);
914 axisX->setRange(newAxisXRange);
912 axisY->setRange(newAxisYRange);
915 axisY->setRange(newAxisYRange);
913
916
914 plot().replot(QCustomPlot::rpQueuedReplot);
917 plot().replot(QCustomPlot::rpQueuedReplot);
915 }
918 }
916 }
919 }
917
920
918 impl->endDrawingZone(this);
921 impl->endDrawingZone(this);
919
922
920 impl->m_IsCalibration = false;
921
922 // Selection / Deselection
923 // Selection / Deselection
923 auto isSelectionZoneMode
924 auto isSelectionZoneMode
924 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
925 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
925 if (isSelectionZoneMode) {
926 if (isSelectionZoneMode) {
926 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
927 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
927 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
928 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
928 if (selectionZoneItemUnderCursor && event->button() == Qt::LeftButton
929 if (selectionZoneItemUnderCursor && event->button() == Qt::LeftButton
929 && !impl->m_HasMovedMouse) {
930 && !impl->m_HasMovedMouse) {
930
931
931 auto zonesUnderCursor = impl->selectionZonesAt(event->pos(), plot());
932 auto zonesUnderCursor = impl->selectionZonesAt(event->pos(), plot());
932 if (zonesUnderCursor.count() > 1) {
933 if (zonesUnderCursor.count() > 1) {
933 // There are multiple zones under the mouse.
934 // There are multiple zones under the mouse.
934 // Performs the selection with a selection dialog.
935 // Performs the selection with a selection dialog.
935 VisualizationMultiZoneSelectionDialog dialog{this};
936 VisualizationMultiZoneSelectionDialog dialog{this};
936 dialog.setZones(zonesUnderCursor);
937 dialog.setZones(zonesUnderCursor);
937 dialog.move(mapToGlobal(event->pos() - QPoint(dialog.width() / 2, 20)));
938 dialog.move(mapToGlobal(event->pos() - QPoint(dialog.width() / 2, 20)));
938 dialog.activateWindow();
939 dialog.activateWindow();
939 dialog.raise();
940 dialog.raise();
940 if (dialog.exec() == QDialog::Accepted) {
941 if (dialog.exec() == QDialog::Accepted) {
941 auto selection = dialog.selectedZones();
942 auto selection = dialog.selectedZones();
942
943
943 if (!isMultiSelectionClick) {
944 if (!isMultiSelectionClick) {
944 parentVisualizationWidget()->selectionZoneManager().clearSelection();
945 parentVisualizationWidget()->selectionZoneManager().clearSelection();
945 }
946 }
946
947
947 for (auto it = selection.cbegin(); it != selection.cend(); ++it) {
948 for (auto it = selection.cbegin(); it != selection.cend(); ++it) {
948 auto zone = it.key();
949 auto zone = it.key();
949 auto isSelected = it.value();
950 auto isSelected = it.value();
950 parentVisualizationWidget()->selectionZoneManager().setSelected(zone,
951 parentVisualizationWidget()->selectionZoneManager().setSelected(zone,
951 isSelected);
952 isSelected);
952
953
953 if (isSelected) {
954 if (isSelected) {
954 // Puts the zone on top of the stack so it can be moved or resized
955 // Puts the zone on top of the stack so it can be moved or resized
955 impl->moveSelectionZoneOnTop(zone, plot());
956 impl->moveSelectionZoneOnTop(zone, plot());
956 }
957 }
957 }
958 }
958 }
959 }
959 }
960 }
960 else {
961 else {
961 if (!isMultiSelectionClick) {
962 if (!isMultiSelectionClick) {
962 parentVisualizationWidget()->selectionZoneManager().select(
963 parentVisualizationWidget()->selectionZoneManager().select(
963 {selectionZoneItemUnderCursor});
964 {selectionZoneItemUnderCursor});
964 impl->moveSelectionZoneOnTop(selectionZoneItemUnderCursor, plot());
965 impl->moveSelectionZoneOnTop(selectionZoneItemUnderCursor, plot());
965 }
966 }
966 else {
967 else {
967 parentVisualizationWidget()->selectionZoneManager().setSelected(
968 parentVisualizationWidget()->selectionZoneManager().setSelected(
968 selectionZoneItemUnderCursor, !selectionZoneItemUnderCursor->selected()
969 selectionZoneItemUnderCursor, !selectionZoneItemUnderCursor->selected()
969 || event->button() == Qt::RightButton);
970 || event->button() == Qt::RightButton);
970 }
971 }
971 }
972 }
972 }
973 }
973 else {
974 else {
974 // No selection change
975 // No selection change
975 }
976 }
976 }
977 }
977 }
978 }
978
979
979 void VisualizationGraphWidget::onDataCacheVariableUpdated()
980 void VisualizationGraphWidget::onDataCacheVariableUpdated()
980 {
981 {
981 auto graphRange = ui->widget->xAxis->range();
982 auto graphRange = ui->widget->xAxis->range();
982 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
983 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
983
984
984 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
985 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
985 auto variable = variableEntry.first;
986 auto variable = variableEntry.first;
986 qCDebug(LOG_VisualizationGraphWidget())
987 qCDebug(LOG_VisualizationGraphWidget())
987 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
988 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
988 qCDebug(LOG_VisualizationGraphWidget())
989 qCDebug(LOG_VisualizationGraphWidget())
989 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
990 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
990 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
991 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
991 impl->updateData(variableEntry.second, variable->dataSeries(), variable->range());
992 impl->updateData(variableEntry.second, variable->dataSeries(), variable->range());
992 }
993 }
993 }
994 }
994 }
995 }
995
996
996 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
997 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
997 const SqpRange &range)
998 const SqpRange &range)
998 {
999 {
999 auto it = impl->m_VariableToPlotMultiMap.find(variable);
1000 auto it = impl->m_VariableToPlotMultiMap.find(variable);
1000 if (it != impl->m_VariableToPlotMultiMap.end()) {
1001 if (it != impl->m_VariableToPlotMultiMap.end()) {
1001 impl->updateData(it->second, variable->dataSeries(), range);
1002 impl->updateData(it->second, variable->dataSeries(), range);
1002 }
1003 }
1003 }
1004 }
@@ -1,601 +1,601
1 #include "Visualization/VisualizationZoneWidget.h"
1 #include "Visualization/VisualizationZoneWidget.h"
2
2
3 #include "Visualization/IVisualizationWidgetVisitor.h"
3 #include "Visualization/IVisualizationWidgetVisitor.h"
4 #include "Visualization/QCustomPlotSynchronizer.h"
4 #include "Visualization/QCustomPlotSynchronizer.h"
5 #include "Visualization/VisualizationGraphWidget.h"
5 #include "Visualization/VisualizationGraphWidget.h"
6 #include "Visualization/VisualizationWidget.h"
6 #include "Visualization/VisualizationWidget.h"
7 #include "ui_VisualizationZoneWidget.h"
7 #include "ui_VisualizationZoneWidget.h"
8
8
9 #include "Common/MimeTypesDef.h"
9 #include "Common/MimeTypesDef.h"
10 #include "Common/VisualizationDef.h"
10 #include "Common/VisualizationDef.h"
11
11
12 #include <Data/SqpRange.h>
12 #include <Data/SqpRange.h>
13 #include <Time/TimeController.h>
13 #include <Time/TimeController.h>
14 #include <Variable/Variable.h>
14 #include <Variable/Variable.h>
15 #include <Variable/VariableController.h>
15 #include <Variable/VariableController.h>
16
16
17 #include <Visualization/operations/FindVariableOperation.h>
17 #include <Visualization/operations/FindVariableOperation.h>
18
18
19 #include <DragAndDrop/DragDropGuiController.h>
19 #include <DragAndDrop/DragDropGuiController.h>
20 #include <QUuid>
20 #include <QUuid>
21 #include <SqpApplication.h>
21 #include <SqpApplication.h>
22 #include <cmath>
22 #include <cmath>
23
23
24 #include <QLayout>
24 #include <QLayout>
25
25
26 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
26 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
27
27
28 namespace {
28 namespace {
29
29
30 /**
30 /**
31 * Applies a function to all graphs of the zone represented by its layout
31 * Applies a function to all graphs of the zone represented by its layout
32 * @param layout the layout that contains graphs
32 * @param layout the layout that contains graphs
33 * @param fun the function to apply to each graph
33 * @param fun the function to apply to each graph
34 */
34 */
35 template <typename Fun>
35 template <typename Fun>
36 void processGraphs(QLayout &layout, Fun fun)
36 void processGraphs(QLayout &layout, Fun fun)
37 {
37 {
38 for (auto i = 0; i < layout.count(); ++i) {
38 for (auto i = 0; i < layout.count(); ++i) {
39 if (auto item = layout.itemAt(i)) {
39 if (auto item = layout.itemAt(i)) {
40 if (auto visualizationGraphWidget
40 if (auto visualizationGraphWidget
41 = qobject_cast<VisualizationGraphWidget *>(item->widget())) {
41 = qobject_cast<VisualizationGraphWidget *>(item->widget())) {
42 fun(*visualizationGraphWidget);
42 fun(*visualizationGraphWidget);
43 }
43 }
44 }
44 }
45 }
45 }
46 }
46 }
47
47
48 /// Generates a default name for a new graph, according to the number of graphs already displayed in
48 /// Generates a default name for a new graph, according to the number of graphs already displayed in
49 /// the zone
49 /// the zone
50 QString defaultGraphName(QLayout &layout)
50 QString defaultGraphName(QLayout &layout)
51 {
51 {
52 QSet<QString> existingNames;
52 QSet<QString> existingNames;
53 processGraphs(
53 processGraphs(
54 layout, [&existingNames](auto &graphWidget) { existingNames.insert(graphWidget.name()); });
54 layout, [&existingNames](auto &graphWidget) { existingNames.insert(graphWidget.name()); });
55
55
56 int zoneNum = 1;
56 int zoneNum = 1;
57 QString name;
57 QString name;
58 do {
58 do {
59 name = QObject::tr("Graph ").append(QString::number(zoneNum));
59 name = QObject::tr("Graph ").append(QString::number(zoneNum));
60 ++zoneNum;
60 ++zoneNum;
61 } while (existingNames.contains(name));
61 } while (existingNames.contains(name));
62
62
63 return name;
63 return name;
64 }
64 }
65
65
66 } // namespace
66 } // namespace
67
67
68 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate {
68 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate {
69
69
70 explicit VisualizationZoneWidgetPrivate()
70 explicit VisualizationZoneWidgetPrivate()
71 : m_SynchronisationGroupId{QUuid::createUuid()},
71 : m_SynchronisationGroupId{QUuid::createUuid()},
72 m_Synchronizer{std::make_unique<QCustomPlotSynchronizer>()}
72 m_Synchronizer{std::make_unique<QCustomPlotSynchronizer>()}
73 {
73 {
74 }
74 }
75 QUuid m_SynchronisationGroupId;
75 QUuid m_SynchronisationGroupId;
76 std::unique_ptr<IGraphSynchronizer> m_Synchronizer;
76 std::unique_ptr<IGraphSynchronizer> m_Synchronizer;
77
77
78 void dropGraph(int index, VisualizationZoneWidget *zoneWidget);
78 void dropGraph(int index, VisualizationZoneWidget *zoneWidget);
79 void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index,
79 void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index,
80 VisualizationZoneWidget *zoneWidget);
80 VisualizationZoneWidget *zoneWidget);
81 };
81 };
82
82
83 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
83 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
84 : VisualizationDragWidget{parent},
84 : VisualizationDragWidget{parent},
85 ui{new Ui::VisualizationZoneWidget},
85 ui{new Ui::VisualizationZoneWidget},
86 impl{spimpl::make_unique_impl<VisualizationZoneWidgetPrivate>()}
86 impl{spimpl::make_unique_impl<VisualizationZoneWidgetPrivate>()}
87 {
87 {
88 ui->setupUi(this);
88 ui->setupUi(this);
89
89
90 ui->zoneNameLabel->setText(name);
90 ui->zoneNameLabel->setText(name);
91
91
92 ui->dragDropContainer->setPlaceHolderType(DragDropGuiController::PlaceHolderType::Graph);
92 ui->dragDropContainer->setPlaceHolderType(DragDropGuiController::PlaceHolderType::Graph);
93 ui->dragDropContainer->setMimeType(MIME_TYPE_GRAPH,
93 ui->dragDropContainer->setMimeType(MIME_TYPE_GRAPH,
94 VisualizationDragDropContainer::DropBehavior::Inserted);
94 VisualizationDragDropContainer::DropBehavior::Inserted);
95 ui->dragDropContainer->setMimeType(
95 ui->dragDropContainer->setMimeType(
96 MIME_TYPE_VARIABLE_LIST, VisualizationDragDropContainer::DropBehavior::InsertedAndMerged);
96 MIME_TYPE_VARIABLE_LIST, VisualizationDragDropContainer::DropBehavior::InsertedAndMerged);
97 ui->dragDropContainer->setMimeType(MIME_TYPE_TIME_RANGE,
97 ui->dragDropContainer->setMimeType(MIME_TYPE_TIME_RANGE,
98 VisualizationDragDropContainer::DropBehavior::Merged);
98 VisualizationDragDropContainer::DropBehavior::Merged);
99 ui->dragDropContainer->setMimeType(MIME_TYPE_ZONE,
99 ui->dragDropContainer->setMimeType(MIME_TYPE_ZONE,
100 VisualizationDragDropContainer::DropBehavior::Forbidden);
100 VisualizationDragDropContainer::DropBehavior::Forbidden);
101 ui->dragDropContainer->setMimeType(MIME_TYPE_SELECTION_ZONE,
101 ui->dragDropContainer->setMimeType(MIME_TYPE_SELECTION_ZONE,
102 VisualizationDragDropContainer::DropBehavior::Forbidden);
102 VisualizationDragDropContainer::DropBehavior::Forbidden);
103 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
103 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
104 return sqpApp->dragDropGuiController().checkMimeDataForVisualization(mimeData,
104 return sqpApp->dragDropGuiController().checkMimeDataForVisualization(mimeData,
105 ui->dragDropContainer);
105 ui->dragDropContainer);
106 });
106 });
107
107
108 auto acceptDragWidgetFun = [](auto dragWidget, auto mimeData) {
108 auto acceptDragWidgetFun = [](auto dragWidget, auto mimeData) {
109 if (!mimeData) {
109 if (!mimeData) {
110 return false;
110 return false;
111 }
111 }
112
112
113 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
113 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
114 auto variables = sqpApp->variableController().variablesForMimeData(
114 auto variables = sqpApp->variableController().variablesForMimeData(
115 mimeData->data(MIME_TYPE_VARIABLE_LIST));
115 mimeData->data(MIME_TYPE_VARIABLE_LIST));
116
116
117 if (variables.count() != 1) {
117 if (variables.count() != 1) {
118 return false;
118 return false;
119 }
119 }
120 auto variable = variables.first();
120 auto variable = variables.first();
121
121
122 if (auto graphWidget = dynamic_cast<const VisualizationGraphWidget *>(dragWidget)) {
122 if (auto graphWidget = dynamic_cast<const VisualizationGraphWidget *>(dragWidget)) {
123 return graphWidget->canDrop(*variable);
123 return graphWidget->canDrop(*variable);
124 }
124 }
125 }
125 }
126
126
127 return true;
127 return true;
128 };
128 };
129 ui->dragDropContainer->setAcceptDragWidgetFunction(acceptDragWidgetFun);
129 ui->dragDropContainer->setAcceptDragWidgetFunction(acceptDragWidgetFun);
130
130
131 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this,
131 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this,
132 &VisualizationZoneWidget::dropMimeData);
132 &VisualizationZoneWidget::dropMimeData);
133 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredOnWidget, this,
133 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredOnWidget, this,
134 &VisualizationZoneWidget::dropMimeDataOnGraph);
134 &VisualizationZoneWidget::dropMimeDataOnGraph);
135
135
136 // 'Close' options : widget is deleted when closed
136 // 'Close' options : widget is deleted when closed
137 setAttribute(Qt::WA_DeleteOnClose);
137 setAttribute(Qt::WA_DeleteOnClose);
138 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
138 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
139 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
139 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
140
140
141 // Synchronisation id
141 // Synchronisation id
142 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronizationGroupId",
142 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronizationGroupId",
143 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
143 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
144 }
144 }
145
145
146 VisualizationZoneWidget::~VisualizationZoneWidget()
146 VisualizationZoneWidget::~VisualizationZoneWidget()
147 {
147 {
148 delete ui;
148 delete ui;
149 }
149 }
150
150
151 void VisualizationZoneWidget::setZoneRange(const SqpRange &range)
151 void VisualizationZoneWidget::setZoneRange(const SqpRange &range)
152 {
152 {
153 if (auto graph = firstGraph()) {
153 if (auto graph = firstGraph()) {
154 graph->setGraphRange(range);
154 graph->setGraphRange(range);
155 }
155 }
156 else {
156 else {
157 qCWarning(LOG_VisualizationZoneWidget())
157 qCWarning(LOG_VisualizationZoneWidget())
158 << tr("setZoneRange:Cannot set the range of an empty zone.");
158 << tr("setZoneRange:Cannot set the range of an empty zone.");
159 }
159 }
160 }
160 }
161
161
162 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
162 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
163 {
163 {
164 // Synchronize new graph with others in the zone
164 // Synchronize new graph with others in the zone
165 impl->m_Synchronizer->addGraph(*graphWidget);
165 impl->m_Synchronizer->addGraph(*graphWidget);
166
166
167 ui->dragDropContainer->addDragWidget(graphWidget);
167 ui->dragDropContainer->addDragWidget(graphWidget);
168 }
168 }
169
169
170 void VisualizationZoneWidget::insertGraph(int index, VisualizationGraphWidget *graphWidget)
170 void VisualizationZoneWidget::insertGraph(int index, VisualizationGraphWidget *graphWidget)
171 {
171 {
172 // Synchronize new graph with others in the zone
172 // Synchronize new graph with others in the zone
173 impl->m_Synchronizer->addGraph(*graphWidget);
173 impl->m_Synchronizer->addGraph(*graphWidget);
174
174
175 ui->dragDropContainer->insertDragWidget(index, graphWidget);
175 ui->dragDropContainer->insertDragWidget(index, graphWidget);
176 }
176 }
177
177
178 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
178 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
179 {
179 {
180 return createGraph(variable, -1);
180 return createGraph(variable, -1);
181 }
181 }
182
182
183 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable,
183 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable,
184 int index)
184 int index)
185 {
185 {
186 auto graphWidget
186 auto graphWidget
187 = new VisualizationGraphWidget{defaultGraphName(*ui->dragDropContainer->layout()), this};
187 = new VisualizationGraphWidget{defaultGraphName(*ui->dragDropContainer->layout()), this};
188
188
189
189
190 // Set graph properties
190 // Set graph properties
191 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
191 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
192 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
192 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
193
193
194
194
195 // Lambda to synchronize zone widget
195 // Lambda to synchronize zone widget
196 auto synchronizeZoneWidget = [this, graphWidget](const SqpRange &graphRange,
196 auto synchronizeZoneWidget = [this, graphWidget](const SqpRange &graphRange,
197 const SqpRange &oldGraphRange) {
197 const SqpRange &oldGraphRange) {
198
198
199 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
199 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
200 auto frameLayout = ui->dragDropContainer->layout();
200 auto frameLayout = ui->dragDropContainer->layout();
201 for (auto i = 0; i < frameLayout->count(); ++i) {
201 for (auto i = 0; i < frameLayout->count(); ++i) {
202 auto graphChild
202 auto graphChild
203 = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
203 = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
204 if (graphChild && (graphChild != graphWidget)) {
204 if (graphChild && (graphChild != graphWidget)) {
205
205
206 auto graphChildRange = graphChild->graphRange();
206 auto graphChildRange = graphChild->graphRange();
207 switch (zoomType) {
207 switch (zoomType) {
208 case AcquisitionZoomType::ZoomIn: {
208 case AcquisitionZoomType::ZoomIn: {
209 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
209 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
210 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
210 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
211 graphChildRange.m_TStart += deltaLeft;
211 graphChildRange.m_TStart += deltaLeft;
212 graphChildRange.m_TEnd -= deltaRight;
212 graphChildRange.m_TEnd -= deltaRight;
213 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomIn");
213 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomIn");
214 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
214 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
215 << deltaLeft;
215 << deltaLeft;
216 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
216 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
217 << deltaRight;
217 << deltaRight;
218 qCDebug(LOG_VisualizationZoneWidget())
218 qCDebug(LOG_VisualizationZoneWidget())
219 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
219 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
220
220
221 break;
221 break;
222 }
222 }
223
223
224 case AcquisitionZoomType::ZoomOut: {
224 case AcquisitionZoomType::ZoomOut: {
225 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomOut");
225 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomOut");
226 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
226 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
227 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
227 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
228 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
228 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
229 << deltaLeft;
229 << deltaLeft;
230 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
230 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
231 << deltaRight;
231 << deltaRight;
232 qCDebug(LOG_VisualizationZoneWidget())
232 qCDebug(LOG_VisualizationZoneWidget())
233 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
233 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
234 graphChildRange.m_TStart -= deltaLeft;
234 graphChildRange.m_TStart -= deltaLeft;
235 graphChildRange.m_TEnd += deltaRight;
235 graphChildRange.m_TEnd += deltaRight;
236 break;
236 break;
237 }
237 }
238 case AcquisitionZoomType::PanRight: {
238 case AcquisitionZoomType::PanRight: {
239 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanRight");
239 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanRight");
240 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
240 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
241 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
241 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
242 graphChildRange.m_TStart += deltaLeft;
242 graphChildRange.m_TStart += deltaLeft;
243 graphChildRange.m_TEnd += deltaRight;
243 graphChildRange.m_TEnd += deltaRight;
244 qCDebug(LOG_VisualizationZoneWidget())
244 qCDebug(LOG_VisualizationZoneWidget())
245 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
245 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
246 break;
246 break;
247 }
247 }
248 case AcquisitionZoomType::PanLeft: {
248 case AcquisitionZoomType::PanLeft: {
249 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanLeft");
249 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanLeft");
250 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
250 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
251 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
251 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
252 graphChildRange.m_TStart -= deltaLeft;
252 graphChildRange.m_TStart -= deltaLeft;
253 graphChildRange.m_TEnd -= deltaRight;
253 graphChildRange.m_TEnd -= deltaRight;
254 break;
254 break;
255 }
255 }
256 case AcquisitionZoomType::Unknown: {
256 case AcquisitionZoomType::Unknown: {
257 qCDebug(LOG_VisualizationZoneWidget())
257 qCDebug(LOG_VisualizationZoneWidget())
258 << tr("Impossible to synchronize: zoom type unknown");
258 << tr("Impossible to synchronize: zoom type unknown");
259 break;
259 break;
260 }
260 }
261 default:
261 default:
262 qCCritical(LOG_VisualizationZoneWidget())
262 qCCritical(LOG_VisualizationZoneWidget())
263 << tr("Impossible to synchronize: zoom type not take into account");
263 << tr("Impossible to synchronize: zoom type not take into account");
264 // No action
264 // No action
265 break;
265 break;
266 }
266 }
267 graphChild->enableAcquisition(false);
267 graphChild->setFlags(GraphFlag::DisableAll);
268 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range before: ")
268 qCDebug(LOG_VisualizationZoneWidget())
269 << graphChild->graphRange();
269 << tr("TORM: Range before: ") << graphChild->graphRange();
270 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range after : ")
270 qCDebug(LOG_VisualizationZoneWidget())
271 << graphChildRange;
271 << tr("TORM: Range after : ") << graphChildRange;
272 qCDebug(LOG_VisualizationZoneWidget())
272 qCDebug(LOG_VisualizationZoneWidget())
273 << tr("TORM: child dt") << graphChildRange.m_TEnd - graphChildRange.m_TStart;
273 << tr("TORM: child dt") << graphChildRange.m_TEnd - graphChildRange.m_TStart;
274 graphChild->setGraphRange(graphChildRange);
274 graphChild->setGraphRange(graphChildRange);
275 graphChild->enableAcquisition(true);
275 graphChild->setFlags(GraphFlag::EnableAll);
276 }
276 }
277 }
277 }
278 };
278 };
279
279
280 // connection for synchronization
280 // connection for synchronization
281 connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
281 connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
282 connect(graphWidget, &VisualizationGraphWidget::variableAdded, this,
282 connect(graphWidget, &VisualizationGraphWidget::variableAdded, this,
283 &VisualizationZoneWidget::onVariableAdded);
283 &VisualizationZoneWidget::onVariableAdded);
284 connect(graphWidget, &VisualizationGraphWidget::variableAboutToBeRemoved, this,
284 connect(graphWidget, &VisualizationGraphWidget::variableAboutToBeRemoved, this,
285 &VisualizationZoneWidget::onVariableAboutToBeRemoved);
285 &VisualizationZoneWidget::onVariableAboutToBeRemoved);
286
286
287 auto range = SqpRange{};
287 auto range = SqpRange{};
288 if (auto firstGraph = this->firstGraph()) {
288 if (auto firstGraph = this->firstGraph()) {
289 // Case of a new graph in a existant zone
289 // Case of a new graph in a existant zone
290 range = firstGraph->graphRange();
290 range = firstGraph->graphRange();
291 }
291 }
292 else {
292 else {
293 // Case of a new graph as the first of the zone
293 // Case of a new graph as the first of the zone
294 range = variable->range();
294 range = variable->range();
295 }
295 }
296
296
297 this->insertGraph(index, graphWidget);
297 this->insertGraph(index, graphWidget);
298
298
299 graphWidget->addVariable(variable, range);
299 graphWidget->addVariable(variable, range);
300 graphWidget->setYRange(variable);
300 graphWidget->setYRange(variable);
301
301
302 return graphWidget;
302 return graphWidget;
303 }
303 }
304
304
305 VisualizationGraphWidget *
305 VisualizationGraphWidget *
306 VisualizationZoneWidget::createGraph(const QList<std::shared_ptr<Variable> > variables, int index)
306 VisualizationZoneWidget::createGraph(const QList<std::shared_ptr<Variable> > variables, int index)
307 {
307 {
308 if (variables.isEmpty()) {
308 if (variables.isEmpty()) {
309 return nullptr;
309 return nullptr;
310 }
310 }
311
311
312 auto graphWidget = createGraph(variables.first(), index);
312 auto graphWidget = createGraph(variables.first(), index);
313 for (auto variableIt = variables.cbegin() + 1; variableIt != variables.cend(); ++variableIt) {
313 for (auto variableIt = variables.cbegin() + 1; variableIt != variables.cend(); ++variableIt) {
314 graphWidget->addVariable(*variableIt, graphWidget->graphRange());
314 graphWidget->addVariable(*variableIt, graphWidget->graphRange());
315 }
315 }
316
316
317 return graphWidget;
317 return graphWidget;
318 }
318 }
319
319
320 VisualizationGraphWidget *VisualizationZoneWidget::firstGraph() const
320 VisualizationGraphWidget *VisualizationZoneWidget::firstGraph() const
321 {
321 {
322 VisualizationGraphWidget *firstGraph = nullptr;
322 VisualizationGraphWidget *firstGraph = nullptr;
323 auto layout = ui->dragDropContainer->layout();
323 auto layout = ui->dragDropContainer->layout();
324 if (layout->count() > 0) {
324 if (layout->count() > 0) {
325 if (auto visualizationGraphWidget
325 if (auto visualizationGraphWidget
326 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
326 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
327 firstGraph = visualizationGraphWidget;
327 firstGraph = visualizationGraphWidget;
328 }
328 }
329 }
329 }
330
330
331 return firstGraph;
331 return firstGraph;
332 }
332 }
333
333
334 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
334 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
335 {
335 {
336 if (visitor) {
336 if (visitor) {
337 visitor->visitEnter(this);
337 visitor->visitEnter(this);
338
338
339 // Apply visitor to graph children: widgets different from graphs are not visited (no
339 // Apply visitor to graph children: widgets different from graphs are not visited (no
340 // action)
340 // action)
341 processGraphs(
341 processGraphs(
342 *ui->dragDropContainer->layout(),
342 *ui->dragDropContainer->layout(),
343 [visitor](VisualizationGraphWidget &graphWidget) { graphWidget.accept(visitor); });
343 [visitor](VisualizationGraphWidget &graphWidget) { graphWidget.accept(visitor); });
344
344
345 visitor->visitLeave(this);
345 visitor->visitLeave(this);
346 }
346 }
347 else {
347 else {
348 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
348 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
349 }
349 }
350 }
350 }
351
351
352 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
352 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
353 {
353 {
354 // A tab can always accomodate a variable
354 // A tab can always accomodate a variable
355 Q_UNUSED(variable);
355 Q_UNUSED(variable);
356 return true;
356 return true;
357 }
357 }
358
358
359 bool VisualizationZoneWidget::contains(const Variable &variable) const
359 bool VisualizationZoneWidget::contains(const Variable &variable) const
360 {
360 {
361 Q_UNUSED(variable);
361 Q_UNUSED(variable);
362 return false;
362 return false;
363 }
363 }
364
364
365 QString VisualizationZoneWidget::name() const
365 QString VisualizationZoneWidget::name() const
366 {
366 {
367 return ui->zoneNameLabel->text();
367 return ui->zoneNameLabel->text();
368 }
368 }
369
369
370 QMimeData *VisualizationZoneWidget::mimeData(const QPoint &position) const
370 QMimeData *VisualizationZoneWidget::mimeData(const QPoint &position) const
371 {
371 {
372 Q_UNUSED(position);
372 Q_UNUSED(position);
373
373
374 auto mimeData = new QMimeData;
374 auto mimeData = new QMimeData;
375 mimeData->setData(MIME_TYPE_ZONE, QByteArray{});
375 mimeData->setData(MIME_TYPE_ZONE, QByteArray{});
376
376
377 if (auto firstGraph = this->firstGraph()) {
377 if (auto firstGraph = this->firstGraph()) {
378 auto timeRangeData = TimeController::mimeDataForTimeRange(firstGraph->graphRange());
378 auto timeRangeData = TimeController::mimeDataForTimeRange(firstGraph->graphRange());
379 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
379 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
380 }
380 }
381
381
382 return mimeData;
382 return mimeData;
383 }
383 }
384
384
385 bool VisualizationZoneWidget::isDragAllowed() const
385 bool VisualizationZoneWidget::isDragAllowed() const
386 {
386 {
387 return true;
387 return true;
388 }
388 }
389
389
390 void VisualizationZoneWidget::notifyMouseMoveInGraph(const QPointF &graphPosition,
390 void VisualizationZoneWidget::notifyMouseMoveInGraph(const QPointF &graphPosition,
391 const QPointF &plotPosition,
391 const QPointF &plotPosition,
392 VisualizationGraphWidget *graphWidget)
392 VisualizationGraphWidget *graphWidget)
393 {
393 {
394 processGraphs(*ui->dragDropContainer->layout(), [&graphPosition, &plotPosition, &graphWidget](
394 processGraphs(*ui->dragDropContainer->layout(), [&graphPosition, &plotPosition, &graphWidget](
395 VisualizationGraphWidget &processedGraph) {
395 VisualizationGraphWidget &processedGraph) {
396
396
397 switch (sqpApp->plotsCursorMode()) {
397 switch (sqpApp->plotsCursorMode()) {
398 case SqpApplication::PlotsCursorMode::Vertical:
398 case SqpApplication::PlotsCursorMode::Vertical:
399 processedGraph.removeHorizontalCursor();
399 processedGraph.removeHorizontalCursor();
400 processedGraph.addVerticalCursorAtViewportPosition(graphPosition.x());
400 processedGraph.addVerticalCursorAtViewportPosition(graphPosition.x());
401 break;
401 break;
402 case SqpApplication::PlotsCursorMode::Temporal:
402 case SqpApplication::PlotsCursorMode::Temporal:
403 processedGraph.addVerticalCursor(plotPosition.x());
403 processedGraph.addVerticalCursor(plotPosition.x());
404 processedGraph.removeHorizontalCursor();
404 processedGraph.removeHorizontalCursor();
405 break;
405 break;
406 case SqpApplication::PlotsCursorMode::Horizontal:
406 case SqpApplication::PlotsCursorMode::Horizontal:
407 processedGraph.removeVerticalCursor();
407 processedGraph.removeVerticalCursor();
408 if (&processedGraph == graphWidget) {
408 if (&processedGraph == graphWidget) {
409 processedGraph.addHorizontalCursorAtViewportPosition(graphPosition.y());
409 processedGraph.addHorizontalCursorAtViewportPosition(graphPosition.y());
410 }
410 }
411 else {
411 else {
412 processedGraph.removeHorizontalCursor();
412 processedGraph.removeHorizontalCursor();
413 }
413 }
414 break;
414 break;
415 case SqpApplication::PlotsCursorMode::Cross:
415 case SqpApplication::PlotsCursorMode::Cross:
416 if (&processedGraph == graphWidget) {
416 if (&processedGraph == graphWidget) {
417 processedGraph.addVerticalCursorAtViewportPosition(graphPosition.x());
417 processedGraph.addVerticalCursorAtViewportPosition(graphPosition.x());
418 processedGraph.addHorizontalCursorAtViewportPosition(graphPosition.y());
418 processedGraph.addHorizontalCursorAtViewportPosition(graphPosition.y());
419 }
419 }
420 else {
420 else {
421 processedGraph.removeHorizontalCursor();
421 processedGraph.removeHorizontalCursor();
422 processedGraph.removeVerticalCursor();
422 processedGraph.removeVerticalCursor();
423 }
423 }
424 break;
424 break;
425 case SqpApplication::PlotsCursorMode::NoCursor:
425 case SqpApplication::PlotsCursorMode::NoCursor:
426 processedGraph.removeHorizontalCursor();
426 processedGraph.removeHorizontalCursor();
427 processedGraph.removeVerticalCursor();
427 processedGraph.removeVerticalCursor();
428 break;
428 break;
429 }
429 }
430
430
431
431
432 });
432 });
433 }
433 }
434
434
435 void VisualizationZoneWidget::notifyMouseLeaveGraph(VisualizationGraphWidget *graphWidget)
435 void VisualizationZoneWidget::notifyMouseLeaveGraph(VisualizationGraphWidget *graphWidget)
436 {
436 {
437 processGraphs(*ui->dragDropContainer->layout(), [](VisualizationGraphWidget &processedGraph) {
437 processGraphs(*ui->dragDropContainer->layout(), [](VisualizationGraphWidget &processedGraph) {
438 processedGraph.removeHorizontalCursor();
438 processedGraph.removeHorizontalCursor();
439 processedGraph.removeVerticalCursor();
439 processedGraph.removeVerticalCursor();
440 });
440 });
441 }
441 }
442
442
443 void VisualizationZoneWidget::closeEvent(QCloseEvent *event)
443 void VisualizationZoneWidget::closeEvent(QCloseEvent *event)
444 {
444 {
445 // Closes graphs in the zone
445 // Closes graphs in the zone
446 processGraphs(*ui->dragDropContainer->layout(),
446 processGraphs(*ui->dragDropContainer->layout(),
447 [](VisualizationGraphWidget &graphWidget) { graphWidget.close(); });
447 [](VisualizationGraphWidget &graphWidget) { graphWidget.close(); });
448
448
449 // Delete synchronization group from variable controller
449 // Delete synchronization group from variable controller
450 QMetaObject::invokeMethod(&sqpApp->variableController(), "onRemoveSynchronizationGroupId",
450 QMetaObject::invokeMethod(&sqpApp->variableController(), "onRemoveSynchronizationGroupId",
451 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
451 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
452
452
453 QWidget::closeEvent(event);
453 QWidget::closeEvent(event);
454 }
454 }
455
455
456 void VisualizationZoneWidget::onVariableAdded(std::shared_ptr<Variable> variable)
456 void VisualizationZoneWidget::onVariableAdded(std::shared_ptr<Variable> variable)
457 {
457 {
458 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronized",
458 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronized",
459 Qt::QueuedConnection, Q_ARG(std::shared_ptr<Variable>, variable),
459 Qt::QueuedConnection, Q_ARG(std::shared_ptr<Variable>, variable),
460 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
460 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
461 }
461 }
462
462
463 void VisualizationZoneWidget::onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable)
463 void VisualizationZoneWidget::onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable)
464 {
464 {
465 QMetaObject::invokeMethod(&sqpApp->variableController(), "desynchronize", Qt::QueuedConnection,
465 QMetaObject::invokeMethod(&sqpApp->variableController(), "desynchronize", Qt::QueuedConnection,
466 Q_ARG(std::shared_ptr<Variable>, variable),
466 Q_ARG(std::shared_ptr<Variable>, variable),
467 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
467 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
468 }
468 }
469
469
470 void VisualizationZoneWidget::dropMimeData(int index, const QMimeData *mimeData)
470 void VisualizationZoneWidget::dropMimeData(int index, const QMimeData *mimeData)
471 {
471 {
472 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
472 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
473 impl->dropGraph(index, this);
473 impl->dropGraph(index, this);
474 }
474 }
475 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
475 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
476 auto variables = sqpApp->variableController().variablesForMimeData(
476 auto variables = sqpApp->variableController().variablesForMimeData(
477 mimeData->data(MIME_TYPE_VARIABLE_LIST));
477 mimeData->data(MIME_TYPE_VARIABLE_LIST));
478 impl->dropVariables(variables, index, this);
478 impl->dropVariables(variables, index, this);
479 }
479 }
480 else {
480 else {
481 qCWarning(LOG_VisualizationZoneWidget())
481 qCWarning(LOG_VisualizationZoneWidget())
482 << tr("VisualizationZoneWidget::dropMimeData, unknown MIME data received.");
482 << tr("VisualizationZoneWidget::dropMimeData, unknown MIME data received.");
483 }
483 }
484 }
484 }
485
485
486 void VisualizationZoneWidget::dropMimeDataOnGraph(VisualizationDragWidget *dragWidget,
486 void VisualizationZoneWidget::dropMimeDataOnGraph(VisualizationDragWidget *dragWidget,
487 const QMimeData *mimeData)
487 const QMimeData *mimeData)
488 {
488 {
489 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(dragWidget);
489 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(dragWidget);
490 if (!graphWidget) {
490 if (!graphWidget) {
491 qCWarning(LOG_VisualizationZoneWidget())
491 qCWarning(LOG_VisualizationZoneWidget())
492 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, dropping in an unknown widget, "
492 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, dropping in an unknown widget, "
493 "drop aborted");
493 "drop aborted");
494 Q_ASSERT(false);
494 Q_ASSERT(false);
495 return;
495 return;
496 }
496 }
497
497
498 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
498 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
499 auto variables = sqpApp->variableController().variablesForMimeData(
499 auto variables = sqpApp->variableController().variablesForMimeData(
500 mimeData->data(MIME_TYPE_VARIABLE_LIST));
500 mimeData->data(MIME_TYPE_VARIABLE_LIST));
501 for (const auto &var : variables) {
501 for (const auto &var : variables) {
502 graphWidget->addVariable(var, graphWidget->graphRange());
502 graphWidget->addVariable(var, graphWidget->graphRange());
503 }
503 }
504 }
504 }
505 else if (mimeData->hasFormat(MIME_TYPE_TIME_RANGE)) {
505 else if (mimeData->hasFormat(MIME_TYPE_TIME_RANGE)) {
506 auto range = TimeController::timeRangeForMimeData(mimeData->data(MIME_TYPE_TIME_RANGE));
506 auto range = TimeController::timeRangeForMimeData(mimeData->data(MIME_TYPE_TIME_RANGE));
507 graphWidget->setGraphRange(range);
507 graphWidget->setGraphRange(range);
508 }
508 }
509 else {
509 else {
510 qCWarning(LOG_VisualizationZoneWidget())
510 qCWarning(LOG_VisualizationZoneWidget())
511 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, unknown MIME data received.");
511 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, unknown MIME data received.");
512 }
512 }
513 }
513 }
514
514
515 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropGraph(
515 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropGraph(
516 int index, VisualizationZoneWidget *zoneWidget)
516 int index, VisualizationZoneWidget *zoneWidget)
517 {
517 {
518 auto &helper = sqpApp->dragDropGuiController();
518 auto &helper = sqpApp->dragDropGuiController();
519
519
520 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
520 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
521 if (!graphWidget) {
521 if (!graphWidget) {
522 qCWarning(LOG_VisualizationZoneWidget())
522 qCWarning(LOG_VisualizationZoneWidget())
523 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the dropped graph is not "
523 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the dropped graph is not "
524 "found or invalid.");
524 "found or invalid.");
525 Q_ASSERT(false);
525 Q_ASSERT(false);
526 return;
526 return;
527 }
527 }
528
528
529 auto parentDragDropContainer
529 auto parentDragDropContainer
530 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
530 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
531 if (!parentDragDropContainer) {
531 if (!parentDragDropContainer) {
532 qCWarning(LOG_VisualizationZoneWidget())
532 qCWarning(LOG_VisualizationZoneWidget())
533 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the parent container of "
533 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the parent container of "
534 "the dropped graph is not found.");
534 "the dropped graph is not found.");
535 Q_ASSERT(false);
535 Q_ASSERT(false);
536 return;
536 return;
537 }
537 }
538
538
539 const auto &variables = graphWidget->variables();
539 const auto &variables = graphWidget->variables();
540
540
541 if (parentDragDropContainer != zoneWidget->ui->dragDropContainer && !variables.isEmpty()) {
541 if (parentDragDropContainer != zoneWidget->ui->dragDropContainer && !variables.isEmpty()) {
542 // The drop didn't occur in the same zone
542 // The drop didn't occur in the same zone
543
543
544 // Abort the requests for the variables (if any)
544 // Abort the requests for the variables (if any)
545 // Commented, because it's not sure if it's needed or not
545 // Commented, because it's not sure if it's needed or not
546 // for (const auto& var : variables)
546 // for (const auto& var : variables)
547 //{
547 //{
548 // sqpApp->variableController().onAbortProgressRequested(var);
548 // sqpApp->variableController().onAbortProgressRequested(var);
549 //}
549 //}
550
550
551 auto previousParentZoneWidget = graphWidget->parentZoneWidget();
551 auto previousParentZoneWidget = graphWidget->parentZoneWidget();
552 auto nbGraph = parentDragDropContainer->countDragWidget();
552 auto nbGraph = parentDragDropContainer->countDragWidget();
553 if (nbGraph == 1) {
553 if (nbGraph == 1) {
554 // This is the only graph in the previous zone, close the zone
554 // This is the only graph in the previous zone, close the zone
555 helper.delayedCloseWidget(previousParentZoneWidget);
555 helper.delayedCloseWidget(previousParentZoneWidget);
556 }
556 }
557 else {
557 else {
558 // Close the graph
558 // Close the graph
559 helper.delayedCloseWidget(graphWidget);
559 helper.delayedCloseWidget(graphWidget);
560 }
560 }
561
561
562 // Creates the new graph in the zone
562 // Creates the new graph in the zone
563 auto newGraphWidget = zoneWidget->createGraph(variables, index);
563 auto newGraphWidget = zoneWidget->createGraph(variables, index);
564 newGraphWidget->addSelectionZones(graphWidget->selectionZoneRanges());
564 newGraphWidget->addSelectionZones(graphWidget->selectionZoneRanges());
565 }
565 }
566 else {
566 else {
567 // The drop occurred in the same zone or the graph is empty
567 // The drop occurred in the same zone or the graph is empty
568 // Simple move of the graph, no variable operation associated
568 // Simple move of the graph, no variable operation associated
569 parentDragDropContainer->layout()->removeWidget(graphWidget);
569 parentDragDropContainer->layout()->removeWidget(graphWidget);
570
570
571 if (variables.isEmpty() && parentDragDropContainer != zoneWidget->ui->dragDropContainer) {
571 if (variables.isEmpty() && parentDragDropContainer != zoneWidget->ui->dragDropContainer) {
572 // The graph is empty and dropped in a different zone.
572 // The graph is empty and dropped in a different zone.
573 // Take the range of the first graph in the zone (if existing).
573 // Take the range of the first graph in the zone (if existing).
574 auto layout = zoneWidget->ui->dragDropContainer->layout();
574 auto layout = zoneWidget->ui->dragDropContainer->layout();
575 if (layout->count() > 0) {
575 if (layout->count() > 0) {
576 if (auto visualizationGraphWidget
576 if (auto visualizationGraphWidget
577 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
577 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
578 graphWidget->setGraphRange(visualizationGraphWidget->graphRange());
578 graphWidget->setGraphRange(visualizationGraphWidget->graphRange());
579 }
579 }
580 }
580 }
581 }
581 }
582
582
583 zoneWidget->ui->dragDropContainer->insertDragWidget(index, graphWidget);
583 zoneWidget->ui->dragDropContainer->insertDragWidget(index, graphWidget);
584 }
584 }
585 }
585 }
586
586
587 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropVariables(
587 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropVariables(
588 const QList<std::shared_ptr<Variable> > &variables, int index,
588 const QList<std::shared_ptr<Variable> > &variables, int index,
589 VisualizationZoneWidget *zoneWidget)
589 VisualizationZoneWidget *zoneWidget)
590 {
590 {
591 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
591 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
592 // compatible variable here
592 // compatible variable here
593 if (variables.count() > 1) {
593 if (variables.count() > 1) {
594 qCWarning(LOG_VisualizationZoneWidget())
594 qCWarning(LOG_VisualizationZoneWidget())
595 << tr("VisualizationZoneWidget::dropVariables, dropping multiple variables, operation "
595 << tr("VisualizationZoneWidget::dropVariables, dropping multiple variables, operation "
596 "aborted.");
596 "aborted.");
597 return;
597 return;
598 }
598 }
599
599
600 zoneWidget->createGraph(variables, index);
600 zoneWidget->createGraph(variables, index);
601 }
601 }
@@ -1,71 +1,73
1 #include "Visualization/operations/RescaleAxeOperation.h"
1 #include "Visualization/operations/RescaleAxeOperation.h"
2 #include "Visualization/VisualizationGraphWidget.h"
2 #include "Visualization/VisualizationGraphWidget.h"
3
3
4 Q_LOGGING_CATEGORY(LOG_RescaleAxeOperation, "RescaleAxeOperation")
4 Q_LOGGING_CATEGORY(LOG_RescaleAxeOperation, "RescaleAxeOperation")
5
5
6 struct RescaleAxeOperation::RescaleAxeOperationPrivate {
6 struct RescaleAxeOperation::RescaleAxeOperationPrivate {
7 explicit RescaleAxeOperationPrivate(std::shared_ptr<Variable> variable, const SqpRange &range)
7 explicit RescaleAxeOperationPrivate(std::shared_ptr<Variable> variable, const SqpRange &range)
8 : m_Variable{variable}, m_Range{range}
8 : m_Variable{variable}, m_Range{range}
9 {
9 {
10 }
10 }
11
11
12 std::shared_ptr<Variable> m_Variable;
12 std::shared_ptr<Variable> m_Variable;
13 SqpRange m_Range;
13 SqpRange m_Range;
14 };
14 };
15
15
16 RescaleAxeOperation::RescaleAxeOperation(std::shared_ptr<Variable> variable, const SqpRange &range)
16 RescaleAxeOperation::RescaleAxeOperation(std::shared_ptr<Variable> variable, const SqpRange &range)
17 : impl{spimpl::make_unique_impl<RescaleAxeOperationPrivate>(variable, range)}
17 : impl{spimpl::make_unique_impl<RescaleAxeOperationPrivate>(variable, range)}
18 {
18 {
19 }
19 }
20
20
21 void RescaleAxeOperation::visitEnter(VisualizationWidget *widget)
21 void RescaleAxeOperation::visitEnter(VisualizationWidget *widget)
22 {
22 {
23 // VisualizationWidget is not intended to contain a variable
23 // VisualizationWidget is not intended to contain a variable
24 Q_UNUSED(widget)
24 Q_UNUSED(widget)
25 }
25 }
26
26
27 void RescaleAxeOperation::visitLeave(VisualizationWidget *widget)
27 void RescaleAxeOperation::visitLeave(VisualizationWidget *widget)
28 {
28 {
29 // VisualizationWidget is not intended to contain a variable
29 // VisualizationWidget is not intended to contain a variable
30 Q_UNUSED(widget)
30 Q_UNUSED(widget)
31 }
31 }
32
32
33 void RescaleAxeOperation::visitEnter(VisualizationTabWidget *tabWidget)
33 void RescaleAxeOperation::visitEnter(VisualizationTabWidget *tabWidget)
34 {
34 {
35 // VisualizationTabWidget is not intended to contain a variable
35 // VisualizationTabWidget is not intended to contain a variable
36 Q_UNUSED(tabWidget)
36 Q_UNUSED(tabWidget)
37 }
37 }
38
38
39 void RescaleAxeOperation::visitLeave(VisualizationTabWidget *tabWidget)
39 void RescaleAxeOperation::visitLeave(VisualizationTabWidget *tabWidget)
40 {
40 {
41 // VisualizationTabWidget is not intended to contain a variable
41 // VisualizationTabWidget is not intended to contain a variable
42 Q_UNUSED(tabWidget)
42 Q_UNUSED(tabWidget)
43 }
43 }
44
44
45 void RescaleAxeOperation::visitEnter(VisualizationZoneWidget *zoneWidget)
45 void RescaleAxeOperation::visitEnter(VisualizationZoneWidget *zoneWidget)
46 {
46 {
47 // VisualizationZoneWidget is not intended to contain a variable
47 // VisualizationZoneWidget is not intended to contain a variable
48 Q_UNUSED(zoneWidget)
48 Q_UNUSED(zoneWidget)
49 }
49 }
50
50
51 void RescaleAxeOperation::visitLeave(VisualizationZoneWidget *zoneWidget)
51 void RescaleAxeOperation::visitLeave(VisualizationZoneWidget *zoneWidget)
52 {
52 {
53 // VisualizationZoneWidget is not intended to contain a variable
53 // VisualizationZoneWidget is not intended to contain a variable
54 Q_UNUSED(zoneWidget)
54 Q_UNUSED(zoneWidget)
55 }
55 }
56
56
57 void RescaleAxeOperation::visit(VisualizationGraphWidget *graphWidget)
57 void RescaleAxeOperation::visit(VisualizationGraphWidget *graphWidget)
58 {
58 {
59 if (graphWidget) {
59 if (graphWidget) {
60 // If the widget contains the variable, rescale it
60 // If the widget contains the variable, rescale it
61 if (impl->m_Variable && graphWidget->contains(*impl->m_Variable)) {
61 if (impl->m_Variable && graphWidget->contains(*impl->m_Variable)) {
62 graphWidget->enableAcquisition(false);
62 // During rescale, acquisition for the graph is disabled but synchronization is still
63 // enabled
64 graphWidget->setFlags(GraphFlag::EnableSynchronization);
63 graphWidget->setGraphRange(impl->m_Range);
65 graphWidget->setGraphRange(impl->m_Range);
64 graphWidget->enableAcquisition(true);
66 graphWidget->setFlags(GraphFlag::EnableAll);
65 }
67 }
66 }
68 }
67 else {
69 else {
68 qCCritical(LOG_RescaleAxeOperation(),
70 qCCritical(LOG_RescaleAxeOperation(),
69 "Can't visit VisualizationGraphWidget : the widget is null");
71 "Can't visit VisualizationGraphWidget : the widget is null");
70 }
72 }
71 }
73 }
@@ -1,109 +1,118
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
16
17 // //////////// //
17 // //////////// //
18 // FuzzingState //
18 // FuzzingState //
19 // //////////// //
19 // //////////// //
20
20
21 const SyncGroup &FuzzingState::syncGroup(SyncGroupId id) const
21 const SyncGroup &FuzzingState::syncGroup(SyncGroupId id) const
22 {
22 {
23 return m_SyncGroupsPool.at(id);
23 return m_SyncGroupsPool.at(id);
24 }
24 }
25
25
26 SyncGroup &FuzzingState::syncGroup(SyncGroupId id)
26 SyncGroup &FuzzingState::syncGroup(SyncGroupId id)
27 {
27 {
28 return m_SyncGroupsPool.at(id);
28 return m_SyncGroupsPool.at(id);
29 }
29 }
30
30
31 const VariableState &FuzzingState::variableState(VariableId id) const
31 const VariableState &FuzzingState::variableState(VariableId id) const
32 {
32 {
33 return m_VariablesPool.at(id);
33 return m_VariablesPool.at(id);
34 }
34 }
35
35
36 VariableState &FuzzingState::variableState(VariableId id)
36 VariableState &FuzzingState::variableState(VariableId id)
37 {
37 {
38 return m_VariablesPool.at(id);
38 return m_VariablesPool.at(id);
39 }
39 }
40
40
41 SyncGroupId FuzzingState::syncGroupId(VariableId variableId) const
41 SyncGroupId FuzzingState::syncGroupId(VariableId variableId) const
42 {
42 {
43 auto end = m_SyncGroupsPool.cend();
43 auto end = m_SyncGroupsPool.cend();
44 auto it
44 auto it
45 = std::find_if(m_SyncGroupsPool.cbegin(), end, [&variableId](const auto &syncGroupEntry) {
45 = std::find_if(m_SyncGroupsPool.cbegin(), end, [&variableId](const auto &syncGroupEntry) {
46 const auto &syncGroup = syncGroupEntry.second;
46 const auto &syncGroup = syncGroupEntry.second;
47 return syncGroup.m_Variables.find(variableId) != syncGroup.m_Variables.end();
47 return syncGroup.m_Variables.find(variableId) != syncGroup.m_Variables.end();
48 });
48 });
49
49
50 return it != end ? it->first : SyncGroupId{};
50 return it != end ? it->first : SyncGroupId{};
51 }
51 }
52
52
53 std::vector<SyncGroupId> FuzzingState::syncGroupsIds() const
53 std::vector<SyncGroupId> FuzzingState::syncGroupsIds() const
54 {
54 {
55 std::vector<SyncGroupId> result{};
55 std::vector<SyncGroupId> result{};
56
56
57 for (const auto &entry : m_SyncGroupsPool) {
57 for (const auto &entry : m_SyncGroupsPool) {
58 result.push_back(entry.first);
58 result.push_back(entry.first);
59 }
59 }
60
60
61 return result;
61 return result;
62 }
62 }
63
63
64 void FuzzingState::synchronizeVariable(VariableId variableId, SyncGroupId syncGroupId)
64 void FuzzingState::synchronizeVariable(VariableId variableId, SyncGroupId syncGroupId)
65 {
65 {
66 if (syncGroupId.isNull()) {
66 if (syncGroupId.isNull()) {
67 return;
67 return;
68 }
68 }
69
69
70 // Registers variable into sync group: if it's the first variable, sets the variable range as
70 // Registers variable into sync group
71 // the sync group range
72 auto &syncGroup = m_SyncGroupsPool.at(syncGroupId);
71 auto &syncGroup = m_SyncGroupsPool.at(syncGroupId);
72 auto &variableState = m_VariablesPool.at(variableId);
73 syncGroup.m_Variables.insert(variableId);
73 syncGroup.m_Variables.insert(variableId);
74 if (syncGroup.m_Variables.size() == 1) {
74 if (syncGroup.m_Variables.size() == 1) {
75 auto &variableState = m_VariablesPool.at(variableId);
75 // If it's the first variable, sets the variable range as the sync group range
76 syncGroup.m_Range = variableState.m_Range;
76 syncGroup.m_Range = variableState.m_Range;
77 }
77 }
78 else {
79 // 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 }
78 }
82 }
79
83
80 void FuzzingState::desynchronizeVariable(VariableId variableId, SyncGroupId syncGroupId)
84 void FuzzingState::desynchronizeVariable(VariableId variableId, SyncGroupId syncGroupId)
81 {
85 {
82 if (syncGroupId.isNull()) {
86 if (syncGroupId.isNull()) {
83 return;
87 return;
84 }
88 }
85
89
86 // Unregisters variable from sync group: if there is no more variable in the group, resets the
90 // Unregisters variable from sync group: if there is no more variable in the group, resets the
87 // range
91 // range
88 auto &syncGroup = m_SyncGroupsPool.at(syncGroupId);
92 auto &syncGroup = m_SyncGroupsPool.at(syncGroupId);
89 syncGroup.m_Variables.erase(variableId);
93 syncGroup.m_Variables.erase(variableId);
90 if (syncGroup.m_Variables.empty()) {
94 if (syncGroup.m_Variables.empty()) {
91 syncGroup.m_Range = INVALID_RANGE;
95 syncGroup.m_Range = INVALID_RANGE;
92 }
96 }
93 }
97 }
94
98
95 void FuzzingState::updateRanges(VariableId variableId, const SqpRange &newRange)
99 void FuzzingState::updateRanges(VariableId variableId, const SqpRange &newRange)
96 {
100 {
97 auto syncGroupId = this->syncGroupId(variableId);
101 auto syncGroupId = this->syncGroupId(variableId);
98
102
99 // Retrieves the variables to update:
103 // Retrieves the variables to update:
100 // - if the variable is synchronized to others, updates all synchronized variables
104 // - if the variable is synchronized to others, updates the range of the group and of all
105 // synchronized variables
101 // - otherwise, updates only the variable
106 // - otherwise, updates only the variable
102 auto variablesToUpdate = syncGroupId.isNull() ? std::set<VariableId>{variableId}
107 if (syncGroupId.isNull()) {
103 : m_SyncGroupsPool.at(syncGroupId).m_Variables;
104
105 // Sets new range
106 for (const auto &variableId : variablesToUpdate) {
107 m_VariablesPool.at(variableId).m_Range = newRange;
108 m_VariablesPool.at(variableId).m_Range = newRange;
108 }
109 }
110 else {
111 auto &syncGroup = m_SyncGroupsPool.at(syncGroupId);
112 syncGroup.m_Range = newRange;
113
114 for (const auto &variableId : syncGroup.m_Variables) {
115 m_VariablesPool.at(variableId).m_Range = newRange;
116 }
117 }
109 }
118 }
@@ -1,265 +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
180 variableController.onRequestDataLoading({variableState.m_Variable}, variableState.m_Range,
181 false);
179 }
182 }
180 };
183 };
181
184
182 struct DesynchronizeOperation : public IFuzzingOperation {
185 struct DesynchronizeOperation : public IFuzzingOperation {
183 bool canExecute(VariableId variableId, const FuzzingState &fuzzingState) const override
186 bool canExecute(VariableId variableId, const FuzzingState &fuzzingState) const override
184 {
187 {
185 auto variable = fuzzingState.variableState(variableId).m_Variable;
188 auto variable = fuzzingState.variableState(variableId).m_Variable;
186 return variable != nullptr && !fuzzingState.syncGroupId(variableId).isNull();
189 return variable != nullptr && !fuzzingState.syncGroupId(variableId).isNull();
187 }
190 }
188
191
189 void execute(VariableId variableId, FuzzingState &fuzzingState,
192 void execute(VariableId variableId, FuzzingState &fuzzingState,
190 VariableController &variableController, const Properties &) const override
193 VariableController &variableController, const Properties &) const override
191 {
194 {
192 auto &variableState = fuzzingState.variableState(variableId);
195 auto &variableState = fuzzingState.variableState(variableId);
193
196
194 // Gets the sync group of the variable
197 // Gets the sync group of the variable
195 auto syncGroupId = fuzzingState.syncGroupId(variableId);
198 auto syncGroupId = fuzzingState.syncGroupId(variableId);
196
199
197 qCInfo(LOG_FuzzingOperations()).noquote() << "Removing" << variableState.m_Variable->name()
200 qCInfo(LOG_FuzzingOperations()).noquote() << "Removing" << variableState.m_Variable->name()
198 << "from synchronization group" << syncGroupId
201 << "from synchronization group" << syncGroupId
199 << "...";
202 << "...";
200 variableController.onAddSynchronized(variableState.m_Variable, syncGroupId);
203 variableController.desynchronize(variableState.m_Variable, syncGroupId);
201
204
202 // Updates state
205 // Updates state
203 fuzzingState.desynchronizeVariable(variableId, syncGroupId);
206 fuzzingState.desynchronizeVariable(variableId, syncGroupId);
204 }
207 }
205 };
208 };
206
209
207 struct UnknownOperation : public IFuzzingOperation {
210 struct UnknownOperation : public IFuzzingOperation {
208 bool canExecute(VariableId, const FuzzingState &) const override { return false; }
211 bool canExecute(VariableId, const FuzzingState &) const override { return false; }
209
212
210 void execute(VariableId, FuzzingState &, VariableController &,
213 void execute(VariableId, FuzzingState &, VariableController &,
211 const Properties &) const override
214 const Properties &) const override
212 {
215 {
213 }
216 }
214 };
217 };
215
218
216 } // namespace
219 } // namespace
217
220
218 std::unique_ptr<IFuzzingOperation> FuzzingOperationFactory::create(FuzzingOperationType type)
221 std::unique_ptr<IFuzzingOperation> FuzzingOperationFactory::create(FuzzingOperationType type)
219 {
222 {
220 switch (type) {
223 switch (type) {
221 case FuzzingOperationType::CREATE:
224 case FuzzingOperationType::CREATE:
222 return std::make_unique<CreateOperation>();
225 return std::make_unique<CreateOperation>();
223 case FuzzingOperationType::DELETE:
226 case FuzzingOperationType::DELETE:
224 return std::make_unique<DeleteOperation>();
227 return std::make_unique<DeleteOperation>();
225 case FuzzingOperationType::PAN_LEFT:
228 case FuzzingOperationType::PAN_LEFT:
226 return std::make_unique<MoveOperation>(
229 return std::make_unique<MoveOperation>(
227 std::minus<double>(), std::minus<double>(),
230 std::minus<double>(), std::minus<double>(),
228 [](const SqpRange &range, const SqpRange &maxRange) {
231 [](const SqpRange &range, const SqpRange &maxRange) {
229 return range.m_TStart - maxRange.m_TStart;
232 return range.m_TStart - maxRange.m_TStart;
230 },
233 },
231 QStringLiteral("Pan left operation"));
234 QStringLiteral("Pan left operation"));
232 case FuzzingOperationType::PAN_RIGHT:
235 case FuzzingOperationType::PAN_RIGHT:
233 return std::make_unique<MoveOperation>(
236 return std::make_unique<MoveOperation>(
234 std::plus<double>(), std::plus<double>(),
237 std::plus<double>(), std::plus<double>(),
235 [](const SqpRange &range, const SqpRange &maxRange) {
238 [](const SqpRange &range, const SqpRange &maxRange) {
236 return maxRange.m_TEnd - range.m_TEnd;
239 return maxRange.m_TEnd - range.m_TEnd;
237 },
240 },
238 QStringLiteral("Pan right operation"));
241 QStringLiteral("Pan right operation"));
239 case FuzzingOperationType::ZOOM_IN:
242 case FuzzingOperationType::ZOOM_IN:
240 return std::make_unique<MoveOperation>(
243 return std::make_unique<MoveOperation>(
241 std::plus<double>(), std::minus<double>(),
244 std::plus<double>(), std::minus<double>(),
242 [](const SqpRange &range, const SqpRange &maxRange) {
245 [](const SqpRange &range, const SqpRange &maxRange) {
243 Q_UNUSED(maxRange)
246 Q_UNUSED(maxRange)
244 return range.m_TEnd - (range.m_TStart + range.m_TEnd) / 2.;
247 return range.m_TEnd - (range.m_TStart + range.m_TEnd) / 2.;
245 },
248 },
246 QStringLiteral("Zoom in operation"));
249 QStringLiteral("Zoom in operation"));
247 case FuzzingOperationType::ZOOM_OUT:
250 case FuzzingOperationType::ZOOM_OUT:
248 return std::make_unique<MoveOperation>(
251 return std::make_unique<MoveOperation>(
249 std::minus<double>(), std::plus<double>(),
252 std::minus<double>(), std::plus<double>(),
250 [](const SqpRange &range, const SqpRange &maxRange) {
253 [](const SqpRange &range, const SqpRange &maxRange) {
251 return std::min(range.m_TStart - maxRange.m_TStart,
254 return std::min(range.m_TStart - maxRange.m_TStart,
252 maxRange.m_TEnd - range.m_TEnd);
255 maxRange.m_TEnd - range.m_TEnd);
253 },
256 },
254 QStringLiteral("Zoom out operation"));
257 QStringLiteral("Zoom out operation"));
255 case FuzzingOperationType::SYNCHRONIZE:
258 case FuzzingOperationType::SYNCHRONIZE:
256 return std::make_unique<SynchronizeOperation>();
259 return std::make_unique<SynchronizeOperation>();
257 case FuzzingOperationType::DESYNCHRONIZE:
260 case FuzzingOperationType::DESYNCHRONIZE:
258 return std::make_unique<DesynchronizeOperation>();
261 return std::make_unique<DesynchronizeOperation>();
259 default:
262 default:
260 // Default case returns unknown operation
263 // Default case returns unknown operation
261 break;
264 break;
262 }
265 }
263
266
264 return std::make_unique<UnknownOperation>();
267 return std::make_unique<UnknownOperation>();
265 }
268 }
@@ -1,228 +1,228
1 #include "FuzzingValidators.h"
1 #include "FuzzingValidators.h"
2 #include "FuzzingDefs.h"
2 #include "FuzzingDefs.h"
3
3
4 #include <Data/DataSeries.h>
4 #include <Data/DataSeries.h>
5 #include <Variable/Variable.h>
5 #include <Variable/Variable.h>
6
6
7 #include <QTest>
7 #include <QTest>
8
8
9 #include <functional>
9 #include <functional>
10
10
11 Q_LOGGING_CATEGORY(LOG_FuzzingValidators, "FuzzingValidators")
11 Q_LOGGING_CATEGORY(LOG_FuzzingValidators, "FuzzingValidators")
12
12
13 namespace {
13 namespace {
14
14
15 // ////////////// //
15 // ////////////// //
16 // DATA VALIDATOR //
16 // DATA VALIDATOR //
17 // ////////////// //
17 // ////////////// //
18
18
19 /// Singleton used to validate data of a variable
19 /// Singleton used to validate data of a variable
20 class DataValidatorHelper {
20 class DataValidatorHelper {
21 public:
21 public:
22 /// @return the single instance of the helper
22 /// @return the single instance of the helper
23 static DataValidatorHelper &instance();
23 static DataValidatorHelper &instance();
24 virtual ~DataValidatorHelper() noexcept = default;
24 virtual ~DataValidatorHelper() noexcept = default;
25
25
26 virtual void validate(const VariableState &variableState) const = 0;
26 virtual void validate(const VariableState &variableState) const = 0;
27 };
27 };
28
28
29 /**
29 /**
30 * Default implementation of @sa DataValidatorHelper
30 * Default implementation of @sa DataValidatorHelper
31 */
31 */
32 class DefaultDataValidatorHelper : public DataValidatorHelper {
32 class DefaultDataValidatorHelper : public DataValidatorHelper {
33 public:
33 public:
34 void validate(const VariableState &variableState) const override
34 void validate(const VariableState &variableState) const override
35 {
35 {
36 Q_UNUSED(variableState);
36 Q_UNUSED(variableState);
37 qCWarning(LOG_FuzzingValidators()).noquote() << "Checking variable's data... WARN: no data "
37 qCWarning(LOG_FuzzingValidators()).noquote() << "Checking variable's data... WARN: no data "
38 "verification is available for this server";
38 "verification is available for this server";
39 }
39 }
40 };
40 };
41
41
42 /// Data resolution in local server's files
42 /// Data resolution in local server's files
43 const auto LOCALHOST_SERVER_RESOLUTION = 4;
43 const auto LOCALHOST_SERVER_RESOLUTION = 4;
44 /// Reference value used to generate the data on the local server (a value is the number of seconds
44 /// Reference value used to generate the data on the local server (a value is the number of seconds
45 /// between the data date and this reference date)
45 /// between the data date and this reference date)
46 const auto LOCALHOST_REFERENCE_VALUE
46 const auto LOCALHOST_REFERENCE_VALUE
47 = DateUtils::secondsSinceEpoch(QDateTime{QDate{2000, 1, 1}, QTime{}, Qt::UTC});
47 = DateUtils::secondsSinceEpoch(QDateTime{QDate{2000, 1, 1}, QTime{}, Qt::UTC});
48
48
49 /**
49 /**
50 * Implementation of @sa DataValidatorHelper for the local AMDA server
50 * Implementation of @sa DataValidatorHelper for the local AMDA server
51 */
51 */
52 class LocalhostServerDataValidatorHelper : public DataValidatorHelper {
52 class LocalhostServerDataValidatorHelper : public DataValidatorHelper {
53 public:
53 public:
54 void validate(const VariableState &variableState) const override
54 void validate(const VariableState &variableState) const override
55 {
55 {
56 // Don't check data for null variable
56 // Don't check data for null variable
57 if (!variableState.m_Variable || variableState.m_Range == INVALID_RANGE) {
57 if (!variableState.m_Variable || variableState.m_Range == INVALID_RANGE) {
58 return;
58 return;
59 }
59 }
60
60
61 auto message = "Checking variable's data...";
61 auto message = "Checking variable's data...";
62 auto toDateString = [](double value) { return DateUtils::dateTime(value).toString(); };
62 auto toDateString = [](double value) { return DateUtils::dateTime(value).toString(); };
63
63
64 // Checks that data are defined
64 // Checks that data are defined
65 auto variableDataSeries = variableState.m_Variable->dataSeries();
65 auto variableDataSeries = variableState.m_Variable->dataSeries();
66 if (variableDataSeries == nullptr && variableState.m_Range != INVALID_RANGE) {
66 if (variableDataSeries == nullptr && variableState.m_Range != INVALID_RANGE) {
67 qCInfo(LOG_FuzzingValidators()).noquote()
67 qCInfo(LOG_FuzzingValidators()).noquote()
68 << message << "FAIL: the variable has no data while a range is defined";
68 << message << "FAIL: the variable has no data while a range is defined";
69 QFAIL("");
69 QFAIL("");
70 }
70 }
71
71
72 auto dataIts = variableDataSeries->xAxisRange(variableState.m_Range.m_TStart,
72 auto dataIts = variableDataSeries->xAxisRange(variableState.m_Range.m_TStart,
73 variableState.m_Range.m_TEnd);
73 variableState.m_Range.m_TEnd);
74
74
75 // Checks that the data are well defined in the range:
75 // Checks that the data are well defined in the range:
76 // - there is at least one data
76 // - there is at least one data
77 // - the data are consistent (no data holes)
77 // - the data are consistent (no data holes)
78 if (std::distance(dataIts.first, dataIts.second) == 0) {
78 if (std::distance(dataIts.first, dataIts.second) == 0) {
79 qCInfo(LOG_FuzzingValidators()).noquote() << message
79 qCInfo(LOG_FuzzingValidators()).noquote() << message
80 << "FAIL: the variable has no data";
80 << "FAIL: the variable has no data";
81 QFAIL("");
81 QFAIL("");
82 }
82 }
83
83
84 auto firstXAxisData = dataIts.first->x();
84 auto firstXAxisData = dataIts.first->x();
85 auto lastXAxisData = (dataIts.second - 1)->x();
85 auto lastXAxisData = (dataIts.second - 1)->x();
86
86
87 if (std::abs(firstXAxisData - variableState.m_Range.m_TStart) > LOCALHOST_SERVER_RESOLUTION
87 if (std::abs(firstXAxisData - variableState.m_Range.m_TStart) > LOCALHOST_SERVER_RESOLUTION
88 || std::abs(lastXAxisData - variableState.m_Range.m_TEnd)
88 || std::abs(lastXAxisData - variableState.m_Range.m_TEnd)
89 > LOCALHOST_SERVER_RESOLUTION) {
89 > LOCALHOST_SERVER_RESOLUTION) {
90 qCInfo(LOG_FuzzingValidators()).noquote()
90 qCInfo(LOG_FuzzingValidators()).noquote()
91 << message << "FAIL: the data in the defined range are inconsistent (data hole "
91 << message << "FAIL: the data in the defined range are inconsistent (data hole "
92 "found at the beginning or the end)";
92 "found at the beginning or the end)";
93 QFAIL("");
93 QFAIL("");
94 }
94 }
95
95
96 auto dataHoleIt = std::adjacent_find(
96 auto dataHoleIt = std::adjacent_find(
97 dataIts.first, dataIts.second, [](const auto &it1, const auto &it2) {
97 dataIts.first, dataIts.second, [](const auto &it1, const auto &it2) {
98 /// @todo: validate resolution
98 /// @todo: validate resolution
99 return std::abs(it1.x() - it2.x()) > 2 * (LOCALHOST_SERVER_RESOLUTION - 1);
99 return std::abs(it1.x() - it2.x()) > 2 * LOCALHOST_SERVER_RESOLUTION;
100 });
100 });
101
101
102 if (dataHoleIt != dataIts.second) {
102 if (dataHoleIt != dataIts.second) {
103 qCInfo(LOG_FuzzingValidators()).noquote()
103 qCInfo(LOG_FuzzingValidators()).noquote()
104 << message << "FAIL: the data in the defined range are inconsistent (data hole "
104 << message << "FAIL: the data in the defined range are inconsistent (data hole "
105 "found between times "
105 "found between times "
106 << toDateString(dataHoleIt->x()) << "and " << toDateString((dataHoleIt + 1)->x())
106 << toDateString(dataHoleIt->x()) << "and " << toDateString((dataHoleIt + 1)->x())
107 << ")";
107 << ")";
108 QFAIL("");
108 QFAIL("");
109 }
109 }
110
110
111 // Checks values
111 // Checks values
112 auto dataIndex = 0;
112 auto dataIndex = 0;
113 for (auto dataIt = dataIts.first; dataIt != dataIts.second; ++dataIt, ++dataIndex) {
113 for (auto dataIt = dataIts.first; dataIt != dataIts.second; ++dataIt, ++dataIndex) {
114 auto xAxisData = dataIt->x();
114 auto xAxisData = dataIt->x();
115 auto valuesData = dataIt->values();
115 auto valuesData = dataIt->values();
116 for (auto valueIndex = 0, valueEnd = valuesData.size(); valueIndex < valueEnd;
116 for (auto valueIndex = 0, valueEnd = valuesData.size(); valueIndex < valueEnd;
117 ++valueIndex) {
117 ++valueIndex) {
118 auto value = valuesData.at(valueIndex);
118 auto value = valuesData.at(valueIndex);
119 auto expectedValue = xAxisData + valueIndex * LOCALHOST_SERVER_RESOLUTION
119 auto expectedValue = xAxisData + valueIndex * LOCALHOST_SERVER_RESOLUTION
120 - LOCALHOST_REFERENCE_VALUE;
120 - LOCALHOST_REFERENCE_VALUE;
121
121
122 if (value != expectedValue) {
122 if (value != expectedValue) {
123 qCInfo(LOG_FuzzingValidators()).noquote()
123 qCInfo(LOG_FuzzingValidators()).noquote()
124 << message << "FAIL: incorrect value data at time"
124 << message << "FAIL: incorrect value data at time"
125 << toDateString(xAxisData) << ", index" << valueIndex << "(found:" << value
125 << toDateString(xAxisData) << ", index" << valueIndex << "(found:" << value
126 << ", expected:" << expectedValue << ")";
126 << ", expected:" << expectedValue << ")";
127 QFAIL("");
127 QFAIL("");
128 }
128 }
129 }
129 }
130 }
130 }
131
131
132 // At this step validation is OK
132 // At this step validation is OK
133 qCInfo(LOG_FuzzingValidators()).noquote() << message << "OK";
133 qCInfo(LOG_FuzzingValidators()).noquote() << message << "OK";
134 }
134 }
135 };
135 };
136
136
137 /// Creates the @sa DataValidatorHelper according to the server passed in parameter
137 /// Creates the @sa DataValidatorHelper according to the server passed in parameter
138 std::unique_ptr<DataValidatorHelper> createDataValidatorInstance(const QString &server)
138 std::unique_ptr<DataValidatorHelper> createDataValidatorInstance(const QString &server)
139 {
139 {
140 if (server == QString{"localhost"}) {
140 if (server == QString{"localhost"}) {
141 return std::make_unique<LocalhostServerDataValidatorHelper>();
141 return std::make_unique<LocalhostServerDataValidatorHelper>();
142 }
142 }
143 else {
143 else {
144 return std::make_unique<DefaultDataValidatorHelper>();
144 return std::make_unique<DefaultDataValidatorHelper>();
145 }
145 }
146 }
146 }
147
147
148 DataValidatorHelper &DataValidatorHelper::instance()
148 DataValidatorHelper &DataValidatorHelper::instance()
149 {
149 {
150 // Creates instance depending on the SCIQLOP_AMDA_SERVER value at compile time
150 // Creates instance depending on the SCIQLOP_AMDA_SERVER value at compile time
151 static auto instance = createDataValidatorInstance(SCIQLOP_AMDA_SERVER);
151 static auto instance = createDataValidatorInstance(SCIQLOP_AMDA_SERVER);
152 return *instance;
152 return *instance;
153 }
153 }
154
154
155 // /////////////// //
155 // /////////////// //
156 // RANGE VALIDATOR //
156 // RANGE VALIDATOR //
157 // /////////////// //
157 // /////////////// //
158
158
159 /**
159 /**
160 * Checks that a range of a variable matches the expected range passed as a parameter
160 * Checks that a range of a variable matches the expected range passed as a parameter
161 * @param variable the variable for which to check the range
161 * @param variable the variable for which to check the range
162 * @param expectedRange the expected range
162 * @param expectedRange the expected range
163 * @param getVariableRangeFun the function to retrieve the range from the variable
163 * @param getVariableRangeFun the function to retrieve the range from the variable
164 * @remarks if the variable is null, checks that the expected range is the invalid range
164 * @remarks if the variable is null, checks that the expected range is the invalid range
165 */
165 */
166 void validateRange(std::shared_ptr<Variable> variable, const SqpRange &expectedRange,
166 void validateRange(std::shared_ptr<Variable> variable, const SqpRange &expectedRange,
167 std::function<SqpRange(const Variable &)> getVariableRangeFun)
167 std::function<SqpRange(const Variable &)> getVariableRangeFun)
168 {
168 {
169 auto compare = [](const auto &range, const auto &expectedRange, const auto &message) {
169 auto compare = [](const auto &range, const auto &expectedRange, const auto &message) {
170 if (range == expectedRange) {
170 if (range == expectedRange) {
171 qCInfo(LOG_FuzzingValidators()).noquote() << message << "OK";
171 qCInfo(LOG_FuzzingValidators()).noquote() << message << "OK";
172 }
172 }
173 else {
173 else {
174 qCInfo(LOG_FuzzingValidators()).noquote() << message << "FAIL (current range:" << range
174 qCInfo(LOG_FuzzingValidators()).noquote() << message << "FAIL (current range:" << range
175 << ", expected range:" << expectedRange
175 << ", expected range:" << expectedRange
176 << ")";
176 << ")";
177 QFAIL("");
177 QFAIL("");
178 }
178 }
179 };
179 };
180
180
181 if (variable) {
181 if (variable) {
182 compare(getVariableRangeFun(*variable), expectedRange, "Checking variable's range...");
182 compare(getVariableRangeFun(*variable), expectedRange, "Checking variable's range...");
183 }
183 }
184 else {
184 else {
185 compare(INVALID_RANGE, expectedRange, "Checking that there is no range set...");
185 compare(INVALID_RANGE, expectedRange, "Checking that there is no range set...");
186 }
186 }
187 }
187 }
188
188
189 /**
189 /**
190 * Default implementation of @sa IFuzzingValidator. This validator takes as parameter of its
190 * Default implementation of @sa IFuzzingValidator. This validator takes as parameter of its
191 * construction a function of validation which is called in the validate() method
191 * construction a function of validation which is called in the validate() method
192 */
192 */
193 class FuzzingValidator : public IFuzzingValidator {
193 class FuzzingValidator : public IFuzzingValidator {
194 public:
194 public:
195 /// Signature of a validation function
195 /// Signature of a validation function
196 using ValidationFunction = std::function<void(const VariableState &variableState)>;
196 using ValidationFunction = std::function<void(const VariableState &variableState)>;
197
197
198 explicit FuzzingValidator(ValidationFunction fun) : m_Fun(std::move(fun)) {}
198 explicit FuzzingValidator(ValidationFunction fun) : m_Fun(std::move(fun)) {}
199
199
200 void validate(const VariableState &variableState) const override { m_Fun(variableState); }
200 void validate(const VariableState &variableState) const override { m_Fun(variableState); }
201
201
202 private:
202 private:
203 ValidationFunction m_Fun;
203 ValidationFunction m_Fun;
204 };
204 };
205
205
206 } // namespace
206 } // namespace
207
207
208 std::unique_ptr<IFuzzingValidator> FuzzingValidatorFactory::create(FuzzingValidatorType type)
208 std::unique_ptr<IFuzzingValidator> FuzzingValidatorFactory::create(FuzzingValidatorType type)
209 {
209 {
210 switch (type) {
210 switch (type) {
211 case FuzzingValidatorType::DATA:
211 case FuzzingValidatorType::DATA:
212 return std::make_unique<FuzzingValidator>([](const VariableState &variableState) {
212 return std::make_unique<FuzzingValidator>([](const VariableState &variableState) {
213 DataValidatorHelper::instance().validate(variableState);
213 DataValidatorHelper::instance().validate(variableState);
214 });
214 });
215 case FuzzingValidatorType::RANGE:
215 case FuzzingValidatorType::RANGE:
216 return std::make_unique<FuzzingValidator>([](const VariableState &variableState) {
216 return std::make_unique<FuzzingValidator>([](const VariableState &variableState) {
217 auto getVariableRange = [](const Variable &variable) { return variable.range(); };
217 auto getVariableRange = [](const Variable &variable) { return variable.range(); };
218 validateRange(variableState.m_Variable, variableState.m_Range, getVariableRange);
218 validateRange(variableState.m_Variable, variableState.m_Range, getVariableRange);
219 });
219 });
220 default:
220 default:
221 // Default case returns invalid validator
221 // Default case returns invalid validator
222 break;
222 break;
223 }
223 }
224
224
225 // Invalid validator
225 // Invalid validator
226 return std::make_unique<FuzzingValidator>(
226 return std::make_unique<FuzzingValidator>(
227 [](const VariableState &) { QFAIL("Invalid validator"); });
227 [](const VariableState &) { QFAIL("Invalid validator"); });
228 }
228 }
@@ -1,391 +1,395
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 using OperationsTypes = std::map<FuzzingOperationType, OperationProperty>;
60 using OperationsTypes = std::map<FuzzingOperationType, OperationProperty>;
61 using OperationsPool = std::map<std::shared_ptr<IFuzzingOperation>, OperationProperty>;
61 using OperationsPool = std::map<std::shared_ptr<IFuzzingOperation>, OperationProperty>;
62
62
63 using Validators = std::vector<std::shared_ptr<IFuzzingValidator> >;
63 using Validators = std::vector<std::shared_ptr<IFuzzingValidator> >;
64
64
65 // ///////// //
65 // ///////// //
66 // Constants //
66 // Constants //
67 // ///////// //
67 // ///////// //
68
68
69 // Defaults values used when the associated properties have not been set for the test
69 // Defaults values used when the associated properties have not been set for the test
70 const auto ACQUISITION_TIMEOUT_DEFAULT_VALUE = 30000;
70 const auto ACQUISITION_TIMEOUT_DEFAULT_VALUE = 30000;
71 const auto NB_MAX_OPERATIONS_DEFAULT_VALUE = 100;
71 const auto NB_MAX_OPERATIONS_DEFAULT_VALUE = 100;
72 const auto NB_MAX_SYNC_GROUPS_DEFAULT_VALUE = 1;
72 const auto NB_MAX_SYNC_GROUPS_DEFAULT_VALUE = 1;
73 const auto NB_MAX_VARIABLES_DEFAULT_VALUE = 1;
73 const auto NB_MAX_VARIABLES_DEFAULT_VALUE = 1;
74 const auto AVAILABLE_OPERATIONS_DEFAULT_VALUE = QVariant::fromValue(
74 const auto AVAILABLE_OPERATIONS_DEFAULT_VALUE = QVariant::fromValue(
75 OperationsTypes{{FuzzingOperationType::CREATE, {1., true}},
75 OperationsTypes{{FuzzingOperationType::CREATE, {1., true}},
76 {FuzzingOperationType::DELETE, {0.1}}, // Delete operation is less frequent
76 {FuzzingOperationType::DELETE, {0.1}}, // Delete operation is less frequent
77 {FuzzingOperationType::PAN_LEFT, {1.}},
77 {FuzzingOperationType::PAN_LEFT, {1.}},
78 {FuzzingOperationType::PAN_RIGHT, {1.}},
78 {FuzzingOperationType::PAN_RIGHT, {1.}},
79 {FuzzingOperationType::ZOOM_IN, {1.}},
79 {FuzzingOperationType::ZOOM_IN, {1.}},
80 {FuzzingOperationType::ZOOM_OUT, {1.}},
80 {FuzzingOperationType::ZOOM_OUT, {1.}},
81 {FuzzingOperationType::SYNCHRONIZE, {0.8}},
81 {FuzzingOperationType::SYNCHRONIZE, {0.8}},
82 {FuzzingOperationType::DESYNCHRONIZE, {0.4}}});
82 {FuzzingOperationType::DESYNCHRONIZE, {0.4}}});
83 const auto CACHE_TOLERANCE_DEFAULT_VALUE = 0.2;
83 const auto CACHE_TOLERANCE_DEFAULT_VALUE = 0.2;
84
84
85 /// Min/max delays between each operation (in ms)
85 /// Min/max delays between each operation (in ms)
86 const auto OPERATION_DELAY_BOUNDS_DEFAULT_VALUE = QVariant::fromValue(std::make_pair(100, 3000));
86 const auto OPERATION_DELAY_BOUNDS_DEFAULT_VALUE = QVariant::fromValue(std::make_pair(100, 3000));
87
87
88 /// Validators for the tests (executed in the order in which they're defined)
88 /// Validators for the tests (executed in the order in which they're defined)
89 const auto VALIDATORS_DEFAULT_VALUE = QVariant::fromValue(
89 const auto VALIDATORS_DEFAULT_VALUE = QVariant::fromValue(
90 ValidatorsTypes{{FuzzingValidatorType::RANGE, FuzzingValidatorType::DATA}});
90 ValidatorsTypes{{FuzzingValidatorType::RANGE, FuzzingValidatorType::DATA}});
91
91
92 /// Min/max number of operations to execute before calling validation
92 /// 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));
93 const auto VALIDATION_FREQUENCY_BOUNDS_DEFAULT_VALUE = QVariant::fromValue(std::make_pair(1, 10));
94
94
95 // /////// //
95 // /////// //
96 // Methods //
96 // Methods //
97 // /////// //
97 // /////// //
98
98
99 /// Goes through the variables pool and operations pool to determine the set of {variable/operation}
99 /// 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)
100 /// pairs that are valid (i.e. operation that can be executed on variable)
101 std::pair<VariablesOperations, Weights> availableOperations(const FuzzingState &fuzzingState,
101 std::pair<VariablesOperations, Weights> availableOperations(const FuzzingState &fuzzingState,
102 const OperationsPool &operationsPool)
102 const OperationsPool &operationsPool)
103 {
103 {
104 VariablesOperations result{};
104 VariablesOperations result{};
105 Weights weights{};
105 Weights weights{};
106
106
107 for (const auto &variablesPoolEntry : fuzzingState.m_VariablesPool) {
107 for (const auto &variablesPoolEntry : fuzzingState.m_VariablesPool) {
108 auto variableId = variablesPoolEntry.first;
108 auto variableId = variablesPoolEntry.first;
109
109
110 for (const auto &operationsPoolEntry : operationsPool) {
110 for (const auto &operationsPoolEntry : operationsPool) {
111 auto operation = operationsPoolEntry.first;
111 auto operation = operationsPoolEntry.first;
112 auto operationProperty = operationsPoolEntry.second;
112 auto operationProperty = operationsPoolEntry.second;
113
113
114 // A pair is valid if the current operation can be executed on the current variable
114 // A pair is valid if the current operation can be executed on the current variable
115 if (operation->canExecute(variableId, fuzzingState)) {
115 if (operation->canExecute(variableId, fuzzingState)) {
116 result.push_back({variableId, operation});
116 result.push_back({variableId, operation});
117 weights.push_back(operationProperty.m_Weight);
117 weights.push_back(operationProperty.m_Weight);
118 }
118 }
119 }
119 }
120 }
120 }
121
121
122 return {result, weights};
122 return {result, weights};
123 }
123 }
124
124
125 OperationsPool createOperationsPool(const OperationsTypes &types)
125 OperationsPool createOperationsPool(const OperationsTypes &types)
126 {
126 {
127 OperationsPool result{};
127 OperationsPool result{};
128
128
129 std::transform(
129 std::transform(
130 types.cbegin(), types.cend(), std::inserter(result, result.end()), [](const auto &type) {
130 types.cbegin(), types.cend(), std::inserter(result, result.end()), [](const auto &type) {
131 return std::make_pair(FuzzingOperationFactory::create(type.first), type.second);
131 return std::make_pair(FuzzingOperationFactory::create(type.first), type.second);
132 });
132 });
133
133
134 return result;
134 return result;
135 }
135 }
136
136
137 Validators createValidators(const ValidatorsTypes &types)
137 Validators createValidators(const ValidatorsTypes &types)
138 {
138 {
139 Validators result{};
139 Validators result{};
140
140
141 std::transform(types.cbegin(), types.cend(), std::inserter(result, result.end()),
141 std::transform(types.cbegin(), types.cend(), std::inserter(result, result.end()),
142 [](const auto &type) { return FuzzingValidatorFactory::create(type); });
142 [](const auto &type) { return FuzzingValidatorFactory::create(type); });
143
143
144 return result;
144 return result;
145 }
145 }
146
146
147 /**
147 /**
148 * Validates all the variables' states passed in parameter, according to a set of validators
148 * Validates all the variables' states passed in parameter, according to a set of validators
149 * @param variablesPool the variables' states
149 * @param variablesPool the variables' states
150 * @param validators the validators used for validation
150 * @param validators the validators used for validation
151 */
151 */
152 void validate(const VariablesPool &variablesPool, const Validators &validators)
152 void validate(const VariablesPool &variablesPool, const Validators &validators)
153 {
153 {
154 for (const auto &variablesPoolEntry : variablesPool) {
154 for (const auto &variablesPoolEntry : variablesPool) {
155 auto variableId = variablesPoolEntry.first;
155 auto variableId = variablesPoolEntry.first;
156 const auto &variableState = variablesPoolEntry.second;
156 const auto &variableState = variablesPoolEntry.second;
157
157
158 auto variableMessage = variableState.m_Variable ? variableState.m_Variable->name()
158 auto variableMessage = variableState.m_Variable ? variableState.m_Variable->name()
159 : QStringLiteral("null variable");
159 : QStringLiteral("null variable");
160 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Validating state of variable at index"
160 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Validating state of variable at index"
161 << variableId << "(" << variableMessage << ")...";
161 << variableId << "(" << variableMessage << ")...";
162
162
163 for (const auto &validator : validators) {
163 for (const auto &validator : validators) {
164 validator->validate(VariableState{variableState});
164 validator->validate(VariableState{variableState});
165 }
165 }
166
166
167 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Validation completed.";
167 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Validation completed.";
168 }
168 }
169 }
169 }
170
170
171 /**
171 /**
172 * Class to run random tests
172 * Class to run random tests
173 */
173 */
174 class FuzzingTest {
174 class FuzzingTest {
175 public:
175 public:
176 explicit FuzzingTest(VariableController &variableController, Properties properties)
176 explicit FuzzingTest(VariableController &variableController, Properties properties)
177 : m_VariableController{variableController},
177 : m_VariableController{variableController},
178 m_Properties{std::move(properties)},
178 m_Properties{std::move(properties)},
179 m_FuzzingState{}
179 m_FuzzingState{}
180 {
180 {
181 // Inits variables pool: at init, all variables are null
181 // Inits variables pool: at init, all variables are null
182 for (auto variableId = 0; variableId < nbMaxVariables(); ++variableId) {
182 for (auto variableId = 0; variableId < nbMaxVariables(); ++variableId) {
183 m_FuzzingState.m_VariablesPool[variableId] = VariableState{};
183 m_FuzzingState.m_VariablesPool[variableId] = VariableState{};
184 }
184 }
185
185
186 // Inits sync groups and registers them into the variable controller
186 // Inits sync groups and registers them into the variable controller
187 for (auto i = 0; i < nbMaxSyncGroups(); ++i) {
187 for (auto i = 0; i < nbMaxSyncGroups(); ++i) {
188 auto syncGroupId = SyncGroupId::createUuid();
188 auto syncGroupId = SyncGroupId::createUuid();
189 variableController.onAddSynchronizationGroupId(syncGroupId);
189 variableController.onAddSynchronizationGroupId(syncGroupId);
190 m_FuzzingState.m_SyncGroupsPool[syncGroupId] = SyncGroup{};
190 m_FuzzingState.m_SyncGroupsPool[syncGroupId] = SyncGroup{};
191 }
191 }
192 }
192 }
193
193
194 void execute()
194 void execute()
195 {
195 {
196 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Running" << nbMaxOperations() << "operations on"
196 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Running" << nbMaxOperations() << "operations on"
197 << nbMaxVariables() << "variable(s)...";
197 << nbMaxVariables() << "variable(s)...";
198
198
199
199
200 // Inits the count of the number of operations before the next validation
200 // Inits the count of the number of operations before the next validation
201 int nextValidationCounter = 0;
201 int nextValidationCounter = 0;
202 auto updateValidationCounter = [this, &nextValidationCounter]() {
202 auto updateValidationCounter = [this, &nextValidationCounter]() {
203 nextValidationCounter = RandomGenerator::instance().generateInt(
203 nextValidationCounter = RandomGenerator::instance().generateInt(
204 validationFrequencies().first, validationFrequencies().second);
204 validationFrequencies().first, validationFrequencies().second);
205 qCInfo(LOG_TestAmdaFuzzing()).noquote()
205 qCInfo(LOG_TestAmdaFuzzing()).noquote()
206 << "Next validation in " << nextValidationCounter << "operation(s)...";
206 << "Next validation in " << nextValidationCounter << "operation(s)...";
207 };
207 };
208 updateValidationCounter();
208 updateValidationCounter();
209
209
210 auto canExecute = true;
210 auto canExecute = true;
211 for (auto i = 0; i < nbMaxOperations() && canExecute; ++i) {
211 for (auto i = 0; i < nbMaxOperations() && canExecute; ++i) {
212 // Retrieves all operations that can be executed in the current context
212 // Retrieves all operations that can be executed in the current context
213 VariablesOperations variableOperations{};
213 VariablesOperations variableOperations{};
214 Weights weights{};
214 Weights weights{};
215 std::tie(variableOperations, weights)
215 std::tie(variableOperations, weights)
216 = availableOperations(m_FuzzingState, operationsPool());
216 = availableOperations(m_FuzzingState, operationsPool());
217
217
218 canExecute = !variableOperations.empty();
218 canExecute = !variableOperations.empty();
219 if (canExecute) {
219 if (canExecute) {
220 --nextValidationCounter;
220 --nextValidationCounter;
221
221
222 // Of the operations available, chooses a random operation and executes it
222 // Of the operations available, chooses a random operation and executes it
223 auto variableOperation
223 auto variableOperation
224 = RandomGenerator::instance().randomChoice(variableOperations, weights);
224 = RandomGenerator::instance().randomChoice(variableOperations, weights);
225
225
226 auto variableId = variableOperation.first;
226 auto variableId = variableOperation.first;
227 auto fuzzingOperation = variableOperation.second;
227 auto fuzzingOperation = variableOperation.second;
228
228
229 auto waitAcquisition = nextValidationCounter == 0
229 auto waitAcquisition = nextValidationCounter == 0
230 || operationsPool().at(fuzzingOperation).m_WaitAcquisition;
230 || operationsPool().at(fuzzingOperation).m_WaitAcquisition;
231
231
232 fuzzingOperation->execute(variableId, m_FuzzingState, m_VariableController,
232 fuzzingOperation->execute(variableId, m_FuzzingState, m_VariableController,
233 m_Properties);
233 m_Properties);
234
234
235 if (waitAcquisition) {
235 if (waitAcquisition) {
236 qCDebug(LOG_TestAmdaFuzzing()) << "Waiting for acquisition to finish...";
236 qCDebug(LOG_TestAmdaFuzzing()) << "Waiting for acquisition to finish...";
237 SignalWaiter{m_VariableController, SIGNAL(acquisitionFinished())}.wait(
237 SignalWaiter{m_VariableController, SIGNAL(acquisitionFinished())}.wait(
238 acquisitionTimeout());
238 acquisitionTimeout());
239
239
240 // Validates variables
240 // Validates variables
241 if (nextValidationCounter == 0) {
241 if (nextValidationCounter == 0) {
242 validate(m_FuzzingState.m_VariablesPool, validators());
242 validate(m_FuzzingState.m_VariablesPool, validators());
243 updateValidationCounter();
243 updateValidationCounter();
244 }
244 }
245 }
245 }
246 else {
246 else {
247 // Delays the next operation with a randomly generated time
247 // Delays the next operation with a randomly generated time
248 auto delay = RandomGenerator::instance().generateInt(operationDelays().first,
248 auto delay = RandomGenerator::instance().generateInt(operationDelays().first,
249 operationDelays().second);
249 operationDelays().second);
250 qCDebug(LOG_TestAmdaFuzzing())
250 qCDebug(LOG_TestAmdaFuzzing())
251 << "Waiting " << delay << "ms before the next operation...";
251 << "Waiting " << delay << "ms before the next operation...";
252 QTest::qWait(delay);
252 QTest::qWait(delay);
253 }
253 }
254 }
254 }
255 else {
255 else {
256 qCInfo(LOG_TestAmdaFuzzing()).noquote()
256 qCInfo(LOG_TestAmdaFuzzing()).noquote()
257 << "No more operations are available, the execution of the test will stop...";
257 << "No more operations are available, the execution of the test will stop...";
258 }
258 }
259 }
259 }
260
260
261 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Execution of the test completed.";
261 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Execution of the test completed.";
262 }
262 }
263
263
264 private:
264 private:
265 OperationsPool operationsPool() const
265 OperationsPool operationsPool() const
266 {
266 {
267 static auto result = createOperationsPool(
267 static auto result = createOperationsPool(
268 m_Properties.value(AVAILABLE_OPERATIONS_PROPERTY, AVAILABLE_OPERATIONS_DEFAULT_VALUE)
268 m_Properties.value(AVAILABLE_OPERATIONS_PROPERTY, AVAILABLE_OPERATIONS_DEFAULT_VALUE)
269 .value<OperationsTypes>());
269 .value<OperationsTypes>());
270 return result;
270 return result;
271 }
271 }
272
272
273 Validators validators() const
273 Validators validators() const
274 {
274 {
275 static auto result
275 static auto result
276 = createValidators(m_Properties.value(VALIDATORS_PROPERTY, VALIDATORS_DEFAULT_VALUE)
276 = createValidators(m_Properties.value(VALIDATORS_PROPERTY, VALIDATORS_DEFAULT_VALUE)
277 .value<ValidatorsTypes>());
277 .value<ValidatorsTypes>());
278 return result;
278 return result;
279 }
279 }
280
280
281 DECLARE_PROPERTY_GETTER(nbMaxOperations, NB_MAX_OPERATIONS, int)
281 DECLARE_PROPERTY_GETTER(nbMaxOperations, NB_MAX_OPERATIONS, int)
282 DECLARE_PROPERTY_GETTER(nbMaxSyncGroups, NB_MAX_SYNC_GROUPS, int)
282 DECLARE_PROPERTY_GETTER(nbMaxSyncGroups, NB_MAX_SYNC_GROUPS, int)
283 DECLARE_PROPERTY_GETTER(nbMaxVariables, NB_MAX_VARIABLES, int)
283 DECLARE_PROPERTY_GETTER(nbMaxVariables, NB_MAX_VARIABLES, int)
284 DECLARE_PROPERTY_GETTER(operationDelays, OPERATION_DELAY_BOUNDS, IntPair)
284 DECLARE_PROPERTY_GETTER(operationDelays, OPERATION_DELAY_BOUNDS, IntPair)
285 DECLARE_PROPERTY_GETTER(validationFrequencies, VALIDATION_FREQUENCY_BOUNDS, IntPair)
285 DECLARE_PROPERTY_GETTER(validationFrequencies, VALIDATION_FREQUENCY_BOUNDS, IntPair)
286 DECLARE_PROPERTY_GETTER(acquisitionTimeout, ACQUISITION_TIMEOUT, int)
286 DECLARE_PROPERTY_GETTER(acquisitionTimeout, ACQUISITION_TIMEOUT, int)
287
287
288 VariableController &m_VariableController;
288 VariableController &m_VariableController;
289 Properties m_Properties;
289 Properties m_Properties;
290 FuzzingState m_FuzzingState;
290 FuzzingState m_FuzzingState;
291 };
291 };
292
292
293 } // namespace
293 } // namespace
294
294
295 Q_DECLARE_METATYPE(OperationsTypes)
295 Q_DECLARE_METATYPE(OperationsTypes)
296
296
297 class TestAmdaFuzzing : public QObject {
297 class TestAmdaFuzzing : public QObject {
298 Q_OBJECT
298 Q_OBJECT
299
299
300 private slots:
300 private slots:
301 /// Input data for @sa testFuzzing()
301 /// Input data for @sa testFuzzing()
302 void testFuzzing_data();
302 void testFuzzing_data();
303 void testFuzzing();
303 void testFuzzing();
304 };
304 };
305
305
306 void TestAmdaFuzzing::testFuzzing_data()
306 void TestAmdaFuzzing::testFuzzing_data()
307 {
307 {
308 // Note: Comment this line to run fuzzing tests
308 // Note: Comment this line to run fuzzing tests
309 QSKIP("Fuzzing tests are disabled by default");
309 QSKIP("Fuzzing tests are disabled by default");
310
310
311 // ////////////// //
311 // ////////////// //
312 // Test structure //
312 // Test structure //
313 // ////////////// //
313 // ////////////// //
314
314
315 QTest::addColumn<Properties>("properties"); // Properties for random test
315 QTest::addColumn<Properties>("properties"); // Properties for random test
316
316
317 // ////////// //
317 // ////////// //
318 // Test cases //
318 // Test cases //
319 // ////////// //
319 // ////////// //
320
320
321 auto maxRange = SqpRange::fromDateTime({2017, 1, 1}, {0, 0}, {2017, 1, 5}, {0, 0});
321 auto maxRange = SqpRange::fromDateTime({2017, 1, 1}, {0, 0}, {2017, 1, 5}, {0, 0});
322 MetadataPool metadataPool{{{"dataType", "vector"}, {"xml:id", "imf"}}};
322 MetadataPool metadataPool{{{"dataType", "vector"}, {"xml:id", "imf"}}};
323
323
324 // Note: we don't use auto here as we want to pass std::shared_ptr<IDataProvider> as is in the
324 // Note: we don't use auto here as we want to pass std::shared_ptr<IDataProvider> as is in the
325 // QVariant
325 // QVariant
326 std::shared_ptr<IDataProvider> provider = std::make_shared<AmdaProvider>();
326 std::shared_ptr<IDataProvider> provider = std::make_shared<AmdaProvider>();
327
327
328 QTest::newRow("fuzzingTest") << Properties{
328 QTest::newRow("fuzzingTest") << Properties{
329 {MAX_RANGE_PROPERTY, QVariant::fromValue(maxRange)},
329 {MAX_RANGE_PROPERTY, QVariant::fromValue(maxRange)},
330 {METADATA_POOL_PROPERTY, QVariant::fromValue(metadataPool)},
330 {METADATA_POOL_PROPERTY, QVariant::fromValue(metadataPool)},
331 {PROVIDER_PROPERTY, QVariant::fromValue(provider)}};
331 {PROVIDER_PROPERTY, QVariant::fromValue(provider)}};
332 }
332 }
333
333
334 void TestAmdaFuzzing::testFuzzing()
334 void TestAmdaFuzzing::testFuzzing()
335 {
335 {
336 QFETCH(Properties, properties);
336 QFETCH(Properties, properties);
337
337
338 // Sets cache property
338 // Sets cache property
339 QSettings settings{};
339 QSettings settings{};
340 auto cacheTolerance = properties.value(CACHE_TOLERANCE_PROPERTY, CACHE_TOLERANCE_DEFAULT_VALUE);
340 auto cacheTolerance = properties.value(CACHE_TOLERANCE_PROPERTY, CACHE_TOLERANCE_DEFAULT_VALUE);
341 settings.setValue(GENERAL_TOLERANCE_AT_INIT_KEY, cacheTolerance);
341 settings.setValue(GENERAL_TOLERANCE_AT_INIT_KEY, cacheTolerance);
342 settings.setValue(GENERAL_TOLERANCE_AT_UPDATE_KEY, cacheTolerance);
342 settings.setValue(GENERAL_TOLERANCE_AT_UPDATE_KEY, cacheTolerance);
343
343
344 auto &variableController = sqpApp->variableController();
344 auto &variableController = sqpApp->variableController();
345 auto &timeController = sqpApp->timeController();
345 auto &timeController = sqpApp->timeController();
346
346
347 // Generates random initial range (bounded to max range)
347 // Generates random initial range (bounded to max range)
348 auto maxRange = properties.value(MAX_RANGE_PROPERTY, QVariant::fromValue(INVALID_RANGE))
348 auto maxRange = properties.value(MAX_RANGE_PROPERTY, QVariant::fromValue(INVALID_RANGE))
349 .value<SqpRange>();
349 .value<SqpRange>();
350
350
351 QVERIFY(maxRange != INVALID_RANGE);
351 QVERIFY(maxRange != INVALID_RANGE);
352
352
353 auto initialRangeStart
353 auto initialRangeStart
354 = RandomGenerator::instance().generateDouble(maxRange.m_TStart, maxRange.m_TEnd);
354 = RandomGenerator::instance().generateDouble(maxRange.m_TStart, maxRange.m_TEnd);
355 auto initialRangeEnd
355 auto initialRangeEnd
356 = RandomGenerator::instance().generateDouble(maxRange.m_TStart, maxRange.m_TEnd);
356 = RandomGenerator::instance().generateDouble(maxRange.m_TStart, maxRange.m_TEnd);
357 if (initialRangeStart > initialRangeEnd) {
357 if (initialRangeStart > initialRangeEnd) {
358 std::swap(initialRangeStart, initialRangeEnd);
358 std::swap(initialRangeStart, initialRangeEnd);
359 }
359 }
360
360
361 // Sets initial range on time controller
361 // Sets initial range on time controller
362 SqpRange initialRange{initialRangeStart, initialRangeEnd};
362 SqpRange initialRange{initialRangeStart, initialRangeEnd};
363 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Setting initial range to" << initialRange << "...";
363 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Setting initial range to" << initialRange << "...";
364 timeController.onTimeToUpdate(initialRange);
364 timeController.onTimeToUpdate(initialRange);
365 properties.insert(INITIAL_RANGE_PROPERTY, QVariant::fromValue(initialRange));
365 properties.insert(INITIAL_RANGE_PROPERTY, QVariant::fromValue(initialRange));
366
366
367 FuzzingTest test{variableController, properties};
367 FuzzingTest test{variableController, properties};
368 test.execute();
368 test.execute();
369 }
369 }
370
370
371 int main(int argc, char *argv[])
371 int main(int argc, char *argv[])
372 {
372 {
373 // 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
375 qputenv("QTEST_FUNCTION_TIMEOUT", QByteArray::number(12*60*60*1000));
376
373 QLoggingCategory::setFilterRules(
377 QLoggingCategory::setFilterRules(
374 "*.warning=false\n"
378 "*.warning=false\n"
375 "*.info=false\n"
379 "*.info=false\n"
376 "*.debug=false\n"
380 "*.debug=false\n"
377 "FuzzingOperations.info=true\n"
381 "FuzzingOperations.info=true\n"
378 "FuzzingValidators.info=true\n"
382 "FuzzingValidators.info=true\n"
379 "TestAmdaFuzzing.info=true\n");
383 "TestAmdaFuzzing.info=true\n");
380
384
381 SqpApplication app{argc, argv};
385 SqpApplication app{argc, argv};
382 SqpApplication::setOrganizationName("LPP");
386 SqpApplication::setOrganizationName("LPP");
383 SqpApplication::setOrganizationDomain("lpp.fr");
387 SqpApplication::setOrganizationDomain("lpp.fr");
384 SqpApplication::setApplicationName("SciQLop-TestFuzzing");
388 SqpApplication::setApplicationName("SciQLop-TestFuzzing");
385 app.setAttribute(Qt::AA_Use96Dpi, true);
389 app.setAttribute(Qt::AA_Use96Dpi, true);
386 TestAmdaFuzzing testObject{};
390 TestAmdaFuzzing testObject{};
387 QTEST_SET_MAIN_SOURCE_PATH
391 QTEST_SET_MAIN_SOURCE_PATH
388 return QTest::qExec(&testObject, argc, argv);
392 return QTest::qExec(&testObject, argc, argv);
389 }
393 }
390
394
391 #include "TestAmdaFuzzing.moc"
395 #include "TestAmdaFuzzing.moc"
General Comments 0
You need to be logged in to leave comments. Login now