##// END OF EJS Templates
Fix bug in synchro for operation (jump + rescaling)
perrinel -
r814:1fc2e26b3db5
parent child
Show More
@@ -1,890 +1,896
1 1 #include <Variable/Variable.h>
2 2 #include <Variable/VariableAcquisitionWorker.h>
3 3 #include <Variable/VariableCacheStrategy.h>
4 4 #include <Variable/VariableCacheStrategyFactory.h>
5 5 #include <Variable/VariableController.h>
6 6 #include <Variable/VariableModel.h>
7 7 #include <Variable/VariableSynchronizationGroup.h>
8 8
9 9 #include <Data/DataProviderParameters.h>
10 10 #include <Data/IDataProvider.h>
11 11 #include <Data/IDataSeries.h>
12 12 #include <Data/VariableRequest.h>
13 13 #include <Time/TimeController.h>
14 14
15 15 #include <QMutex>
16 16 #include <QThread>
17 17 #include <QUuid>
18 18 #include <QtCore/QItemSelectionModel>
19 19
20 20 #include <deque>
21 21 #include <set>
22 22 #include <unordered_map>
23 23
24 24 Q_LOGGING_CATEGORY(LOG_VariableController, "VariableController")
25 25
26 26 namespace {
27 27
28 28 SqpRange computeSynchroRangeRequested(const SqpRange &varRange, const SqpRange &graphRange,
29 29 const SqpRange &oldGraphRange)
30 30 {
31 31 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
32 32
33 33 auto varRangeRequested = varRange;
34 34 switch (zoomType) {
35 35 case AcquisitionZoomType::ZoomIn: {
36 36 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
37 37 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
38 38 varRangeRequested.m_TStart += deltaLeft;
39 39 varRangeRequested.m_TEnd -= deltaRight;
40 40 break;
41 41 }
42 42
43 43 case AcquisitionZoomType::ZoomOut: {
44 44 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
45 45 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
46 46 varRangeRequested.m_TStart -= deltaLeft;
47 47 varRangeRequested.m_TEnd += deltaRight;
48 48 break;
49 49 }
50 50 case AcquisitionZoomType::PanRight: {
51 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
51 52 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
52 varRangeRequested.m_TStart += deltaRight;
53 varRangeRequested.m_TStart += deltaLeft;
53 54 varRangeRequested.m_TEnd += deltaRight;
54 55 break;
55 56 }
56 57 case AcquisitionZoomType::PanLeft: {
57 58 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
59 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
58 60 varRangeRequested.m_TStart -= deltaLeft;
59 varRangeRequested.m_TEnd -= deltaLeft;
61 varRangeRequested.m_TEnd -= deltaRight;
60 62 break;
61 63 }
62 64 case AcquisitionZoomType::Unknown: {
63 65 qCCritical(LOG_VariableController())
64 66 << VariableController::tr("Impossible to synchronize: zoom type unknown");
65 67 break;
66 68 }
67 69 default:
68 70 qCCritical(LOG_VariableController()) << VariableController::tr(
69 71 "Impossible to synchronize: zoom type not take into account");
70 72 // No action
71 73 break;
72 74 }
73 75
74 76 return varRangeRequested;
75 77 }
76 78 }
77 79
78 80 struct VariableController::VariableControllerPrivate {
79 81 explicit VariableControllerPrivate(VariableController *parent)
80 82 : m_WorkingMutex{},
81 83 m_VariableModel{new VariableModel{parent}},
82 84 m_VariableSelectionModel{new QItemSelectionModel{m_VariableModel, parent}},
83 85 // m_VariableCacheStrategy{std::make_unique<VariableCacheStrategy>()},
84 86 m_VariableCacheStrategy{VariableCacheStrategyFactory::createCacheStrategy(
85 87 CacheStrategy::SingleThreshold)},
86 88 m_VariableAcquisitionWorker{std::make_unique<VariableAcquisitionWorker>()},
87 89 q{parent}
88 90 {
89 91
90 92 m_VariableAcquisitionWorker->moveToThread(&m_VariableAcquisitionWorkerThread);
91 93 m_VariableAcquisitionWorkerThread.setObjectName("VariableAcquisitionWorkerThread");
92 94 }
93 95
94 96
95 97 virtual ~VariableControllerPrivate()
96 98 {
97 99 qCDebug(LOG_VariableController()) << tr("VariableControllerPrivate destruction");
98 100 m_VariableAcquisitionWorkerThread.quit();
99 101 m_VariableAcquisitionWorkerThread.wait();
100 102 }
101 103
102 104
103 105 void processRequest(std::shared_ptr<Variable> var, const SqpRange &rangeRequested,
104 106 QUuid varRequestId);
105 107
106 108 QVector<SqpRange> provideNotInCacheDateTimeList(std::shared_ptr<Variable> variable,
107 109 const SqpRange &dateTime);
108 110
109 111 std::shared_ptr<Variable> findVariable(QUuid vIdentifier);
110 112 std::shared_ptr<IDataSeries>
111 113 retrieveDataSeries(const QVector<AcquisitionDataPacket> acqDataPacketVector);
112 114
113 115 void registerProvider(std::shared_ptr<IDataProvider> provider);
114 116
115 117 void storeVariableRequest(QUuid varId, QUuid varRequestId, const VariableRequest &varRequest);
116 118 QUuid acceptVariableRequest(QUuid varId, std::shared_ptr<IDataSeries> dataSeries);
117 119 void updateVariableRequest(QUuid varRequestId);
118 120 void cancelVariableRequest(QUuid varRequestId);
119 121
120 122 SqpRange getLastRequestedRange(QUuid varId);
121 123
122 124 QMutex m_WorkingMutex;
123 125 /// Variable model. The VariableController has the ownership
124 126 VariableModel *m_VariableModel;
125 127 QItemSelectionModel *m_VariableSelectionModel;
126 128
127 129
128 130 TimeController *m_TimeController{nullptr};
129 131 std::unique_ptr<VariableCacheStrategy> m_VariableCacheStrategy;
130 132 std::unique_ptr<VariableAcquisitionWorker> m_VariableAcquisitionWorker;
131 133 QThread m_VariableAcquisitionWorkerThread;
132 134
133 135 std::unordered_map<std::shared_ptr<Variable>, std::shared_ptr<IDataProvider> >
134 136 m_VariableToProviderMap;
135 137 std::unordered_map<std::shared_ptr<Variable>, QUuid> m_VariableToIdentifierMap;
136 138 std::map<QUuid, std::shared_ptr<VariableSynchronizationGroup> >
137 139 m_GroupIdToVariableSynchronizationGroupMap;
138 140 std::map<QUuid, QUuid> m_VariableIdGroupIdMap;
139 141 std::set<std::shared_ptr<IDataProvider> > m_ProviderSet;
140 142
141 143 std::map<QUuid, std::map<QUuid, VariableRequest> > m_VarRequestIdToVarIdVarRequestMap;
142 144
143 145 std::map<QUuid, std::deque<QUuid> > m_VarIdToVarRequestIdQueueMap;
144 146
145 147
146 148 VariableController *q;
147 149 };
148 150
149 151
150 152 VariableController::VariableController(QObject *parent)
151 153 : QObject{parent}, impl{spimpl::make_unique_impl<VariableControllerPrivate>(this)}
152 154 {
153 155 qCDebug(LOG_VariableController()) << tr("VariableController construction")
154 156 << QThread::currentThread();
155 157
156 158 connect(impl->m_VariableModel, &VariableModel::abortProgessRequested, this,
157 159 &VariableController::onAbortProgressRequested);
158 160
159 161 connect(impl->m_VariableAcquisitionWorker.get(),
160 162 &VariableAcquisitionWorker::variableCanceledRequested, this,
161 163 &VariableController::onAbortAcquisitionRequested);
162 164
163 165 connect(impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::dataProvided, this,
164 166 &VariableController::onDataProvided);
165 167 connect(impl->m_VariableAcquisitionWorker.get(),
166 168 &VariableAcquisitionWorker::variableRequestInProgress, this,
167 169 &VariableController::onVariableRetrieveDataInProgress);
168 170
169 171
170 172 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::started,
171 173 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::initialize);
172 174 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::finished,
173 175 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::finalize);
174 176
175 177
176 178 impl->m_VariableAcquisitionWorkerThread.start();
177 179 }
178 180
179 181 VariableController::~VariableController()
180 182 {
181 183 qCDebug(LOG_VariableController()) << tr("VariableController destruction")
182 184 << QThread::currentThread();
183 185 this->waitForFinish();
184 186 }
185 187
186 188 VariableModel *VariableController::variableModel() noexcept
187 189 {
188 190 return impl->m_VariableModel;
189 191 }
190 192
191 193 QItemSelectionModel *VariableController::variableSelectionModel() noexcept
192 194 {
193 195 return impl->m_VariableSelectionModel;
194 196 }
195 197
196 198 void VariableController::setTimeController(TimeController *timeController) noexcept
197 199 {
198 200 impl->m_TimeController = timeController;
199 201 }
200 202
201 203 std::shared_ptr<Variable>
202 204 VariableController::cloneVariable(std::shared_ptr<Variable> variable) noexcept
203 205 {
204 206 if (impl->m_VariableModel->containsVariable(variable)) {
205 207 // Clones variable
206 208 auto duplicate = variable->clone();
207 209
208 210 // Adds clone to model
209 211 impl->m_VariableModel->addVariable(duplicate);
210 212
211 213 // Generates clone identifier
212 214 impl->m_VariableToIdentifierMap[duplicate] = QUuid::createUuid();
213 215
214 216 // Registers provider
215 217 auto variableProvider = impl->m_VariableToProviderMap.at(variable);
216 218 auto duplicateProvider = variableProvider != nullptr ? variableProvider->clone() : nullptr;
217 219
218 220 impl->m_VariableToProviderMap[duplicate] = duplicateProvider;
219 221 if (duplicateProvider) {
220 222 impl->registerProvider(duplicateProvider);
221 223 }
222 224
223 225 return duplicate;
224 226 }
225 227 else {
226 228 qCCritical(LOG_VariableController())
227 229 << tr("Can't create duplicate of variable %1: variable not registered in the model")
228 230 .arg(variable->name());
229 231 return nullptr;
230 232 }
231 233 }
232 234
233 235 void VariableController::deleteVariable(std::shared_ptr<Variable> variable) noexcept
234 236 {
235 237 if (!variable) {
236 238 qCCritical(LOG_VariableController()) << "Can't delete variable: variable is null";
237 239 return;
238 240 }
239 241
240 242 // Spreads in SciQlop that the variable will be deleted, so that potential receivers can
241 243 // make some treatments before the deletion
242 244 emit variableAboutToBeDeleted(variable);
243 245
244 246 // Deletes identifier
245 247 impl->m_VariableToIdentifierMap.erase(variable);
246 248
247 249 // Deletes provider
248 250 auto nbProvidersDeleted = impl->m_VariableToProviderMap.erase(variable);
249 251 qCDebug(LOG_VariableController())
250 252 << tr("Number of providers deleted for variable %1: %2")
251 253 .arg(variable->name(), QString::number(nbProvidersDeleted));
252 254
253 255
254 256 // Deletes from model
255 257 impl->m_VariableModel->deleteVariable(variable);
256 258 }
257 259
258 260 void VariableController::deleteVariables(
259 261 const QVector<std::shared_ptr<Variable> > &variables) noexcept
260 262 {
261 263 for (auto variable : qAsConst(variables)) {
262 264 deleteVariable(variable);
263 265 }
264 266 }
265 267
266 268 std::shared_ptr<Variable>
267 269 VariableController::createVariable(const QString &name, const QVariantHash &metadata,
268 270 std::shared_ptr<IDataProvider> provider) noexcept
269 271 {
270 272 if (!impl->m_TimeController) {
271 273 qCCritical(LOG_VariableController())
272 274 << tr("Impossible to create variable: The time controller is null");
273 275 return nullptr;
274 276 }
275 277
276 278 auto range = impl->m_TimeController->dateTime();
277 279
278 280 if (auto newVariable = impl->m_VariableModel->createVariable(name, metadata)) {
279 281 auto identifier = QUuid::createUuid();
280 282
281 283 // store the provider
282 284 impl->registerProvider(provider);
283 285
284 286 // Associate the provider
285 287 impl->m_VariableToProviderMap[newVariable] = provider;
286 288 qCInfo(LOG_VariableController()) << "createVariable: " << identifier;
287 289 impl->m_VariableToIdentifierMap[newVariable] = identifier;
288 290
289 291
290 292 auto varRequestId = QUuid::createUuid();
291 293 impl->processRequest(newVariable, range, varRequestId);
292 294 impl->updateVariableRequest(varRequestId);
293 295
294 296 return newVariable;
295 297 }
296 298 }
297 299
298 300 void VariableController::onDateTimeOnSelection(const SqpRange &dateTime)
299 301 {
300 302 // TODO check synchronisation and Rescale
301 303 qCDebug(LOG_VariableController()) << "VariableController::onDateTimeOnSelection"
302 304 << QThread::currentThread()->objectName();
303 305 auto selectedRows = impl->m_VariableSelectionModel->selectedRows();
304 306 auto varRequestId = QUuid::createUuid();
305 307
306 308 for (const auto &selectedRow : qAsConst(selectedRows)) {
307 309 if (auto selectedVariable = impl->m_VariableModel->variable(selectedRow.row())) {
308 310 selectedVariable->setRange(dateTime);
309 311 impl->processRequest(selectedVariable, dateTime, varRequestId);
310 312
311 313 // notify that rescale operation has to be done
312 314 emit rangeChanged(selectedVariable, dateTime);
313 315 }
314 316 }
315 317 impl->updateVariableRequest(varRequestId);
316 318 }
317 319
318 320 void VariableController::onDataProvided(QUuid vIdentifier, const SqpRange &rangeRequested,
319 321 const SqpRange &cacheRangeRequested,
320 322 QVector<AcquisitionDataPacket> dataAcquired)
321 323 {
322 324 auto retrievedDataSeries = impl->retrieveDataSeries(dataAcquired);
323 325 auto varRequestId = impl->acceptVariableRequest(vIdentifier, retrievedDataSeries);
324 326 if (!varRequestId.isNull()) {
325 327 impl->updateVariableRequest(varRequestId);
326 328 }
327 329 }
328 330
329 331 void VariableController::onVariableRetrieveDataInProgress(QUuid identifier, double progress)
330 332 {
331 333 qCDebug(LOG_VariableController())
332 334 << "TORM: variableController::onVariableRetrieveDataInProgress"
333 335 << QThread::currentThread()->objectName() << progress;
334 336 if (auto var = impl->findVariable(identifier)) {
335 337 impl->m_VariableModel->setDataProgress(var, progress);
336 338 }
337 339 else {
338 340 qCCritical(LOG_VariableController())
339 341 << tr("Impossible to notify progression of a null variable");
340 342 }
341 343 }
342 344
343 345 void VariableController::onAbortProgressRequested(std::shared_ptr<Variable> variable)
344 346 {
345 347 auto it = impl->m_VariableToIdentifierMap.find(variable);
346 348 if (it != impl->m_VariableToIdentifierMap.cend()) {
347 349 impl->m_VariableAcquisitionWorker->abortProgressRequested(it->second);
348 350
349 351 QUuid varRequestId;
350 352 auto varIdToVarRequestIdQueueMapIt = impl->m_VarIdToVarRequestIdQueueMap.find(it->second);
351 353 if (varIdToVarRequestIdQueueMapIt != impl->m_VarIdToVarRequestIdQueueMap.cend()) {
352 354 auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second;
353 355 varRequestId = varRequestIdQueue.front();
354 356 impl->cancelVariableRequest(varRequestId);
355 357
356 358 // Finish the progression for the request
357 359 impl->m_VariableModel->setDataProgress(variable, 0.0);
358 360 }
359 361 else {
360 362 qCWarning(LOG_VariableController())
361 363 << tr("Aborting progression of inexistant variable request detected !!!")
362 364 << QThread::currentThread()->objectName();
363 365 }
364 366 }
365 367 else {
366 368 qCWarning(LOG_VariableController())
367 369 << tr("Aborting progression of inexistant variable detected !!!")
368 370 << QThread::currentThread()->objectName();
369 371 }
370 372 }
371 373
372 374 void VariableController::onAbortAcquisitionRequested(QUuid vIdentifier)
373 375 {
374 376 qCDebug(LOG_VariableController()) << "TORM: variableController::onAbortAcquisitionRequested"
375 377 << QThread::currentThread()->objectName() << vIdentifier;
376 378
377 379 if (auto var = impl->findVariable(vIdentifier)) {
378 380 this->onAbortProgressRequested(var);
379 381 }
380 382 else {
381 383 qCCritical(LOG_VariableController())
382 384 << tr("Impossible to abort Acquisition Requestof a null variable");
383 385 }
384 386 }
385 387
386 388 void VariableController::onAddSynchronizationGroupId(QUuid synchronizationGroupId)
387 389 {
388 390 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronizationGroupId"
389 391 << QThread::currentThread()->objectName()
390 392 << synchronizationGroupId;
391 393 auto vSynchroGroup = std::make_shared<VariableSynchronizationGroup>();
392 394 impl->m_GroupIdToVariableSynchronizationGroupMap.insert(
393 395 std::make_pair(synchronizationGroupId, vSynchroGroup));
394 396 }
395 397
396 398 void VariableController::onRemoveSynchronizationGroupId(QUuid synchronizationGroupId)
397 399 {
398 400 impl->m_GroupIdToVariableSynchronizationGroupMap.erase(synchronizationGroupId);
399 401 }
400 402
401 403 void VariableController::onAddSynchronized(std::shared_ptr<Variable> variable,
402 404 QUuid synchronizationGroupId)
403 405
404 406 {
405 407 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronized"
406 408 << synchronizationGroupId;
407 409 auto varToVarIdIt = impl->m_VariableToIdentifierMap.find(variable);
408 410 if (varToVarIdIt != impl->m_VariableToIdentifierMap.cend()) {
409 411 auto groupIdToVSGIt
410 412 = impl->m_GroupIdToVariableSynchronizationGroupMap.find(synchronizationGroupId);
411 413 if (groupIdToVSGIt != impl->m_GroupIdToVariableSynchronizationGroupMap.cend()) {
412 414 impl->m_VariableIdGroupIdMap.insert(
413 415 std::make_pair(varToVarIdIt->second, synchronizationGroupId));
414 416 groupIdToVSGIt->second->addVariableId(varToVarIdIt->second);
415 417 }
416 418 else {
417 419 qCCritical(LOG_VariableController())
418 420 << tr("Impossible to synchronize a variable with an unknown sycnhronization group")
419 421 << variable->name();
420 422 }
421 423 }
422 424 else {
423 425 qCCritical(LOG_VariableController())
424 426 << tr("Impossible to synchronize a variable with no identifier") << variable->name();
425 427 }
426 428 }
427 429
428 430 void VariableController::desynchronize(std::shared_ptr<Variable> variable,
429 431 QUuid synchronizationGroupId)
430 432 {
431 433 // Gets variable id
432 434 auto variableIt = impl->m_VariableToIdentifierMap.find(variable);
433 435 if (variableIt == impl->m_VariableToIdentifierMap.cend()) {
434 436 qCCritical(LOG_VariableController())
435 437 << tr("Can't desynchronize variable %1: variable identifier not found")
436 438 .arg(variable->name());
437 439 return;
438 440 }
439 441
440 442 // Gets synchronization group
441 443 auto groupIt = impl->m_GroupIdToVariableSynchronizationGroupMap.find(synchronizationGroupId);
442 444 if (groupIt == impl->m_GroupIdToVariableSynchronizationGroupMap.cend()) {
443 445 qCCritical(LOG_VariableController())
444 446 << tr("Can't desynchronize variable %1: unknown synchronization group")
445 447 .arg(variable->name());
446 448 return;
447 449 }
448 450
449 451 auto variableId = variableIt->second;
450 452
451 453 // Removes variable from synchronization group
452 454 auto synchronizationGroup = groupIt->second;
453 455 synchronizationGroup->removeVariableId(variableId);
454 456
455 457 // Removes link between variable and synchronization group
456 458 impl->m_VariableIdGroupIdMap.erase(variableId);
457 459 }
458 460
459 461 void VariableController::onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables,
460 462 const SqpRange &range, const SqpRange &oldRange,
461 463 bool synchronise)
462 464 {
463 465 // NOTE: oldRange isn't really necessary since oldRange == variable->range().
464 466
465 467 // we want to load data of the variable for the dateTime.
466 468 // First we check if the cache contains some of them.
467 469 // For the other, we ask the provider to give them.
468 470
469 471 auto varRequestId = QUuid::createUuid();
470 472 qCDebug(LOG_VariableController()) << "VariableController::onRequestDataLoading"
471 473 << QThread::currentThread()->objectName() << varRequestId;
472 474
473 475 for (const auto &var : variables) {
474 476 qCDebug(LOG_VariableController()) << "processRequest for" << var->name() << varRequestId;
475 477 impl->processRequest(var, range, varRequestId);
476 478 }
477 479
478 480 if (synchronise) {
479 481 // Get the group ids
480 482 qCDebug(LOG_VariableController())
481 483 << "TORM VariableController::onRequestDataLoading for synchro var ENABLE";
482 484 auto groupIds = std::set<QUuid>{};
483 485 auto groupIdToOldRangeMap = std::map<QUuid, SqpRange>{};
484 486 for (const auto &var : variables) {
485 487 auto varToVarIdIt = impl->m_VariableToIdentifierMap.find(var);
486 488 if (varToVarIdIt != impl->m_VariableToIdentifierMap.cend()) {
487 489 auto vId = varToVarIdIt->second;
488 490 auto varIdToGroupIdIt = impl->m_VariableIdGroupIdMap.find(vId);
489 491 if (varIdToGroupIdIt != impl->m_VariableIdGroupIdMap.cend()) {
490 492 auto gId = varIdToGroupIdIt->second;
491 493 groupIdToOldRangeMap.insert(std::make_pair(gId, var->range()));
492 494 if (groupIds.find(gId) == groupIds.cend()) {
493 495 qCDebug(LOG_VariableController()) << "Synchro detect group " << gId;
494 496 groupIds.insert(gId);
495 497 }
496 498 }
497 499 }
498 500 }
499 501
500 502 // We assume here all group ids exist
501 503 for (const auto &gId : groupIds) {
502 504 auto vSynchronizationGroup = impl->m_GroupIdToVariableSynchronizationGroupMap.at(gId);
503 505 auto vSyncIds = vSynchronizationGroup->getIds();
504 506 qCDebug(LOG_VariableController()) << "Var in synchro group ";
505 507 for (auto vId : vSyncIds) {
506 508 auto var = impl->findVariable(vId);
507 509
508 510 // Don't process already processed var
509 511 if (!variables.contains(var)) {
510 512 if (var != nullptr) {
511 513 qCDebug(LOG_VariableController()) << "processRequest synchro for"
512 514 << var->name();
513 515 auto vSyncRangeRequested = computeSynchroRangeRequested(
514 516 var->range(), range, groupIdToOldRangeMap.at(gId));
515 517 qCDebug(LOG_VariableController()) << "synchro RR" << vSyncRangeRequested;
516 518 impl->processRequest(var, vSyncRangeRequested, varRequestId);
517 519 }
518 520 else {
519 521 qCCritical(LOG_VariableController())
520 522
521 523 << tr("Impossible to synchronize a null variable");
522 524 }
523 525 }
524 526 }
525 527 }
526 528 }
527 529
528 530 impl->updateVariableRequest(varRequestId);
529 531 }
530 532
531 533
532 534 void VariableController::initialize()
533 535 {
534 536 qCDebug(LOG_VariableController()) << tr("VariableController init") << QThread::currentThread();
535 537 impl->m_WorkingMutex.lock();
536 538 qCDebug(LOG_VariableController()) << tr("VariableController init END");
537 539 }
538 540
539 541 void VariableController::finalize()
540 542 {
541 543 impl->m_WorkingMutex.unlock();
542 544 }
543 545
544 546 void VariableController::waitForFinish()
545 547 {
546 548 QMutexLocker locker{&impl->m_WorkingMutex};
547 549 }
548 550
549 551 AcquisitionZoomType VariableController::getZoomType(const SqpRange &range, const SqpRange &oldRange)
550 552 {
551 553 // t1.m_TStart <= t2.m_TStart && t2.m_TEnd <= t1.m_TEnd
552 554 auto zoomType = AcquisitionZoomType::Unknown;
553 555 if (range.m_TStart <= oldRange.m_TStart && oldRange.m_TEnd <= range.m_TEnd) {
556 qCCritical(LOG_VariableController()) << "zoomtype: ZoomOut";
554 557 zoomType = AcquisitionZoomType::ZoomOut;
555 558 }
556 559 else if (range.m_TStart > oldRange.m_TStart && range.m_TEnd > oldRange.m_TEnd) {
560 qCCritical(LOG_VariableController()) << "zoomtype: PanRight";
557 561 zoomType = AcquisitionZoomType::PanRight;
558 562 }
559 563 else if (range.m_TStart < oldRange.m_TStart && range.m_TEnd < oldRange.m_TEnd) {
564 qCCritical(LOG_VariableController()) << "zoomtype: PanLeft";
560 565 zoomType = AcquisitionZoomType::PanLeft;
561 566 }
562 567 else if (range.m_TStart > oldRange.m_TStart && oldRange.m_TEnd > range.m_TEnd) {
568 qCCritical(LOG_VariableController()) << "zoomtype: ZoomIn";
563 569 zoomType = AcquisitionZoomType::ZoomIn;
564 570 }
565 571 else {
566 572 qCCritical(LOG_VariableController()) << "getZoomType: Unknown type detected";
567 573 }
568 574 return zoomType;
569 575 }
570 576
571 577 void VariableController::VariableControllerPrivate::processRequest(std::shared_ptr<Variable> var,
572 578 const SqpRange &rangeRequested,
573 579 QUuid varRequestId)
574 580 {
575 581 auto varRequest = VariableRequest{};
576 582
577 583 auto it = m_VariableToIdentifierMap.find(var);
578 584 if (it != m_VariableToIdentifierMap.cend()) {
579 585
580 586 auto varId = it->second;
581 587
582 588 auto oldRange = getLastRequestedRange(varId);
583 589
584 590 // check for update oldRange to the last request range.
585 591 if (oldRange == INVALID_RANGE) {
586 592 oldRange = var->range();
587 593 }
588 594
589 595 auto varStrategyRangesRequested
590 596 = m_VariableCacheStrategy->computeRange(oldRange, rangeRequested);
591 597
592 598 auto notInCacheRangeList = QVector<SqpRange>{varStrategyRangesRequested.second};
593 599 auto inCacheRangeList = QVector<SqpRange>{};
594 600 if (m_VarIdToVarRequestIdQueueMap.find(varId) == m_VarIdToVarRequestIdQueueMap.cend()) {
595 601 notInCacheRangeList
596 602 = var->provideNotInCacheRangeList(varStrategyRangesRequested.second);
597 603 inCacheRangeList = var->provideInCacheRangeList(varStrategyRangesRequested.second);
598 604 }
599 605
600 606 if (!notInCacheRangeList.empty()) {
601 607 varRequest.m_RangeRequested = varStrategyRangesRequested.first;
602 608 varRequest.m_CacheRangeRequested = varStrategyRangesRequested.second;
603 609
604 610 // store VarRequest
605 611 storeVariableRequest(varId, varRequestId, varRequest);
606 612
607 613 auto varProvider = m_VariableToProviderMap.at(var);
608 614 if (varProvider != nullptr) {
609 615 auto varRequestIdCanceled = m_VariableAcquisitionWorker->pushVariableRequest(
610 616 varRequestId, varId, varStrategyRangesRequested.first,
611 617 varStrategyRangesRequested.second,
612 618 DataProviderParameters{std::move(notInCacheRangeList), var->metadata()},
613 619 varProvider);
614 620
615 621 if (!varRequestIdCanceled.isNull()) {
616 622 qCDebug(LOG_VariableAcquisitionWorker()) << tr("vsarRequestIdCanceled: ")
617 623 << varRequestIdCanceled;
618 624 cancelVariableRequest(varRequestIdCanceled);
619 625 }
620 626 }
621 627 else {
622 628 qCCritical(LOG_VariableController())
623 629 << "Impossible to provide data with a null provider";
624 630 }
625 631
626 632 if (!inCacheRangeList.empty()) {
627 633 emit q->updateVarDisplaying(var, inCacheRangeList.first());
628 634 }
629 635 }
630 636 else {
631 637 varRequest.m_RangeRequested = varStrategyRangesRequested.first;
632 638 varRequest.m_CacheRangeRequested = varStrategyRangesRequested.second;
633 639 // store VarRequest
634 640 storeVariableRequest(varId, varRequestId, varRequest);
635 641 acceptVariableRequest(
636 642 varId, var->dataSeries()->subDataSeries(varStrategyRangesRequested.second));
637 643 }
638 644 }
639 645 }
640 646
641 647 std::shared_ptr<Variable>
642 648 VariableController::VariableControllerPrivate::findVariable(QUuid vIdentifier)
643 649 {
644 650 std::shared_ptr<Variable> var;
645 651 auto findReply = [vIdentifier](const auto &entry) { return vIdentifier == entry.second; };
646 652
647 653 auto end = m_VariableToIdentifierMap.cend();
648 654 auto it = std::find_if(m_VariableToIdentifierMap.cbegin(), end, findReply);
649 655 if (it != end) {
650 656 var = it->first;
651 657 }
652 658 else {
653 659 qCCritical(LOG_VariableController())
654 660 << tr("Impossible to find the variable with the identifier: ") << vIdentifier;
655 661 }
656 662
657 663 return var;
658 664 }
659 665
660 666 std::shared_ptr<IDataSeries> VariableController::VariableControllerPrivate::retrieveDataSeries(
661 667 const QVector<AcquisitionDataPacket> acqDataPacketVector)
662 668 {
663 669 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size")
664 670 << acqDataPacketVector.size();
665 671 std::shared_ptr<IDataSeries> dataSeries;
666 672 if (!acqDataPacketVector.isEmpty()) {
667 673 dataSeries = acqDataPacketVector[0].m_DateSeries;
668 674 for (int i = 1; i < acqDataPacketVector.size(); ++i) {
669 675 dataSeries->merge(acqDataPacketVector[i].m_DateSeries.get());
670 676 }
671 677 }
672 678 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size END")
673 679 << acqDataPacketVector.size();
674 680 return dataSeries;
675 681 }
676 682
677 683 void VariableController::VariableControllerPrivate::registerProvider(
678 684 std::shared_ptr<IDataProvider> provider)
679 685 {
680 686 if (m_ProviderSet.find(provider) == m_ProviderSet.end()) {
681 687 qCDebug(LOG_VariableController()) << tr("Registering of a new provider")
682 688 << provider->objectName();
683 689 m_ProviderSet.insert(provider);
684 690 connect(provider.get(), &IDataProvider::dataProvided, m_VariableAcquisitionWorker.get(),
685 691 &VariableAcquisitionWorker::onVariableDataAcquired);
686 692 connect(provider.get(), &IDataProvider::dataProvidedProgress,
687 693 m_VariableAcquisitionWorker.get(),
688 694 &VariableAcquisitionWorker::onVariableRetrieveDataInProgress);
689 695 connect(provider.get(), &IDataProvider::dataProvidedFailed,
690 696 m_VariableAcquisitionWorker.get(),
691 697 &VariableAcquisitionWorker::onVariableAcquisitionFailed);
692 698 }
693 699 else {
694 700 qCDebug(LOG_VariableController()) << tr("Cannot register provider, it already exists ");
695 701 }
696 702 }
697 703
698 704 void VariableController::VariableControllerPrivate::storeVariableRequest(
699 705 QUuid varId, QUuid varRequestId, const VariableRequest &varRequest)
700 706 {
701 707 // First request for the variable. we can create an entry for it
702 708 auto varIdToVarRequestIdQueueMapIt = m_VarIdToVarRequestIdQueueMap.find(varId);
703 709 if (varIdToVarRequestIdQueueMapIt == m_VarIdToVarRequestIdQueueMap.cend()) {
704 710 auto varRequestIdQueue = std::deque<QUuid>{};
705 711 qCDebug(LOG_VariableController()) << tr("Store REQUEST in QUEUE");
706 712 varRequestIdQueue.push_back(varRequestId);
707 713 m_VarIdToVarRequestIdQueueMap.insert(std::make_pair(varId, std::move(varRequestIdQueue)));
708 714 }
709 715 else {
710 716 qCDebug(LOG_VariableController()) << tr("Store REQUEST in EXISTING QUEUE");
711 717 auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second;
712 718 varRequestIdQueue.push_back(varRequestId);
713 719 }
714 720
715 721 auto varRequestIdToVarIdVarRequestMapIt = m_VarRequestIdToVarIdVarRequestMap.find(varRequestId);
716 722 if (varRequestIdToVarIdVarRequestMapIt == m_VarRequestIdToVarIdVarRequestMap.cend()) {
717 723 auto varIdToVarRequestMap = std::map<QUuid, VariableRequest>{};
718 724 varIdToVarRequestMap.insert(std::make_pair(varId, varRequest));
719 725 qCDebug(LOG_VariableController()) << tr("Store REQUESTID in MAP");
720 726 m_VarRequestIdToVarIdVarRequestMap.insert(
721 727 std::make_pair(varRequestId, std::move(varIdToVarRequestMap)));
722 728 }
723 729 else {
724 730 auto &varIdToVarRequestMap = varRequestIdToVarIdVarRequestMapIt->second;
725 731 qCDebug(LOG_VariableController()) << tr("Store REQUESTID in EXISTING MAP");
726 732 varIdToVarRequestMap.insert(std::make_pair(varId, varRequest));
727 733 }
728 734 }
729 735
730 736 QUuid VariableController::VariableControllerPrivate::acceptVariableRequest(
731 737 QUuid varId, std::shared_ptr<IDataSeries> dataSeries)
732 738 {
733 739 QUuid varRequestId;
734 740 auto varIdToVarRequestIdQueueMapIt = m_VarIdToVarRequestIdQueueMap.find(varId);
735 741 if (varIdToVarRequestIdQueueMapIt != m_VarIdToVarRequestIdQueueMap.cend()) {
736 742 auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second;
737 743 varRequestId = varRequestIdQueue.front();
738 744 auto varRequestIdToVarIdVarRequestMapIt
739 745 = m_VarRequestIdToVarIdVarRequestMap.find(varRequestId);
740 746 if (varRequestIdToVarIdVarRequestMapIt != m_VarRequestIdToVarIdVarRequestMap.cend()) {
741 747 auto &varIdToVarRequestMap = varRequestIdToVarIdVarRequestMapIt->second;
742 748 auto varIdToVarRequestMapIt = varIdToVarRequestMap.find(varId);
743 749 if (varIdToVarRequestMapIt != varIdToVarRequestMap.cend()) {
744 750 qCDebug(LOG_VariableController()) << tr("acceptVariableRequest");
745 751 auto &varRequest = varIdToVarRequestMapIt->second;
746 752 varRequest.m_DataSeries = dataSeries;
747 753 varRequest.m_CanUpdate = true;
748 754 }
749 755 else {
750 756 qCDebug(LOG_VariableController())
751 757 << tr("Impossible to acceptVariableRequest of a unknown variable id attached "
752 758 "to a variableRequestId")
753 759 << varRequestId << varId;
754 760 }
755 761 }
756 762 else {
757 763 qCCritical(LOG_VariableController())
758 764 << tr("Impossible to acceptVariableRequest of a unknown variableRequestId")
759 765 << varRequestId;
760 766 }
761 767
762 768 varRequestIdQueue.pop_front();
763 769 if (varRequestIdQueue.empty()) {
764 770 qCDebug(LOG_VariableController())
765 771 << tr("TORM Erase REQUEST because it has been accepted") << varId;
766 772 m_VarIdToVarRequestIdQueueMap.erase(varId);
767 773 }
768 774 }
769 775 else {
770 776 qCCritical(LOG_VariableController())
771 777 << tr("Impossible to acceptVariableRequest of a unknown variable id") << varId;
772 778 }
773 779
774 780 return varRequestId;
775 781 }
776 782
777 783 void VariableController::VariableControllerPrivate::updateVariableRequest(QUuid varRequestId)
778 784 {
779 785
780 786 auto varRequestIdToVarIdVarRequestMapIt = m_VarRequestIdToVarIdVarRequestMap.find(varRequestId);
781 787 if (varRequestIdToVarIdVarRequestMapIt != m_VarRequestIdToVarIdVarRequestMap.cend()) {
782 788 bool processVariableUpdate = true;
783 789 auto &varIdToVarRequestMap = varRequestIdToVarIdVarRequestMapIt->second;
784 790 for (auto varIdToVarRequestMapIt = varIdToVarRequestMap.cbegin();
785 791 (varIdToVarRequestMapIt != varIdToVarRequestMap.cend()) && processVariableUpdate;
786 792 ++varIdToVarRequestMapIt) {
787 793 processVariableUpdate &= varIdToVarRequestMapIt->second.m_CanUpdate;
788 794 qCDebug(LOG_VariableController()) << tr("updateVariableRequest")
789 795 << processVariableUpdate;
790 796 }
791 797
792 798 if (processVariableUpdate) {
793 799 for (auto varIdToVarRequestMapIt = varIdToVarRequestMap.cbegin();
794 800 varIdToVarRequestMapIt != varIdToVarRequestMap.cend(); ++varIdToVarRequestMapIt) {
795 801 if (auto var = findVariable(varIdToVarRequestMapIt->first)) {
796 802 auto &varRequest = varIdToVarRequestMapIt->second;
797 803 var->setRange(varRequest.m_RangeRequested);
798 804 var->setCacheRange(varRequest.m_CacheRangeRequested);
799 805 qCDebug(LOG_VariableController()) << tr("1: onDataProvided")
800 806 << varRequest.m_RangeRequested;
801 807 qCDebug(LOG_VariableController()) << tr("2: onDataProvided")
802 808 << varRequest.m_CacheRangeRequested;
803 809 var->mergeDataSeries(varRequest.m_DataSeries);
804 810 qCDebug(LOG_VariableController()) << tr("3: onDataProvided");
805 811
806 812 /// @todo MPL: confirm
807 813 // Variable update is notified only if there is no pending request for it
808 814 // if
809 815 // (m_VarIdToVarRequestIdQueueMap.count(varIdToVarRequestMapIt->first)
810 816 // == 0) {
811 817 emit var->updated();
812 818 // }
813 819 }
814 820 else {
815 821 qCCritical(LOG_VariableController())
816 822 << tr("Impossible to update data to a null variable");
817 823 }
818 824 }
819 825
820 826 // cleaning varRequestId
821 827 qCDebug(LOG_VariableController()) << tr("0: erase REQUEST in MAP ?")
822 828 << m_VarRequestIdToVarIdVarRequestMap.size();
823 829 m_VarRequestIdToVarIdVarRequestMap.erase(varRequestId);
824 830 qCDebug(LOG_VariableController()) << tr("1: erase REQUEST in MAP ?")
825 831 << m_VarRequestIdToVarIdVarRequestMap.size();
826 832 }
827 833 }
828 834 else {
829 835 qCCritical(LOG_VariableController())
830 836 << tr("Cannot updateVariableRequest for a unknow varRequestId") << varRequestId;
831 837 }
832 838 }
833 839
834 840 void VariableController::VariableControllerPrivate::cancelVariableRequest(QUuid varRequestId)
835 841 {
836 842 // cleaning varRequestId
837 843 m_VarRequestIdToVarIdVarRequestMap.erase(varRequestId);
838 844
839 845 for (auto varIdToVarRequestIdQueueMapIt = m_VarIdToVarRequestIdQueueMap.begin();
840 846 varIdToVarRequestIdQueueMapIt != m_VarIdToVarRequestIdQueueMap.end();) {
841 847 auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second;
842 848 varRequestIdQueue.erase(
843 849 std::remove(varRequestIdQueue.begin(), varRequestIdQueue.end(), varRequestId),
844 850 varRequestIdQueue.end());
845 851 if (varRequestIdQueue.empty()) {
846 852 varIdToVarRequestIdQueueMapIt
847 853 = m_VarIdToVarRequestIdQueueMap.erase(varIdToVarRequestIdQueueMapIt);
848 854 }
849 855 else {
850 856 ++varIdToVarRequestIdQueueMapIt;
851 857 }
852 858 }
853 859 }
854 860
855 861 SqpRange VariableController::VariableControllerPrivate::getLastRequestedRange(QUuid varId)
856 862 {
857 863 auto lastRangeRequested = SqpRange{INVALID_RANGE};
858 864 auto varIdToVarRequestIdQueueMapIt = m_VarIdToVarRequestIdQueueMap.find(varId);
859 865 if (varIdToVarRequestIdQueueMapIt != m_VarIdToVarRequestIdQueueMap.cend()) {
860 866 auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second;
861 867 auto varRequestId = varRequestIdQueue.back();
862 868 auto varRequestIdToVarIdVarRequestMapIt
863 869 = m_VarRequestIdToVarIdVarRequestMap.find(varRequestId);
864 870 if (varRequestIdToVarIdVarRequestMapIt != m_VarRequestIdToVarIdVarRequestMap.cend()) {
865 871 auto &varIdToVarRequestMap = varRequestIdToVarIdVarRequestMapIt->second;
866 872 auto varIdToVarRequestMapIt = varIdToVarRequestMap.find(varId);
867 873 if (varIdToVarRequestMapIt != varIdToVarRequestMap.cend()) {
868 874 auto &varRequest = varIdToVarRequestMapIt->second;
869 875 lastRangeRequested = varRequest.m_RangeRequested;
870 876 }
871 877 else {
872 878 qCDebug(LOG_VariableController())
873 879 << tr("Impossible to getLastRequestedRange of a unknown variable id attached "
874 880 "to a variableRequestId")
875 881 << varRequestId << varId;
876 882 }
877 883 }
878 884 else {
879 885 qCCritical(LOG_VariableController())
880 886 << tr("Impossible to getLastRequestedRange of a unknown variableRequestId")
881 887 << varRequestId;
882 888 }
883 889 }
884 890 else {
885 891 qDebug(LOG_VariableController())
886 892 << tr("Impossible to getLastRequestedRange of a unknown variable id") << varId;
887 893 }
888 894
889 895 return lastRangeRequested;
890 896 }
@@ -1,310 +1,391
1 1 #include <QObject>
2 2 #include <QtTest>
3 3
4 4 #include <memory>
5 5
6 6 #include <Data/DataProviderParameters.h>
7 7 #include <Data/IDataProvider.h>
8 8 #include <Data/ScalarSeries.h>
9 9 #include <Time/TimeController.h>
10 10 #include <Variable/Variable.h>
11 11 #include <Variable/VariableController.h>
12 12 #include <Variable/VariableModel.h>
13 13
14 14 namespace {
15 15
16 16 /// Delay after each operation on the variable before validating it (in ms)
17 17 const auto OPERATION_DELAY = 100;
18 18
19 19 /**
20 20 * Generates values according to a range. The value generated for a time t is the number of seconds
21 21 * of difference between t and a reference value (which is midnight -> 00:00:00)
22 22 *
23 23 * Example: For a range between 00:00:10 and 00:00:20, the generated values are
24 24 * {10,11,12,13,14,15,16,17,18,19,20}
25 25 */
26 26 std::vector<double> values(const SqpRange &range)
27 27 {
28 28 QTime referenceTime{0, 0};
29 29
30 30 std::vector<double> result{};
31 31
32 32 for (auto i = range.m_TStart; i <= range.m_TEnd; ++i) {
33 33 auto time = DateUtils::dateTime(i).time();
34 34 result.push_back(referenceTime.secsTo(time));
35 35 }
36 36
37 37 return result;
38 38 }
39 39
40 40 /// Provider used for the tests
41 41 class TestProvider : public IDataProvider {
42 42 std::shared_ptr<IDataProvider> clone() const { return std::make_shared<TestProvider>(); }
43 43
44 44 void requestDataLoading(QUuid acqIdentifier, const DataProviderParameters &parameters) override
45 45 {
46 46 const auto &ranges = parameters.m_Times;
47 47
48 48 for (const auto &range : ranges) {
49 49 // Generates data series
50 50 auto valuesData = values(range);
51 51
52 52 std::vector<double> xAxisData{};
53 53 for (auto i = range.m_TStart; i <= range.m_TEnd; ++i) {
54 54 xAxisData.push_back(i);
55 55 }
56 56
57 57 auto dataSeries = std::make_shared<ScalarSeries>(
58 58 std::move(xAxisData), std::move(valuesData), Unit{"t", true}, Unit{});
59 59
60 60 emit dataProvided(acqIdentifier, dataSeries, range);
61 61 }
62 62 }
63 63
64 64 void requestDataAborting(QUuid acqIdentifier) override
65 65 {
66 66 // Does nothing
67 67 }
68 68 };
69 69
70 70 /**
71 71 * Interface representing an operation performed on a variable controller.
72 72 * This interface is used in tests to apply a set of operations and check the status of the
73 73 * controller after each operation
74 74 */
75 75 struct IOperation {
76 76 virtual ~IOperation() = default;
77 77 /// Executes the operation on the variable controller
78 78 virtual void exec(VariableController &variableController) const = 0;
79 79 };
80 80
81 81 /**
82 82 *Variable creation operation in the controller
83 83 */
84 84 struct Create : public IOperation {
85 85 explicit Create(int index) : m_Index{index} {}
86 86
87 87 void exec(VariableController &variableController) const override
88 88 {
89 89 auto variable = variableController.createVariable(QString::number(m_Index), {},
90 90 std::make_unique<TestProvider>());
91 91 }
92 92
93 93 int m_Index; ///< The index of the variable to create in the controller
94 94 };
95 95
96 96 /**
97 97 * Variable move/shift operation in the controller
98 98 */
99 99 struct Move : public IOperation {
100 100 explicit Move(int index, const SqpRange &newRange, bool shift = false)
101 101 : m_Index{index}, m_NewRange{newRange}, m_Shift{shift}
102 102 {
103 103 }
104 104
105 105 void exec(VariableController &variableController) const override
106 106 {
107 107 if (auto variable = variableController.variableModel()->variable(m_Index)) {
108 108 variableController.onRequestDataLoading({variable}, m_NewRange, variable->range(),
109 109 !m_Shift);
110 110 }
111 111 }
112 112
113 113 int m_Index; ///< The index of the variable to move
114 114 SqpRange m_NewRange; ///< The new range of the variable
115 115 bool m_Shift; ///< Performs a shift (
116 116 };
117 117
118 118 /**
119 119 * Variable synchronization/desynchronization operation in the controller
120 120 */
121 121 struct Synchronize : public IOperation {
122 122 explicit Synchronize(int index, QUuid syncId, bool synchronize = true)
123 123 : m_Index{index}, m_SyncId{syncId}, m_Synchronize{synchronize}
124 124 {
125 125 }
126 126
127 127 void exec(VariableController &variableController) const override
128 128 {
129 129 if (auto variable = variableController.variableModel()->variable(m_Index)) {
130 130 if (m_Synchronize) {
131 131 variableController.onAddSynchronized(variable, m_SyncId);
132 132 }
133 133 else {
134 134 variableController.desynchronize(variable, m_SyncId);
135 135 }
136 136 }
137 137 }
138 138
139 139 int m_Index; ///< The index of the variable to sync/desync
140 140 QUuid m_SyncId; ///< The synchronization group of the variable
141 141 bool m_Synchronize; ///< Performs sync or desync operation
142 142 };
143 143
144 144 /**
145 145 * Test Iteration
146 146 *
147 147 * A test iteration includes an operation to be performed, and a set of expected ranges after each
148 148 * operation. Each range is tested after the operation to ensure that:
149 149 * - the range of the variable is the expected range
150 150 * - the data of the variable are those generated for the expected range
151 151 */
152 152 struct Iteration {
153 153 std::shared_ptr<IOperation> m_Operation; ///< Operation to perform
154 154 std::map<int, SqpRange> m_ExpectedRanges; ///< Expected ranges (by variable index)
155 155 };
156 156
157 157 using Iterations = std::vector<Iteration>;
158 158
159 159 } // namespace
160 160
161 161 Q_DECLARE_METATYPE(Iterations)
162 162
163 163 class TestVariableSync : public QObject {
164 164 Q_OBJECT
165 165
166 166 private slots:
167 167 /// Input data for @sa testSync()
168 168 void testSync_data();
169 169
170 170 /// Tests synchronization between variables through several operations
171 171 void testSync();
172 172 };
173 173
174 void TestVariableSync::testSync_data()
175 {
176 // ////////////// //
177 // Test structure //
178 // ////////////// //
179
180 QTest::addColumn<QUuid>("syncId");
181 QTest::addColumn<SqpRange>("initialRange");
182 QTest::addColumn<Iterations>("iterations");
183
184 // ////////// //
185 // Test cases //
186 // ////////// //
174 namespace {
187 175
176 void testSyncCase1()
177 {
188 178 // Id used to synchronize variables in the controller
189 179 auto syncId = QUuid::createUuid();
190 180
191 181 /// Generates a range according to a start time and a end time (the date is the same)
192 182 auto range = [](const QTime &startTime, const QTime &endTime) {
193 183 return SqpRange{DateUtils::secondsSinceEpoch(QDateTime{{2017, 1, 1}, startTime, Qt::UTC}),
194 184 DateUtils::secondsSinceEpoch(QDateTime{{2017, 1, 1}, endTime, Qt::UTC})};
195 185 };
196 186
197 187 auto initialRange = range({12, 0}, {13, 0});
198 188
199 189 Iterations iterations{};
200 190 // Creates variables var0, var1 and var2
201 191 iterations.push_back({std::make_shared<Create>(0), {{0, initialRange}}});
202 192 iterations.push_back({std::make_shared<Create>(1), {{0, initialRange}, {1, initialRange}}});
203 193 iterations.push_back(
204 194 {std::make_shared<Create>(2), {{0, initialRange}, {1, initialRange}, {2, initialRange}}});
205 195
206 196 // Adds variables into the sync group (ranges don't need to be tested here)
207 197 iterations.push_back({std::make_shared<Synchronize>(0, syncId)});
208 198 iterations.push_back({std::make_shared<Synchronize>(1, syncId)});
209 199 iterations.push_back({std::make_shared<Synchronize>(2, syncId)});
210 200
211 201 // Moves var0: ranges of var0, var1 and var2 change
212 202 auto newRange = range({12, 30}, {13, 30});
213 203 iterations.push_back(
214 204 {std::make_shared<Move>(0, newRange), {{0, newRange}, {1, newRange}, {2, newRange}}});
215 205
216 206 // Moves var1: ranges of var0, var1 and var2 change
217 207 newRange = range({13, 0}, {14, 0});
218 208 iterations.push_back(
219 209 {std::make_shared<Move>(0, newRange), {{0, newRange}, {1, newRange}, {2, newRange}}});
220 210
221 211 // Moves var2: ranges of var0, var1 and var2 change
222 212 newRange = range({13, 30}, {14, 30});
223 213 iterations.push_back(
224 214 {std::make_shared<Move>(0, newRange), {{0, newRange}, {1, newRange}, {2, newRange}}});
225 215
226 216 // Desyncs var2 and moves var0:
227 217 // - ranges of var0 and var1 change
228 218 // - range of var2 doesn't change anymore
229 219 auto var2Range = newRange;
230 220 newRange = range({13, 45}, {14, 45});
231 221 iterations.push_back({std::make_shared<Synchronize>(2, syncId, false)});
232 222 iterations.push_back(
233 223 {std::make_shared<Move>(0, newRange), {{0, newRange}, {1, newRange}, {2, var2Range}}});
234 224
235 225 // Shifts var0: although var1 is synchronized with var0, its range doesn't change
236 226 auto var1Range = newRange;
237 227 newRange = range({14, 45}, {15, 45});
238 228 iterations.push_back({std::make_shared<Move>(0, newRange, true),
239 229 {{0, newRange}, {1, var1Range}, {2, var2Range}}});
240 230
241 231 // Moves var0 through several operations:
242 232 // - range of var0 changes
243 233 // - range or var1 changes according to the previous shift (one hour)
244 234 auto moveVar0 = [&iterations](const auto &var0NewRange, const auto &var1ExpectedRange) {
245 235 iterations.push_back(
246 236 {std::make_shared<Move>(0, var0NewRange), {{0, var0NewRange}, {1, var1ExpectedRange}}});
247 237 };
248 238 // Pan left
249 239 moveVar0(range({14, 30}, {15, 30}), range({13, 30}, {14, 30}));
250 240 // Pan right
251 241 moveVar0(range({16, 0}, {17, 0}), range({15, 0}, {16, 0}));
252 242 // Zoom in
253 243 moveVar0(range({16, 30}, {16, 45}), range({15, 30}, {15, 45}));
254 244 // Zoom out
255 245 moveVar0(range({12, 0}, {18, 0}), range({11, 0}, {17, 0}));
256 246
257 QTest::newRow("sync1") << syncId << initialRange << std::move(iterations);
247 QTest::newRow("sync1") << syncId << initialRange << std::move(iterations) << 200;
248 }
249
250 void testSyncCase2()
251 {
252 // Id used to synchronize variables in the controller
253 auto syncId = QUuid::createUuid();
254
255 /// Generates a range according to a start time and a end time (the date is the same)
256 auto dateTime = [](int year, int month, int day, int hours, int minutes, int seconds) {
257 return DateUtils::secondsSinceEpoch(
258 QDateTime{{year, month, day}, QTime{hours, minutes, seconds}, Qt::UTC});
259 };
260
261 auto initialRange = SqpRange{dateTime(2017, 1, 1, 12, 0, 0), dateTime(2017, 1, 1, 13, 0, 0)};
262
263 Iterations iterations{};
264 // Creates variables var0 and var1
265 iterations.push_back({std::make_shared<Create>(0), {{0, initialRange}}});
266 iterations.push_back({std::make_shared<Create>(1), {{0, initialRange}, {1, initialRange}}});
267
268 // Adds variables into the sync group (ranges don't need to be tested here)
269 iterations.push_back({std::make_shared<Synchronize>(0, syncId)});
270 iterations.push_back({std::make_shared<Synchronize>(1, syncId)});
271
272
273 // Moves var0 through several operations:
274 // - range of var0 changes
275 // - range or var1 changes according to the previous shift (one hour)
276 auto moveVar0 = [&iterations](const auto &var0NewRange) {
277 iterations.push_back(
278 {std::make_shared<Move>(0, var0NewRange), {{0, var0NewRange}, {1, var0NewRange}}});
279 };
280 moveVar0(SqpRange{dateTime(2017, 1, 1, 12, 0, 0), dateTime(2017, 1, 1, 13, 0, 0)});
281 moveVar0(SqpRange{dateTime(2017, 1, 1, 14, 0, 0), dateTime(2017, 1, 1, 15, 0, 0)});
282 moveVar0(SqpRange{dateTime(2017, 1, 1, 8, 0, 0), dateTime(2017, 1, 1, 9, 0, 0)});
283 // moveVar0(SqpRange{dateTime(2017, 1, 1, 7, 30, 0), dateTime(2017, 1, 1, 9, 30, 0)});
284 moveVar0(SqpRange{dateTime(2017, 1, 1, 2, 0, 0), dateTime(2017, 1, 1, 4, 0, 0)});
285 moveVar0(SqpRange{dateTime(2017, 1, 1, 6, 0, 0), dateTime(2017, 1, 1, 8, 0, 0)});
286
287 moveVar0(SqpRange{dateTime(2017, 1, 10, 6, 0, 0), dateTime(2017, 1, 15, 8, 0, 0)});
288 moveVar0(SqpRange{dateTime(2017, 1, 17, 6, 0, 0), dateTime(2017, 1, 25, 8, 0, 0)});
289 moveVar0(SqpRange{dateTime(2017, 1, 2, 6, 0, 0), dateTime(2017, 1, 8, 8, 0, 0)});
290
291 moveVar0(SqpRange{dateTime(2017, 4, 10, 6, 0, 0), dateTime(2017, 6, 15, 8, 0, 0)});
292 moveVar0(SqpRange{dateTime(2017, 1, 17, 6, 0, 0), dateTime(2017, 2, 25, 8, 0, 0)});
293 moveVar0(SqpRange{dateTime(2017, 7, 2, 6, 0, 0), dateTime(2017, 10, 8, 8, 0, 0)});
294 moveVar0(SqpRange{dateTime(2017, 4, 10, 6, 0, 0), dateTime(2017, 6, 15, 8, 0, 0)});
295 moveVar0(SqpRange{dateTime(2017, 1, 17, 6, 0, 0), dateTime(2017, 2, 25, 8, 0, 0)});
296 moveVar0(SqpRange{dateTime(2017, 7, 2, 6, 0, 0), dateTime(2017, 10, 8, 8, 0, 0)});
297 moveVar0(SqpRange{dateTime(2017, 4, 10, 6, 0, 0), dateTime(2017, 6, 15, 8, 0, 0)});
298 moveVar0(SqpRange{dateTime(2017, 1, 17, 6, 0, 0), dateTime(2017, 2, 25, 8, 0, 0)});
299 moveVar0(SqpRange{dateTime(2017, 7, 2, 6, 0, 0), dateTime(2017, 10, 8, 8, 0, 0)});
300 moveVar0(SqpRange{dateTime(2017, 4, 10, 6, 0, 0), dateTime(2017, 6, 15, 8, 0, 0)});
301 moveVar0(SqpRange{dateTime(2017, 1, 17, 6, 0, 0), dateTime(2017, 2, 25, 8, 0, 0)});
302 moveVar0(SqpRange{dateTime(2017, 7, 2, 6, 0, 0), dateTime(2017, 10, 8, 8, 0, 0)});
303
304
305 QTest::newRow("sync2") << syncId << initialRange << iterations << 4000;
306 // QTest::newRow("sync3") << syncId << initialRange << iterations << 5000;
307 }
308 }
309
310 void TestVariableSync::testSync_data()
311 {
312 // ////////////// //
313 // Test structure //
314 // ////////////// //
315
316 QTest::addColumn<QUuid>("syncId");
317 QTest::addColumn<SqpRange>("initialRange");
318 QTest::addColumn<Iterations>("iterations");
319 QTest::addColumn<int>("operationDelay");
320
321 // ////////// //
322 // Test cases //
323 // ////////// //
324
325 testSyncCase1();
326 testSyncCase2();
258 327 }
259 328
260 329 void TestVariableSync::testSync()
261 330 {
262 331 // Inits controllers
263 332 TimeController timeController{};
264 333 VariableController variableController{};
265 334 variableController.setTimeController(&timeController);
266 335
267 336 QFETCH(QUuid, syncId);
268 337 QFETCH(SqpRange, initialRange);
269 338 timeController.onTimeToUpdate(initialRange);
270 339
271 340 // Synchronization group used
272 341 variableController.onAddSynchronizationGroupId(syncId);
273 342
274 // For each iteration:
275 // - execute operation
276 // - compare the variables' state to the expected states
277 QFETCH(Iterations, iterations);
278 for (const auto &iteration : iterations) {
279 iteration.m_Operation->exec(variableController);
280 QTest::qWait(OPERATION_DELAY);
281
282 for (const auto &expectedRangeEntry : iteration.m_ExpectedRanges) {
343 auto validateRanges = [&variableController](const auto &expectedRanges) {
344 for (const auto &expectedRangeEntry : expectedRanges) {
283 345 auto variableIndex = expectedRangeEntry.first;
284 346 auto expectedRange = expectedRangeEntry.second;
285 347
286 348 // Gets the variable in the controller
287 349 auto variable = variableController.variableModel()->variable(variableIndex);
288 350
289 351 // Compares variable's range to the expected range
290 352 QVERIFY(variable != nullptr);
291 353 auto range = variable->range();
292 354 QCOMPARE(range, expectedRange);
293 355
294 356 // Compares variable's data with values expected for its range
295 357 auto dataSeries = variable->dataSeries();
296 358 QVERIFY(dataSeries != nullptr);
297 359
298 360 auto it = dataSeries->xAxisRange(range.m_TStart, range.m_TEnd);
299 361 auto expectedValues = values(range);
362 qInfo() << std::distance(it.first, it.second) << expectedValues.size();
300 363 QVERIFY(std::equal(it.first, it.second, expectedValues.cbegin(), expectedValues.cend(),
301 364 [](const auto &dataSeriesIt, const auto &expectedValue) {
302 365 return dataSeriesIt.value() == expectedValue;
303 366 }));
304 367 }
368 };
369
370 // For each iteration:
371 // - execute operation
372 // - compare the variables' state to the expected states
373 QFETCH(Iterations, iterations);
374 QFETCH(int, operationDelay);
375 for (const auto &iteration : iterations) {
376 iteration.m_Operation->exec(variableController);
377 QTest::qWait(operationDelay);
378
379 validateRanges(iteration.m_ExpectedRanges);
380 }
381
382 for (const auto &iteration : iterations) {
383 iteration.m_Operation->exec(variableController);
305 384 }
385 QTest::qWait(operationDelay);
386 validateRanges(iterations.back().m_ExpectedRanges);
306 387 }
307 388
308 389 QTEST_MAIN(TestVariableSync)
309 390
310 391 #include "TestVariableSync.moc"
@@ -1,302 +1,304
1 1 #include "Visualization/VisualizationZoneWidget.h"
2 2
3 3 #include "Visualization/IVisualizationWidgetVisitor.h"
4 4 #include "Visualization/QCustomPlotSynchronizer.h"
5 5 #include "Visualization/VisualizationGraphWidget.h"
6 6 #include "ui_VisualizationZoneWidget.h"
7 7
8 8 #include <Data/SqpRange.h>
9 9 #include <Variable/Variable.h>
10 10 #include <Variable/VariableController.h>
11 11
12 12 #include <QUuid>
13 13 #include <SqpApplication.h>
14 14 #include <cmath>
15 15
16 16 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
17 17
18 18 namespace {
19 19
20 20 /// Minimum height for graph added in zones (in pixels)
21 21 const auto GRAPH_MINIMUM_HEIGHT = 300;
22 22
23 23 /// Generates a default name for a new graph, according to the number of graphs already displayed in
24 24 /// the zone
25 25 QString defaultGraphName(const QLayout &layout)
26 26 {
27 27 auto count = 0;
28 28 for (auto i = 0; i < layout.count(); ++i) {
29 29 if (dynamic_cast<VisualizationGraphWidget *>(layout.itemAt(i)->widget())) {
30 30 count++;
31 31 }
32 32 }
33 33
34 34 return QObject::tr("Graph %1").arg(count + 1);
35 35 }
36 36
37 37 /**
38 38 * Applies a function to all graphs of the zone represented by its layout
39 39 * @param layout the layout that contains graphs
40 40 * @param fun the function to apply to each graph
41 41 */
42 42 template <typename Fun>
43 43 void processGraphs(QLayout &layout, Fun fun)
44 44 {
45 45 for (auto i = 0; i < layout.count(); ++i) {
46 46 if (auto item = layout.itemAt(i)) {
47 47 if (auto visualizationGraphWidget
48 48 = dynamic_cast<VisualizationGraphWidget *>(item->widget())) {
49 49 fun(*visualizationGraphWidget);
50 50 }
51 51 }
52 52 }
53 53 }
54 54
55 55 } // namespace
56 56
57 57 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate {
58 58
59 59 explicit VisualizationZoneWidgetPrivate()
60 60 : m_SynchronisationGroupId{QUuid::createUuid()},
61 61 m_Synchronizer{std::make_unique<QCustomPlotSynchronizer>()}
62 62 {
63 63 }
64 64 QUuid m_SynchronisationGroupId;
65 65 std::unique_ptr<IGraphSynchronizer> m_Synchronizer;
66 66 };
67 67
68 68 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
69 69 : QWidget{parent},
70 70 ui{new Ui::VisualizationZoneWidget},
71 71 impl{spimpl::make_unique_impl<VisualizationZoneWidgetPrivate>()}
72 72 {
73 73 ui->setupUi(this);
74 74
75 75 ui->zoneNameLabel->setText(name);
76 76
77 77 // 'Close' options : widget is deleted when closed
78 78 setAttribute(Qt::WA_DeleteOnClose);
79 79 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
80 80 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
81 81
82 82 // Synchronisation id
83 83 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronizationGroupId",
84 84 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
85 85 }
86 86
87 87 VisualizationZoneWidget::~VisualizationZoneWidget()
88 88 {
89 89 delete ui;
90 90 }
91 91
92 92 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
93 93 {
94 94 // Synchronize new graph with others in the zone
95 95 impl->m_Synchronizer->addGraph(*graphWidget);
96 96
97 97 ui->visualizationZoneFrame->layout()->addWidget(graphWidget);
98 98 }
99 99
100 100 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
101 101 {
102 102 auto graphWidget = new VisualizationGraphWidget{
103 103 defaultGraphName(*ui->visualizationZoneFrame->layout()), this};
104 104
105 105
106 106 // Set graph properties
107 107 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
108 108 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
109 109
110 110
111 111 // Lambda to synchronize zone widget
112 112 auto synchronizeZoneWidget = [this, graphWidget](const SqpRange &graphRange,
113 113 const SqpRange &oldGraphRange) {
114 114
115 115 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
116 116 auto frameLayout = ui->visualizationZoneFrame->layout();
117 117 for (auto i = 0; i < frameLayout->count(); ++i) {
118 118 auto graphChild
119 119 = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
120 120 if (graphChild && (graphChild != graphWidget)) {
121 121
122 122 auto graphChildRange = graphChild->graphRange();
123 123 switch (zoomType) {
124 124 case AcquisitionZoomType::ZoomIn: {
125 125 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
126 126 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
127 127 graphChildRange.m_TStart += deltaLeft;
128 128 graphChildRange.m_TEnd -= deltaRight;
129 129 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomIn");
130 130 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
131 131 << deltaLeft;
132 132 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
133 133 << deltaRight;
134 134 qCDebug(LOG_VisualizationZoneWidget())
135 135 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
136 136
137 137 break;
138 138 }
139 139
140 140 case AcquisitionZoomType::ZoomOut: {
141 141 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomOut");
142 142 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
143 143 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
144 144 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
145 145 << deltaLeft;
146 146 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
147 147 << deltaRight;
148 148 qCDebug(LOG_VisualizationZoneWidget())
149 149 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
150 150 graphChildRange.m_TStart -= deltaLeft;
151 151 graphChildRange.m_TEnd += deltaRight;
152 152 break;
153 153 }
154 154 case AcquisitionZoomType::PanRight: {
155 155 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanRight");
156 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
156 157 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
157 graphChildRange.m_TStart += deltaRight;
158 graphChildRange.m_TStart += deltaLeft;
158 159 graphChildRange.m_TEnd += deltaRight;
159 160 qCDebug(LOG_VisualizationZoneWidget())
160 161 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
161 162 break;
162 163 }
163 164 case AcquisitionZoomType::PanLeft: {
164 165 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanLeft");
165 166 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
167 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
166 168 graphChildRange.m_TStart -= deltaLeft;
167 graphChildRange.m_TEnd -= deltaLeft;
169 graphChildRange.m_TEnd -= deltaRight;
168 170 break;
169 171 }
170 172 case AcquisitionZoomType::Unknown: {
171 173 qCDebug(LOG_VisualizationZoneWidget())
172 174 << tr("Impossible to synchronize: zoom type unknown");
173 175 break;
174 176 }
175 177 default:
176 178 qCCritical(LOG_VisualizationZoneWidget())
177 179 << tr("Impossible to synchronize: zoom type not take into account");
178 180 // No action
179 181 break;
180 182 }
181 183 graphChild->enableAcquisition(false);
182 184 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range before: ")
183 185 << graphChild->graphRange();
184 186 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range after : ")
185 187 << graphChildRange;
186 188 qCDebug(LOG_VisualizationZoneWidget())
187 189 << tr("TORM: child dt") << graphChildRange.m_TEnd - graphChildRange.m_TStart;
188 190 graphChild->setGraphRange(graphChildRange);
189 191 graphChild->enableAcquisition(true);
190 192 }
191 193 }
192 194 };
193 195
194 196 // connection for synchronization
195 197 connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
196 198 connect(graphWidget, &VisualizationGraphWidget::variableAdded, this,
197 199 &VisualizationZoneWidget::onVariableAdded);
198 200 connect(graphWidget, &VisualizationGraphWidget::variableAboutToBeRemoved, this,
199 201 &VisualizationZoneWidget::onVariableAboutToBeRemoved);
200 202
201 203 auto range = SqpRange{};
202 204
203 205 // Apply visitor to graph children
204 206 auto layout = ui->visualizationZoneFrame->layout();
205 207 if (layout->count() > 0) {
206 208 // Case of a new graph in a existant zone
207 209 if (auto visualizationGraphWidget
208 210 = dynamic_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
209 211 range = visualizationGraphWidget->graphRange();
210 212 }
211 213 }
212 214 else {
213 215 // Case of a new graph as the first of the zone
214 216 range = variable->range();
215 217 }
216 218
217 219 this->addGraph(graphWidget);
218 220
219 221 graphWidget->addVariable(variable, range);
220 222
221 223 // get y using variable range
222 224 if (auto dataSeries = variable->dataSeries()) {
223 225 dataSeries->lockRead();
224 226 auto valuesBounds
225 227 = dataSeries->valuesBounds(variable->range().m_TStart, variable->range().m_TEnd);
226 228 auto end = dataSeries->cend();
227 229 if (valuesBounds.first != end && valuesBounds.second != end) {
228 230 auto rangeValue = [](const auto &value) { return std::isnan(value) ? 0. : value; };
229 231
230 232 auto minValue = rangeValue(valuesBounds.first->minValue());
231 233 auto maxValue = rangeValue(valuesBounds.second->maxValue());
232 234
233 235 graphWidget->setYRange(SqpRange{minValue, maxValue});
234 236 }
235 237 dataSeries->unlock();
236 238 }
237 239
238 240 return graphWidget;
239 241 }
240 242
241 243 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
242 244 {
243 245 if (visitor) {
244 246 visitor->visitEnter(this);
245 247
246 248 // Apply visitor to graph children: widgets different from graphs are not visited (no
247 249 // action)
248 250 processGraphs(
249 251 *ui->visualizationZoneFrame->layout(),
250 252 [visitor](VisualizationGraphWidget &graphWidget) { graphWidget.accept(visitor); });
251 253
252 254 visitor->visitLeave(this);
253 255 }
254 256 else {
255 257 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
256 258 }
257 259 }
258 260
259 261 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
260 262 {
261 263 // A tab can always accomodate a variable
262 264 Q_UNUSED(variable);
263 265 return true;
264 266 }
265 267
266 268 bool VisualizationZoneWidget::contains(const Variable &variable) const
267 269 {
268 270 Q_UNUSED(variable);
269 271 return false;
270 272 }
271 273
272 274 QString VisualizationZoneWidget::name() const
273 275 {
274 276 return ui->zoneNameLabel->text();
275 277 }
276 278
277 279 void VisualizationZoneWidget::closeEvent(QCloseEvent *event)
278 280 {
279 281 // Closes graphs in the zone
280 282 processGraphs(*ui->visualizationZoneFrame->layout(),
281 283 [](VisualizationGraphWidget &graphWidget) { graphWidget.close(); });
282 284
283 285 // Delete synchronization group from variable controller
284 286 QMetaObject::invokeMethod(&sqpApp->variableController(), "onRemoveSynchronizationGroupId",
285 287 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
286 288
287 289 QWidget::closeEvent(event);
288 290 }
289 291
290 292 void VisualizationZoneWidget::onVariableAdded(std::shared_ptr<Variable> variable)
291 293 {
292 294 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronized",
293 295 Qt::QueuedConnection, Q_ARG(std::shared_ptr<Variable>, variable),
294 296 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
295 297 }
296 298
297 299 void VisualizationZoneWidget::onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable)
298 300 {
299 301 QMetaObject::invokeMethod(&sqpApp->variableController(), "desynchronize", Qt::QueuedConnection,
300 302 Q_ARG(std::shared_ptr<Variable>, variable),
301 303 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
302 304 }
General Comments 3
Under Review
author

Auto status change to "Under Review"

Approved
author

Status change > Approved

You need to be logged in to leave comments. Login now