##// END OF EJS Templates
temp commit
Alexandre Leroux -
r680:00ac2d91df64
parent child
Show More
This diff has been collapsed as it changes many lines, (775 lines changed) Show them Hide them
@@ -0,0 +1,775
1 #include <Variable/Variable.h>
2 #include <Variable/VariableAcquisitionWorker.h>
3 #include <Variable/VariableCacheStrategy.h>
4 #include <Variable/VariableController.h>
5 #include <Variable/VariableModel.h>
6 #include <Variable/VariableSynchronizationGroup.h>
7
8 #include <Data/DataProviderParameters.h>
9 #include <Data/IDataProvider.h>
10 #include <Data/IDataSeries.h>
11 #include <Data/VariableRequest.h>
12 #include <Time/TimeController.h>
13
14 #include <QMutex>
15 #include <QThread>
16 #include <QUuid>
17 #include <QtCore/QItemSelectionModel>
18
19 #include <deque>
20 #include <set>
21 #include <unordered_map>
22
23 Q_LOGGING_CATEGORY(LOG_VariableController, "VariableController")
24
25 namespace {
26
27 SqpRange computeSynchroRangeRequested(const SqpRange &varRange, const SqpRange &graphRange,
28 const SqpRange &oldGraphRange)
29 {
30 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
31
32 auto varRangeRequested = varRange;
33 switch (zoomType) {
34 case AcquisitionZoomType::ZoomIn: {
35 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
36 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
37 varRangeRequested.m_TStart += deltaLeft;
38 varRangeRequested.m_TEnd -= deltaRight;
39 break;
40 }
41
42 case AcquisitionZoomType::ZoomOut: {
43 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
44 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
45 varRangeRequested.m_TStart -= deltaLeft;
46 varRangeRequested.m_TEnd += deltaRight;
47 break;
48 }
49 case AcquisitionZoomType::PanRight: {
50 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
51 varRangeRequested.m_TStart += deltaRight;
52 varRangeRequested.m_TEnd += deltaRight;
53 break;
54 }
55 case AcquisitionZoomType::PanLeft: {
56 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
57 varRangeRequested.m_TStart -= deltaLeft;
58 varRangeRequested.m_TEnd -= deltaLeft;
59 break;
60 }
61 case AcquisitionZoomType::Unknown: {
62 qCCritical(LOG_VariableController())
63 << VariableController::tr("Impossible to synchronize: zoom type unknown");
64 break;
65 }
66 default:
67 qCCritical(LOG_VariableController()) << VariableController::tr(
68 "Impossible to synchronize: zoom type not take into account");
69 // No action
70 break;
71 }
72
73 return varRangeRequested;
74 }
75 }
76
77 struct VariableController::VariableControllerPrivate {
78 explicit VariableControllerPrivate(VariableController *parent)
79 : m_WorkingMutex{},
80 m_VariableModel{new VariableModel{parent}},
81 m_VariableSelectionModel{new QItemSelectionModel{m_VariableModel, parent}},
82 m_VariableCacheStrategy{std::make_unique<VariableCacheStrategy>()},
83 m_VariableAcquisitionWorker{std::make_unique<VariableAcquisitionWorker>()},
84 q{parent}
85 {
86
87 m_VariableAcquisitionWorker->moveToThread(&m_VariableAcquisitionWorkerThread);
88 m_VariableAcquisitionWorkerThread.setObjectName("VariableAcquisitionWorkerThread");
89 }
90
91
92 virtual ~VariableControllerPrivate()
93 {
94 qCDebug(LOG_VariableController()) << tr("VariableControllerPrivate destruction");
95 m_VariableAcquisitionWorkerThread.quit();
96 m_VariableAcquisitionWorkerThread.wait();
97 }
98
99
100 void processRequest(std::shared_ptr<Variable> var, const SqpRange &rangeRequested,
101 QUuid varRequestId);
102
103 QVector<SqpRange> provideNotInCacheDateTimeList(std::shared_ptr<Variable> variable,
104 const SqpRange &dateTime);
105
106 std::shared_ptr<Variable> findVariable(QUuid vIdentifier);
107 std::shared_ptr<IDataSeries>
108 retrieveDataSeries(const QVector<AcquisitionDataPacket> acqDataPacketVector);
109
110 void registerProvider(std::shared_ptr<IDataProvider> provider);
111
112 void storeVariableRequest(QUuid varId, QUuid varRequestId, const VariableRequest &varRequest);
113 QUuid acceptVariableRequest(QUuid varId, std::shared_ptr<IDataSeries> dataSeries);
114 void updateVariableRequest(QUuid varRequestId);
115 void cancelVariableRequest(QUuid varRequestId);
116
117 QMutex m_WorkingMutex;
118 /// Variable model. The VariableController has the ownership
119 VariableModel *m_VariableModel;
120 QItemSelectionModel *m_VariableSelectionModel;
121
122
123 TimeController *m_TimeController{nullptr};
124 std::unique_ptr<VariableCacheStrategy> m_VariableCacheStrategy;
125 std::unique_ptr<VariableAcquisitionWorker> m_VariableAcquisitionWorker;
126 QThread m_VariableAcquisitionWorkerThread;
127
128 std::unordered_map<std::shared_ptr<Variable>, std::shared_ptr<IDataProvider> >
129 m_VariableToProviderMap;
130 std::unordered_map<std::shared_ptr<Variable>, QUuid> m_VariableToIdentifierMap;
131 std::map<QUuid, std::shared_ptr<VariableSynchronizationGroup> >
132 m_GroupIdToVariableSynchronizationGroupMap;
133 std::map<QUuid, QUuid> m_VariableIdGroupIdMap;
134 std::set<std::shared_ptr<IDataProvider> > m_ProviderSet;
135
136 std::map<QUuid, std::map<QUuid, VariableRequest> > m_VarRequestIdToVarIdVarRequestMap;
137
138 std::map<QUuid, std::deque<QUuid> > m_VarIdToVarRequestIdQueueMap;
139
140
141 VariableController *q;
142 };
143
144
145 VariableController::VariableController(QObject *parent)
146 : QObject{parent}, impl{spimpl::make_unique_impl<VariableControllerPrivate>(this)}
147 {
148 qCDebug(LOG_VariableController()) << tr("VariableController construction")
149 << QThread::currentThread();
150
151 connect(impl->m_VariableModel, &VariableModel::abortProgessRequested, this,
152 &VariableController::onAbortProgressRequested);
153
154 connect(impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::dataProvided, this,
155 &VariableController::onDataProvided);
156 connect(impl->m_VariableAcquisitionWorker.get(),
157 &VariableAcquisitionWorker::variableRequestInProgress, this,
158 &VariableController::onVariableRetrieveDataInProgress);
159
160 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::started,
161 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::initialize);
162 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::finished,
163 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::finalize);
164
165
166 impl->m_VariableAcquisitionWorkerThread.start();
167 }
168
169 VariableController::~VariableController()
170 {
171 qCDebug(LOG_VariableController()) << tr("VariableController destruction")
172 << QThread::currentThread();
173 this->waitForFinish();
174 }
175
176 VariableModel *VariableController::variableModel() noexcept
177 {
178 return impl->m_VariableModel;
179 }
180
181 QItemSelectionModel *VariableController::variableSelectionModel() noexcept
182 {
183 return impl->m_VariableSelectionModel;
184 }
185
186 void VariableController::setTimeController(TimeController *timeController) noexcept
187 {
188 impl->m_TimeController = timeController;
189 }
190
191 std::shared_ptr<Variable>
192 VariableController::cloneVariable(std::shared_ptr<Variable> variable) noexcept
193 {
194 if (impl->m_VariableModel->containsVariable(variable)) {
195 // Clones variable
196 auto duplicate = variable->clone();
197
198 // Adds clone to model
199 impl->m_VariableModel->addVariable(duplicate);
200
201 // Generates clone identifier
202 impl->m_VariableToIdentifierMap[duplicate] = QUuid::createUuid();
203
204 // Registers provider
205 auto variableProvider = impl->m_VariableToProviderMap.at(variable);
206 auto duplicateProvider = variableProvider != nullptr ? variableProvider->clone() : nullptr;
207
208 impl->m_VariableToProviderMap[duplicate] = duplicateProvider;
209 if (duplicateProvider) {
210 impl->registerProvider(duplicateProvider);
211 }
212
213 return duplicate;
214 }
215 else {
216 qCCritical(LOG_VariableController())
217 << tr("Can't create duplicate of variable %1: variable not registered in the model")
218 .arg(variable->name());
219 return nullptr;
220 }
221 }
222
223 void VariableController::deleteVariable(std::shared_ptr<Variable> variable) noexcept
224 {
225 if (!variable) {
226 qCCritical(LOG_VariableController()) << "Can't delete variable: variable is null";
227 return;
228 }
229
230 // Spreads in SciQlop that the variable will be deleted, so that potential receivers can
231 // make some treatments before the deletion
232 emit variableAboutToBeDeleted(variable);
233
234 // Deletes identifier
235 impl->m_VariableToIdentifierMap.erase(variable);
236
237 // Deletes provider
238 auto nbProvidersDeleted = impl->m_VariableToProviderMap.erase(variable);
239 qCDebug(LOG_VariableController())
240 << tr("Number of providers deleted for variable %1: %2")
241 .arg(variable->name(), QString::number(nbProvidersDeleted));
242
243
244 // Deletes from model
245 impl->m_VariableModel->deleteVariable(variable);
246 }
247
248 void VariableController::deleteVariables(
249 const QVector<std::shared_ptr<Variable> > &variables) noexcept
250 {
251 for (auto variable : qAsConst(variables)) {
252 deleteVariable(variable);
253 }
254 }
255
256 void VariableController::abortProgress(std::shared_ptr<Variable> variable)
257 {
258 }
259
260 std::shared_ptr<Variable>
261 VariableController::createVariable(const QString &name, const QVariantHash &metadata,
262 std::shared_ptr<IDataProvider> provider) noexcept
263 {
264 if (!impl->m_TimeController) {
265 qCCritical(LOG_VariableController())
266 << tr("Impossible to create variable: The time controller is null");
267 return nullptr;
268 }
269
270 auto range = impl->m_TimeController->dateTime();
271
272 if (auto newVariable = impl->m_VariableModel->createVariable(name, range, metadata)) {
273 auto identifier = QUuid::createUuid();
274
275 // store the provider
276 impl->registerProvider(provider);
277
278 // Associate the provider
279 impl->m_VariableToProviderMap[newVariable] = provider;
280 impl->m_VariableToIdentifierMap[newVariable] = identifier;
281
282
283 auto varRequestId = QUuid::createUuid();
284 qCInfo(LOG_VariableController()) << "processRequest for" << name << varRequestId;
285 impl->processRequest(newVariable, range, varRequestId);
286 impl->updateVariableRequest(varRequestId);
287
288 return newVariable;
289 }
290 }
291
292 void VariableController::onDateTimeOnSelection(const SqpRange &dateTime)
293 {
294 // TODO check synchronisation and Rescale
295 qCDebug(LOG_VariableController()) << "VariableController::onDateTimeOnSelection"
296 << QThread::currentThread()->objectName();
297 auto selectedRows = impl->m_VariableSelectionModel->selectedRows();
298 auto varRequestId = QUuid::createUuid();
299
300 for (const auto &selectedRow : qAsConst(selectedRows)) {
301 if (auto selectedVariable = impl->m_VariableModel->variable(selectedRow.row())) {
302 selectedVariable->setRange(dateTime);
303 impl->processRequest(selectedVariable, dateTime, varRequestId);
304
305 // notify that rescale operation has to be done
306 emit rangeChanged(selectedVariable, dateTime);
307 }
308 }
309 impl->updateVariableRequest(varRequestId);
310 }
311
312 void VariableController::onDataProvided(QUuid vIdentifier, const SqpRange &rangeRequested,
313 const SqpRange &cacheRangeRequested,
314 QVector<AcquisitionDataPacket> dataAcquired)
315 {
316 auto retrievedDataSeries = impl->retrieveDataSeries(dataAcquired);
317 auto varRequestId = impl->acceptVariableRequest(vIdentifier, retrievedDataSeries);
318 if (!varRequestId.isNull()) {
319 impl->updateVariableRequest(varRequestId);
320 }
321 }
322
323 void VariableController::onVariableRetrieveDataInProgress(QUuid identifier, double progress)
324 {
325 if (auto var = impl->findVariable(identifier)) {
326 impl->m_VariableModel->setDataProgress(var, progress);
327 }
328 else {
329 qCCritical(LOG_VariableController())
330 << tr("Impossible to notify progression of a null variable");
331 }
332 }
333
334 void VariableController::onAbortProgressRequested(std::shared_ptr<Variable> variable)
335 {
336 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAbortProgressRequested"
337 << QThread::currentThread()->objectName();
338
339 auto it = impl->m_VariableToIdentifierMap.find(variable);
340 if (it != impl->m_VariableToIdentifierMap.cend()) {
341 impl->m_VariableToProviderMap.at(variable)->requestDataAborting(it->second);
342 }
343 else {
344 qCWarning(LOG_VariableController())
345 << tr("Aborting progression of inexistant variable detected !!!")
346 << QThread::currentThread()->objectName();
347 }
348 }
349
350 void VariableController::onAddSynchronizationGroupId(QUuid synchronizationGroupId)
351 {
352 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronizationGroupId"
353 << QThread::currentThread()->objectName()
354 << synchronizationGroupId;
355 auto vSynchroGroup = std::make_shared<VariableSynchronizationGroup>();
356 impl->m_GroupIdToVariableSynchronizationGroupMap.insert(
357 std::make_pair(synchronizationGroupId, vSynchroGroup));
358 }
359
360 void VariableController::onRemoveSynchronizationGroupId(QUuid synchronizationGroupId)
361 {
362 impl->m_GroupIdToVariableSynchronizationGroupMap.erase(synchronizationGroupId);
363 }
364
365 void VariableController::onAddSynchronized(std::shared_ptr<Variable> variable,
366 QUuid synchronizationGroupId)
367
368 {
369 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronized"
370 << synchronizationGroupId;
371 auto varToVarIdIt = impl->m_VariableToIdentifierMap.find(variable);
372 if (varToVarIdIt != impl->m_VariableToIdentifierMap.cend()) {
373 auto groupIdToVSGIt
374 = impl->m_GroupIdToVariableSynchronizationGroupMap.find(synchronizationGroupId);
375 if (groupIdToVSGIt != impl->m_GroupIdToVariableSynchronizationGroupMap.cend()) {
376 impl->m_VariableIdGroupIdMap.insert(
377 std::make_pair(varToVarIdIt->second, synchronizationGroupId));
378 groupIdToVSGIt->second->addVariableId(varToVarIdIt->second);
379 }
380 else {
381 qCCritical(LOG_VariableController())
382 << tr("Impossible to synchronize a variable with an unknown sycnhronization group")
383 << variable->name();
384 }
385 }
386 else {
387 qCCritical(LOG_VariableController())
388 << tr("Impossible to synchronize a variable with no identifier") << variable->name();
389 }
390 }
391
392
393 void VariableController::onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables,
394 const SqpRange &range, const SqpRange &oldRange,
395 bool synchronise)
396 {
397 // NOTE: oldRange isn't really necessary since oldRange == variable->range().
398
399 // we want to load data of the variable for the dateTime.
400 // First we check if the cache contains some of them.
401 // For the other, we ask the provider to give them.
402
403 auto varRequestId = QUuid::createUuid();
404 qCInfo(LOG_VariableController()) << "VariableController::onRequestDataLoading"
405 << QThread::currentThread()->objectName() << varRequestId;
406
407 for (const auto &var : variables) {
408 qCDebug(LOG_VariableController()) << "processRequest for" << var->name() << varRequestId;
409 impl->processRequest(var, range, varRequestId);
410 }
411
412 if (synchronise) {
413 // Get the group ids
414 qCDebug(LOG_VariableController())
415 << "TORM VariableController::onRequestDataLoading for synchro var ENABLE";
416 auto groupIds = std::set<QUuid>{};
417 auto groupIdToOldRangeMap = std::map<QUuid, SqpRange>{};
418 for (const auto &var : variables) {
419 auto varToVarIdIt = impl->m_VariableToIdentifierMap.find(var);
420 if (varToVarIdIt != impl->m_VariableToIdentifierMap.cend()) {
421 auto vId = varToVarIdIt->second;
422 auto varIdToGroupIdIt = impl->m_VariableIdGroupIdMap.find(vId);
423 if (varIdToGroupIdIt != impl->m_VariableIdGroupIdMap.cend()) {
424 auto gId = varIdToGroupIdIt->second;
425 groupIdToOldRangeMap.insert(std::make_pair(gId, var->range()));
426 if (groupIds.find(gId) == groupIds.cend()) {
427 qCDebug(LOG_VariableController()) << "Synchro detect group " << gId;
428 groupIds.insert(gId);
429 }
430 }
431 }
432 }
433
434 // We assume here all group ids exist
435 for (const auto &gId : groupIds) {
436 auto vSynchronizationGroup = impl->m_GroupIdToVariableSynchronizationGroupMap.at(gId);
437 auto vSyncIds = vSynchronizationGroup->getIds();
438 qCDebug(LOG_VariableController()) << "Var in synchro group ";
439 for (auto vId : vSyncIds) {
440 auto var = impl->findVariable(vId);
441
442 // Don't process already processed var
443 if (!variables.contains(var)) {
444 if (var != nullptr) {
445 qCDebug(LOG_VariableController()) << "processRequest synchro for"
446 << var->name();
447 auto vSyncRangeRequested = computeSynchroRangeRequested(
448 var->range(), range, groupIdToOldRangeMap.at(gId));
449 qCDebug(LOG_VariableController()) << "synchro RR" << vSyncRangeRequested;
450 impl->processRequest(var, vSyncRangeRequested, varRequestId);
451 }
452 else {
453 qCCritical(LOG_VariableController())
454
455 << tr("Impossible to synchronize a null variable");
456 }
457 }
458 }
459 }
460 }
461
462 impl->updateVariableRequest(varRequestId);
463 }
464
465
466 void VariableController::initialize()
467 {
468 qCDebug(LOG_VariableController()) << tr("VariableController init") << QThread::currentThread();
469 impl->m_WorkingMutex.lock();
470 qCDebug(LOG_VariableController()) << tr("VariableController init END");
471 }
472
473 void VariableController::finalize()
474 {
475 impl->m_WorkingMutex.unlock();
476 }
477
478 void VariableController::waitForFinish()
479 {
480 QMutexLocker locker{&impl->m_WorkingMutex};
481 }
482
483 AcquisitionZoomType VariableController::getZoomType(const SqpRange &range, const SqpRange &oldRange)
484 {
485 // t1.m_TStart <= t2.m_TStart && t2.m_TEnd <= t1.m_TEnd
486 auto zoomType = AcquisitionZoomType::Unknown;
487 if (range.m_TStart <= oldRange.m_TStart && oldRange.m_TEnd <= range.m_TEnd) {
488 zoomType = AcquisitionZoomType::ZoomOut;
489 }
490 else if (range.m_TStart > oldRange.m_TStart && range.m_TEnd > oldRange.m_TEnd) {
491 zoomType = AcquisitionZoomType::PanRight;
492 }
493 else if (range.m_TStart < oldRange.m_TStart && range.m_TEnd < oldRange.m_TEnd) {
494 zoomType = AcquisitionZoomType::PanLeft;
495 }
496 else if (range.m_TStart > oldRange.m_TStart && oldRange.m_TEnd > range.m_TEnd) {
497 zoomType = AcquisitionZoomType::ZoomIn;
498 }
499 else {
500 qCCritical(LOG_VariableController()) << "getZoomType: Unknown type detected";
501 }
502 return zoomType;
503 }
504
505 void VariableController::VariableControllerPrivate::processRequest(std::shared_ptr<Variable> var,
506 const SqpRange &rangeRequested,
507 QUuid varRequestId)
508 {
509
510 // TODO: protect at
511 auto varRequest = VariableRequest{};
512 auto varId = m_VariableToIdentifierMap.at(var);
513
514 auto varStrategyRangesRequested
515 = m_VariableCacheStrategy->computeStrategyRanges(var->range(), rangeRequested);
516 auto notInCacheRangeList = var->provideNotInCacheRangeList(varStrategyRangesRequested.second);
517 auto inCacheRangeList = var->provideInCacheRangeList(varStrategyRangesRequested.second);
518
519 if (!notInCacheRangeList.empty()) {
520 varRequest.m_RangeRequested = varStrategyRangesRequested.first;
521 varRequest.m_CacheRangeRequested = varStrategyRangesRequested.second;
522 qCDebug(LOG_VariableAcquisitionWorker()) << tr("TORM processRequest RR ") << rangeRequested;
523 qCDebug(LOG_VariableAcquisitionWorker()) << tr("TORM processRequest R ")
524 << varStrategyRangesRequested.first;
525 qCDebug(LOG_VariableAcquisitionWorker()) << tr("TORM processRequest CR ")
526 << varStrategyRangesRequested.second;
527 // store VarRequest
528 storeVariableRequest(varId, varRequestId, varRequest);
529
530 auto varProvider = m_VariableToProviderMap.at(var);
531 if (varProvider != nullptr) {
532 auto varRequestIdCanceled = m_VariableAcquisitionWorker->pushVariableRequest(
533 varRequestId, varId, varStrategyRangesRequested.first,
534 varStrategyRangesRequested.second,
535 DataProviderParameters{std::move(notInCacheRangeList), var->metadata()},
536 varProvider);
537
538 if (!varRequestIdCanceled.isNull()) {
539 qCInfo(LOG_VariableAcquisitionWorker()) << tr("varRequestIdCanceled: ")
540 << varRequestIdCanceled;
541 cancelVariableRequest(varRequestIdCanceled);
542 }
543 }
544 else {
545 qCCritical(LOG_VariableController())
546 << "Impossible to provide data with a null provider";
547 }
548
549 if (!inCacheRangeList.empty()) {
550 emit q->updateVarDisplaying(var, inCacheRangeList.first());
551 }
552 }
553 else {
554
555 varRequest.m_RangeRequested = varStrategyRangesRequested.first;
556 varRequest.m_CacheRangeRequested = varStrategyRangesRequested.second;
557 // store VarRequest
558 storeVariableRequest(varId, varRequestId, varRequest);
559 acceptVariableRequest(varId,
560 var->dataSeries()->subDataSeries(varStrategyRangesRequested.second));
561 }
562 }
563
564 std::shared_ptr<Variable>
565 VariableController::VariableControllerPrivate::findVariable(QUuid vIdentifier)
566 {
567 std::shared_ptr<Variable> var;
568 auto findReply = [vIdentifier](const auto &entry) { return vIdentifier == entry.second; };
569
570 auto end = m_VariableToIdentifierMap.cend();
571 auto it = std::find_if(m_VariableToIdentifierMap.cbegin(), end, findReply);
572 if (it != end) {
573 var = it->first;
574 }
575 else {
576 qCCritical(LOG_VariableController())
577 << tr("Impossible to find the variable with the identifier: ") << vIdentifier;
578 }
579
580 return var;
581 }
582
583 std::shared_ptr<IDataSeries> VariableController::VariableControllerPrivate::retrieveDataSeries(
584 const QVector<AcquisitionDataPacket> acqDataPacketVector)
585 {
586 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size")
587 << acqDataPacketVector.size();
588 std::shared_ptr<IDataSeries> dataSeries;
589 if (!acqDataPacketVector.isEmpty()) {
590 dataSeries = acqDataPacketVector[0].m_DateSeries;
591 for (int i = 1; i < acqDataPacketVector.size(); ++i) {
592 dataSeries->merge(acqDataPacketVector[i].m_DateSeries.get());
593 }
594 }
595 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size END")
596 << acqDataPacketVector.size();
597 return dataSeries;
598 }
599
600 void VariableController::VariableControllerPrivate::registerProvider(
601 std::shared_ptr<IDataProvider> provider)
602 {
603 if (m_ProviderSet.find(provider) == m_ProviderSet.end()) {
604 qCDebug(LOG_VariableController()) << tr("Registering of a new provider")
605 << provider->objectName();
606 m_ProviderSet.insert(provider);
607 connect(provider.get(), &IDataProvider::dataProvided, m_VariableAcquisitionWorker.get(),
608 &VariableAcquisitionWorker::onVariableDataAcquired);
609 connect(provider.get(), &IDataProvider::dataProvidedProgress,
610 m_VariableAcquisitionWorker.get(),
611 &VariableAcquisitionWorker::onVariableRetrieveDataInProgress);
612 }
613 else {
614 qCDebug(LOG_VariableController()) << tr("Cannot register provider, it already exists ");
615 }
616 }
617
618 void VariableController::VariableControllerPrivate::storeVariableRequest(
619 QUuid varId, QUuid varRequestId, const VariableRequest &varRequest)
620 {
621 // First request for the variable. we can create an entry for it
622 auto varIdToVarRequestIdQueueMapIt = m_VarIdToVarRequestIdQueueMap.find(varId);
623 if (varIdToVarRequestIdQueueMapIt == m_VarIdToVarRequestIdQueueMap.cend()) {
624 auto varRequestIdQueue = std::deque<QUuid>{};
625 qCDebug(LOG_VariableController()) << tr("Store REQUEST in QUEUE");
626 varRequestIdQueue.push_back(varRequestId);
627 m_VarIdToVarRequestIdQueueMap.insert(std::make_pair(varId, std::move(varRequestIdQueue)));
628 }
629 else {
630 qCDebug(LOG_VariableController()) << tr("Store REQUEST in EXISTING QUEUE");
631 auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second;
632 varRequestIdQueue.push_back(varRequestId);
633 }
634
635 auto varRequestIdToVarIdVarRequestMapIt = m_VarRequestIdToVarIdVarRequestMap.find(varRequestId);
636 if (varRequestIdToVarIdVarRequestMapIt == m_VarRequestIdToVarIdVarRequestMap.cend()) {
637 auto varIdToVarRequestMap = std::map<QUuid, VariableRequest>{};
638 varIdToVarRequestMap.insert(std::make_pair(varId, varRequest));
639 qCDebug(LOG_VariableController()) << tr("Store REQUESTID in MAP");
640 m_VarRequestIdToVarIdVarRequestMap.insert(
641 std::make_pair(varRequestId, std::move(varIdToVarRequestMap)));
642 }
643 else {
644 auto &varIdToVarRequestMap = varRequestIdToVarIdVarRequestMapIt->second;
645 qCDebug(LOG_VariableController()) << tr("Store REQUESTID in EXISTING MAP");
646 varIdToVarRequestMap.insert(std::make_pair(varId, varRequest));
647 }
648 }
649
650 QUuid VariableController::VariableControllerPrivate::acceptVariableRequest(
651 QUuid varId, std::shared_ptr<IDataSeries> dataSeries)
652 {
653 QUuid varRequestId;
654 auto varIdToVarRequestIdQueueMapIt = m_VarIdToVarRequestIdQueueMap.find(varId);
655 if (varIdToVarRequestIdQueueMapIt != m_VarIdToVarRequestIdQueueMap.cend()) {
656 auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second;
657 varRequestId = varRequestIdQueue.front();
658 auto varRequestIdToVarIdVarRequestMapIt
659 = m_VarRequestIdToVarIdVarRequestMap.find(varRequestId);
660 if (varRequestIdToVarIdVarRequestMapIt != m_VarRequestIdToVarIdVarRequestMap.cend()) {
661 auto &varIdToVarRequestMap = varRequestIdToVarIdVarRequestMapIt->second;
662 auto varIdToVarRequestMapIt = varIdToVarRequestMap.find(varId);
663 if (varIdToVarRequestMapIt != varIdToVarRequestMap.cend()) {
664 qCDebug(LOG_VariableController()) << tr("acceptVariableRequest");
665 auto &varRequest = varIdToVarRequestMapIt->second;
666 varRequest.m_DataSeries = dataSeries;
667 varRequest.m_CanUpdate = true;
668 }
669 else {
670 qCDebug(LOG_VariableController())
671 << tr("Impossible to acceptVariableRequest of a unknown variable id attached "
672 "to a variableRequestId")
673 << varRequestId << varId;
674 }
675 }
676 else {
677 qCCritical(LOG_VariableController())
678 << tr("Impossible to acceptVariableRequest of a unknown variableRequestId")
679 << varRequestId;
680 }
681
682 qCDebug(LOG_VariableController()) << tr("1: erase REQUEST in QUEUE ?")
683 << varRequestIdQueue.size();
684 varRequestIdQueue.pop_front();
685 qCDebug(LOG_VariableController()) << tr("2: erase REQUEST in QUEUE ?")
686 << varRequestIdQueue.size();
687 if (varRequestIdQueue.empty()) {
688 m_VarIdToVarRequestIdQueueMap.erase(varId);
689 }
690 }
691 else {
692 qCCritical(LOG_VariableController())
693 << tr("Impossible to acceptVariableRequest of a unknown variable id") << varId;
694 }
695
696 return varRequestId;
697 }
698
699 void VariableController::VariableControllerPrivate::updateVariableRequest(QUuid varRequestId)
700 {
701
702 auto varRequestIdToVarIdVarRequestMapIt = m_VarRequestIdToVarIdVarRequestMap.find(varRequestId);
703 if (varRequestIdToVarIdVarRequestMapIt != m_VarRequestIdToVarIdVarRequestMap.cend()) {
704 bool processVariableUpdate = true;
705 auto &varIdToVarRequestMap = varRequestIdToVarIdVarRequestMapIt->second;
706 for (auto varIdToVarRequestMapIt = varIdToVarRequestMap.cbegin();
707 (varIdToVarRequestMapIt != varIdToVarRequestMap.cend()) && processVariableUpdate;
708 ++varIdToVarRequestMapIt) {
709 processVariableUpdate &= varIdToVarRequestMapIt->second.m_CanUpdate;
710 qCDebug(LOG_VariableController()) << tr("updateVariableRequest")
711 << processVariableUpdate;
712 }
713
714 if (processVariableUpdate) {
715 for (auto varIdToVarRequestMapIt = varIdToVarRequestMap.cbegin();
716 varIdToVarRequestMapIt != varIdToVarRequestMap.cend(); ++varIdToVarRequestMapIt) {
717 if (auto var = findVariable(varIdToVarRequestMapIt->first)) {
718 auto &varRequest = varIdToVarRequestMapIt->second;
719 var->setRange(varRequest.m_RangeRequested);
720 var->setCacheRange(varRequest.m_CacheRangeRequested);
721 qCDebug(LOG_VariableController()) << tr("1: onDataProvided")
722 << varRequest.m_RangeRequested;
723 qCDebug(LOG_VariableController()) << tr("2: onDataProvided")
724 << varRequest.m_CacheRangeRequested;
725 var->mergeDataSeries(varRequest.m_DataSeries);
726 qCDebug(LOG_VariableController()) << tr("3: onDataProvided")
727 << varRequest.m_DataSeries->range();
728 qCDebug(LOG_VariableController()) << tr("4: onDataProvided");
729
730 /// @todo MPL: confirm
731 // Variable update is notified only if there is no pending request for it
732 if (m_VarIdToVarRequestIdQueueMap.count(varIdToVarRequestMapIt->first) == 0) {
733 emit var->updated();
734 }
735 }
736 else {
737 qCCritical(LOG_VariableController())
738 << tr("Impossible to update data to a null variable");
739 }
740 }
741
742 // cleaning varRequestId
743 qCDebug(LOG_VariableController()) << tr("0: erase REQUEST in MAP ?")
744 << m_VarRequestIdToVarIdVarRequestMap.size();
745 m_VarRequestIdToVarIdVarRequestMap.erase(varRequestId);
746 qCDebug(LOG_VariableController()) << tr("1: erase REQUEST in MAP ?")
747 << m_VarRequestIdToVarIdVarRequestMap.size();
748 }
749 }
750 else {
751 qCCritical(LOG_VariableController())
752 << tr("Cannot updateVariableRequest for a unknow varRequestId") << varRequestId;
753 }
754 }
755
756 void VariableController::VariableControllerPrivate::cancelVariableRequest(QUuid varRequestId)
757 {
758 // cleaning varRequestId
759 m_VarRequestIdToVarIdVarRequestMap.erase(varRequestId);
760
761 for (auto varIdToVarRequestIdQueueMapIt = m_VarIdToVarRequestIdQueueMap.begin();
762 varIdToVarRequestIdQueueMapIt != m_VarIdToVarRequestIdQueueMap.end();) {
763 auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second;
764 varRequestIdQueue.erase(
765 std::remove(varRequestIdQueue.begin(), varRequestIdQueue.end(), varRequestId),
766 varRequestIdQueue.end());
767 if (varRequestIdQueue.empty()) {
768 varIdToVarRequestIdQueueMapIt
769 = m_VarIdToVarRequestIdQueueMap.erase(varIdToVarRequestIdQueueMapIt);
770 }
771 else {
772 ++varIdToVarRequestIdQueueMapIt;
773 }
774 }
775 }
This diff has been collapsed as it changes many lines, (636 lines changed) Show them Hide them
@@ -0,0 +1,636
1 #include "Data/DataSeries.h"
2 #include "Data/ScalarSeries.h"
3 #include "Data/VectorSeries.h"
4
5 #include <cmath>
6
7 #include <QObject>
8 #include <QtTest>
9
10 Q_DECLARE_METATYPE(std::shared_ptr<ScalarSeries>)
11 Q_DECLARE_METATYPE(std::shared_ptr<VectorSeries>)
12
13 namespace {
14
15 using DataContainer = std::vector<double>;
16
17 void validateRange(DataSeriesIterator first, DataSeriesIterator last, const DataContainer &xData,
18 const DataContainer &valuesData)
19 {
20 QVERIFY(std::equal(first, last, xData.cbegin(), xData.cend(),
21 [](const auto &it, const auto &expectedX) { return it.x() == expectedX; }));
22 QVERIFY(std::equal(
23 first, last, valuesData.cbegin(), valuesData.cend(),
24 [](const auto &it, const auto &expectedVal) { return it.value() == expectedVal; }));
25 }
26
27 void validateRange(DataSeriesIterator first, DataSeriesIterator last, const DataContainer &xData,
28 const std::vector<DataContainer> &valuesData)
29 {
30 QVERIFY(std::equal(first, last, xData.cbegin(), xData.cend(),
31 [](const auto &it, const auto &expectedX) { return it.x() == expectedX; }));
32 for (auto i = 0; i < valuesData.size(); ++i) {
33 auto componentData = valuesData.at(i);
34
35 QVERIFY(std::equal(
36 first, last, componentData.cbegin(), componentData.cend(),
37 [i](const auto &it, const auto &expectedVal) { return it.value(i) == expectedVal; }));
38 }
39 }
40
41 } // namespace
42
43 class TestDataSeries : public QObject {
44 Q_OBJECT
45 private:
46 template <typename T>
47 void testValuesBoundsStructure()
48 {
49 // ////////////// //
50 // Test structure //
51 // ////////////// //
52
53 // Data series to get values bounds
54 QTest::addColumn<std::shared_ptr<T> >("dataSeries");
55
56 // x-axis range
57 QTest::addColumn<double>("minXAxis");
58 QTest::addColumn<double>("maxXAxis");
59
60 // Expected results
61 QTest::addColumn<bool>(
62 "expectedOK"); // Test is expected to be ok (i.e. method doesn't return end iterators)
63 QTest::addColumn<double>("expectedMinValue");
64 QTest::addColumn<double>("expectedMaxValue");
65 }
66
67 template <typename T>
68 void testValuesBounds()
69 {
70 QFETCH(std::shared_ptr<T>, dataSeries);
71 QFETCH(double, minXAxis);
72 QFETCH(double, maxXAxis);
73
74 QFETCH(bool, expectedOK);
75 QFETCH(double, expectedMinValue);
76 QFETCH(double, expectedMaxValue);
77
78 auto minMaxIts = dataSeries->valuesBounds(minXAxis, maxXAxis);
79 auto end = dataSeries->cend();
80
81 // Checks iterators with expected result
82 QCOMPARE(expectedOK, minMaxIts.first != end && minMaxIts.second != end);
83
84 if (expectedOK) {
85 auto compare = [](const auto &v1, const auto &v2) {
86 return (std::isnan(v1) && std::isnan(v2)) || v1 == v2;
87 };
88
89 QVERIFY(compare(expectedMinValue, minMaxIts.first->minValue()));
90 QVERIFY(compare(expectedMaxValue, minMaxIts.second->maxValue()));
91 }
92 }
93
94 template <typename T>
95 void testPurgeStructure()
96 {
97 // ////////////// //
98 // Test structure //
99 // ////////////// //
100
101 // Data series to purge
102 QTest::addColumn<std::shared_ptr<T> >("dataSeries");
103 QTest::addColumn<double>("min");
104 QTest::addColumn<double>("max");
105
106 // Expected values after purge
107 QTest::addColumn<DataContainer>("expectedXAxisData");
108 QTest::addColumn<std::vector<DataContainer> >("expectedValuesData");
109 }
110
111 template <typename T>
112 void testPurge()
113 {
114 QFETCH(std::shared_ptr<T>, dataSeries);
115 QFETCH(double, min);
116 QFETCH(double, max);
117
118 dataSeries->purge(min, max);
119
120 // Validates results
121 QFETCH(DataContainer, expectedXAxisData);
122 QFETCH(std::vector<DataContainer>, expectedValuesData);
123
124 validateRange(dataSeries->cbegin(), dataSeries->cend(), expectedXAxisData,
125 expectedValuesData);
126 }
127
128 private slots:
129
130 /// Input test data
131 /// @sa testCtor()
132 void testCtor_data();
133
134 /// Tests construction of a data series
135 void testCtor();
136
137 /// Input test data
138 /// @sa testMerge()
139 void testMerge_data();
140
141 /// Tests merge of two data series
142 void testMerge();
143
144 /// Input test data
145 /// @sa testPurgeScalar()
146 void testPurgeScalar_data();
147
148 /// Tests purge of a scalar series
149 void testPurgeScalar();
150
151 /// Input test data
152 /// @sa testPurgeVector()
153 void testPurgeVector_data();
154
155 /// Tests purge of a vector series
156 void testPurgeVector();
157
158 /// Input test data
159 /// @sa testMinXAxisData()
160 void testMinXAxisData_data();
161
162 /// Tests get min x-axis data of a data series
163 void testMinXAxisData();
164
165 /// Input test data
166 /// @sa testMaxXAxisData()
167 void testMaxXAxisData_data();
168
169 /// Tests get max x-axis data of a data series
170 void testMaxXAxisData();
171
172 /// Input test data
173 /// @sa testXAxisRange()
174 void testXAxisRange_data();
175
176 /// Tests get x-axis range of a data series
177 void testXAxisRange();
178
179 /// Input test data
180 /// @sa testValuesBoundsScalar()
181 void testValuesBoundsScalar_data();
182
183 /// Tests get values bounds of a scalar series
184 void testValuesBoundsScalar();
185
186 /// Input test data
187 /// @sa testValuesBoundsVector()
188 void testValuesBoundsVector_data();
189
190 /// Tests get values bounds of a vector series
191 void testValuesBoundsVector();
192 };
193
194 void TestDataSeries::testCtor_data()
195 {
196 // ////////////// //
197 // Test structure //
198 // ////////////// //
199
200 // x-axis data
201 QTest::addColumn<DataContainer>("xAxisData");
202 // values data
203 QTest::addColumn<DataContainer>("valuesData");
204
205 // expected x-axis data
206 QTest::addColumn<DataContainer>("expectedXAxisData");
207 // expected values data
208 QTest::addColumn<DataContainer>("expectedValuesData");
209
210 // ////////// //
211 // Test cases //
212 // ////////// //
213
214 QTest::newRow("invalidData (different sizes of vectors)")
215 << DataContainer{1., 2., 3., 4., 5.} << DataContainer{100., 200., 300.} << DataContainer{}
216 << DataContainer{};
217
218 QTest::newRow("sortedData") << DataContainer{1., 2., 3., 4., 5.}
219 << DataContainer{100., 200., 300., 400., 500.}
220 << DataContainer{1., 2., 3., 4., 5.}
221 << DataContainer{100., 200., 300., 400., 500.};
222
223 QTest::newRow("unsortedData") << DataContainer{5., 4., 3., 2., 1.}
224 << DataContainer{100., 200., 300., 400., 500.}
225 << DataContainer{1., 2., 3., 4., 5.}
226 << DataContainer{500., 400., 300., 200., 100.};
227
228 QTest::newRow("unsortedData2")
229 << DataContainer{1., 4., 3., 5., 2.} << DataContainer{100., 200., 300., 400., 500.}
230 << DataContainer{1., 2., 3., 4., 5.} << DataContainer{100., 500., 300., 200., 400.};
231 }
232
233 void TestDataSeries::testCtor()
234 {
235 // Creates series
236 QFETCH(DataContainer, xAxisData);
237 QFETCH(DataContainer, valuesData);
238
239 auto series = std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData),
240 Unit{}, Unit{});
241
242 // Validates results : we check that the data series is sorted on its x-axis data
243 QFETCH(DataContainer, expectedXAxisData);
244 QFETCH(DataContainer, expectedValuesData);
245
246 validateRange(series->cbegin(), series->cend(), expectedXAxisData, expectedValuesData);
247 }
248
249 namespace {
250
251 std::shared_ptr<ScalarSeries> createScalarSeries(DataContainer xAxisData, DataContainer valuesData)
252 {
253 return std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData), Unit{},
254 Unit{});
255 }
256
257 std::shared_ptr<VectorSeries> createVectorSeries(DataContainer xAxisData, DataContainer xValuesData,
258 DataContainer yValuesData,
259 DataContainer zValuesData)
260 {
261 return std::make_shared<VectorSeries>(std::move(xAxisData), std::move(xValuesData),
262 std::move(yValuesData), std::move(zValuesData), Unit{},
263 Unit{});
264 }
265
266 } // namespace
267
268 void TestDataSeries::testMerge_data()
269 {
270 // ////////////// //
271 // Test structure //
272 // ////////////// //
273
274 // Data series to merge
275 QTest::addColumn<std::shared_ptr<ScalarSeries> >("dataSeries");
276 QTest::addColumn<std::shared_ptr<ScalarSeries> >("dataSeries2");
277
278 // Expected values in the first data series after merge
279 QTest::addColumn<DataContainer>("expectedXAxisData");
280 QTest::addColumn<DataContainer>("expectedValuesData");
281
282 // ////////// //
283 // Test cases //
284 // ////////// //
285
286 QTest::newRow("sortedMerge")
287 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
288 << createScalarSeries({6., 7., 8., 9., 10.}, {600., 700., 800., 900., 1000.})
289 << DataContainer{1., 2., 3., 4., 5., 6., 7., 8., 9., 10.}
290 << DataContainer{100., 200., 300., 400., 500., 600., 700., 800., 900., 1000.};
291
292 QTest::newRow("unsortedMerge")
293 << createScalarSeries({6., 7., 8., 9., 10.}, {600., 700., 800., 900., 1000.})
294 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
295 << DataContainer{1., 2., 3., 4., 5., 6., 7., 8., 9., 10.}
296 << DataContainer{100., 200., 300., 400., 500., 600., 700., 800., 900., 1000.};
297
298 QTest::newRow("unsortedMerge2 (merge not made because source is in the bounds of dest)")
299 << createScalarSeries({1., 2., 8., 9., 10}, {100., 200., 800., 900., 1000.})
300 << createScalarSeries({3., 4., 5., 6., 7.}, {300., 400., 500., 600., 700.})
301 << DataContainer{1., 2., 8., 9., 10.} << DataContainer{100., 200., 800., 900., 1000.};
302
303 QTest::newRow("unsortedMerge3")
304 << createScalarSeries({3., 4., 5., 7., 8}, {300., 400., 500., 700., 800.})
305 << createScalarSeries({1., 2., 3., 7., 10.}, {100., 200., 333., 777., 1000.})
306 << DataContainer{1., 2., 3., 4., 5., 7., 8., 10.}
307 << DataContainer{100., 200., 300., 400., 500., 700., 800., 1000.};
308 }
309
310 void TestDataSeries::testMerge()
311 {
312 // Merges series
313 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries);
314 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries2);
315
316 dataSeries->merge(dataSeries2.get());
317
318 // Validates results : we check that the merge is valid and the data series is sorted on its
319 // x-axis data
320 QFETCH(DataContainer, expectedXAxisData);
321 QFETCH(DataContainer, expectedValuesData);
322
323 validateRange(dataSeries->cbegin(), dataSeries->cend(), expectedXAxisData, expectedValuesData);
324 }
325
326 void TestDataSeries::testPurgeScalar_data()
327 {
328 testPurgeStructure<ScalarSeries>();
329
330 // ////////// //
331 // Test cases //
332 // ////////// //
333
334 QTest::newRow("purgeScalar") << createScalarSeries({1., 2., 3., 4., 5.},
335 {100., 200., 300., 400., 500.})
336 << 2. << 4. << DataContainer{2., 3., 4.}
337 << std::vector<DataContainer>{{200., 300., 400.}};
338 QTest::newRow("purgeScalar2") << createScalarSeries({1., 2., 3., 4., 5.},
339 {100., 200., 300., 400., 500.})
340 << 0. << 2.5 << DataContainer{1., 2.}
341 << std::vector<DataContainer>{{100., 200.}};
342 QTest::newRow("purgeScalar3") << createScalarSeries({1., 2., 3., 4., 5.},
343 {100., 200., 300., 400., 500.})
344 << 3.5 << 7. << DataContainer{4., 5.}
345 << std::vector<DataContainer>{{400., 500.}};
346 QTest::newRow("purgeScalar4") << createScalarSeries({1., 2., 3., 4., 5.},
347 {100., 200., 300., 400., 500.})
348 << 0. << 7. << DataContainer{1., 2., 3., 4., 5.}
349 << std::vector<DataContainer>{{100., 200., 300., 400., 500.}};
350 QTest::newRow("purgeScalar5") << createScalarSeries({1., 2., 3., 4., 5.},
351 {100., 200., 300., 400., 500.})
352 << 5.5 << 7. << DataContainer{} << std::vector<DataContainer>{{}};
353 }
354
355 void TestDataSeries::testPurgeScalar()
356 {
357 testPurge<ScalarSeries>();
358 }
359
360 void TestDataSeries::testPurgeVector_data()
361 {
362 testPurgeStructure<VectorSeries>();
363
364 // ////////// //
365 // Test cases //
366 // ////////// //
367
368 QTest::newRow("purgeVector") << createVectorSeries({1., 2., 3., 4., 5.}, {6., 7., 8., 9., 10.},
369 {11., 12., 13., 14., 15.},
370 {16., 17., 18., 19., 20.})
371 << 2. << 4. << DataContainer{2., 3., 4.}
372 << std::vector<DataContainer>{
373 {7., 8., 9.}, {12., 13., 14.}, {17., 18., 19.}};
374 }
375
376 void TestDataSeries::testPurgeVector()
377 {
378 testPurge<VectorSeries>();
379 }
380
381 void TestDataSeries::testMinXAxisData_data()
382 {
383 // ////////////// //
384 // Test structure //
385 // ////////////// //
386
387 // Data series to get min data
388 QTest::addColumn<std::shared_ptr<ScalarSeries> >("dataSeries");
389
390 // Min data
391 QTest::addColumn<double>("min");
392
393 // Expected results
394 QTest::addColumn<bool>(
395 "expectedOK"); // if true, expects to have a result (i.e. the iterator != end iterator)
396 QTest::addColumn<double>(
397 "expectedMin"); // Expected value when method doesn't return end iterator
398
399 // ////////// //
400 // Test cases //
401 // ////////// //
402
403 QTest::newRow("minData1") << createScalarSeries({1., 2., 3., 4., 5.},
404 {100., 200., 300., 400., 500.})
405 << 0. << true << 1.;
406 QTest::newRow("minData2") << createScalarSeries({1., 2., 3., 4., 5.},
407 {100., 200., 300., 400., 500.})
408 << 1. << true << 1.;
409 QTest::newRow("minData3") << createScalarSeries({1., 2., 3., 4., 5.},
410 {100., 200., 300., 400., 500.})
411 << 1.1 << true << 2.;
412 QTest::newRow("minData4") << createScalarSeries({1., 2., 3., 4., 5.},
413 {100., 200., 300., 400., 500.})
414 << 5. << true << 5.;
415 QTest::newRow("minData5") << createScalarSeries({1., 2., 3., 4., 5.},
416 {100., 200., 300., 400., 500.})
417 << 5.1 << false << std::numeric_limits<double>::quiet_NaN();
418 QTest::newRow("minData6") << createScalarSeries({}, {}) << 1.1 << false
419 << std::numeric_limits<double>::quiet_NaN();
420 }
421
422 void TestDataSeries::testMinXAxisData()
423 {
424 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries);
425 QFETCH(double, min);
426
427 QFETCH(bool, expectedOK);
428 QFETCH(double, expectedMin);
429
430 auto it = dataSeries->minXAxisData(min);
431
432 QCOMPARE(expectedOK, it != dataSeries->cend());
433
434 // If the method doesn't return a end iterator, checks with expected value
435 if (expectedOK) {
436 QCOMPARE(expectedMin, it->x());
437 }
438 }
439
440 void TestDataSeries::testMaxXAxisData_data()
441 {
442 // ////////////// //
443 // Test structure //
444 // ////////////// //
445
446 // Data series to get max data
447 QTest::addColumn<std::shared_ptr<ScalarSeries> >("dataSeries");
448
449 // Max data
450 QTest::addColumn<double>("max");
451
452 // Expected results
453 QTest::addColumn<bool>(
454 "expectedOK"); // if true, expects to have a result (i.e. the iterator != end iterator)
455 QTest::addColumn<double>(
456 "expectedMax"); // Expected value when method doesn't return end iterator
457
458 // ////////// //
459 // Test cases //
460 // ////////// //
461
462 QTest::newRow("maxData1") << createScalarSeries({1., 2., 3., 4., 5.},
463 {100., 200., 300., 400., 500.})
464 << 6. << true << 5.;
465 QTest::newRow("maxData2") << createScalarSeries({1., 2., 3., 4., 5.},
466 {100., 200., 300., 400., 500.})
467 << 5. << true << 5.;
468 QTest::newRow("maxData3") << createScalarSeries({1., 2., 3., 4., 5.},
469 {100., 200., 300., 400., 500.})
470 << 4.9 << true << 4.;
471 QTest::newRow("maxData4") << createScalarSeries({1., 2., 3., 4., 5.},
472 {100., 200., 300., 400., 500.})
473 << 1.1 << true << 1.;
474 QTest::newRow("maxData5") << createScalarSeries({1., 2., 3., 4., 5.},
475 {100., 200., 300., 400., 500.})
476 << 1. << true << 1.;
477 QTest::newRow("maxData6") << createScalarSeries({}, {}) << 1.1 << false
478 << std::numeric_limits<double>::quiet_NaN();
479 }
480
481 void TestDataSeries::testMaxXAxisData()
482 {
483 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries);
484 QFETCH(double, max);
485
486 QFETCH(bool, expectedOK);
487 QFETCH(double, expectedMax);
488
489 auto it = dataSeries->maxXAxisData(max);
490
491 QCOMPARE(expectedOK, it != dataSeries->cend());
492
493 // If the method doesn't return a end iterator, checks with expected value
494 if (expectedOK) {
495 QCOMPARE(expectedMax, it->x());
496 }
497 }
498
499 void TestDataSeries::testXAxisRange_data()
500 {
501 // ////////////// //
502 // Test structure //
503 // ////////////// //
504
505 // Data series to get x-axis range
506 QTest::addColumn<std::shared_ptr<ScalarSeries> >("dataSeries");
507
508 // Min/max values
509 QTest::addColumn<double>("min");
510 QTest::addColumn<double>("max");
511
512 // Expected values
513 QTest::addColumn<DataContainer>("expectedXAxisData");
514 QTest::addColumn<DataContainer>("expectedValuesData");
515
516 // ////////// //
517 // Test cases //
518 // ////////// //
519
520 QTest::newRow("xAxisRange1") << createScalarSeries({1., 2., 3., 4., 5.},
521 {100., 200., 300., 400., 500.})
522 << -1. << 3.2 << DataContainer{1., 2., 3.}
523 << DataContainer{100., 200., 300.};
524 QTest::newRow("xAxisRange2") << createScalarSeries({1., 2., 3., 4., 5.},
525 {100., 200., 300., 400., 500.})
526 << 1. << 4. << DataContainer{1., 2., 3., 4.}
527 << DataContainer{100., 200., 300., 400.};
528 QTest::newRow("xAxisRange3") << createScalarSeries({1., 2., 3., 4., 5.},
529 {100., 200., 300., 400., 500.})
530 << 1. << 3.9 << DataContainer{1., 2., 3.}
531 << DataContainer{100., 200., 300.};
532 QTest::newRow("xAxisRange4") << createScalarSeries({1., 2., 3., 4., 5.},
533 {100., 200., 300., 400., 500.})
534 << 0. << 0.9 << DataContainer{} << DataContainer{};
535 QTest::newRow("xAxisRange5") << createScalarSeries({1., 2., 3., 4., 5.},
536 {100., 200., 300., 400., 500.})
537 << 0. << 1. << DataContainer{1.} << DataContainer{100.};
538 QTest::newRow("xAxisRange6") << createScalarSeries({1., 2., 3., 4., 5.},
539 {100., 200., 300., 400., 500.})
540 << 2.1 << 6. << DataContainer{3., 4., 5.}
541 << DataContainer{300., 400., 500.};
542 QTest::newRow("xAxisRange7") << createScalarSeries({1., 2., 3., 4., 5.},
543 {100., 200., 300., 400., 500.})
544 << 6. << 9. << DataContainer{} << DataContainer{};
545 QTest::newRow("xAxisRange8") << createScalarSeries({1., 2., 3., 4., 5.},
546 {100., 200., 300., 400., 500.})
547 << 5. << 9. << DataContainer{5.} << DataContainer{500.};
548 }
549
550 void TestDataSeries::testXAxisRange()
551 {
552 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries);
553 QFETCH(double, min);
554 QFETCH(double, max);
555
556 QFETCH(DataContainer, expectedXAxisData);
557 QFETCH(DataContainer, expectedValuesData);
558
559 auto bounds = dataSeries->xAxisRange(min, max);
560 validateRange(bounds.first, bounds.second, expectedXAxisData, expectedValuesData);
561 }
562
563 void TestDataSeries::testValuesBoundsScalar_data()
564 {
565 testValuesBoundsStructure<ScalarSeries>();
566
567 // ////////// //
568 // Test cases //
569 // ////////// //
570 auto nan = std::numeric_limits<double>::quiet_NaN();
571
572 QTest::newRow("scalarBounds1")
573 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.}) << 0. << 6.
574 << true << 100. << 500.;
575 QTest::newRow("scalarBounds2")
576 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.}) << 2. << 4.
577 << true << 200. << 400.;
578 QTest::newRow("scalarBounds3")
579 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.}) << 0. << 0.5
580 << false << nan << nan;
581 QTest::newRow("scalarBounds4")
582 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.}) << 5.1 << 6.
583 << false << nan << nan;
584 QTest::newRow("scalarBounds5") << createScalarSeries({1.}, {100.}) << 0. << 2. << true << 100.
585 << 100.;
586 QTest::newRow("scalarBounds6") << createScalarSeries({}, {}) << 0. << 2. << false << nan << nan;
587
588 // Tests with NaN values: NaN values are not included in min/max search
589 QTest::newRow("scalarBounds7")
590 << createScalarSeries({1., 2., 3., 4., 5.}, {nan, 200., 300., 400., nan}) << 0. << 6.
591 << true << 200. << 400.;
592 QTest::newRow("scalarBounds8")
593 << createScalarSeries({1., 2., 3., 4., 5.}, {nan, nan, nan, nan, nan}) << 0. << 6. << true
594 << std::numeric_limits<double>::quiet_NaN() << std::numeric_limits<double>::quiet_NaN();
595 }
596
597 void TestDataSeries::testValuesBoundsScalar()
598 {
599 testValuesBounds<ScalarSeries>();
600 }
601
602 void TestDataSeries::testValuesBoundsVector_data()
603 {
604 testValuesBoundsStructure<VectorSeries>();
605
606 // ////////// //
607 // Test cases //
608 // ////////// //
609 auto nan = std::numeric_limits<double>::quiet_NaN();
610
611 QTest::newRow("vectorBounds1")
612 << createVectorSeries({1., 2., 3., 4., 5.}, {10., 15., 20., 13., 12.},
613 {35., 24., 10., 9., 0.3}, {13., 14., 12., 9., 24.})
614 << 0. << 6. << true << 0.3 << 35.; // min/max in same component
615 QTest::newRow("vectorBounds2")
616 << createVectorSeries({1., 2., 3., 4., 5.}, {2.3, 15., 20., 13., 12.},
617 {35., 24., 10., 9., 4.}, {13., 14., 12., 9., 24.})
618 << 0. << 6. << true << 2.3 << 35.; // min/max in same entry
619 QTest::newRow("vectorBounds3")
620 << createVectorSeries({1., 2., 3., 4., 5.}, {2.3, 15., 20., 13., 12.},
621 {35., 24., 10., 9., 4.}, {13., 14., 12., 9., 24.})
622 << 2. << 3. << true << 10. << 24.;
623
624 // Tests with NaN values: NaN values are not included in min/max search
625 QTest::newRow("vectorBounds4")
626 << createVectorSeries({1., 2.}, {nan, nan}, {nan, nan}, {nan, nan}) << 0. << 6. << true
627 << nan << nan;
628 }
629
630 void TestDataSeries::testValuesBoundsVector()
631 {
632 testValuesBounds<VectorSeries>();
633 }
634
635 QTEST_MAIN(TestDataSeries)
636 #include "TestDataSeries.moc"
@@ -1,460 +1,462
1 /*
1 /*
2 ====================================================================
2 ====================================================================
3 A Smart Pointer to IMPLementation (i.e. Smart PIMPL or just SPIMPL).
3 A Smart Pointer to IMPLementation (i.e. Smart PIMPL or just SPIMPL).
4 ====================================================================
4 ====================================================================
5
5
6 Version: 1.1
6 Version: 1.1
7
7
8 Latest version:
8 Latest version:
9 https://github.com/oliora/samples/blob/master/spimpl.h
9 https://github.com/oliora/samples/blob/master/spimpl.h
10 Rationale and description:
10 Rationale and description:
11 http://oliora.github.io/2015/12/29/pimpl-and-rule-of-zero.html
11 http://oliora.github.io/2015/12/29/pimpl-and-rule-of-zero.html
12
12
13 Copyright (c) 2015 Andrey Upadyshev (oliora@gmail.com)
13 Copyright (c) 2015 Andrey Upadyshev (oliora@gmail.com)
14
14
15 Distributed under the Boost Software License, Version 1.0.
15 Distributed under the Boost Software License, Version 1.0.
16 See http://www.boost.org/LICENSE_1_0.txt
16 See http://www.boost.org/LICENSE_1_0.txt
17
17
18 Changes history
18 Changes history
19 ---------------
19 ---------------
20 v1.1:
20 v1.1:
21 - auto_ptr support is disabled by default for C++17 compatibility
21 - auto_ptr support is disabled by default for C++17 compatibility
22 v1.0:
22 v1.0:
23 - Released
23 - Released
24 */
24 */
25
25
26 #ifndef SPIMPL_H_
26 #ifndef SPIMPL_H_
27 #define SPIMPL_H_
27 #define SPIMPL_H_
28
28
29 #include <cassert>
29 #include <cassert>
30 #include <memory>
30 #include <memory>
31 #include <type_traits>
31 #include <type_traits>
32
32
33 #if defined _MSC_VER && _MSC_VER < 1900 // MS Visual Studio before VS2015
33 #if defined _MSC_VER && _MSC_VER < 1900 // MS Visual Studio before VS2015
34 #define SPIMPL_NO_CPP11_NOEXCEPT
34 #define SPIMPL_NO_CPP11_NOEXCEPT
35 #define SPIMPL_NO_CPP11_CONSTEXPR
35 #define SPIMPL_NO_CPP11_CONSTEXPR
36 #define SPIMPL_NO_CPP11_DEFAULT_MOVE_SPEC_FUNC
36 #define SPIMPL_NO_CPP11_DEFAULT_MOVE_SPEC_FUNC
37 #endif
37 #endif
38
38
39 #if !defined SPIMPL_NO_CPP11_NOEXCEPT
39 #if !defined SPIMPL_NO_CPP11_NOEXCEPT
40 #define SPIMPL_NOEXCEPT noexcept
40 #define SPIMPL_NOEXCEPT noexcept
41 #else
41 #else
42 #define SPIMPL_NOEXCEPT
42 #define SPIMPL_NOEXCEPT
43 #endif
43 #endif
44
44
45 #if !defined SPIMPL_NO_CPP11_CONSTEXPR
45 #if !defined SPIMPL_NO_CPP11_CONSTEXPR
46 #define SPIMPL_CONSTEXPR constexpr
46 #define SPIMPL_CONSTEXPR constexpr
47 #else
47 #else
48 #define SPIMPL_CONSTEXPR
48 #define SPIMPL_CONSTEXPR
49 #endif
49 #endif
50
50
51 // define SPIMPL_HAS_AUTO_PTR to enable constructor and assignment operator that accept
51 // define SPIMPL_HAS_AUTO_PTR to enable constructor and assignment operator that accept
52 // std::auto_ptr
52 // std::auto_ptr
53 // TODO: auto detect std::auto_ptr support
53 // TODO: auto detect std::auto_ptr support
54
54
55
55
56 namespace spimpl {
56 namespace spimpl {
57 namespace details {
57 namespace details {
58 template <class T>
58 template <class T>
59 T *default_copy(T *src)
59 T *default_copy(T *src)
60 {
60 {
61 static_assert(sizeof(T) > 0, "default_copy cannot copy incomplete type");
61 static_assert(sizeof(T) > 0, "default_copy cannot copy incomplete type");
62 static_assert(!std::is_void<T>::value, "default_copy cannot copy incomplete type");
62 static_assert(!std::is_void<T>::value, "default_copy cannot copy incomplete type");
63 return new T(*src);
63 return new T(*src);
64 }
64 }
65
65
66 template <class T>
66 template <class T>
67 void default_delete(T *p) SPIMPL_NOEXCEPT
67 void default_delete(T *p) SPIMPL_NOEXCEPT
68 {
68 {
69 static_assert(sizeof(T) > 0, "default_delete cannot delete incomplete type");
69 static_assert(sizeof(T) > 0, "default_delete cannot delete incomplete type");
70 static_assert(!std::is_void<T>::value, "default_delete cannot delete incomplete type");
70 static_assert(!std::is_void<T>::value, "default_delete cannot delete incomplete type");
71 delete p;
71 delete p;
72 }
72 }
73
73
74 template <class T>
74 template <class T>
75 struct default_deleter {
75 struct default_deleter {
76 using type = void (*)(T *);
76 using type = void (*)(T *);
77 };
77 };
78
78
79 template <class T>
79 template <class T>
80 using default_deleter_t = typename default_deleter<T>::type;
80 using default_deleter_t = typename default_deleter<T>::type;
81
81
82 template <class T>
82 template <class T>
83 struct default_copier {
83 struct default_copier {
84 using type = T *(*)(T *);
84 using type = T *(*)(T *);
85 };
85 };
86
86
87 template <class T>
87 template <class T>
88 using default_copier_t = typename default_copier<T>::type;
88 using default_copier_t = typename default_copier<T>::type;
89
89
90 template <class T, class D, class C>
90 template <class T, class D, class C>
91 struct is_default_manageable
91 struct is_default_manageable
92 : public std::integral_constant<bool, std::is_same<D, default_deleter_t<T> >::value
92 : public std::integral_constant<bool,
93 && std::is_same<C, default_copier_t<T> >::value> {
93 std::is_same<D, default_deleter_t<T> >::value
94 && std::is_same<C, default_copier_t<T> >::value> {
94 };
95 };
95 }
96 }
96
97
97
98
98 template <class T, class Deleter = details::default_deleter_t<T>,
99 template <class T, class Deleter = details::default_deleter_t<T>,
99 class Copier = details::default_copier_t<T> >
100 class Copier = details::default_copier_t<T> >
100 class impl_ptr {
101 class impl_ptr {
101 private:
102 private:
102 static_assert(!std::is_array<T>::value,
103 static_assert(!std::is_array<T>::value,
103 "impl_ptr specialization for arrays is not implemented");
104 "impl_ptr specialization for arrays is not implemented");
104 struct dummy_t_ {
105 struct dummy_t_ {
105 int dummy__;
106 int dummy__;
106 };
107 };
107
108
108 public:
109 public:
109 using pointer = T *;
110 using pointer = T *;
110 using element_type = T;
111 using element_type = T;
111 using copier_type = typename std::decay<Copier>::type;
112 using copier_type = typename std::decay<Copier>::type;
112 using deleter_type = typename std::decay<Deleter>::type;
113 using deleter_type = typename std::decay<Deleter>::type;
113 using unique_ptr_type = std::unique_ptr<T, deleter_type>;
114 using unique_ptr_type = std::unique_ptr<T, deleter_type>;
114 using is_default_manageable = details::is_default_manageable<T, deleter_type, copier_type>;
115 using is_default_manageable = details::is_default_manageable<T, deleter_type, copier_type>;
115
116
116 SPIMPL_CONSTEXPR impl_ptr() SPIMPL_NOEXCEPT : ptr_(nullptr, deleter_type{}),
117 SPIMPL_CONSTEXPR impl_ptr() SPIMPL_NOEXCEPT : ptr_(nullptr, deleter_type{}),
117 copier_(copier_type{})
118 copier_(copier_type{})
118 {
119 {
119 }
120 }
120
121
121 SPIMPL_CONSTEXPR impl_ptr(std::nullptr_t) SPIMPL_NOEXCEPT : impl_ptr() {}
122 SPIMPL_CONSTEXPR impl_ptr(std::nullptr_t) SPIMPL_NOEXCEPT : impl_ptr() {}
122
123
123 template <class D, class C>
124 template <class D, class C>
124 impl_ptr(pointer p, D &&d, C &&c,
125 impl_ptr(pointer p, D &&d, C &&c,
125 typename std::enable_if<std::is_convertible<D, deleter_type>::value
126 typename std::enable_if<std::is_convertible<D, deleter_type>::value
126 && std::is_convertible<C, copier_type>::value,
127 && std::is_convertible<C, copier_type>::value,
127 dummy_t_>::type
128 dummy_t_>::type
128 = dummy_t_()) SPIMPL_NOEXCEPT : ptr_(std::move(p), std::forward<D>(d)),
129 = dummy_t_()) SPIMPL_NOEXCEPT : ptr_(std::move(p), std::forward<D>(d)),
129 copier_(std::forward<C>(c))
130 copier_(std::forward<C>(c))
130 {
131 {
131 }
132 }
132
133
133 template <class U>
134 template <class U>
134 impl_ptr(U *u, typename std::enable_if<std::is_convertible<U *, pointer>::value
135 impl_ptr(U *u,
135 && is_default_manageable::value,
136 typename std::enable_if<std::is_convertible<U *, pointer>::value
136 dummy_t_>::type
137 && is_default_manageable::value,
137 = dummy_t_()) SPIMPL_NOEXCEPT
138 dummy_t_>::type
139 = dummy_t_()) SPIMPL_NOEXCEPT
138 : impl_ptr(u, &details::default_delete<T>, &details::default_copy<T>)
140 : impl_ptr(u, &details::default_delete<T>, &details::default_copy<T>)
139 {
141 {
140 }
142 }
141
143
142 impl_ptr(const impl_ptr &r) : impl_ptr(r.clone()) {}
144 impl_ptr(const impl_ptr &r) : impl_ptr(r.clone()) {}
143
145
144 #ifndef SPIMPL_NO_CPP11_DEFAULT_MOVE_SPEC_FUNC
146 #ifndef SPIMPL_NO_CPP11_DEFAULT_MOVE_SPEC_FUNC
145 impl_ptr(impl_ptr &&r) SPIMPL_NOEXCEPT = default;
147 impl_ptr(impl_ptr &&r) SPIMPL_NOEXCEPT = default;
146 #else
148 #else
147 impl_ptr(impl_ptr &&r) SPIMPL_NOEXCEPT : ptr_(std::move(r.ptr_)), copier_(std::move(r.copier_))
149 impl_ptr(impl_ptr &&r) SPIMPL_NOEXCEPT : ptr_(std::move(r.ptr_)), copier_(std::move(r.copier_))
148 {
150 {
149 }
151 }
150 #endif
152 #endif
151
153
152 #ifdef SPIMPL_HAS_AUTO_PTR
154 #ifdef SPIMPL_HAS_AUTO_PTR
153 template <class U>
155 template <class U>
154 impl_ptr(std::auto_ptr<U> &&u, typename std::enable_if<std::is_convertible<U *, pointer>::value
156 impl_ptr(std::auto_ptr<U> &&u,
155 && is_default_manageable::value,
157 typename std::enable_if<std::is_convertible<U *, pointer>::value
156 dummy_t_>::type
158 && is_default_manageable::value,
157 = dummy_t_()) SPIMPL_NOEXCEPT
159 dummy_t_>::type
158 : ptr_(u.release(), &details::default_delete<T>),
160 = dummy_t_()) SPIMPL_NOEXCEPT : ptr_(u.release(), &details::default_delete<T>),
159 copier_(&details::default_copy<T>)
161 copier_(&details::default_copy<T>)
160 {
162 {
161 }
163 }
162 #endif
164 #endif
163
165
164 template <class U>
166 template <class U>
165 impl_ptr(std::unique_ptr<U> &&u,
167 impl_ptr(std::unique_ptr<U> &&u,
166 typename std::enable_if<std::is_convertible<U *, pointer>::value
168 typename std::enable_if<std::is_convertible<U *, pointer>::value
167 && is_default_manageable::value,
169 && is_default_manageable::value,
168 dummy_t_>::type
170 dummy_t_>::type
169 = dummy_t_()) SPIMPL_NOEXCEPT : ptr_(u.release(), &details::default_delete<T>),
171 = dummy_t_()) SPIMPL_NOEXCEPT : ptr_(u.release(), &details::default_delete<T>),
170 copier_(&details::default_copy<T>)
172 copier_(&details::default_copy<T>)
171 {
173 {
172 }
174 }
173
175
174 template <class U, class D, class C>
176 template <class U, class D, class C>
175 impl_ptr(std::unique_ptr<U, D> &&u, C &&c,
177 impl_ptr(std::unique_ptr<U, D> &&u, C &&c,
176 typename std::enable_if<std::is_convertible<U *, pointer>::value
178 typename std::enable_if<std::is_convertible<U *, pointer>::value
177 && std::is_convertible<D, deleter_type>::value
179 && std::is_convertible<D, deleter_type>::value
178 && std::is_convertible<C, copier_type>::value,
180 && std::is_convertible<C, copier_type>::value,
179 dummy_t_>::type
181 dummy_t_>::type
180 = dummy_t_()) SPIMPL_NOEXCEPT : ptr_(std::move(u)),
182 = dummy_t_()) SPIMPL_NOEXCEPT : ptr_(std::move(u)),
181 copier_(std::forward<C>(c))
183 copier_(std::forward<C>(c))
182 {
184 {
183 }
185 }
184
186
185 template <class U, class D, class C>
187 template <class U, class D, class C>
186 impl_ptr(impl_ptr<U, D, C> &&u,
188 impl_ptr(impl_ptr<U, D, C> &&u,
187 typename std::enable_if<std::is_convertible<U *, pointer>::value
189 typename std::enable_if<std::is_convertible<U *, pointer>::value
188 && std::is_convertible<D, deleter_type>::value
190 && std::is_convertible<D, deleter_type>::value
189 && std::is_convertible<C, copier_type>::value,
191 && std::is_convertible<C, copier_type>::value,
190 dummy_t_>::type
192 dummy_t_>::type
191 = dummy_t_()) SPIMPL_NOEXCEPT : ptr_(std::move(u.ptr_)),
193 = dummy_t_()) SPIMPL_NOEXCEPT : ptr_(std::move(u.ptr_)),
192 copier_(std::move(u.copier_))
194 copier_(std::move(u.copier_))
193 {
195 {
194 }
196 }
195
197
196 impl_ptr &operator=(const impl_ptr &r)
198 impl_ptr &operator=(const impl_ptr &r)
197 {
199 {
198 if (this == &r)
200 if (this == &r)
199 return *this;
201 return *this;
200
202
201 return operator=(r.clone());
203 return operator=(r.clone());
202 }
204 }
203
205
204 #ifndef SPIMPL_NO_CPP11_DEFAULT_MOVE_SPEC_FUNC
206 #ifndef SPIMPL_NO_CPP11_DEFAULT_MOVE_SPEC_FUNC
205 impl_ptr &operator=(impl_ptr &&r) SPIMPL_NOEXCEPT = default;
207 impl_ptr &operator=(impl_ptr &&r) SPIMPL_NOEXCEPT = default;
206 #else
208 #else
207 impl_ptr &operator=(impl_ptr &&r) SPIMPL_NOEXCEPT
209 impl_ptr &operator=(impl_ptr &&r) SPIMPL_NOEXCEPT
208 {
210 {
209 ptr_ = std::move(r.ptr_);
211 ptr_ = std::move(r.ptr_);
210 copier_ = std::move(r.copier_);
212 copier_ = std::move(r.copier_);
211 return *this;
213 return *this;
212 }
214 }
213 #endif
215 #endif
214
216
215 template <class U, class D, class C>
217 template <class U, class D, class C>
216 typename std::enable_if<std::is_convertible<U *, pointer>::value
218 typename std::enable_if<std::is_convertible<U *, pointer>::value
217 && std::is_convertible<D, deleter_type>::value
219 && std::is_convertible<D, deleter_type>::value
218 && std::is_convertible<C, copier_type>::value,
220 && std::is_convertible<C, copier_type>::value,
219 impl_ptr &>::type
221 impl_ptr &>::type
220 operator=(impl_ptr<U, D, C> &&u) SPIMPL_NOEXCEPT
222 operator=(impl_ptr<U, D, C> &&u) SPIMPL_NOEXCEPT
221 {
223 {
222 ptr_ = std::move(u.ptr_);
224 ptr_ = std::move(u.ptr_);
223 copier_ = std::move(u.copier_);
225 copier_ = std::move(u.copier_);
224 return *this;
226 return *this;
225 }
227 }
226
228
227 template <class U, class D, class C>
229 template <class U, class D, class C>
228 typename std::enable_if<std::is_convertible<U *, pointer>::value
230 typename std::enable_if<std::is_convertible<U *, pointer>::value
229 && std::is_convertible<D, deleter_type>::value
231 && std::is_convertible<D, deleter_type>::value
230 && std::is_convertible<C, copier_type>::value,
232 && std::is_convertible<C, copier_type>::value,
231 impl_ptr &>::type
233 impl_ptr &>::type
232 operator=(const impl_ptr<U, D, C> &u)
234 operator=(const impl_ptr<U, D, C> &u)
233 {
235 {
234 return operator=(u.clone());
236 return operator=(u.clone());
235 }
237 }
236
238
237 //
239 //
238
240
239 #ifdef SPIMPL_HAS_AUTO_PTR
241 #ifdef SPIMPL_HAS_AUTO_PTR
240 template <class U>
242 template <class U>
241 typename std::enable_if<std::is_convertible<U *, pointer>::value
243 typename std::enable_if<std::is_convertible<U *, pointer>::value
242 && is_default_manageable::value,
244 && is_default_manageable::value,
243 impl_ptr &>::type
245 impl_ptr &>::type
244 operator=(std::auto_ptr<U> &&u) SPIMPL_NOEXCEPT
246 operator=(std::auto_ptr<U> &&u) SPIMPL_NOEXCEPT
245 {
247 {
246 return operator=(impl_ptr(std::move(u)));
248 return operator=(impl_ptr(std::move(u)));
247 }
249 }
248 #endif
250 #endif
249
251
250 template <class U>
252 template <class U>
251 typename std::enable_if<std::is_convertible<U *, pointer>::value
253 typename std::enable_if<std::is_convertible<U *, pointer>::value
252 && is_default_manageable::value,
254 && is_default_manageable::value,
253 impl_ptr &>::type
255 impl_ptr &>::type
254 operator=(std::unique_ptr<U> &&u) SPIMPL_NOEXCEPT
256 operator=(std::unique_ptr<U> &&u) SPIMPL_NOEXCEPT
255 {
257 {
256 return operator=(impl_ptr(std::move(u)));
258 return operator=(impl_ptr(std::move(u)));
257 }
259 }
258
260
259 impl_ptr clone() const
261 impl_ptr clone() const
260 {
262 {
261 return impl_ptr(ptr_ ? copier_(ptr_.get()) : nullptr, ptr_.get_deleter(), copier_);
263 return impl_ptr(ptr_ ? copier_(ptr_.get()) : nullptr, ptr_.get_deleter(), copier_);
262 }
264 }
263
265
264 typename std::remove_reference<T>::type &operator*() const { return *ptr_; }
266 typename std::remove_reference<T>::type &operator*() const { return *ptr_; }
265 pointer operator->() const SPIMPL_NOEXCEPT { return get(); }
267 pointer operator->() const SPIMPL_NOEXCEPT { return get(); }
266 pointer get() const SPIMPL_NOEXCEPT { return ptr_.get(); }
268 pointer get() const SPIMPL_NOEXCEPT { return ptr_.get(); }
267
269
268 void swap(impl_ptr &u) SPIMPL_NOEXCEPT
270 void swap(impl_ptr &u) SPIMPL_NOEXCEPT
269 {
271 {
270 using std::swap;
272 using std::swap;
271 ptr_.swap(u.ptr_);
273 ptr_.swap(u.ptr_);
272 swap(copier_, u.copier_);
274 swap(copier_, u.copier_);
273 }
275 }
274
276
275 pointer release() SPIMPL_NOEXCEPT { return ptr_.release(); }
277 pointer release() SPIMPL_NOEXCEPT { return ptr_.release(); }
276
278
277 unique_ptr_type release_unique() SPIMPL_NOEXCEPT { return std::move(ptr_); }
279 unique_ptr_type release_unique() SPIMPL_NOEXCEPT { return std::move(ptr_); }
278
280
279 explicit operator bool() const SPIMPL_NOEXCEPT { return static_cast<bool>(ptr_); }
281 explicit operator bool() const SPIMPL_NOEXCEPT { return static_cast<bool>(ptr_); }
280
282
281 typename std::remove_reference<deleter_type>::type &get_deleter() SPIMPL_NOEXCEPT
283 typename std::remove_reference<deleter_type>::type &get_deleter() SPIMPL_NOEXCEPT
282 {
284 {
283 return ptr_.get_deleter();
285 return ptr_.get_deleter();
284 }
286 }
285 const typename std::remove_reference<deleter_type>::type &get_deleter() const SPIMPL_NOEXCEPT
287 const typename std::remove_reference<deleter_type>::type &get_deleter() const SPIMPL_NOEXCEPT
286 {
288 {
287 return ptr_.get_deleter();
289 return ptr_.get_deleter();
288 }
290 }
289
291
290 typename std::remove_reference<copier_type>::type &get_copier() SPIMPL_NOEXCEPT
292 typename std::remove_reference<copier_type>::type &get_copier() SPIMPL_NOEXCEPT
291 {
293 {
292 return copier_;
294 return copier_;
293 }
295 }
294 const typename std::remove_reference<copier_type>::type &get_copier() const SPIMPL_NOEXCEPT
296 const typename std::remove_reference<copier_type>::type &get_copier() const SPIMPL_NOEXCEPT
295 {
297 {
296 return copier_;
298 return copier_;
297 }
299 }
298
300
299 private:
301 private:
300 unique_ptr_type ptr_;
302 unique_ptr_type ptr_;
301 copier_type copier_;
303 copier_type copier_;
302 };
304 };
303
305
304
306
305 template <class T, class D, class C>
307 template <class T, class D, class C>
306 inline void swap(impl_ptr<T, D, C> &l, impl_ptr<T, D, C> &r) SPIMPL_NOEXCEPT
308 inline void swap(impl_ptr<T, D, C> &l, impl_ptr<T, D, C> &r) SPIMPL_NOEXCEPT
307 {
309 {
308 l.swap(r);
310 l.swap(r);
309 }
311 }
310
312
311
313
312 template <class T1, class D1, class C1, class T2, class D2, class C2>
314 template <class T1, class D1, class C1, class T2, class D2, class C2>
313 inline bool operator==(const impl_ptr<T1, D1, C1> &l, const impl_ptr<T2, D2, C2> &r)
315 inline bool operator==(const impl_ptr<T1, D1, C1> &l, const impl_ptr<T2, D2, C2> &r)
314 {
316 {
315 return l.get() == r.get();
317 return l.get() == r.get();
316 }
318 }
317
319
318 template <class T1, class D1, class C1, class T2, class D2, class C2>
320 template <class T1, class D1, class C1, class T2, class D2, class C2>
319 inline bool operator!=(const impl_ptr<T1, D1, C1> &l, const impl_ptr<T2, D2, C2> &r)
321 inline bool operator!=(const impl_ptr<T1, D1, C1> &l, const impl_ptr<T2, D2, C2> &r)
320 {
322 {
321 return !(l == r);
323 return !(l == r);
322 }
324 }
323
325
324 template <class T1, class D1, class C1, class T2, class D2, class C2>
326 template <class T1, class D1, class C1, class T2, class D2, class C2>
325 inline bool operator<(const impl_ptr<T1, D1, C1> &l, const impl_ptr<T2, D2, C2> &r)
327 inline bool operator<(const impl_ptr<T1, D1, C1> &l, const impl_ptr<T2, D2, C2> &r)
326 {
328 {
327 using P1 = typename impl_ptr<T1, D1, C1>::pointer;
329 using P1 = typename impl_ptr<T1, D1, C1>::pointer;
328 using P2 = typename impl_ptr<T2, D2, C2>::pointer;
330 using P2 = typename impl_ptr<T2, D2, C2>::pointer;
329 using CT = typename std::common_type<P1, P2>::type;
331 using CT = typename std::common_type<P1, P2>::type;
330 return std::less<CT>()(l.get(), r.get());
332 return std::less<CT>()(l.get(), r.get());
331 }
333 }
332
334
333 template <class T1, class D1, class C1, class T2, class D2, class C2>
335 template <class T1, class D1, class C1, class T2, class D2, class C2>
334 inline bool operator>(const impl_ptr<T1, D1, C1> &l, const impl_ptr<T2, D2, C2> &r)
336 inline bool operator>(const impl_ptr<T1, D1, C1> &l, const impl_ptr<T2, D2, C2> &r)
335 {
337 {
336 return r < l;
338 return r < l;
337 }
339 }
338
340
339 template <class T1, class D1, class C1, class T2, class D2, class C2>
341 template <class T1, class D1, class C1, class T2, class D2, class C2>
340 inline bool operator<=(const impl_ptr<T1, D1, C1> &l, const impl_ptr<T2, D2, C2> &r)
342 inline bool operator<=(const impl_ptr<T1, D1, C1> &l, const impl_ptr<T2, D2, C2> &r)
341 {
343 {
342 return !(r < l);
344 return !(r < l);
343 }
345 }
344
346
345 template <class T1, class D1, class C1, class T2, class D2, class C2>
347 template <class T1, class D1, class C1, class T2, class D2, class C2>
346 inline bool operator>=(const impl_ptr<T1, D1, C1> &l, const impl_ptr<T2, D2, C2> &r)
348 inline bool operator>=(const impl_ptr<T1, D1, C1> &l, const impl_ptr<T2, D2, C2> &r)
347 {
349 {
348 return !(l < r);
350 return !(l < r);
349 }
351 }
350
352
351 template <class T, class D, class C>
353 template <class T, class D, class C>
352 inline bool operator==(const impl_ptr<T, D, C> &p, std::nullptr_t) SPIMPL_NOEXCEPT
354 inline bool operator==(const impl_ptr<T, D, C> &p, std::nullptr_t) SPIMPL_NOEXCEPT
353 {
355 {
354 return !p;
356 return !p;
355 }
357 }
356
358
357 template <class T, class D, class C>
359 template <class T, class D, class C>
358 inline bool operator==(std::nullptr_t, const impl_ptr<T, D, C> &p) SPIMPL_NOEXCEPT
360 inline bool operator==(std::nullptr_t, const impl_ptr<T, D, C> &p) SPIMPL_NOEXCEPT
359 {
361 {
360 return !p;
362 return !p;
361 }
363 }
362
364
363 template <class T, class D, class C>
365 template <class T, class D, class C>
364 inline bool operator!=(const impl_ptr<T, D, C> &p, std::nullptr_t) SPIMPL_NOEXCEPT
366 inline bool operator!=(const impl_ptr<T, D, C> &p, std::nullptr_t) SPIMPL_NOEXCEPT
365 {
367 {
366 return static_cast<bool>(p);
368 return static_cast<bool>(p);
367 }
369 }
368
370
369 template <class T, class D, class C>
371 template <class T, class D, class C>
370 inline bool operator!=(std::nullptr_t, const impl_ptr<T, D, C> &p) SPIMPL_NOEXCEPT
372 inline bool operator!=(std::nullptr_t, const impl_ptr<T, D, C> &p) SPIMPL_NOEXCEPT
371 {
373 {
372 return static_cast<bool>(p);
374 return static_cast<bool>(p);
373 }
375 }
374
376
375 template <class T, class D, class C>
377 template <class T, class D, class C>
376 inline bool operator<(const impl_ptr<T, D, C> &l, std::nullptr_t)
378 inline bool operator<(const impl_ptr<T, D, C> &l, std::nullptr_t)
377 {
379 {
378 using P = typename impl_ptr<T, D, C>::pointer;
380 using P = typename impl_ptr<T, D, C>::pointer;
379 return std::less<P>()(l.get(), nullptr);
381 return std::less<P>()(l.get(), nullptr);
380 }
382 }
381
383
382 template <class T, class D, class C>
384 template <class T, class D, class C>
383 inline bool operator<(std::nullptr_t, const impl_ptr<T, D, C> &p)
385 inline bool operator<(std::nullptr_t, const impl_ptr<T, D, C> &p)
384 {
386 {
385 using P = typename impl_ptr<T, D, C>::pointer;
387 using P = typename impl_ptr<T, D, C>::pointer;
386 return std::less<P>()(nullptr, p.get());
388 return std::less<P>()(nullptr, p.get());
387 }
389 }
388
390
389 template <class T, class D, class C>
391 template <class T, class D, class C>
390 inline bool operator>(const impl_ptr<T, D, C> &p, std::nullptr_t)
392 inline bool operator>(const impl_ptr<T, D, C> &p, std::nullptr_t)
391 {
393 {
392 return nullptr < p;
394 return nullptr < p;
393 }
395 }
394
396
395 template <class T, class D, class C>
397 template <class T, class D, class C>
396 inline bool operator>(std::nullptr_t, const impl_ptr<T, D, C> &p)
398 inline bool operator>(std::nullptr_t, const impl_ptr<T, D, C> &p)
397 {
399 {
398 return p < nullptr;
400 return p < nullptr;
399 }
401 }
400
402
401 template <class T, class D, class C>
403 template <class T, class D, class C>
402 inline bool operator<=(const impl_ptr<T, D, C> &p, std::nullptr_t)
404 inline bool operator<=(const impl_ptr<T, D, C> &p, std::nullptr_t)
403 {
405 {
404 return !(nullptr < p);
406 return !(nullptr < p);
405 }
407 }
406
408
407 template <class T, class D, class C>
409 template <class T, class D, class C>
408 inline bool operator<=(std::nullptr_t, const impl_ptr<T, D, C> &p)
410 inline bool operator<=(std::nullptr_t, const impl_ptr<T, D, C> &p)
409 {
411 {
410 return !(p < nullptr);
412 return !(p < nullptr);
411 }
413 }
412
414
413 template <class T, class D, class C>
415 template <class T, class D, class C>
414 inline bool operator>=(const impl_ptr<T, D, C> &p, std::nullptr_t)
416 inline bool operator>=(const impl_ptr<T, D, C> &p, std::nullptr_t)
415 {
417 {
416 return !(p < nullptr);
418 return !(p < nullptr);
417 }
419 }
418
420
419 template <class T, class D, class C>
421 template <class T, class D, class C>
420 inline bool operator>=(std::nullptr_t, const impl_ptr<T, D, C> &p)
422 inline bool operator>=(std::nullptr_t, const impl_ptr<T, D, C> &p)
421 {
423 {
422 return !(nullptr < p);
424 return !(nullptr < p);
423 }
425 }
424
426
425
427
426 template <class T, class... Args>
428 template <class T, class... Args>
427 inline impl_ptr<T> make_impl(Args &&... args)
429 inline impl_ptr<T> make_impl(Args &&... args)
428 {
430 {
429 return impl_ptr<T>(new T(std::forward<Args>(args)...), &details::default_delete<T>,
431 return impl_ptr<T>(new T(std::forward<Args>(args)...), &details::default_delete<T>,
430 &details::default_copy<T>);
432 &details::default_copy<T>);
431 }
433 }
432
434
433
435
434 // Helpers to manage unique impl, stored in std::unique_ptr
436 // Helpers to manage unique impl, stored in std::unique_ptr
435
437
436 template <class T, class Deleter = void (*)(T *)>
438 template <class T, class Deleter = void (*)(T *)>
437 using unique_impl_ptr = std::unique_ptr<T, Deleter>;
439 using unique_impl_ptr = std::unique_ptr<T, Deleter>;
438
440
439 template <class T, class... Args>
441 template <class T, class... Args>
440 inline unique_impl_ptr<T> make_unique_impl(Args &&... args)
442 inline unique_impl_ptr<T> make_unique_impl(Args &&... args)
441 {
443 {
442 static_assert(!std::is_array<T>::value, "unique_impl_ptr does not support arrays");
444 static_assert(!std::is_array<T>::value, "unique_impl_ptr does not support arrays");
443 return unique_impl_ptr<T>(new T(std::forward<Args>(args)...), &details::default_delete<T>);
445 return unique_impl_ptr<T>(new T(std::forward<Args>(args)...), &details::default_delete<T>);
444 }
446 }
445 }
447 }
446
448
447 namespace std {
449 namespace std {
448 template <class T, class D, class C>
450 template <class T, class D, class C>
449 struct hash<spimpl::impl_ptr<T, D, C> > {
451 struct hash<spimpl::impl_ptr<T, D, C> > {
450 using argument_type = spimpl::impl_ptr<T, D, C>;
452 using argument_type = spimpl::impl_ptr<T, D, C>;
451 using result_type = size_t;
453 using result_type = size_t;
452
454
453 result_type operator()(const argument_type &p) const SPIMPL_NOEXCEPT
455 result_type operator()(const argument_type &p) const SPIMPL_NOEXCEPT
454 {
456 {
455 return hash<typename argument_type::pointer>()(p.get());
457 return hash<typename argument_type::pointer>()(p.get());
456 }
458 }
457 };
459 };
458 }
460 }
459
461
460 #endif // SPIMPL_H_
462 #endif // SPIMPL_H_
@@ -1,143 +1,143
1 #include "DataSource/DataSourceController.h"
1 #include "DataSource/DataSourceController.h"
2 #include "DataSource/DataSourceItem.h"
2 #include "DataSource/DataSourceItem.h"
3
3
4 #include <Data/IDataProvider.h>
4 #include <Data/IDataProvider.h>
5
5
6 #include <QMutex>
6 #include <QMutex>
7 #include <QThread>
7 #include <QThread>
8
8
9 #include <QDir>
9 #include <QDir>
10 #include <QStandardPaths>
10 #include <QStandardPaths>
11
11
12 Q_LOGGING_CATEGORY(LOG_DataSourceController, "DataSourceController")
12 Q_LOGGING_CATEGORY(LOG_DataSourceController, "DataSourceController")
13
13
14 namespace {
14 namespace {
15
15
16 /**
16 /**
17 * Builds the metadata of the variable that will be generated from the loading of an item
17 * Builds the metadata of the variable that will be generated from the loading of an item
18 * @param dataSourceItem the data source item from which to generate the metadata
18 * @param dataSourceItem the data source item from which to generate the metadata
19 * @return the metadata of the variable
19 * @return the metadata of the variable
20 */
20 */
21 QVariantHash variableMetadata(const DataSourceItem &dataSourceItem)
21 QVariantHash variableMetadata(const DataSourceItem &dataSourceItem)
22 {
22 {
23 // Variable metadata contains...
23 // Variable metadata contains...
24
24
25 // ... all metadata of the item
25 // ... all metadata of the item
26 auto result = dataSourceItem.data();
26 auto result = dataSourceItem.data();
27
27
28 // ... and the name of the plugin, recovered from root item
28 // ... and the name of the plugin, recovered from root item
29 result.insert(QStringLiteral("plugin"), dataSourceItem.rootItem().name());
29 result.insert(QStringLiteral("plugin"), dataSourceItem.rootItem().name());
30
30
31 return result;
31 return result;
32 }
32 }
33
33
34 } // namespace
34 } // namespace
35
35
36 class DataSourceController::DataSourceControllerPrivate {
36 class DataSourceController::DataSourceControllerPrivate {
37 public:
37 public:
38 QMutex m_WorkingMutex;
38 QMutex m_WorkingMutex;
39 /// Data sources registered
39 /// Data sources registered
40 QHash<QUuid, QString> m_DataSources;
40 QHash<QUuid, QString> m_DataSources;
41 /// Data sources structures
41 /// Data sources structures
42 std::map<QUuid, std::unique_ptr<DataSourceItem> > m_DataSourceItems;
42 std::map<QUuid, std::unique_ptr<DataSourceItem> > m_DataSourceItems;
43 /// Data providers registered
43 /// Data providers registered
44 /// @remarks Data providers are stored as shared_ptr as they can be sent to a variable and
44 /// @remarks Data providers are stored as shared_ptr as they can be sent to a variable and
45 /// continue to live without necessarily the data source controller
45 /// continue to live without necessarily the data source controller
46 std::map<QUuid, std::shared_ptr<IDataProvider> > m_DataProviders;
46 std::map<QUuid, std::shared_ptr<IDataProvider> > m_DataProviders;
47 };
47 };
48
48
49 DataSourceController::DataSourceController(QObject *parent)
49 DataSourceController::DataSourceController(QObject *parent)
50 : impl{spimpl::make_unique_impl<DataSourceControllerPrivate>()}
50 : impl{spimpl::make_unique_impl<DataSourceControllerPrivate>()}
51 {
51 {
52 qCDebug(LOG_DataSourceController()) << tr("DataSourceController construction")
52 qCDebug(LOG_DataSourceController())
53 << QThread::currentThread();
53 << tr("DataSourceController construction") << QThread::currentThread();
54 }
54 }
55
55
56 DataSourceController::~DataSourceController()
56 DataSourceController::~DataSourceController()
57 {
57 {
58 qCDebug(LOG_DataSourceController()) << tr("DataSourceController destruction")
58 qCDebug(LOG_DataSourceController())
59 << QThread::currentThread();
59 << tr("DataSourceController destruction") << QThread::currentThread();
60 this->waitForFinish();
60 this->waitForFinish();
61 }
61 }
62
62
63 QUuid DataSourceController::registerDataSource(const QString &dataSourceName) noexcept
63 QUuid DataSourceController::registerDataSource(const QString &dataSourceName) noexcept
64 {
64 {
65 auto dataSourceUid = QUuid::createUuid();
65 auto dataSourceUid = QUuid::createUuid();
66 impl->m_DataSources.insert(dataSourceUid, dataSourceName);
66 impl->m_DataSources.insert(dataSourceUid, dataSourceName);
67
67
68 return dataSourceUid;
68 return dataSourceUid;
69 }
69 }
70
70
71 void DataSourceController::setDataSourceItem(
71 void DataSourceController::setDataSourceItem(
72 const QUuid &dataSourceUid, std::unique_ptr<DataSourceItem> dataSourceItem) noexcept
72 const QUuid &dataSourceUid, std::unique_ptr<DataSourceItem> dataSourceItem) noexcept
73 {
73 {
74 if (!dataSourceItem) {
74 if (!dataSourceItem) {
75 qCWarning(LOG_DataSourceController())
75 qCWarning(LOG_DataSourceController())
76 << tr("Data source item can't be registered (null item)");
76 << tr("Data source item can't be registered (null item)");
77 return;
77 return;
78 }
78 }
79
79
80 if (impl->m_DataSources.contains(dataSourceUid)) {
80 if (impl->m_DataSources.contains(dataSourceUid)) {
81 // The data provider is implicitly converted to a shared_ptr
81 // The data provider is implicitly converted to a shared_ptr
82 impl->m_DataSourceItems.insert(std::make_pair(dataSourceUid, std::move(dataSourceItem)));
82 impl->m_DataSourceItems.insert(std::make_pair(dataSourceUid, std::move(dataSourceItem)));
83
83
84 // Retrieves the data source item to emit the signal with it
84 // Retrieves the data source item to emit the signal with it
85 auto it = impl->m_DataSourceItems.find(dataSourceUid);
85 auto it = impl->m_DataSourceItems.find(dataSourceUid);
86 if (it != impl->m_DataSourceItems.end()) {
86 if (it != impl->m_DataSourceItems.end()) {
87 emit dataSourceItemSet(it->second.get());
87 emit dataSourceItemSet(it->second.get());
88 }
88 }
89 }
89 }
90 else {
90 else {
91 qCWarning(LOG_DataSourceController()) << tr("Can't set data source item for uid %1 : no "
91 qCWarning(LOG_DataSourceController()) << tr("Can't set data source item for uid %1 : no "
92 "data source has been registered with the uid")
92 "data source has been registered with the uid")
93 .arg(dataSourceUid.toString());
93 .arg(dataSourceUid.toString());
94 }
94 }
95 }
95 }
96
96
97 void DataSourceController::setDataProvider(const QUuid &dataSourceUid,
97 void DataSourceController::setDataProvider(const QUuid &dataSourceUid,
98 std::unique_ptr<IDataProvider> dataProvider) noexcept
98 std::unique_ptr<IDataProvider> dataProvider) noexcept
99 {
99 {
100 if (impl->m_DataSources.contains(dataSourceUid)) {
100 if (impl->m_DataSources.contains(dataSourceUid)) {
101 impl->m_DataProviders.insert(std::make_pair(dataSourceUid, std::move(dataProvider)));
101 impl->m_DataProviders.insert(std::make_pair(dataSourceUid, std::move(dataProvider)));
102 }
102 }
103 else {
103 else {
104 qCWarning(LOG_DataSourceController()) << tr("Can't set data provider for uid %1 : no data "
104 qCWarning(LOG_DataSourceController()) << tr("Can't set data provider for uid %1 : no data "
105 "source has been registered with the uid")
105 "source has been registered with the uid")
106 .arg(dataSourceUid.toString());
106 .arg(dataSourceUid.toString());
107 }
107 }
108 }
108 }
109
109
110 void DataSourceController::loadProductItem(const QUuid &dataSourceUid,
110 void DataSourceController::loadProductItem(const QUuid &dataSourceUid,
111 const DataSourceItem &productItem) noexcept
111 const DataSourceItem &productItem) noexcept
112 {
112 {
113 if (productItem.type() == DataSourceItemType::PRODUCT
113 if (productItem.type() == DataSourceItemType::PRODUCT
114 || productItem.type() == DataSourceItemType::COMPONENT) {
114 || productItem.type() == DataSourceItemType::COMPONENT) {
115 /// Retrieves the data provider of the data source (if any)
115 /// Retrieves the data provider of the data source (if any)
116 auto it = impl->m_DataProviders.find(dataSourceUid);
116 auto it = impl->m_DataProviders.find(dataSourceUid);
117 auto dataProvider = (it != impl->m_DataProviders.end()) ? it->second : nullptr;
117 auto dataProvider = (it != impl->m_DataProviders.end()) ? it->second : nullptr;
118
118
119 emit variableCreationRequested(productItem.name(), variableMetadata(productItem),
119 emit variableCreationRequested(productItem.name(), variableMetadata(productItem),
120 dataProvider);
120 dataProvider);
121 }
121 }
122 else {
122 else {
123 qCWarning(LOG_DataSourceController()) << tr("Can't load an item that is not a product");
123 qCWarning(LOG_DataSourceController()) << tr("Can't load an item that is not a product");
124 }
124 }
125 }
125 }
126
126
127 void DataSourceController::initialize()
127 void DataSourceController::initialize()
128 {
128 {
129 qCDebug(LOG_DataSourceController()) << tr("DataSourceController init")
129 qCDebug(LOG_DataSourceController())
130 << QThread::currentThread();
130 << tr("DataSourceController init") << QThread::currentThread();
131 impl->m_WorkingMutex.lock();
131 impl->m_WorkingMutex.lock();
132 qCDebug(LOG_DataSourceController()) << tr("DataSourceController init END");
132 qCDebug(LOG_DataSourceController()) << tr("DataSourceController init END");
133 }
133 }
134
134
135 void DataSourceController::finalize()
135 void DataSourceController::finalize()
136 {
136 {
137 impl->m_WorkingMutex.unlock();
137 impl->m_WorkingMutex.unlock();
138 }
138 }
139
139
140 void DataSourceController::waitForFinish()
140 void DataSourceController::waitForFinish()
141 {
141 {
142 QMutexLocker locker{&impl->m_WorkingMutex};
142 QMutexLocker locker{&impl->m_WorkingMutex};
143 }
143 }
@@ -1,134 +1,134
1 #include "Network/NetworkController.h"
1 #include "Network/NetworkController.h"
2
2
3 #include <QMutex>
3 #include <QMutex>
4 #include <QNetworkAccessManager>
4 #include <QNetworkAccessManager>
5 #include <QNetworkReply>
5 #include <QNetworkReply>
6 #include <QNetworkRequest>
6 #include <QNetworkRequest>
7 #include <QReadWriteLock>
7 #include <QReadWriteLock>
8 #include <QThread>
8 #include <QThread>
9
9
10 #include <unordered_map>
10 #include <unordered_map>
11
11
12 Q_LOGGING_CATEGORY(LOG_NetworkController, "NetworkController")
12 Q_LOGGING_CATEGORY(LOG_NetworkController, "NetworkController")
13
13
14 struct NetworkController::NetworkControllerPrivate {
14 struct NetworkController::NetworkControllerPrivate {
15 explicit NetworkControllerPrivate(NetworkController *parent) : m_WorkingMutex{} {}
15 explicit NetworkControllerPrivate(NetworkController *parent) : m_WorkingMutex{} {}
16
16
17 void lockRead() { m_Lock.lockForRead(); }
17 void lockRead() { m_Lock.lockForRead(); }
18 void lockWrite() { m_Lock.lockForWrite(); }
18 void lockWrite() { m_Lock.lockForWrite(); }
19 void unlock() { m_Lock.unlock(); }
19 void unlock() { m_Lock.unlock(); }
20
20
21 QMutex m_WorkingMutex;
21 QMutex m_WorkingMutex;
22
22
23 QReadWriteLock m_Lock;
23 QReadWriteLock m_Lock;
24 std::unordered_map<QNetworkReply *, QUuid> m_NetworkReplyToVariableId;
24 std::unordered_map<QNetworkReply *, QUuid> m_NetworkReplyToVariableId;
25 std::unique_ptr<QNetworkAccessManager> m_AccessManager{nullptr};
25 std::unique_ptr<QNetworkAccessManager> m_AccessManager{nullptr};
26 };
26 };
27
27
28 NetworkController::NetworkController(QObject *parent)
28 NetworkController::NetworkController(QObject *parent)
29 : QObject(parent), impl{spimpl::make_unique_impl<NetworkControllerPrivate>(this)}
29 : QObject(parent), impl{spimpl::make_unique_impl<NetworkControllerPrivate>(this)}
30 {
30 {
31 }
31 }
32
32
33 void NetworkController::onProcessRequested(const QNetworkRequest &request, QUuid identifier,
33 void NetworkController::onProcessRequested(const QNetworkRequest &request, QUuid identifier,
34 std::function<void(QNetworkReply *, QUuid)> callback)
34 std::function<void(QNetworkReply *, QUuid)> callback)
35 {
35 {
36 qCDebug(LOG_NetworkController()) << tr("NetworkController registered")
36 qCDebug(LOG_NetworkController())
37 << QThread::currentThread()->objectName();
37 << tr("NetworkController registered") << QThread::currentThread()->objectName();
38 auto reply = impl->m_AccessManager->get(request);
38 auto reply = impl->m_AccessManager->get(request);
39
39
40 // Store the couple reply id
40 // Store the couple reply id
41 impl->lockWrite();
41 impl->lockWrite();
42 impl->m_NetworkReplyToVariableId[reply] = identifier;
42 impl->m_NetworkReplyToVariableId[reply] = identifier;
43 impl->unlock();
43 impl->unlock();
44
44
45 auto onReplyFinished = [reply, this, identifier, callback]() {
45 auto onReplyFinished = [reply, this, identifier, callback]() {
46
46
47 qCDebug(LOG_NetworkController()) << tr("NetworkController onReplyFinished")
47 qCDebug(LOG_NetworkController())
48 << QThread::currentThread() << reply;
48 << tr("NetworkController onReplyFinished") << QThread::currentThread() << reply;
49 impl->lockRead();
49 impl->lockRead();
50 auto it = impl->m_NetworkReplyToVariableId.find(reply);
50 auto it = impl->m_NetworkReplyToVariableId.find(reply);
51 impl->unlock();
51 impl->unlock();
52 if (it != impl->m_NetworkReplyToVariableId.cend()) {
52 if (it != impl->m_NetworkReplyToVariableId.cend()) {
53 impl->lockWrite();
53 impl->lockWrite();
54 impl->m_NetworkReplyToVariableId.erase(reply);
54 impl->m_NetworkReplyToVariableId.erase(reply);
55 impl->unlock();
55 impl->unlock();
56 // Deletes reply
56 // Deletes reply
57 callback(reply, identifier);
57 callback(reply, identifier);
58 reply->deleteLater();
58 reply->deleteLater();
59
59
60 emit this->replyDownloadProgress(identifier, 0);
60 emit this->replyDownloadProgress(identifier, 0);
61 }
61 }
62
62
63 qCDebug(LOG_NetworkController()) << tr("NetworkController onReplyFinished END")
63 qCDebug(LOG_NetworkController())
64 << QThread::currentThread() << reply;
64 << tr("NetworkController onReplyFinished END") << QThread::currentThread() << reply;
65 };
65 };
66
66
67 auto onReplyProgress = [reply, this](qint64 bytesRead, qint64 totalBytes) {
67 auto onReplyProgress = [reply, this](qint64 bytesRead, qint64 totalBytes) {
68
68
69 double progress = (bytesRead * 100.0) / totalBytes;
69 double progress = (bytesRead * 100.0) / totalBytes;
70 qCDebug(LOG_NetworkController()) << tr("NetworkController onReplyProgress") << progress
70 qCDebug(LOG_NetworkController()) << tr("NetworkController onReplyProgress") << progress
71 << QThread::currentThread() << reply;
71 << QThread::currentThread() << reply;
72 impl->lockRead();
72 impl->lockRead();
73 auto it = impl->m_NetworkReplyToVariableId.find(reply);
73 auto it = impl->m_NetworkReplyToVariableId.find(reply);
74 impl->unlock();
74 impl->unlock();
75 if (it != impl->m_NetworkReplyToVariableId.cend()) {
75 if (it != impl->m_NetworkReplyToVariableId.cend()) {
76 emit this->replyDownloadProgress(it->second, progress);
76 emit this->replyDownloadProgress(it->second, progress);
77 }
77 }
78 qCDebug(LOG_NetworkController()) << tr("NetworkController onReplyProgress END")
78 qCDebug(LOG_NetworkController())
79 << QThread::currentThread() << reply;
79 << tr("NetworkController onReplyProgress END") << QThread::currentThread() << reply;
80 };
80 };
81
81
82
82
83 connect(reply, &QNetworkReply::finished, this, onReplyFinished);
83 connect(reply, &QNetworkReply::finished, this, onReplyFinished);
84 connect(reply, &QNetworkReply::downloadProgress, this, onReplyProgress);
84 connect(reply, &QNetworkReply::downloadProgress, this, onReplyProgress);
85 qCDebug(LOG_NetworkController()) << tr("NetworkController registered END")
85 qCDebug(LOG_NetworkController()) << tr("NetworkController registered END")
86 << QThread::currentThread()->objectName() << reply;
86 << QThread::currentThread()->objectName() << reply;
87 }
87 }
88
88
89 void NetworkController::initialize()
89 void NetworkController::initialize()
90 {
90 {
91 qCDebug(LOG_NetworkController()) << tr("NetworkController init") << QThread::currentThread();
91 qCDebug(LOG_NetworkController()) << tr("NetworkController init") << QThread::currentThread();
92 impl->m_WorkingMutex.lock();
92 impl->m_WorkingMutex.lock();
93 impl->m_AccessManager = std::make_unique<QNetworkAccessManager>();
93 impl->m_AccessManager = std::make_unique<QNetworkAccessManager>();
94
94
95
95
96 auto onReplyErrors = [this](QNetworkReply *reply, const QList<QSslError> &errors) {
96 auto onReplyErrors = [this](QNetworkReply *reply, const QList<QSslError> &errors) {
97
97
98 qCCritical(LOG_NetworkController()) << tr("NetworkAcessManager errors: ") << errors;
98 qCCritical(LOG_NetworkController()) << tr("NetworkAcessManager errors: ") << errors;
99
99
100 };
100 };
101
101
102
102
103 connect(impl->m_AccessManager.get(), &QNetworkAccessManager::sslErrors, this, onReplyErrors);
103 connect(impl->m_AccessManager.get(), &QNetworkAccessManager::sslErrors, this, onReplyErrors);
104
104
105 qCDebug(LOG_NetworkController()) << tr("NetworkController init END");
105 qCDebug(LOG_NetworkController()) << tr("NetworkController init END");
106 }
106 }
107
107
108 void NetworkController::finalize()
108 void NetworkController::finalize()
109 {
109 {
110 impl->m_WorkingMutex.unlock();
110 impl->m_WorkingMutex.unlock();
111 }
111 }
112
112
113 void NetworkController::onReplyCanceled(QUuid identifier)
113 void NetworkController::onReplyCanceled(QUuid identifier)
114 {
114 {
115 auto findReply = [identifier](const auto &entry) { return identifier == entry.second; };
115 auto findReply = [identifier](const auto &entry) { return identifier == entry.second; };
116 qCDebug(LOG_NetworkController()) << tr("NetworkController onReplyCanceled")
116 qCDebug(LOG_NetworkController())
117 << QThread::currentThread();
117 << tr("NetworkController onReplyCanceled") << QThread::currentThread();
118
118
119
119
120 impl->lockRead();
120 impl->lockRead();
121 auto end = impl->m_NetworkReplyToVariableId.cend();
121 auto end = impl->m_NetworkReplyToVariableId.cend();
122 auto it = std::find_if(impl->m_NetworkReplyToVariableId.cbegin(), end, findReply);
122 auto it = std::find_if(impl->m_NetworkReplyToVariableId.cbegin(), end, findReply);
123 impl->unlock();
123 impl->unlock();
124 if (it != end) {
124 if (it != end) {
125 it->first->abort();
125 it->first->abort();
126 }
126 }
127 qCDebug(LOG_NetworkController()) << tr("NetworkController onReplyCanceled END")
127 qCDebug(LOG_NetworkController())
128 << QThread::currentThread();
128 << tr("NetworkController onReplyCanceled END") << QThread::currentThread();
129 }
129 }
130
130
131 void NetworkController::waitForFinish()
131 void NetworkController::waitForFinish()
132 {
132 {
133 QMutexLocker locker{&impl->m_WorkingMutex};
133 QMutexLocker locker{&impl->m_WorkingMutex};
134 }
134 }
@@ -1,307 +1,307
1 #include "Variable/Variable.h"
1 #include "Variable/Variable.h"
2
2
3 #include <Data/IDataSeries.h>
3 #include <Data/IDataSeries.h>
4 #include <Data/SqpRange.h>
4 #include <Data/SqpRange.h>
5
5
6 #include <QMutex>
6 #include <QMutex>
7 #include <QReadWriteLock>
7 #include <QReadWriteLock>
8 #include <QThread>
8 #include <QThread>
9
9
10 Q_LOGGING_CATEGORY(LOG_Variable, "Variable")
10 Q_LOGGING_CATEGORY(LOG_Variable, "Variable")
11
11
12 struct Variable::VariablePrivate {
12 struct Variable::VariablePrivate {
13 explicit VariablePrivate(const QString &name, const SqpRange &dateTime,
13 explicit VariablePrivate(const QString &name, const SqpRange &dateTime,
14 const QVariantHash &metadata)
14 const QVariantHash &metadata)
15 : m_Name{name},
15 : m_Name{name},
16 m_Range{dateTime},
16 m_Range{dateTime},
17 m_Metadata{metadata},
17 m_Metadata{metadata},
18 m_DataSeries{nullptr},
18 m_DataSeries{nullptr},
19 m_RealRange{INVALID_RANGE},
19 m_RealRange{INVALID_RANGE},
20 m_NbPoints{0}
20 m_NbPoints{0}
21 {
21 {
22 }
22 }
23
23
24 VariablePrivate(const VariablePrivate &other)
24 VariablePrivate(const VariablePrivate &other)
25 : m_Name{other.m_Name},
25 : m_Name{other.m_Name},
26 m_Range{other.m_Range},
26 m_Range{other.m_Range},
27 m_Metadata{other.m_Metadata},
27 m_Metadata{other.m_Metadata},
28 m_DataSeries{other.m_DataSeries != nullptr ? other.m_DataSeries->clone() : nullptr},
28 m_DataSeries{other.m_DataSeries != nullptr ? other.m_DataSeries->clone() : nullptr},
29 m_RealRange{other.m_RealRange},
29 m_RealRange{other.m_RealRange},
30 m_NbPoints{other.m_NbPoints}
30 m_NbPoints{other.m_NbPoints}
31 {
31 {
32 }
32 }
33
33
34 void lockRead() { m_Lock.lockForRead(); }
34 void lockRead() { m_Lock.lockForRead(); }
35 void lockWrite() { m_Lock.lockForWrite(); }
35 void lockWrite() { m_Lock.lockForWrite(); }
36 void unlock() { m_Lock.unlock(); }
36 void unlock() { m_Lock.unlock(); }
37
37
38 void purgeDataSeries()
38 void purgeDataSeries()
39 {
39 {
40 if (m_DataSeries) {
40 if (m_DataSeries) {
41 m_DataSeries->purge(m_CacheRange.m_TStart, m_CacheRange.m_TEnd);
41 m_DataSeries->purge(m_CacheRange.m_TStart, m_CacheRange.m_TEnd);
42 }
42 }
43 updateRealRange();
43 updateRealRange();
44 updateNbPoints();
44 updateNbPoints();
45 }
45 }
46
46
47 void updateNbPoints() { m_NbPoints = m_DataSeries ? m_DataSeries->nbPoints() : 0; }
47 void updateNbPoints() { m_NbPoints = m_DataSeries ? m_DataSeries->nbPoints() : 0; }
48
48
49 /// Updates real range according to current variable range and data series
49 /// Updates real range according to current variable range and data series
50 void updateRealRange()
50 void updateRealRange()
51 {
51 {
52 if (m_DataSeries) {
52 if (m_DataSeries) {
53 m_DataSeries->lockRead();
53 m_DataSeries->lockRead();
54 auto end = m_DataSeries->cend();
54 auto end = m_DataSeries->cend();
55 auto minXAxisIt = m_DataSeries->minXAxisData(m_Range.m_TStart);
55 auto minXAxisIt = m_DataSeries->minXAxisData(m_Range.m_TStart);
56 auto maxXAxisIt = m_DataSeries->maxXAxisData(m_Range.m_TEnd);
56 auto maxXAxisIt = m_DataSeries->maxXAxisData(m_Range.m_TEnd);
57
57
58 m_RealRange = (minXAxisIt != end && maxXAxisIt != end)
58 m_RealRange = (minXAxisIt != end && maxXAxisIt != end)
59 ? SqpRange{minXAxisIt->x(), maxXAxisIt->x()}
59 ? SqpRange{minXAxisIt->x(), maxXAxisIt->x()}
60 : INVALID_RANGE;
60 : INVALID_RANGE;
61 m_DataSeries->unlock();
61 m_DataSeries->unlock();
62 }
62 }
63 else {
63 else {
64 m_RealRange = INVALID_RANGE;
64 m_RealRange = INVALID_RANGE;
65 }
65 }
66 }
66 }
67
67
68 QString m_Name;
68 QString m_Name;
69
69
70 SqpRange m_Range;
70 SqpRange m_Range;
71 SqpRange m_CacheRange;
71 SqpRange m_CacheRange;
72 QVariantHash m_Metadata;
72 QVariantHash m_Metadata;
73 std::shared_ptr<IDataSeries> m_DataSeries;
73 std::shared_ptr<IDataSeries> m_DataSeries;
74 SqpRange m_RealRange;
74 SqpRange m_RealRange;
75 int m_NbPoints;
75 int m_NbPoints;
76
76
77 QReadWriteLock m_Lock;
77 QReadWriteLock m_Lock;
78 };
78 };
79
79
80 Variable::Variable(const QString &name, const SqpRange &dateTime, const QVariantHash &metadata)
80 Variable::Variable(const QString &name, const SqpRange &dateTime, const QVariantHash &metadata)
81 : impl{spimpl::make_unique_impl<VariablePrivate>(name, dateTime, metadata)}
81 : impl{spimpl::make_unique_impl<VariablePrivate>(name, dateTime, metadata)}
82 {
82 {
83 }
83 }
84
84
85 Variable::Variable(const Variable &other)
85 Variable::Variable(const Variable &other)
86 : impl{spimpl::make_unique_impl<VariablePrivate>(*other.impl)}
86 : impl{spimpl::make_unique_impl<VariablePrivate>(*other.impl)}
87 {
87 {
88 }
88 }
89
89
90 std::shared_ptr<Variable> Variable::clone() const
90 std::shared_ptr<Variable> Variable::clone() const
91 {
91 {
92 return std::make_shared<Variable>(*this);
92 return std::make_shared<Variable>(*this);
93 }
93 }
94
94
95 QString Variable::name() const noexcept
95 QString Variable::name() const noexcept
96 {
96 {
97 impl->lockRead();
97 impl->lockRead();
98 auto name = impl->m_Name;
98 auto name = impl->m_Name;
99 impl->unlock();
99 impl->unlock();
100 return name;
100 return name;
101 }
101 }
102
102
103 void Variable::setName(const QString &name) noexcept
103 void Variable::setName(const QString &name) noexcept
104 {
104 {
105 impl->lockWrite();
105 impl->lockWrite();
106 impl->m_Name = name;
106 impl->m_Name = name;
107 impl->unlock();
107 impl->unlock();
108 }
108 }
109
109
110 SqpRange Variable::range() const noexcept
110 SqpRange Variable::range() const noexcept
111 {
111 {
112 impl->lockRead();
112 impl->lockRead();
113 auto range = impl->m_Range;
113 auto range = impl->m_Range;
114 impl->unlock();
114 impl->unlock();
115 return range;
115 return range;
116 }
116 }
117
117
118 void Variable::setRange(const SqpRange &range) noexcept
118 void Variable::setRange(const SqpRange &range) noexcept
119 {
119 {
120 impl->lockWrite();
120 impl->lockWrite();
121 impl->m_Range = range;
121 impl->m_Range = range;
122 impl->updateRealRange();
122 impl->updateRealRange();
123 impl->unlock();
123 impl->unlock();
124 }
124 }
125
125
126 SqpRange Variable::cacheRange() const noexcept
126 SqpRange Variable::cacheRange() const noexcept
127 {
127 {
128 impl->lockRead();
128 impl->lockRead();
129 auto cacheRange = impl->m_CacheRange;
129 auto cacheRange = impl->m_CacheRange;
130 impl->unlock();
130 impl->unlock();
131 return cacheRange;
131 return cacheRange;
132 }
132 }
133
133
134 void Variable::setCacheRange(const SqpRange &cacheRange) noexcept
134 void Variable::setCacheRange(const SqpRange &cacheRange) noexcept
135 {
135 {
136 impl->lockWrite();
136 impl->lockWrite();
137 if (cacheRange != impl->m_CacheRange) {
137 if (cacheRange != impl->m_CacheRange) {
138 impl->m_CacheRange = cacheRange;
138 impl->m_CacheRange = cacheRange;
139 impl->purgeDataSeries();
139 impl->purgeDataSeries();
140 }
140 }
141 impl->unlock();
141 impl->unlock();
142 }
142 }
143
143
144 int Variable::nbPoints() const noexcept
144 int Variable::nbPoints() const noexcept
145 {
145 {
146 return impl->m_NbPoints;
146 return impl->m_NbPoints;
147 }
147 }
148
148
149 SqpRange Variable::realRange() const noexcept
149 SqpRange Variable::realRange() const noexcept
150 {
150 {
151 return impl->m_RealRange;
151 return impl->m_RealRange;
152 }
152 }
153
153
154 void Variable::mergeDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept
154 void Variable::mergeDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept
155 {
155 {
156 qCDebug(LOG_Variable()) << "TORM Variable::mergeDataSeries"
156 qCDebug(LOG_Variable()) << "TORM Variable::mergeDataSeries"
157 << QThread::currentThread()->objectName();
157 << QThread::currentThread()->objectName();
158 if (!dataSeries) {
158 if (!dataSeries) {
159 /// @todo ALX : log
159 /// @todo ALX : log
160 return;
160 return;
161 }
161 }
162
162
163 // Add or merge the data
163 // Add or merge the data
164 impl->lockWrite();
164 impl->lockWrite();
165 if (!impl->m_DataSeries) {
165 if (!impl->m_DataSeries) {
166 impl->m_DataSeries = dataSeries->clone();
166 impl->m_DataSeries = dataSeries->clone();
167 }
167 }
168 else {
168 else {
169 impl->m_DataSeries->merge(dataSeries.get());
169 impl->m_DataSeries->merge(dataSeries.get());
170 }
170 }
171 impl->purgeDataSeries();
171 impl->purgeDataSeries();
172 impl->unlock();
172 impl->unlock();
173 }
173 }
174
174
175 std::shared_ptr<IDataSeries> Variable::dataSeries() const noexcept
175 std::shared_ptr<IDataSeries> Variable::dataSeries() const noexcept
176 {
176 {
177 impl->lockRead();
177 impl->lockRead();
178 auto dataSeries = impl->m_DataSeries;
178 auto dataSeries = impl->m_DataSeries;
179 impl->unlock();
179 impl->unlock();
180
180
181 return dataSeries;
181 return dataSeries;
182 }
182 }
183
183
184 QVariantHash Variable::metadata() const noexcept
184 QVariantHash Variable::metadata() const noexcept
185 {
185 {
186 impl->lockRead();
186 impl->lockRead();
187 auto metadata = impl->m_Metadata;
187 auto metadata = impl->m_Metadata;
188 impl->unlock();
188 impl->unlock();
189 return metadata;
189 return metadata;
190 }
190 }
191
191
192 bool Variable::contains(const SqpRange &range) const noexcept
192 bool Variable::contains(const SqpRange &range) const noexcept
193 {
193 {
194 impl->lockRead();
194 impl->lockRead();
195 auto res = impl->m_Range.contains(range);
195 auto res = impl->m_Range.contains(range);
196 impl->unlock();
196 impl->unlock();
197 return res;
197 return res;
198 }
198 }
199
199
200 bool Variable::intersect(const SqpRange &range) const noexcept
200 bool Variable::intersect(const SqpRange &range) const noexcept
201 {
201 {
202
202
203 impl->lockRead();
203 impl->lockRead();
204 auto res = impl->m_Range.intersect(range);
204 auto res = impl->m_Range.intersect(range);
205 impl->unlock();
205 impl->unlock();
206 return res;
206 return res;
207 }
207 }
208
208
209 bool Variable::isInside(const SqpRange &range) const noexcept
209 bool Variable::isInside(const SqpRange &range) const noexcept
210 {
210 {
211 impl->lockRead();
211 impl->lockRead();
212 auto res = range.contains(SqpRange{impl->m_Range.m_TStart, impl->m_Range.m_TEnd});
212 auto res = range.contains(SqpRange{impl->m_Range.m_TStart, impl->m_Range.m_TEnd});
213 impl->unlock();
213 impl->unlock();
214 return res;
214 return res;
215 }
215 }
216
216
217 bool Variable::cacheContains(const SqpRange &range) const noexcept
217 bool Variable::cacheContains(const SqpRange &range) const noexcept
218 {
218 {
219 impl->lockRead();
219 impl->lockRead();
220 auto res = impl->m_CacheRange.contains(range);
220 auto res = impl->m_CacheRange.contains(range);
221 impl->unlock();
221 impl->unlock();
222 return res;
222 return res;
223 }
223 }
224
224
225 bool Variable::cacheIntersect(const SqpRange &range) const noexcept
225 bool Variable::cacheIntersect(const SqpRange &range) const noexcept
226 {
226 {
227 impl->lockRead();
227 impl->lockRead();
228 auto res = impl->m_CacheRange.intersect(range);
228 auto res = impl->m_CacheRange.intersect(range);
229 impl->unlock();
229 impl->unlock();
230 return res;
230 return res;
231 }
231 }
232
232
233 bool Variable::cacheIsInside(const SqpRange &range) const noexcept
233 bool Variable::cacheIsInside(const SqpRange &range) const noexcept
234 {
234 {
235 impl->lockRead();
235 impl->lockRead();
236 auto res = range.contains(SqpRange{impl->m_CacheRange.m_TStart, impl->m_CacheRange.m_TEnd});
236 auto res = range.contains(SqpRange{impl->m_CacheRange.m_TStart, impl->m_CacheRange.m_TEnd});
237 impl->unlock();
237 impl->unlock();
238 return res;
238 return res;
239 }
239 }
240
240
241
241
242 QVector<SqpRange> Variable::provideNotInCacheRangeList(const SqpRange &range) const noexcept
242 QVector<SqpRange> Variable::provideNotInCacheRangeList(const SqpRange &range) const noexcept
243 {
243 {
244 // This code assume that cach in contigue. Can return 0, 1 or 2 SqpRange
244 // This code assume that cach in contigue. Can return 0, 1 or 2 SqpRange
245
245
246 auto notInCache = QVector<SqpRange>{};
246 auto notInCache = QVector<SqpRange>{};
247
247
248 if (!this->cacheContains(range)) {
248 if (!this->cacheContains(range)) {
249 if (range.m_TEnd <= impl->m_CacheRange.m_TStart
249 if (range.m_TEnd <= impl->m_CacheRange.m_TStart
250 || range.m_TStart >= impl->m_CacheRange.m_TEnd) {
250 || range.m_TStart >= impl->m_CacheRange.m_TEnd) {
251 notInCache << range;
251 notInCache << range;
252 }
252 }
253 else if (range.m_TStart < impl->m_CacheRange.m_TStart
253 else if (range.m_TStart < impl->m_CacheRange.m_TStart
254 && range.m_TEnd <= impl->m_CacheRange.m_TEnd) {
254 && range.m_TEnd <= impl->m_CacheRange.m_TEnd) {
255 notInCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TStart};
255 notInCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TStart};
256 }
256 }
257 else if (range.m_TStart < impl->m_CacheRange.m_TStart
257 else if (range.m_TStart < impl->m_CacheRange.m_TStart
258 && range.m_TEnd > impl->m_CacheRange.m_TEnd) {
258 && range.m_TEnd > impl->m_CacheRange.m_TEnd) {
259 notInCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TStart}
259 notInCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TStart}
260 << SqpRange{impl->m_CacheRange.m_TEnd, range.m_TEnd};
260 << SqpRange{impl->m_CacheRange.m_TEnd, range.m_TEnd};
261 }
261 }
262 else if (range.m_TStart < impl->m_CacheRange.m_TEnd) {
262 else if (range.m_TStart < impl->m_CacheRange.m_TEnd) {
263 notInCache << SqpRange{impl->m_CacheRange.m_TEnd, range.m_TEnd};
263 notInCache << SqpRange{impl->m_CacheRange.m_TEnd, range.m_TEnd};
264 }
264 }
265 else {
265 else {
266 qCCritical(LOG_Variable()) << tr("Detection of unknown case.")
266 qCCritical(LOG_Variable())
267 << QThread::currentThread();
267 << tr("Detection of unknown case.") << QThread::currentThread();
268 }
268 }
269 }
269 }
270
270
271 return notInCache;
271 return notInCache;
272 }
272 }
273
273
274 QVector<SqpRange> Variable::provideInCacheRangeList(const SqpRange &range) const noexcept
274 QVector<SqpRange> Variable::provideInCacheRangeList(const SqpRange &range) const noexcept
275 {
275 {
276 // This code assume that cach in contigue. Can return 0 or 1 SqpRange
276 // This code assume that cach in contigue. Can return 0 or 1 SqpRange
277
277
278 auto inCache = QVector<SqpRange>{};
278 auto inCache = QVector<SqpRange>{};
279
279
280
280
281 if (this->intersect(range)) {
281 if (this->intersect(range)) {
282 if (range.m_TStart <= impl->m_CacheRange.m_TStart
282 if (range.m_TStart <= impl->m_CacheRange.m_TStart
283 && range.m_TEnd >= impl->m_CacheRange.m_TStart
283 && range.m_TEnd >= impl->m_CacheRange.m_TStart
284 && range.m_TEnd < impl->m_CacheRange.m_TEnd) {
284 && range.m_TEnd < impl->m_CacheRange.m_TEnd) {
285 inCache << SqpRange{impl->m_CacheRange.m_TStart, range.m_TEnd};
285 inCache << SqpRange{impl->m_CacheRange.m_TStart, range.m_TEnd};
286 }
286 }
287
287
288 else if (range.m_TStart >= impl->m_CacheRange.m_TStart
288 else if (range.m_TStart >= impl->m_CacheRange.m_TStart
289 && range.m_TEnd <= impl->m_CacheRange.m_TEnd) {
289 && range.m_TEnd <= impl->m_CacheRange.m_TEnd) {
290 inCache << range;
290 inCache << range;
291 }
291 }
292 else if (range.m_TStart > impl->m_CacheRange.m_TStart
292 else if (range.m_TStart > impl->m_CacheRange.m_TStart
293 && range.m_TEnd > impl->m_CacheRange.m_TEnd) {
293 && range.m_TEnd > impl->m_CacheRange.m_TEnd) {
294 inCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TEnd};
294 inCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TEnd};
295 }
295 }
296 else if (range.m_TStart <= impl->m_CacheRange.m_TStart
296 else if (range.m_TStart <= impl->m_CacheRange.m_TStart
297 && range.m_TEnd >= impl->m_CacheRange.m_TEnd) {
297 && range.m_TEnd >= impl->m_CacheRange.m_TEnd) {
298 inCache << impl->m_CacheRange;
298 inCache << impl->m_CacheRange;
299 }
299 }
300 else {
300 else {
301 qCCritical(LOG_Variable()) << tr("Detection of unknown case.")
301 qCCritical(LOG_Variable())
302 << QThread::currentThread();
302 << tr("Detection of unknown case.") << QThread::currentThread();
303 }
303 }
304 }
304 }
305
305
306 return inCache;
306 return inCache;
307 }
307 }
@@ -1,238 +1,238
1 #include "Variable/VariableAcquisitionWorker.h"
1 #include "Variable/VariableAcquisitionWorker.h"
2
2
3 #include "Variable/Variable.h"
3 #include "Variable/Variable.h"
4
4
5 #include <Data/AcquisitionRequest.h>
5 #include <Data/AcquisitionRequest.h>
6 #include <Data/SqpRange.h>
6 #include <Data/SqpRange.h>
7
7
8 #include <unordered_map>
8 #include <unordered_map>
9 #include <utility>
9 #include <utility>
10
10
11 #include <QMutex>
11 #include <QMutex>
12 #include <QReadWriteLock>
12 #include <QReadWriteLock>
13 #include <QThread>
13 #include <QThread>
14
14
15 Q_LOGGING_CATEGORY(LOG_VariableAcquisitionWorker, "VariableAcquisitionWorker")
15 Q_LOGGING_CATEGORY(LOG_VariableAcquisitionWorker, "VariableAcquisitionWorker")
16
16
17 struct VariableAcquisitionWorker::VariableAcquisitionWorkerPrivate {
17 struct VariableAcquisitionWorker::VariableAcquisitionWorkerPrivate {
18
18
19 explicit VariableAcquisitionWorkerPrivate() : m_Lock{QReadWriteLock::Recursive} {}
19 explicit VariableAcquisitionWorkerPrivate() : m_Lock{QReadWriteLock::Recursive} {}
20
20
21 void lockRead() { m_Lock.lockForRead(); }
21 void lockRead() { m_Lock.lockForRead(); }
22 void lockWrite() { m_Lock.lockForWrite(); }
22 void lockWrite() { m_Lock.lockForWrite(); }
23 void unlock() { m_Lock.unlock(); }
23 void unlock() { m_Lock.unlock(); }
24
24
25 void removeVariableRequest(QUuid vIdentifier);
25 void removeVariableRequest(QUuid vIdentifier);
26
26
27 QMutex m_WorkingMutex;
27 QMutex m_WorkingMutex;
28 QReadWriteLock m_Lock;
28 QReadWriteLock m_Lock;
29
29
30 std::map<QUuid, QVector<AcquisitionDataPacket> > m_AcqIdentifierToAcqDataPacketVectorMap;
30 std::map<QUuid, QVector<AcquisitionDataPacket> > m_AcqIdentifierToAcqDataPacketVectorMap;
31 std::map<QUuid, AcquisitionRequest> m_AcqIdentifierToAcqRequestMap;
31 std::map<QUuid, AcquisitionRequest> m_AcqIdentifierToAcqRequestMap;
32 std::map<QUuid, std::pair<QUuid, QUuid> > m_VIdentifierToCurrrentAcqIdNextIdPairMap;
32 std::map<QUuid, std::pair<QUuid, QUuid> > m_VIdentifierToCurrrentAcqIdNextIdPairMap;
33 };
33 };
34
34
35
35
36 VariableAcquisitionWorker::VariableAcquisitionWorker(QObject *parent)
36 VariableAcquisitionWorker::VariableAcquisitionWorker(QObject *parent)
37 : QObject{parent}, impl{spimpl::make_unique_impl<VariableAcquisitionWorkerPrivate>()}
37 : QObject{parent}, impl{spimpl::make_unique_impl<VariableAcquisitionWorkerPrivate>()}
38 {
38 {
39 }
39 }
40
40
41 VariableAcquisitionWorker::~VariableAcquisitionWorker()
41 VariableAcquisitionWorker::~VariableAcquisitionWorker()
42 {
42 {
43 qCInfo(LOG_VariableAcquisitionWorker()) << tr("VariableAcquisitionWorker destruction")
43 qCInfo(LOG_VariableAcquisitionWorker())
44 << QThread::currentThread();
44 << tr("VariableAcquisitionWorker destruction") << QThread::currentThread();
45 this->waitForFinish();
45 this->waitForFinish();
46 }
46 }
47
47
48
48
49 QUuid VariableAcquisitionWorker::pushVariableRequest(QUuid varRequestId, QUuid vIdentifier,
49 QUuid VariableAcquisitionWorker::pushVariableRequest(QUuid varRequestId, QUuid vIdentifier,
50 SqpRange rangeRequested,
50 SqpRange rangeRequested,
51 SqpRange cacheRangeRequested,
51 SqpRange cacheRangeRequested,
52 DataProviderParameters parameters,
52 DataProviderParameters parameters,
53 std::shared_ptr<IDataProvider> provider)
53 std::shared_ptr<IDataProvider> provider)
54 {
54 {
55 qCDebug(LOG_VariableAcquisitionWorker())
55 qCDebug(LOG_VariableAcquisitionWorker())
56 << tr("TORM VariableAcquisitionWorker::pushVariableRequest ") << cacheRangeRequested;
56 << tr("TORM VariableAcquisitionWorker::pushVariableRequest ") << cacheRangeRequested;
57 auto varRequestIdCanceled = QUuid();
57 auto varRequestIdCanceled = QUuid();
58
58
59 // Request creation
59 // Request creation
60 auto acqRequest = AcquisitionRequest{};
60 auto acqRequest = AcquisitionRequest{};
61 acqRequest.m_VarRequestId = varRequestId;
61 acqRequest.m_VarRequestId = varRequestId;
62 acqRequest.m_vIdentifier = vIdentifier;
62 acqRequest.m_vIdentifier = vIdentifier;
63 acqRequest.m_DataProviderParameters = parameters;
63 acqRequest.m_DataProviderParameters = parameters;
64 acqRequest.m_RangeRequested = rangeRequested;
64 acqRequest.m_RangeRequested = rangeRequested;
65 acqRequest.m_CacheRangeRequested = cacheRangeRequested;
65 acqRequest.m_CacheRangeRequested = cacheRangeRequested;
66 acqRequest.m_Size = parameters.m_Times.size();
66 acqRequest.m_Size = parameters.m_Times.size();
67 acqRequest.m_Provider = provider;
67 acqRequest.m_Provider = provider;
68
68
69
69
70 // Register request
70 // Register request
71 impl->lockWrite();
71 impl->lockWrite();
72 impl->m_AcqIdentifierToAcqRequestMap.insert(
72 impl->m_AcqIdentifierToAcqRequestMap.insert(
73 std::make_pair(acqRequest.m_AcqIdentifier, acqRequest));
73 std::make_pair(acqRequest.m_AcqIdentifier, acqRequest));
74
74
75 auto it = impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.find(vIdentifier);
75 auto it = impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.find(vIdentifier);
76 if (it != impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.cend()) {
76 if (it != impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.cend()) {
77 // A current request already exists, we can replace the next one
77 // A current request already exists, we can replace the next one
78 auto nextAcqId = it->second.second;
78 auto nextAcqId = it->second.second;
79 auto acqIdentifierToAcqRequestMapIt = impl->m_AcqIdentifierToAcqRequestMap.find(nextAcqId);
79 auto acqIdentifierToAcqRequestMapIt = impl->m_AcqIdentifierToAcqRequestMap.find(nextAcqId);
80 if (acqIdentifierToAcqRequestMapIt != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
80 if (acqIdentifierToAcqRequestMapIt != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
81 auto request = acqIdentifierToAcqRequestMapIt->second;
81 auto request = acqIdentifierToAcqRequestMapIt->second;
82 varRequestIdCanceled = request.m_VarRequestId;
82 varRequestIdCanceled = request.m_VarRequestId;
83 }
83 }
84
84
85 it->second.second = acqRequest.m_AcqIdentifier;
85 it->second.second = acqRequest.m_AcqIdentifier;
86 impl->unlock();
86 impl->unlock();
87 }
87 }
88 else {
88 else {
89 // First request for the variable, it must be stored and executed
89 // First request for the variable, it must be stored and executed
90 impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.insert(
90 impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.insert(
91 std::make_pair(vIdentifier, std::make_pair(acqRequest.m_AcqIdentifier, QUuid())));
91 std::make_pair(vIdentifier, std::make_pair(acqRequest.m_AcqIdentifier, QUuid())));
92 impl->unlock();
92 impl->unlock();
93
93
94 QMetaObject::invokeMethod(this, "onExecuteRequest", Qt::QueuedConnection,
94 QMetaObject::invokeMethod(this, "onExecuteRequest", Qt::QueuedConnection,
95 Q_ARG(QUuid, acqRequest.m_AcqIdentifier));
95 Q_ARG(QUuid, acqRequest.m_AcqIdentifier));
96 }
96 }
97
97
98 return varRequestIdCanceled;
98 return varRequestIdCanceled;
99 }
99 }
100
100
101 void VariableAcquisitionWorker::abortProgressRequested(QUuid vIdentifier)
101 void VariableAcquisitionWorker::abortProgressRequested(QUuid vIdentifier)
102 {
102 {
103 // TODO
103 // TODO
104 }
104 }
105
105
106 void VariableAcquisitionWorker::onVariableRetrieveDataInProgress(QUuid acqIdentifier,
106 void VariableAcquisitionWorker::onVariableRetrieveDataInProgress(QUuid acqIdentifier,
107 double progress)
107 double progress)
108 {
108 {
109 // TODO
109 // TODO
110 }
110 }
111
111
112 void VariableAcquisitionWorker::onVariableDataAcquired(QUuid acqIdentifier,
112 void VariableAcquisitionWorker::onVariableDataAcquired(QUuid acqIdentifier,
113 std::shared_ptr<IDataSeries> dataSeries,
113 std::shared_ptr<IDataSeries> dataSeries,
114 SqpRange dataRangeAcquired)
114 SqpRange dataRangeAcquired)
115 {
115 {
116 qCDebug(LOG_VariableAcquisitionWorker()) << tr("onVariableDataAcquired on range ")
116 qCDebug(LOG_VariableAcquisitionWorker())
117 << acqIdentifier << dataRangeAcquired;
117 << tr("onVariableDataAcquired on range ") << acqIdentifier << dataRangeAcquired;
118 impl->lockWrite();
118 impl->lockWrite();
119 auto aIdToARit = impl->m_AcqIdentifierToAcqRequestMap.find(acqIdentifier);
119 auto aIdToARit = impl->m_AcqIdentifierToAcqRequestMap.find(acqIdentifier);
120 if (aIdToARit != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
120 if (aIdToARit != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
121 // Store the result
121 // Store the result
122 auto dataPacket = AcquisitionDataPacket{};
122 auto dataPacket = AcquisitionDataPacket{};
123 dataPacket.m_Range = dataRangeAcquired;
123 dataPacket.m_Range = dataRangeAcquired;
124 dataPacket.m_DateSeries = dataSeries;
124 dataPacket.m_DateSeries = dataSeries;
125
125
126 auto aIdToADPVit = impl->m_AcqIdentifierToAcqDataPacketVectorMap.find(acqIdentifier);
126 auto aIdToADPVit = impl->m_AcqIdentifierToAcqDataPacketVectorMap.find(acqIdentifier);
127 if (aIdToADPVit != impl->m_AcqIdentifierToAcqDataPacketVectorMap.cend()) {
127 if (aIdToADPVit != impl->m_AcqIdentifierToAcqDataPacketVectorMap.cend()) {
128 // A current request result already exists, we can update it
128 // A current request result already exists, we can update it
129 aIdToADPVit->second.push_back(dataPacket);
129 aIdToADPVit->second.push_back(dataPacket);
130 }
130 }
131 else {
131 else {
132 // First request result for the variable, it must be stored
132 // First request result for the variable, it must be stored
133 impl->m_AcqIdentifierToAcqDataPacketVectorMap.insert(
133 impl->m_AcqIdentifierToAcqDataPacketVectorMap.insert(
134 std::make_pair(acqIdentifier, QVector<AcquisitionDataPacket>() << dataPacket));
134 std::make_pair(acqIdentifier, QVector<AcquisitionDataPacket>() << dataPacket));
135 }
135 }
136
136
137
137
138 // Decrement the counter of the request
138 // Decrement the counter of the request
139 auto &acqRequest = aIdToARit->second;
139 auto &acqRequest = aIdToARit->second;
140 acqRequest.m_Size = acqRequest.m_Size - 1;
140 acqRequest.m_Size = acqRequest.m_Size - 1;
141
141
142 // if the counter is 0, we can return data then run the next request if it exists and
142 // if the counter is 0, we can return data then run the next request if it exists and
143 // removed the finished request
143 // removed the finished request
144 if (acqRequest.m_Size == 0) {
144 if (acqRequest.m_Size == 0) {
145 // Return the data
145 // Return the data
146 aIdToADPVit = impl->m_AcqIdentifierToAcqDataPacketVectorMap.find(acqIdentifier);
146 aIdToADPVit = impl->m_AcqIdentifierToAcqDataPacketVectorMap.find(acqIdentifier);
147 if (aIdToADPVit != impl->m_AcqIdentifierToAcqDataPacketVectorMap.cend()) {
147 if (aIdToADPVit != impl->m_AcqIdentifierToAcqDataPacketVectorMap.cend()) {
148 emit dataProvided(acqRequest.m_vIdentifier, acqRequest.m_RangeRequested,
148 emit dataProvided(acqRequest.m_vIdentifier, acqRequest.m_RangeRequested,
149 acqRequest.m_CacheRangeRequested, aIdToADPVit->second);
149 acqRequest.m_CacheRangeRequested, aIdToADPVit->second);
150 }
150 }
151
151
152 // Execute the next one
152 // Execute the next one
153 auto it
153 auto it
154 = impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.find(acqRequest.m_vIdentifier);
154 = impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.find(acqRequest.m_vIdentifier);
155
155
156 if (it != impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.cend()) {
156 if (it != impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.cend()) {
157 if (it->second.second.isNull()) {
157 if (it->second.second.isNull()) {
158 // There is no next request, we can remove the variable request
158 // There is no next request, we can remove the variable request
159 impl->removeVariableRequest(acqRequest.m_vIdentifier);
159 impl->removeVariableRequest(acqRequest.m_vIdentifier);
160 }
160 }
161 else {
161 else {
162 auto acqIdentifierToRemove = it->second.first;
162 auto acqIdentifierToRemove = it->second.first;
163 // Move the next request to the current request
163 // Move the next request to the current request
164 it->second.first = it->second.second;
164 it->second.first = it->second.second;
165 it->second.second = QUuid();
165 it->second.second = QUuid();
166 // Remove AcquisitionRequest and results;
166 // Remove AcquisitionRequest and results;
167 impl->m_AcqIdentifierToAcqRequestMap.erase(acqIdentifierToRemove);
167 impl->m_AcqIdentifierToAcqRequestMap.erase(acqIdentifierToRemove);
168 impl->m_AcqIdentifierToAcqDataPacketVectorMap.erase(acqIdentifierToRemove);
168 impl->m_AcqIdentifierToAcqDataPacketVectorMap.erase(acqIdentifierToRemove);
169 // Execute the current request
169 // Execute the current request
170 QMetaObject::invokeMethod(this, "onExecuteRequest", Qt::QueuedConnection,
170 QMetaObject::invokeMethod(this, "onExecuteRequest", Qt::QueuedConnection,
171 Q_ARG(QUuid, it->second.first));
171 Q_ARG(QUuid, it->second.first));
172 }
172 }
173 }
173 }
174 else {
174 else {
175 qCCritical(LOG_VariableAcquisitionWorker())
175 qCCritical(LOG_VariableAcquisitionWorker())
176 << tr("Impossible to execute the acquisition on an unfound variable ");
176 << tr("Impossible to execute the acquisition on an unfound variable ");
177 }
177 }
178 }
178 }
179 }
179 }
180 else {
180 else {
181 qCCritical(LOG_VariableAcquisitionWorker())
181 qCCritical(LOG_VariableAcquisitionWorker())
182 << tr("Impossible to retrieve AcquisitionRequest for the incoming data");
182 << tr("Impossible to retrieve AcquisitionRequest for the incoming data");
183 }
183 }
184 impl->unlock();
184 impl->unlock();
185 }
185 }
186
186
187 void VariableAcquisitionWorker::initialize()
187 void VariableAcquisitionWorker::initialize()
188 {
188 {
189 qCDebug(LOG_VariableAcquisitionWorker()) << tr("VariableAcquisitionWorker init")
189 qCDebug(LOG_VariableAcquisitionWorker())
190 << QThread::currentThread();
190 << tr("VariableAcquisitionWorker init") << QThread::currentThread();
191 impl->m_WorkingMutex.lock();
191 impl->m_WorkingMutex.lock();
192 qCDebug(LOG_VariableAcquisitionWorker()) << tr("VariableAcquisitionWorker init END");
192 qCDebug(LOG_VariableAcquisitionWorker()) << tr("VariableAcquisitionWorker init END");
193 }
193 }
194
194
195 void VariableAcquisitionWorker::finalize()
195 void VariableAcquisitionWorker::finalize()
196 {
196 {
197 impl->m_WorkingMutex.unlock();
197 impl->m_WorkingMutex.unlock();
198 }
198 }
199
199
200 void VariableAcquisitionWorker::waitForFinish()
200 void VariableAcquisitionWorker::waitForFinish()
201 {
201 {
202 QMutexLocker locker{&impl->m_WorkingMutex};
202 QMutexLocker locker{&impl->m_WorkingMutex};
203 }
203 }
204
204
205 void VariableAcquisitionWorker::VariableAcquisitionWorkerPrivate::removeVariableRequest(
205 void VariableAcquisitionWorker::VariableAcquisitionWorkerPrivate::removeVariableRequest(
206 QUuid vIdentifier)
206 QUuid vIdentifier)
207 {
207 {
208 lockWrite();
208 lockWrite();
209 auto it = m_VIdentifierToCurrrentAcqIdNextIdPairMap.find(vIdentifier);
209 auto it = m_VIdentifierToCurrrentAcqIdNextIdPairMap.find(vIdentifier);
210
210
211 if (it != m_VIdentifierToCurrrentAcqIdNextIdPairMap.cend()) {
211 if (it != m_VIdentifierToCurrrentAcqIdNextIdPairMap.cend()) {
212 // A current request already exists, we can replace the next one
212 // A current request already exists, we can replace the next one
213
213
214 m_AcqIdentifierToAcqRequestMap.erase(it->second.first);
214 m_AcqIdentifierToAcqRequestMap.erase(it->second.first);
215 m_AcqIdentifierToAcqDataPacketVectorMap.erase(it->second.first);
215 m_AcqIdentifierToAcqDataPacketVectorMap.erase(it->second.first);
216
216
217 m_AcqIdentifierToAcqRequestMap.erase(it->second.second);
217 m_AcqIdentifierToAcqRequestMap.erase(it->second.second);
218 m_AcqIdentifierToAcqDataPacketVectorMap.erase(it->second.second);
218 m_AcqIdentifierToAcqDataPacketVectorMap.erase(it->second.second);
219 }
219 }
220 m_VIdentifierToCurrrentAcqIdNextIdPairMap.erase(vIdentifier);
220 m_VIdentifierToCurrrentAcqIdNextIdPairMap.erase(vIdentifier);
221 unlock();
221 unlock();
222 }
222 }
223
223
224 void VariableAcquisitionWorker::onExecuteRequest(QUuid acqIdentifier)
224 void VariableAcquisitionWorker::onExecuteRequest(QUuid acqIdentifier)
225 {
225 {
226 qCDebug(LOG_VariableAcquisitionWorker()) << tr("onExecuteRequest") << QThread::currentThread();
226 qCDebug(LOG_VariableAcquisitionWorker()) << tr("onExecuteRequest") << QThread::currentThread();
227 impl->lockRead();
227 impl->lockRead();
228 auto it = impl->m_AcqIdentifierToAcqRequestMap.find(acqIdentifier);
228 auto it = impl->m_AcqIdentifierToAcqRequestMap.find(acqIdentifier);
229 if (it != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
229 if (it != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
230 auto request = it->second;
230 auto request = it->second;
231 impl->unlock();
231 impl->unlock();
232 request.m_Provider->requestDataLoading(acqIdentifier, request.m_DataProviderParameters);
232 request.m_Provider->requestDataLoading(acqIdentifier, request.m_DataProviderParameters);
233 }
233 }
234 else {
234 else {
235 impl->unlock();
235 impl->unlock();
236 // TODO log no acqIdentifier recognized
236 // TODO log no acqIdentifier recognized
237 }
237 }
238 }
238 }
@@ -1,225 +1,225
1 #include "Variable/VariableCacheController.h"
1 #include "Variable/VariableCacheController.h"
2
2
3 #include "Variable/Variable.h"
3 #include "Variable/Variable.h"
4 #include <unordered_map>
4 #include <unordered_map>
5
5
6 #include <QThread>
6 #include <QThread>
7 Q_LOGGING_CATEGORY(LOG_VariableCacheController, "VariableCacheController")
7 Q_LOGGING_CATEGORY(LOG_VariableCacheController, "VariableCacheController")
8
8
9 struct VariableCacheController::VariableCacheControllerPrivate {
9 struct VariableCacheController::VariableCacheControllerPrivate {
10
10
11 std::unordered_map<std::shared_ptr<Variable>, QVector<SqpRange> > m_VariableToSqpRangeListMap;
11 std::unordered_map<std::shared_ptr<Variable>, QVector<SqpRange> > m_VariableToSqpRangeListMap;
12
12
13 void addInCacheDataByEnd(const SqpRange &dateTime, QVector<SqpRange> &dateTimeList,
13 void addInCacheDataByEnd(const SqpRange &dateTime, QVector<SqpRange> &dateTimeList,
14 QVector<SqpRange> &notInCache, int cacheIndex, double currentTStart);
14 QVector<SqpRange> &notInCache, int cacheIndex, double currentTStart);
15
15
16 void addInCacheDataByStart(const SqpRange &dateTime, QVector<SqpRange> &dateTimeList,
16 void addInCacheDataByStart(const SqpRange &dateTime, QVector<SqpRange> &dateTimeList,
17 QVector<SqpRange> &notInCache, int cacheIndex, double currentTStart);
17 QVector<SqpRange> &notInCache, int cacheIndex, double currentTStart);
18
18
19
19
20 void addDateTimeRecurse(const SqpRange &dateTime, QVector<SqpRange> &dateTimeList,
20 void addDateTimeRecurse(const SqpRange &dateTime, QVector<SqpRange> &dateTimeList,
21 int cacheIndex);
21 int cacheIndex);
22 };
22 };
23
23
24
24
25 VariableCacheController::VariableCacheController(QObject *parent)
25 VariableCacheController::VariableCacheController(QObject *parent)
26 : QObject{parent}, impl{spimpl::make_unique_impl<VariableCacheControllerPrivate>()}
26 : QObject{parent}, impl{spimpl::make_unique_impl<VariableCacheControllerPrivate>()}
27 {
27 {
28 }
28 }
29
29
30 void VariableCacheController::addDateTime(std::shared_ptr<Variable> variable,
30 void VariableCacheController::addDateTime(std::shared_ptr<Variable> variable,
31 const SqpRange &dateTime)
31 const SqpRange &dateTime)
32 {
32 {
33 qCDebug(LOG_VariableCacheController()) << "VariableCacheController::addDateTime"
33 qCDebug(LOG_VariableCacheController())
34 << QThread::currentThread()->objectName();
34 << "VariableCacheController::addDateTime" << QThread::currentThread()->objectName();
35 if (variable) {
35 if (variable) {
36 auto findVariableIte = impl->m_VariableToSqpRangeListMap.find(variable);
36 auto findVariableIte = impl->m_VariableToSqpRangeListMap.find(variable);
37 if (findVariableIte == impl->m_VariableToSqpRangeListMap.end()) {
37 if (findVariableIte == impl->m_VariableToSqpRangeListMap.end()) {
38 impl->m_VariableToSqpRangeListMap[variable].push_back(dateTime);
38 impl->m_VariableToSqpRangeListMap[variable].push_back(dateTime);
39 }
39 }
40 else {
40 else {
41
41
42 // addDateTime modify the list<SqpRange> of the variable in a way to ensure
42 // addDateTime modify the list<SqpRange> of the variable in a way to ensure
43 // that the list is ordered : l(0) < l(1). We assume also a < b
43 // that the list is ordered : l(0) < l(1). We assume also a < b
44 // (with a & b of type SqpRange) means ts(b) > te(a)
44 // (with a & b of type SqpRange) means ts(b) > te(a)
45
45
46 // The algorithm will try the merge of two interval:
46 // The algorithm will try the merge of two interval:
47 // - dateTime will be compare with the first interval of the list:
47 // - dateTime will be compare with the first interval of the list:
48 // A: if it is inferior, it will be inserted and it's finished.
48 // A: if it is inferior, it will be inserted and it's finished.
49 // B: if it is in intersection, it will be merge then the merged one
49 // B: if it is in intersection, it will be merge then the merged one
50 // will be compared to the next interval. The old one is remove from the list
50 // will be compared to the next interval. The old one is remove from the list
51 // C: if it is superior, we do the same with the next interval of the list
51 // C: if it is superior, we do the same with the next interval of the list
52
52
53 try {
53 try {
54 impl->addDateTimeRecurse(dateTime, impl->m_VariableToSqpRangeListMap.at(variable),
54 impl->addDateTimeRecurse(dateTime, impl->m_VariableToSqpRangeListMap.at(variable),
55 0);
55 0);
56 }
56 }
57 catch (const std::out_of_range &e) {
57 catch (const std::out_of_range &e) {
58 qCWarning(LOG_VariableCacheController()) << "addDateTime" << e.what();
58 qCWarning(LOG_VariableCacheController()) << "addDateTime" << e.what();
59 }
59 }
60 }
60 }
61 }
61 }
62 }
62 }
63
63
64 void VariableCacheController::clear(std::shared_ptr<Variable> variable) noexcept
64 void VariableCacheController::clear(std::shared_ptr<Variable> variable) noexcept
65 {
65 {
66 if (!variable) {
66 if (!variable) {
67 qCCritical(LOG_VariableCacheController()) << "Can't clear variable cache: variable is null";
67 qCCritical(LOG_VariableCacheController()) << "Can't clear variable cache: variable is null";
68 return;
68 return;
69 }
69 }
70
70
71 auto nbEntries = impl->m_VariableToSqpRangeListMap.erase(variable);
71 auto nbEntries = impl->m_VariableToSqpRangeListMap.erase(variable);
72
72
73 auto clearCacheMessage
73 auto clearCacheMessage
74 = (nbEntries != 0)
74 = (nbEntries != 0)
75 ? tr("Variable cache cleared for variable %1").arg(variable->name())
75 ? tr("Variable cache cleared for variable %1").arg(variable->name())
76 : tr("No deletion of variable cache: no cache was associated with the variable");
76 : tr("No deletion of variable cache: no cache was associated with the variable");
77 qCDebug(LOG_VariableCacheController()) << clearCacheMessage;
77 qCDebug(LOG_VariableCacheController()) << clearCacheMessage;
78 }
78 }
79
79
80 QVector<SqpRange>
80 QVector<SqpRange>
81 VariableCacheController::provideNotInCacheDateTimeList(std::shared_ptr<Variable> variable,
81 VariableCacheController::provideNotInCacheDateTimeList(std::shared_ptr<Variable> variable,
82 const SqpRange &dateTime)
82 const SqpRange &dateTime)
83 {
83 {
84 qCDebug(LOG_VariableCacheController())
84 qCDebug(LOG_VariableCacheController())
85 << "VariableCacheController::provideNotInCacheDateTimeList"
85 << "VariableCacheController::provideNotInCacheDateTimeList"
86 << QThread::currentThread()->objectName();
86 << QThread::currentThread()->objectName();
87 auto notInCache = QVector<SqpRange>{};
87 auto notInCache = QVector<SqpRange>{};
88
88
89 // This algorithm is recursif. The idea is to localise the start time then the end time in the
89 // This algorithm is recursif. The idea is to localise the start time then the end time in the
90 // list of date time request associated to the variable
90 // list of date time request associated to the variable
91 // We assume that the list is ordered in a way that l(0) < l(1). We assume also a < b
91 // We assume that the list is ordered in a way that l(0) < l(1). We assume also a < b
92 // (with a & b of type SqpRange) means ts(b) > te(a)
92 // (with a & b of type SqpRange) means ts(b) > te(a)
93 auto it = impl->m_VariableToSqpRangeListMap.find(variable);
93 auto it = impl->m_VariableToSqpRangeListMap.find(variable);
94 if (it != impl->m_VariableToSqpRangeListMap.end()) {
94 if (it != impl->m_VariableToSqpRangeListMap.end()) {
95 impl->addInCacheDataByStart(dateTime, it->second, notInCache, 0, dateTime.m_TStart);
95 impl->addInCacheDataByStart(dateTime, it->second, notInCache, 0, dateTime.m_TStart);
96 }
96 }
97 else {
97 else {
98 notInCache << dateTime;
98 notInCache << dateTime;
99 }
99 }
100
100
101 return notInCache;
101 return notInCache;
102 }
102 }
103
103
104 QVector<SqpRange>
104 QVector<SqpRange>
105 VariableCacheController::dateCacheList(std::shared_ptr<Variable> variable) const noexcept
105 VariableCacheController::dateCacheList(std::shared_ptr<Variable> variable) const noexcept
106 {
106 {
107 qCDebug(LOG_VariableCacheController()) << "VariableCacheController::dateCacheList"
107 qCDebug(LOG_VariableCacheController())
108 << QThread::currentThread()->objectName();
108 << "VariableCacheController::dateCacheList" << QThread::currentThread()->objectName();
109 try {
109 try {
110 return impl->m_VariableToSqpRangeListMap.at(variable);
110 return impl->m_VariableToSqpRangeListMap.at(variable);
111 }
111 }
112 catch (const std::out_of_range &e) {
112 catch (const std::out_of_range &e) {
113 qCWarning(LOG_VariableCacheController()) << e.what();
113 qCWarning(LOG_VariableCacheController()) << e.what();
114 return QVector<SqpRange>{};
114 return QVector<SqpRange>{};
115 }
115 }
116 }
116 }
117
117
118 void VariableCacheController::VariableCacheControllerPrivate::addDateTimeRecurse(
118 void VariableCacheController::VariableCacheControllerPrivate::addDateTimeRecurse(
119 const SqpRange &dateTime, QVector<SqpRange> &dateTimeList, int cacheIndex)
119 const SqpRange &dateTime, QVector<SqpRange> &dateTimeList, int cacheIndex)
120 {
120 {
121 const auto dateTimeListSize = dateTimeList.count();
121 const auto dateTimeListSize = dateTimeList.count();
122 if (cacheIndex >= dateTimeListSize) {
122 if (cacheIndex >= dateTimeListSize) {
123 dateTimeList.push_back(dateTime);
123 dateTimeList.push_back(dateTime);
124 // there is no anymore interval to compore, we can just push_back it
124 // there is no anymore interval to compore, we can just push_back it
125 return;
125 return;
126 }
126 }
127
127
128 auto currentDateTime = dateTimeList[cacheIndex];
128 auto currentDateTime = dateTimeList[cacheIndex];
129
129
130 if (dateTime.m_TEnd < currentDateTime.m_TStart) {
130 if (dateTime.m_TEnd < currentDateTime.m_TStart) {
131 // The compared one is < to current one compared, we can insert it
131 // The compared one is < to current one compared, we can insert it
132 dateTimeList.insert(cacheIndex, dateTime);
132 dateTimeList.insert(cacheIndex, dateTime);
133 }
133 }
134 else if (dateTime.m_TStart > currentDateTime.m_TEnd) {
134 else if (dateTime.m_TStart > currentDateTime.m_TEnd) {
135 // The compared one is > to current one compared we can comparet if to the next one
135 // The compared one is > to current one compared we can comparet if to the next one
136 addDateTimeRecurse(dateTime, dateTimeList, ++cacheIndex);
136 addDateTimeRecurse(dateTime, dateTimeList, ++cacheIndex);
137 }
137 }
138 else {
138 else {
139 // Merge cases: we need to merge the two interval, remove the old one from the list then
139 // Merge cases: we need to merge the two interval, remove the old one from the list then
140 // rerun the algo from this index with the merged interval
140 // rerun the algo from this index with the merged interval
141 auto mTStart = std::min(dateTime.m_TStart, currentDateTime.m_TStart);
141 auto mTStart = std::min(dateTime.m_TStart, currentDateTime.m_TStart);
142 auto mTEnd = std::max(dateTime.m_TEnd, currentDateTime.m_TEnd);
142 auto mTEnd = std::max(dateTime.m_TEnd, currentDateTime.m_TEnd);
143 auto mergeDateTime = SqpRange{mTStart, mTEnd};
143 auto mergeDateTime = SqpRange{mTStart, mTEnd};
144
144
145 dateTimeList.remove(cacheIndex);
145 dateTimeList.remove(cacheIndex);
146 addDateTimeRecurse(mergeDateTime, dateTimeList, cacheIndex);
146 addDateTimeRecurse(mergeDateTime, dateTimeList, cacheIndex);
147 }
147 }
148 }
148 }
149
149
150
150
151 void VariableCacheController::VariableCacheControllerPrivate::addInCacheDataByEnd(
151 void VariableCacheController::VariableCacheControllerPrivate::addInCacheDataByEnd(
152 const SqpRange &dateTime, QVector<SqpRange> &dateTimeList, QVector<SqpRange> &notInCache,
152 const SqpRange &dateTime, QVector<SqpRange> &dateTimeList, QVector<SqpRange> &notInCache,
153 int cacheIndex, double currentTStart)
153 int cacheIndex, double currentTStart)
154 {
154 {
155 const auto dateTimeListSize = dateTimeList.count();
155 const auto dateTimeListSize = dateTimeList.count();
156 if (cacheIndex >= dateTimeListSize) {
156 if (cacheIndex >= dateTimeListSize) {
157 if (currentTStart < dateTime.m_TEnd) {
157 if (currentTStart < dateTime.m_TEnd) {
158
158
159 // te localised after all other interval: The last interval is [currentTsart, te]
159 // te localised after all other interval: The last interval is [currentTsart, te]
160 notInCache.push_back(SqpRange{currentTStart, dateTime.m_TEnd});
160 notInCache.push_back(SqpRange{currentTStart, dateTime.m_TEnd});
161 }
161 }
162 return;
162 return;
163 }
163 }
164
164
165 auto currentDateTimeJ = dateTimeList[cacheIndex];
165 auto currentDateTimeJ = dateTimeList[cacheIndex];
166 if (dateTime.m_TEnd <= currentDateTimeJ.m_TStart) {
166 if (dateTime.m_TEnd <= currentDateTimeJ.m_TStart) {
167 // te localised between to interval: The last interval is [currentTsart, te]
167 // te localised between to interval: The last interval is [currentTsart, te]
168 notInCache.push_back(SqpRange{currentTStart, dateTime.m_TEnd});
168 notInCache.push_back(SqpRange{currentTStart, dateTime.m_TEnd});
169 }
169 }
170 else {
170 else {
171 notInCache.push_back(SqpRange{currentTStart, currentDateTimeJ.m_TStart});
171 notInCache.push_back(SqpRange{currentTStart, currentDateTimeJ.m_TStart});
172 if (dateTime.m_TEnd > currentDateTimeJ.m_TEnd) {
172 if (dateTime.m_TEnd > currentDateTimeJ.m_TEnd) {
173 // te not localised before the current interval: we need to look at the next interval
173 // te not localised before the current interval: we need to look at the next interval
174 addInCacheDataByEnd(dateTime, dateTimeList, notInCache, ++cacheIndex,
174 addInCacheDataByEnd(dateTime, dateTimeList, notInCache, ++cacheIndex,
175 currentDateTimeJ.m_TEnd);
175 currentDateTimeJ.m_TEnd);
176 }
176 }
177 }
177 }
178 }
178 }
179
179
180 void VariableCacheController::VariableCacheControllerPrivate::addInCacheDataByStart(
180 void VariableCacheController::VariableCacheControllerPrivate::addInCacheDataByStart(
181 const SqpRange &dateTime, QVector<SqpRange> &dateTimeList, QVector<SqpRange> &notInCache,
181 const SqpRange &dateTime, QVector<SqpRange> &dateTimeList, QVector<SqpRange> &notInCache,
182 int cacheIndex, double currentTStart)
182 int cacheIndex, double currentTStart)
183 {
183 {
184 const auto dateTimeListSize = dateTimeList.count();
184 const auto dateTimeListSize = dateTimeList.count();
185 if (cacheIndex >= dateTimeListSize) {
185 if (cacheIndex >= dateTimeListSize) {
186 // ts localised after all other interval: The last interval is [ts, te]
186 // ts localised after all other interval: The last interval is [ts, te]
187 notInCache.push_back(SqpRange{currentTStart, dateTime.m_TEnd});
187 notInCache.push_back(SqpRange{currentTStart, dateTime.m_TEnd});
188 return;
188 return;
189 }
189 }
190
190
191 auto currentDateTimeI = dateTimeList[cacheIndex];
191 auto currentDateTimeI = dateTimeList[cacheIndex];
192 if (currentTStart < currentDateTimeI.m_TStart) {
192 if (currentTStart < currentDateTimeI.m_TStart) {
193
193
194 // ts localised between to interval: let's localized te
194 // ts localised between to interval: let's localized te
195 addInCacheDataByEnd(dateTime, dateTimeList, notInCache, cacheIndex, currentTStart);
195 addInCacheDataByEnd(dateTime, dateTimeList, notInCache, cacheIndex, currentTStart);
196 }
196 }
197 else if (currentTStart < currentDateTimeI.m_TEnd) {
197 else if (currentTStart < currentDateTimeI.m_TEnd) {
198 if (dateTime.m_TEnd > currentDateTimeI.m_TEnd) {
198 if (dateTime.m_TEnd > currentDateTimeI.m_TEnd) {
199 // ts not localised before the current interval: we need to look at the next interval
199 // ts not localised before the current interval: we need to look at the next interval
200 // We can assume now current tstart is the last interval tend, because data between them
200 // We can assume now current tstart is the last interval tend, because data between them
201 // are
201 // are
202 // in the cache
202 // in the cache
203 addInCacheDataByStart(dateTime, dateTimeList, notInCache, ++cacheIndex,
203 addInCacheDataByStart(dateTime, dateTimeList, notInCache, ++cacheIndex,
204 currentDateTimeI.m_TEnd);
204 currentDateTimeI.m_TEnd);
205 }
205 }
206 }
206 }
207 else {
207 else {
208 // ts not localised before the current interval: we need to look at the next interval
208 // ts not localised before the current interval: we need to look at the next interval
209 addInCacheDataByStart(dateTime, dateTimeList, notInCache, ++cacheIndex, currentTStart);
209 addInCacheDataByStart(dateTime, dateTimeList, notInCache, ++cacheIndex, currentTStart);
210 }
210 }
211 }
211 }
212
212
213
213
214 void VariableCacheController::displayCache(std::shared_ptr<Variable> variable) const
214 void VariableCacheController::displayCache(std::shared_ptr<Variable> variable) const
215 {
215 {
216 auto variableDateTimeList = impl->m_VariableToSqpRangeListMap.find(variable);
216 auto variableDateTimeList = impl->m_VariableToSqpRangeListMap.find(variable);
217 if (variableDateTimeList != impl->m_VariableToSqpRangeListMap.end()) {
217 if (variableDateTimeList != impl->m_VariableToSqpRangeListMap.end()) {
218 qCInfo(LOG_VariableCacheController()) << tr("VariableCacheController::displayCache")
218 qCInfo(LOG_VariableCacheController())
219 << variableDateTimeList->second;
219 << tr("VariableCacheController::displayCache") << variableDateTimeList->second;
220 }
220 }
221 else {
221 else {
222 qCWarning(LOG_VariableCacheController())
222 qCWarning(LOG_VariableCacheController())
223 << tr("Cannot display a variable that is not in the cache");
223 << tr("Cannot display a variable that is not in the cache");
224 }
224 }
225 }
225 }
@@ -1,805 +1,805
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/VariableController.h>
4 #include <Variable/VariableController.h>
5 #include <Variable/VariableModel.h>
5 #include <Variable/VariableModel.h>
6 #include <Variable/VariableSynchronizationGroup.h>
6 #include <Variable/VariableSynchronizationGroup.h>
7
7
8 #include <Data/DataProviderParameters.h>
8 #include <Data/DataProviderParameters.h>
9 #include <Data/IDataProvider.h>
9 #include <Data/IDataProvider.h>
10 #include <Data/IDataSeries.h>
10 #include <Data/IDataSeries.h>
11 #include <Data/VariableRequest.h>
11 #include <Data/VariableRequest.h>
12 #include <Time/TimeController.h>
12 #include <Time/TimeController.h>
13
13
14 #include <QMutex>
14 #include <QMutex>
15 #include <QThread>
15 #include <QThread>
16 #include <QUuid>
16 #include <QUuid>
17 #include <QtCore/QItemSelectionModel>
17 #include <QtCore/QItemSelectionModel>
18
18
19 #include <deque>
19 #include <deque>
20 #include <set>
20 #include <set>
21 #include <unordered_map>
21 #include <unordered_map>
22
22
23 Q_LOGGING_CATEGORY(LOG_VariableController, "VariableController")
23 Q_LOGGING_CATEGORY(LOG_VariableController, "VariableController")
24
24
25 namespace {
25 namespace {
26
26
27 SqpRange computeSynchroRangeRequested(const SqpRange &varRange, const SqpRange &graphRange,
27 SqpRange computeSynchroRangeRequested(const SqpRange &varRange, const SqpRange &graphRange,
28 const SqpRange &oldGraphRange)
28 const SqpRange &oldGraphRange)
29 {
29 {
30 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
30 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
31
31
32 auto varRangeRequested = varRange;
32 auto varRangeRequested = varRange;
33 switch (zoomType) {
33 switch (zoomType) {
34 case AcquisitionZoomType::ZoomIn: {
34 case AcquisitionZoomType::ZoomIn: {
35 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
35 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
36 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
36 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
37 varRangeRequested.m_TStart += deltaLeft;
37 varRangeRequested.m_TStart += deltaLeft;
38 varRangeRequested.m_TEnd -= deltaRight;
38 varRangeRequested.m_TEnd -= deltaRight;
39 break;
39 break;
40 }
40 }
41
41
42 case AcquisitionZoomType::ZoomOut: {
42 case AcquisitionZoomType::ZoomOut: {
43 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
43 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
44 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
44 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
45 varRangeRequested.m_TStart -= deltaLeft;
45 varRangeRequested.m_TStart -= deltaLeft;
46 varRangeRequested.m_TEnd += deltaRight;
46 varRangeRequested.m_TEnd += deltaRight;
47 break;
47 break;
48 }
48 }
49 case AcquisitionZoomType::PanRight: {
49 case AcquisitionZoomType::PanRight: {
50 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
50 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
51 varRangeRequested.m_TStart += deltaRight;
51 varRangeRequested.m_TStart += deltaRight;
52 varRangeRequested.m_TEnd += deltaRight;
52 varRangeRequested.m_TEnd += deltaRight;
53 break;
53 break;
54 }
54 }
55 case AcquisitionZoomType::PanLeft: {
55 case AcquisitionZoomType::PanLeft: {
56 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
56 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
57 varRangeRequested.m_TStart -= deltaLeft;
57 varRangeRequested.m_TStart -= deltaLeft;
58 varRangeRequested.m_TEnd -= deltaLeft;
58 varRangeRequested.m_TEnd -= deltaLeft;
59 break;
59 break;
60 }
60 }
61 case AcquisitionZoomType::Unknown: {
61 case AcquisitionZoomType::Unknown: {
62 qCCritical(LOG_VariableController())
62 qCCritical(LOG_VariableController())
63 << VariableController::tr("Impossible to synchronize: zoom type unknown");
63 << VariableController::tr("Impossible to synchronize: zoom type unknown");
64 break;
64 break;
65 }
65 }
66 default:
66 default:
67 qCCritical(LOG_VariableController()) << VariableController::tr(
67 qCCritical(LOG_VariableController()) << VariableController::tr(
68 "Impossible to synchronize: zoom type not take into account");
68 "Impossible to synchronize: zoom type not take into account");
69 // No action
69 // No action
70 break;
70 break;
71 }
71 }
72
72
73 return varRangeRequested;
73 return varRangeRequested;
74 }
74 }
75 }
75 }
76
76
77 struct VariableController::VariableControllerPrivate {
77 struct VariableController::VariableControllerPrivate {
78 explicit VariableControllerPrivate(VariableController *parent)
78 explicit VariableControllerPrivate(VariableController *parent)
79 : m_WorkingMutex{},
79 : m_WorkingMutex{},
80 m_VariableModel{new VariableModel{parent}},
80 m_VariableModel{new VariableModel{parent}},
81 m_VariableSelectionModel{new QItemSelectionModel{m_VariableModel, parent}},
81 m_VariableSelectionModel{new QItemSelectionModel{m_VariableModel, parent}},
82 m_VariableCacheStrategy{std::make_unique<VariableCacheStrategy>()},
82 m_VariableCacheStrategy{std::make_unique<VariableCacheStrategy>()},
83 m_VariableAcquisitionWorker{std::make_unique<VariableAcquisitionWorker>()},
83 m_VariableAcquisitionWorker{std::make_unique<VariableAcquisitionWorker>()},
84 q{parent}
84 q{parent}
85 {
85 {
86
86
87 m_VariableAcquisitionWorker->moveToThread(&m_VariableAcquisitionWorkerThread);
87 m_VariableAcquisitionWorker->moveToThread(&m_VariableAcquisitionWorkerThread);
88 m_VariableAcquisitionWorkerThread.setObjectName("VariableAcquisitionWorkerThread");
88 m_VariableAcquisitionWorkerThread.setObjectName("VariableAcquisitionWorkerThread");
89 }
89 }
90
90
91
91
92 virtual ~VariableControllerPrivate()
92 virtual ~VariableControllerPrivate()
93 {
93 {
94 qCDebug(LOG_VariableController()) << tr("VariableControllerPrivate destruction");
94 qCDebug(LOG_VariableController()) << tr("VariableControllerPrivate destruction");
95 m_VariableAcquisitionWorkerThread.quit();
95 m_VariableAcquisitionWorkerThread.quit();
96 m_VariableAcquisitionWorkerThread.wait();
96 m_VariableAcquisitionWorkerThread.wait();
97 }
97 }
98
98
99
99
100 void processRequest(std::shared_ptr<Variable> var, const SqpRange &rangeRequested,
100 void processRequest(std::shared_ptr<Variable> var, const SqpRange &rangeRequested,
101 QUuid varRequestId);
101 QUuid varRequestId);
102
102
103 QVector<SqpRange> provideNotInCacheDateTimeList(std::shared_ptr<Variable> variable,
103 QVector<SqpRange> provideNotInCacheDateTimeList(std::shared_ptr<Variable> variable,
104 const SqpRange &dateTime);
104 const SqpRange &dateTime);
105
105
106 std::shared_ptr<Variable> findVariable(QUuid vIdentifier);
106 std::shared_ptr<Variable> findVariable(QUuid vIdentifier);
107 std::shared_ptr<IDataSeries>
107 std::shared_ptr<IDataSeries>
108 retrieveDataSeries(const QVector<AcquisitionDataPacket> acqDataPacketVector);
108 retrieveDataSeries(const QVector<AcquisitionDataPacket> acqDataPacketVector);
109
109
110 void registerProvider(std::shared_ptr<IDataProvider> provider);
110 void registerProvider(std::shared_ptr<IDataProvider> provider);
111
111
112 void storeVariableRequest(QUuid varId, QUuid varRequestId, const VariableRequest &varRequest);
112 void storeVariableRequest(QUuid varId, QUuid varRequestId, const VariableRequest &varRequest);
113 QUuid acceptVariableRequest(QUuid varId, std::shared_ptr<IDataSeries> dataSeries);
113 QUuid acceptVariableRequest(QUuid varId, std::shared_ptr<IDataSeries> dataSeries);
114 void updateVariableRequest(QUuid varRequestId);
114 void updateVariableRequest(QUuid varRequestId);
115 void cancelVariableRequest(QUuid varRequestId);
115 void cancelVariableRequest(QUuid varRequestId);
116
116
117 QMutex m_WorkingMutex;
117 QMutex m_WorkingMutex;
118 /// Variable model. The VariableController has the ownership
118 /// Variable model. The VariableController has the ownership
119 VariableModel *m_VariableModel;
119 VariableModel *m_VariableModel;
120 QItemSelectionModel *m_VariableSelectionModel;
120 QItemSelectionModel *m_VariableSelectionModel;
121
121
122
122
123 TimeController *m_TimeController{nullptr};
123 TimeController *m_TimeController{nullptr};
124 std::unique_ptr<VariableCacheStrategy> m_VariableCacheStrategy;
124 std::unique_ptr<VariableCacheStrategy> m_VariableCacheStrategy;
125 std::unique_ptr<VariableAcquisitionWorker> m_VariableAcquisitionWorker;
125 std::unique_ptr<VariableAcquisitionWorker> m_VariableAcquisitionWorker;
126 QThread m_VariableAcquisitionWorkerThread;
126 QThread m_VariableAcquisitionWorkerThread;
127
127
128 std::unordered_map<std::shared_ptr<Variable>, std::shared_ptr<IDataProvider> >
128 std::unordered_map<std::shared_ptr<Variable>, std::shared_ptr<IDataProvider> >
129 m_VariableToProviderMap;
129 m_VariableToProviderMap;
130 std::unordered_map<std::shared_ptr<Variable>, QUuid> m_VariableToIdentifierMap;
130 std::unordered_map<std::shared_ptr<Variable>, QUuid> m_VariableToIdentifierMap;
131 std::map<QUuid, std::shared_ptr<VariableSynchronizationGroup> >
131 std::map<QUuid, std::shared_ptr<VariableSynchronizationGroup> >
132 m_GroupIdToVariableSynchronizationGroupMap;
132 m_GroupIdToVariableSynchronizationGroupMap;
133 std::map<QUuid, QUuid> m_VariableIdGroupIdMap;
133 std::map<QUuid, QUuid> m_VariableIdGroupIdMap;
134 std::set<std::shared_ptr<IDataProvider> > m_ProviderSet;
134 std::set<std::shared_ptr<IDataProvider> > m_ProviderSet;
135
135
136 std::map<QUuid, std::map<QUuid, VariableRequest> > m_VarRequestIdToVarIdVarRequestMap;
136 std::map<QUuid, std::map<QUuid, VariableRequest> > m_VarRequestIdToVarIdVarRequestMap;
137
137
138 std::map<QUuid, std::deque<QUuid> > m_VarIdToVarRequestIdQueueMap;
138 std::map<QUuid, std::deque<QUuid> > m_VarIdToVarRequestIdQueueMap;
139
139
140
140
141 VariableController *q;
141 VariableController *q;
142 };
142 };
143
143
144
144
145 VariableController::VariableController(QObject *parent)
145 VariableController::VariableController(QObject *parent)
146 : QObject{parent}, impl{spimpl::make_unique_impl<VariableControllerPrivate>(this)}
146 : QObject{parent}, impl{spimpl::make_unique_impl<VariableControllerPrivate>(this)}
147 {
147 {
148 qCDebug(LOG_VariableController()) << tr("VariableController construction")
148 qCDebug(LOG_VariableController())
149 << QThread::currentThread();
149 << tr("VariableController construction") << QThread::currentThread();
150
150
151 connect(impl->m_VariableModel, &VariableModel::abortProgessRequested, this,
151 connect(impl->m_VariableModel, &VariableModel::abortProgessRequested, this,
152 &VariableController::onAbortProgressRequested);
152 &VariableController::onAbortProgressRequested);
153
153
154 connect(impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::dataProvided, this,
154 connect(impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::dataProvided, this,
155 &VariableController::onDataProvided);
155 &VariableController::onDataProvided);
156 connect(impl->m_VariableAcquisitionWorker.get(),
156 connect(impl->m_VariableAcquisitionWorker.get(),
157 &VariableAcquisitionWorker::variableRequestInProgress, this,
157 &VariableAcquisitionWorker::variableRequestInProgress, this,
158 &VariableController::onVariableRetrieveDataInProgress);
158 &VariableController::onVariableRetrieveDataInProgress);
159
159
160 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::started,
160 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::started,
161 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::initialize);
161 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::initialize);
162 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::finished,
162 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::finished,
163 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::finalize);
163 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::finalize);
164
164
165
165
166 impl->m_VariableAcquisitionWorkerThread.start();
166 impl->m_VariableAcquisitionWorkerThread.start();
167 }
167 }
168
168
169 VariableController::~VariableController()
169 VariableController::~VariableController()
170 {
170 {
171 qCDebug(LOG_VariableController()) << tr("VariableController destruction")
171 qCDebug(LOG_VariableController())
172 << QThread::currentThread();
172 << tr("VariableController destruction") << QThread::currentThread();
173 this->waitForFinish();
173 this->waitForFinish();
174 }
174 }
175
175
176 VariableModel *VariableController::variableModel() noexcept
176 VariableModel *VariableController::variableModel() noexcept
177 {
177 {
178 return impl->m_VariableModel;
178 return impl->m_VariableModel;
179 }
179 }
180
180
181 QItemSelectionModel *VariableController::variableSelectionModel() noexcept
181 QItemSelectionModel *VariableController::variableSelectionModel() noexcept
182 {
182 {
183 return impl->m_VariableSelectionModel;
183 return impl->m_VariableSelectionModel;
184 }
184 }
185
185
186 void VariableController::setTimeController(TimeController *timeController) noexcept
186 void VariableController::setTimeController(TimeController *timeController) noexcept
187 {
187 {
188 impl->m_TimeController = timeController;
188 impl->m_TimeController = timeController;
189 }
189 }
190
190
191 std::shared_ptr<Variable>
191 std::shared_ptr<Variable>
192 VariableController::cloneVariable(std::shared_ptr<Variable> variable) noexcept
192 VariableController::cloneVariable(std::shared_ptr<Variable> variable) noexcept
193 {
193 {
194 if (impl->m_VariableModel->containsVariable(variable)) {
194 if (impl->m_VariableModel->containsVariable(variable)) {
195 // Clones variable
195 // Clones variable
196 auto duplicate = variable->clone();
196 auto duplicate = variable->clone();
197
197
198 // Adds clone to model
198 // Adds clone to model
199 impl->m_VariableModel->addVariable(duplicate);
199 impl->m_VariableModel->addVariable(duplicate);
200
200
201 // Generates clone identifier
201 // Generates clone identifier
202 impl->m_VariableToIdentifierMap[duplicate] = QUuid::createUuid();
202 impl->m_VariableToIdentifierMap[duplicate] = QUuid::createUuid();
203
203
204 // Registers provider
204 // Registers provider
205 auto variableProvider = impl->m_VariableToProviderMap.at(variable);
205 auto variableProvider = impl->m_VariableToProviderMap.at(variable);
206 auto duplicateProvider = variableProvider != nullptr ? variableProvider->clone() : nullptr;
206 auto duplicateProvider = variableProvider != nullptr ? variableProvider->clone() : nullptr;
207
207
208 impl->m_VariableToProviderMap[duplicate] = duplicateProvider;
208 impl->m_VariableToProviderMap[duplicate] = duplicateProvider;
209 if (duplicateProvider) {
209 if (duplicateProvider) {
210 impl->registerProvider(duplicateProvider);
210 impl->registerProvider(duplicateProvider);
211 }
211 }
212
212
213 return duplicate;
213 return duplicate;
214 }
214 }
215 else {
215 else {
216 qCCritical(LOG_VariableController())
216 qCCritical(LOG_VariableController())
217 << tr("Can't create duplicate of variable %1: variable not registered in the model")
217 << tr("Can't create duplicate of variable %1: variable not registered in the model")
218 .arg(variable->name());
218 .arg(variable->name());
219 return nullptr;
219 return nullptr;
220 }
220 }
221 }
221 }
222
222
223 void VariableController::deleteVariable(std::shared_ptr<Variable> variable) noexcept
223 void VariableController::deleteVariable(std::shared_ptr<Variable> variable) noexcept
224 {
224 {
225 if (!variable) {
225 if (!variable) {
226 qCCritical(LOG_VariableController()) << "Can't delete variable: variable is null";
226 qCCritical(LOG_VariableController()) << "Can't delete variable: variable is null";
227 return;
227 return;
228 }
228 }
229
229
230 // Spreads in SciQlop that the variable will be deleted, so that potential receivers can
230 // Spreads in SciQlop that the variable will be deleted, so that potential receivers can
231 // make some treatments before the deletion
231 // make some treatments before the deletion
232 emit variableAboutToBeDeleted(variable);
232 emit variableAboutToBeDeleted(variable);
233
233
234 // Deletes identifier
234 // Deletes identifier
235 impl->m_VariableToIdentifierMap.erase(variable);
235 impl->m_VariableToIdentifierMap.erase(variable);
236
236
237 // Deletes provider
237 // Deletes provider
238 auto nbProvidersDeleted = impl->m_VariableToProviderMap.erase(variable);
238 auto nbProvidersDeleted = impl->m_VariableToProviderMap.erase(variable);
239 qCDebug(LOG_VariableController())
239 qCDebug(LOG_VariableController())
240 << tr("Number of providers deleted for variable %1: %2")
240 << tr("Number of providers deleted for variable %1: %2")
241 .arg(variable->name(), QString::number(nbProvidersDeleted));
241 .arg(variable->name(), QString::number(nbProvidersDeleted));
242
242
243
243
244 // Deletes from model
244 // Deletes from model
245 impl->m_VariableModel->deleteVariable(variable);
245 impl->m_VariableModel->deleteVariable(variable);
246 }
246 }
247
247
248 void VariableController::deleteVariables(
248 void VariableController::deleteVariables(
249 const QVector<std::shared_ptr<Variable> > &variables) noexcept
249 const QVector<std::shared_ptr<Variable> > &variables) noexcept
250 {
250 {
251 for (auto variable : qAsConst(variables)) {
251 for (auto variable : qAsConst(variables)) {
252 deleteVariable(variable);
252 deleteVariable(variable);
253 }
253 }
254 }
254 }
255
255
256 void VariableController::abortProgress(std::shared_ptr<Variable> variable)
256 void VariableController::abortProgress(std::shared_ptr<Variable> variable)
257 {
257 {
258 }
258 }
259
259
260 std::shared_ptr<Variable>
260 std::shared_ptr<Variable>
261 VariableController::createVariable(const QString &name, const QVariantHash &metadata,
261 VariableController::createVariable(const QString &name, const QVariantHash &metadata,
262 std::shared_ptr<IDataProvider> provider) noexcept
262 std::shared_ptr<IDataProvider> provider) noexcept
263 {
263 {
264 if (!impl->m_TimeController) {
264 if (!impl->m_TimeController) {
265 qCCritical(LOG_VariableController())
265 qCCritical(LOG_VariableController())
266 << tr("Impossible to create variable: The time controller is null");
266 << tr("Impossible to create variable: The time controller is null");
267 return nullptr;
267 return nullptr;
268 }
268 }
269
269
270 auto range = impl->m_TimeController->dateTime();
270 auto range = impl->m_TimeController->dateTime();
271
271
272 if (auto newVariable = impl->m_VariableModel->createVariable(name, range, metadata)) {
272 if (auto newVariable = impl->m_VariableModel->createVariable(name, range, metadata)) {
273 auto identifier = QUuid::createUuid();
273 auto identifier = QUuid::createUuid();
274
274
275 // store the provider
275 // store the provider
276 impl->registerProvider(provider);
276 impl->registerProvider(provider);
277
277
278 // Associate the provider
278 // Associate the provider
279 impl->m_VariableToProviderMap[newVariable] = provider;
279 impl->m_VariableToProviderMap[newVariable] = provider;
280 impl->m_VariableToIdentifierMap[newVariable] = identifier;
280 impl->m_VariableToIdentifierMap[newVariable] = identifier;
281
281
282
282
283 auto varRequestId = QUuid::createUuid();
283 auto varRequestId = QUuid::createUuid();
284 qCInfo(LOG_VariableController()) << "processRequest for" << name << varRequestId;
284 qCInfo(LOG_VariableController()) << "processRequest for" << name << varRequestId;
285 impl->processRequest(newVariable, range, varRequestId);
285 impl->processRequest(newVariable, range, varRequestId);
286 impl->updateVariableRequest(varRequestId);
286 impl->updateVariableRequest(varRequestId);
287
287
288 return newVariable;
288 return newVariable;
289 }
289 }
290 }
290 }
291
291
292 void VariableController::onDateTimeOnSelection(const SqpRange &dateTime)
292 void VariableController::onDateTimeOnSelection(const SqpRange &dateTime)
293 {
293 {
294 // TODO check synchronisation and Rescale
294 // TODO check synchronisation and Rescale
295 qCDebug(LOG_VariableController()) << "VariableController::onDateTimeOnSelection"
295 qCDebug(LOG_VariableController())
296 << QThread::currentThread()->objectName();
296 << "VariableController::onDateTimeOnSelection" << QThread::currentThread()->objectName();
297 auto selectedRows = impl->m_VariableSelectionModel->selectedRows();
297 auto selectedRows = impl->m_VariableSelectionModel->selectedRows();
298 auto varRequestId = QUuid::createUuid();
298 auto varRequestId = QUuid::createUuid();
299
299
300 for (const auto &selectedRow : qAsConst(selectedRows)) {
300 for (const auto &selectedRow : qAsConst(selectedRows)) {
301 if (auto selectedVariable = impl->m_VariableModel->variable(selectedRow.row())) {
301 if (auto selectedVariable = impl->m_VariableModel->variable(selectedRow.row())) {
302 selectedVariable->setRange(dateTime);
302 selectedVariable->setRange(dateTime);
303 impl->processRequest(selectedVariable, dateTime, varRequestId);
303 impl->processRequest(selectedVariable, dateTime, varRequestId);
304
304
305 // notify that rescale operation has to be done
305 // notify that rescale operation has to be done
306 emit rangeChanged(selectedVariable, dateTime);
306 emit rangeChanged(selectedVariable, dateTime);
307 }
307 }
308 }
308 }
309 impl->updateVariableRequest(varRequestId);
309 impl->updateVariableRequest(varRequestId);
310 }
310 }
311
311
312 void VariableController::onDataProvided(QUuid vIdentifier, const SqpRange &rangeRequested,
312 void VariableController::onDataProvided(QUuid vIdentifier, const SqpRange &rangeRequested,
313 const SqpRange &cacheRangeRequested,
313 const SqpRange &cacheRangeRequested,
314 QVector<AcquisitionDataPacket> dataAcquired)
314 QVector<AcquisitionDataPacket> dataAcquired)
315 {
315 {
316 auto retrievedDataSeries = impl->retrieveDataSeries(dataAcquired);
316 auto retrievedDataSeries = impl->retrieveDataSeries(dataAcquired);
317 auto varRequestId = impl->acceptVariableRequest(vIdentifier, retrievedDataSeries);
317 auto varRequestId = impl->acceptVariableRequest(vIdentifier, retrievedDataSeries);
318 if (!varRequestId.isNull()) {
318 if (!varRequestId.isNull()) {
319 impl->updateVariableRequest(varRequestId);
319 impl->updateVariableRequest(varRequestId);
320 }
320 }
321 }
321 }
322
322
323 void VariableController::onVariableRetrieveDataInProgress(QUuid identifier, double progress)
323 void VariableController::onVariableRetrieveDataInProgress(QUuid identifier, double progress)
324 {
324 {
325 if (auto var = impl->findVariable(identifier)) {
325 if (auto var = impl->findVariable(identifier)) {
326 impl->m_VariableModel->setDataProgress(var, progress);
326 impl->m_VariableModel->setDataProgress(var, progress);
327 }
327 }
328 else {
328 else {
329 qCCritical(LOG_VariableController())
329 qCCritical(LOG_VariableController())
330 << tr("Impossible to notify progression of a null variable");
330 << tr("Impossible to notify progression of a null variable");
331 }
331 }
332 }
332 }
333
333
334 void VariableController::onAbortProgressRequested(std::shared_ptr<Variable> variable)
334 void VariableController::onAbortProgressRequested(std::shared_ptr<Variable> variable)
335 {
335 {
336 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAbortProgressRequested"
336 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAbortProgressRequested"
337 << QThread::currentThread()->objectName();
337 << QThread::currentThread()->objectName();
338
338
339 auto it = impl->m_VariableToIdentifierMap.find(variable);
339 auto it = impl->m_VariableToIdentifierMap.find(variable);
340 if (it != impl->m_VariableToIdentifierMap.cend()) {
340 if (it != impl->m_VariableToIdentifierMap.cend()) {
341 impl->m_VariableToProviderMap.at(variable)->requestDataAborting(it->second);
341 impl->m_VariableToProviderMap.at(variable)->requestDataAborting(it->second);
342 }
342 }
343 else {
343 else {
344 qCWarning(LOG_VariableController())
344 qCWarning(LOG_VariableController())
345 << tr("Aborting progression of inexistant variable detected !!!")
345 << tr("Aborting progression of inexistant variable detected !!!")
346 << QThread::currentThread()->objectName();
346 << QThread::currentThread()->objectName();
347 }
347 }
348 }
348 }
349
349
350 void VariableController::onAddSynchronizationGroupId(QUuid synchronizationGroupId)
350 void VariableController::onAddSynchronizationGroupId(QUuid synchronizationGroupId)
351 {
351 {
352 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronizationGroupId"
352 qCDebug(LOG_VariableController())
353 << QThread::currentThread()->objectName()
353 << "TORM: VariableController::onAddSynchronizationGroupId"
354 << synchronizationGroupId;
354 << QThread::currentThread()->objectName() << synchronizationGroupId;
355 auto vSynchroGroup = std::make_shared<VariableSynchronizationGroup>();
355 auto vSynchroGroup = std::make_shared<VariableSynchronizationGroup>();
356 impl->m_GroupIdToVariableSynchronizationGroupMap.insert(
356 impl->m_GroupIdToVariableSynchronizationGroupMap.insert(
357 std::make_pair(synchronizationGroupId, vSynchroGroup));
357 std::make_pair(synchronizationGroupId, vSynchroGroup));
358 }
358 }
359
359
360 void VariableController::onRemoveSynchronizationGroupId(QUuid synchronizationGroupId)
360 void VariableController::onRemoveSynchronizationGroupId(QUuid synchronizationGroupId)
361 {
361 {
362 impl->m_GroupIdToVariableSynchronizationGroupMap.erase(synchronizationGroupId);
362 impl->m_GroupIdToVariableSynchronizationGroupMap.erase(synchronizationGroupId);
363 }
363 }
364
364
365 void VariableController::onAddSynchronized(std::shared_ptr<Variable> variable,
365 void VariableController::onAddSynchronized(std::shared_ptr<Variable> variable,
366 QUuid synchronizationGroupId)
366 QUuid synchronizationGroupId)
367
367
368 {
368 {
369 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronized"
369 qCDebug(LOG_VariableController())
370 << synchronizationGroupId;
370 << "TORM: VariableController::onAddSynchronized" << synchronizationGroupId;
371 auto varToVarIdIt = impl->m_VariableToIdentifierMap.find(variable);
371 auto varToVarIdIt = impl->m_VariableToIdentifierMap.find(variable);
372 if (varToVarIdIt != impl->m_VariableToIdentifierMap.cend()) {
372 if (varToVarIdIt != impl->m_VariableToIdentifierMap.cend()) {
373 auto groupIdToVSGIt
373 auto groupIdToVSGIt
374 = impl->m_GroupIdToVariableSynchronizationGroupMap.find(synchronizationGroupId);
374 = impl->m_GroupIdToVariableSynchronizationGroupMap.find(synchronizationGroupId);
375 if (groupIdToVSGIt != impl->m_GroupIdToVariableSynchronizationGroupMap.cend()) {
375 if (groupIdToVSGIt != impl->m_GroupIdToVariableSynchronizationGroupMap.cend()) {
376 impl->m_VariableIdGroupIdMap.insert(
376 impl->m_VariableIdGroupIdMap.insert(
377 std::make_pair(varToVarIdIt->second, synchronizationGroupId));
377 std::make_pair(varToVarIdIt->second, synchronizationGroupId));
378 groupIdToVSGIt->second->addVariableId(varToVarIdIt->second);
378 groupIdToVSGIt->second->addVariableId(varToVarIdIt->second);
379 }
379 }
380 else {
380 else {
381 qCCritical(LOG_VariableController())
381 qCCritical(LOG_VariableController())
382 << tr("Impossible to synchronize a variable with an unknown sycnhronization group")
382 << tr("Impossible to synchronize a variable with an unknown sycnhronization group")
383 << variable->name();
383 << variable->name();
384 }
384 }
385 }
385 }
386 else {
386 else {
387 qCCritical(LOG_VariableController())
387 qCCritical(LOG_VariableController())
388 << tr("Impossible to synchronize a variable with no identifier") << variable->name();
388 << tr("Impossible to synchronize a variable with no identifier") << variable->name();
389 }
389 }
390 }
390 }
391
391
392 void VariableController::desynchronize(std::shared_ptr<Variable> variable,
392 void VariableController::desynchronize(std::shared_ptr<Variable> variable,
393 QUuid synchronizationGroupId)
393 QUuid synchronizationGroupId)
394 {
394 {
395 // Gets variable id
395 // Gets variable id
396 auto variableIt = impl->m_VariableToIdentifierMap.find(variable);
396 auto variableIt = impl->m_VariableToIdentifierMap.find(variable);
397 if (variableIt == impl->m_VariableToIdentifierMap.cend()) {
397 if (variableIt == impl->m_VariableToIdentifierMap.cend()) {
398 qCCritical(LOG_VariableController())
398 qCCritical(LOG_VariableController())
399 << tr("Can't desynchronize variable %1: variable identifier not found")
399 << tr("Can't desynchronize variable %1: variable identifier not found")
400 .arg(variable->name());
400 .arg(variable->name());
401 return;
401 return;
402 }
402 }
403
403
404 // Gets synchronization group
404 // Gets synchronization group
405 auto groupIt = impl->m_GroupIdToVariableSynchronizationGroupMap.find(synchronizationGroupId);
405 auto groupIt = impl->m_GroupIdToVariableSynchronizationGroupMap.find(synchronizationGroupId);
406 if (groupIt == impl->m_GroupIdToVariableSynchronizationGroupMap.cend()) {
406 if (groupIt == impl->m_GroupIdToVariableSynchronizationGroupMap.cend()) {
407 qCCritical(LOG_VariableController())
407 qCCritical(LOG_VariableController())
408 << tr("Can't desynchronize variable %1: unknown synchronization group")
408 << tr("Can't desynchronize variable %1: unknown synchronization group")
409 .arg(variable->name());
409 .arg(variable->name());
410 return;
410 return;
411 }
411 }
412
412
413 auto variableId = variableIt->second;
413 auto variableId = variableIt->second;
414
414
415 // Removes variable from synchronization group
415 // Removes variable from synchronization group
416 auto synchronizationGroup = groupIt->second;
416 auto synchronizationGroup = groupIt->second;
417 synchronizationGroup->removeVariableId(variableId);
417 synchronizationGroup->removeVariableId(variableId);
418
418
419 // Removes link between variable and synchronization group
419 // Removes link between variable and synchronization group
420 impl->m_VariableIdGroupIdMap.erase(variableId);
420 impl->m_VariableIdGroupIdMap.erase(variableId);
421 }
421 }
422
422
423 void VariableController::onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables,
423 void VariableController::onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables,
424 const SqpRange &range, const SqpRange &oldRange,
424 const SqpRange &range, const SqpRange &oldRange,
425 bool synchronise)
425 bool synchronise)
426 {
426 {
427 // NOTE: oldRange isn't really necessary since oldRange == variable->range().
427 // NOTE: oldRange isn't really necessary since oldRange == variable->range().
428
428
429 // we want to load data of the variable for the dateTime.
429 // we want to load data of the variable for the dateTime.
430 // First we check if the cache contains some of them.
430 // First we check if the cache contains some of them.
431 // For the other, we ask the provider to give them.
431 // For the other, we ask the provider to give them.
432
432
433 auto varRequestId = QUuid::createUuid();
433 auto varRequestId = QUuid::createUuid();
434 qCInfo(LOG_VariableController()) << "VariableController::onRequestDataLoading"
434 qCInfo(LOG_VariableController()) << "VariableController::onRequestDataLoading"
435 << QThread::currentThread()->objectName() << varRequestId;
435 << QThread::currentThread()->objectName() << varRequestId;
436
436
437 for (const auto &var : variables) {
437 for (const auto &var : variables) {
438 qCDebug(LOG_VariableController()) << "processRequest for" << var->name() << varRequestId;
438 qCDebug(LOG_VariableController()) << "processRequest for" << var->name() << varRequestId;
439 impl->processRequest(var, range, varRequestId);
439 impl->processRequest(var, range, varRequestId);
440 }
440 }
441
441
442 if (synchronise) {
442 if (synchronise) {
443 // Get the group ids
443 // Get the group ids
444 qCDebug(LOG_VariableController())
444 qCDebug(LOG_VariableController())
445 << "TORM VariableController::onRequestDataLoading for synchro var ENABLE";
445 << "TORM VariableController::onRequestDataLoading for synchro var ENABLE";
446 auto groupIds = std::set<QUuid>{};
446 auto groupIds = std::set<QUuid>{};
447 auto groupIdToOldRangeMap = std::map<QUuid, SqpRange>{};
447 auto groupIdToOldRangeMap = std::map<QUuid, SqpRange>{};
448 for (const auto &var : variables) {
448 for (const auto &var : variables) {
449 auto varToVarIdIt = impl->m_VariableToIdentifierMap.find(var);
449 auto varToVarIdIt = impl->m_VariableToIdentifierMap.find(var);
450 if (varToVarIdIt != impl->m_VariableToIdentifierMap.cend()) {
450 if (varToVarIdIt != impl->m_VariableToIdentifierMap.cend()) {
451 auto vId = varToVarIdIt->second;
451 auto vId = varToVarIdIt->second;
452 auto varIdToGroupIdIt = impl->m_VariableIdGroupIdMap.find(vId);
452 auto varIdToGroupIdIt = impl->m_VariableIdGroupIdMap.find(vId);
453 if (varIdToGroupIdIt != impl->m_VariableIdGroupIdMap.cend()) {
453 if (varIdToGroupIdIt != impl->m_VariableIdGroupIdMap.cend()) {
454 auto gId = varIdToGroupIdIt->second;
454 auto gId = varIdToGroupIdIt->second;
455 groupIdToOldRangeMap.insert(std::make_pair(gId, var->range()));
455 groupIdToOldRangeMap.insert(std::make_pair(gId, var->range()));
456 if (groupIds.find(gId) == groupIds.cend()) {
456 if (groupIds.find(gId) == groupIds.cend()) {
457 qCDebug(LOG_VariableController()) << "Synchro detect group " << gId;
457 qCDebug(LOG_VariableController()) << "Synchro detect group " << gId;
458 groupIds.insert(gId);
458 groupIds.insert(gId);
459 }
459 }
460 }
460 }
461 }
461 }
462 }
462 }
463
463
464 // We assume here all group ids exist
464 // We assume here all group ids exist
465 for (const auto &gId : groupIds) {
465 for (const auto &gId : groupIds) {
466 auto vSynchronizationGroup = impl->m_GroupIdToVariableSynchronizationGroupMap.at(gId);
466 auto vSynchronizationGroup = impl->m_GroupIdToVariableSynchronizationGroupMap.at(gId);
467 auto vSyncIds = vSynchronizationGroup->getIds();
467 auto vSyncIds = vSynchronizationGroup->getIds();
468 qCDebug(LOG_VariableController()) << "Var in synchro group ";
468 qCDebug(LOG_VariableController()) << "Var in synchro group ";
469 for (auto vId : vSyncIds) {
469 for (auto vId : vSyncIds) {
470 auto var = impl->findVariable(vId);
470 auto var = impl->findVariable(vId);
471
471
472 // Don't process already processed var
472 // Don't process already processed var
473 if (!variables.contains(var)) {
473 if (!variables.contains(var)) {
474 if (var != nullptr) {
474 if (var != nullptr) {
475 qCDebug(LOG_VariableController()) << "processRequest synchro for"
475 qCDebug(LOG_VariableController())
476 << var->name();
476 << "processRequest synchro for" << var->name();
477 auto vSyncRangeRequested = computeSynchroRangeRequested(
477 auto vSyncRangeRequested = computeSynchroRangeRequested(
478 var->range(), range, groupIdToOldRangeMap.at(gId));
478 var->range(), range, groupIdToOldRangeMap.at(gId));
479 qCDebug(LOG_VariableController()) << "synchro RR" << vSyncRangeRequested;
479 qCDebug(LOG_VariableController()) << "synchro RR" << vSyncRangeRequested;
480 impl->processRequest(var, vSyncRangeRequested, varRequestId);
480 impl->processRequest(var, vSyncRangeRequested, varRequestId);
481 }
481 }
482 else {
482 else {
483 qCCritical(LOG_VariableController())
483 qCCritical(LOG_VariableController())
484
484
485 << tr("Impossible to synchronize a null variable");
485 << tr("Impossible to synchronize a null variable");
486 }
486 }
487 }
487 }
488 }
488 }
489 }
489 }
490 }
490 }
491
491
492 impl->updateVariableRequest(varRequestId);
492 impl->updateVariableRequest(varRequestId);
493 }
493 }
494
494
495
495
496 void VariableController::initialize()
496 void VariableController::initialize()
497 {
497 {
498 qCDebug(LOG_VariableController()) << tr("VariableController init") << QThread::currentThread();
498 qCDebug(LOG_VariableController()) << tr("VariableController init") << QThread::currentThread();
499 impl->m_WorkingMutex.lock();
499 impl->m_WorkingMutex.lock();
500 qCDebug(LOG_VariableController()) << tr("VariableController init END");
500 qCDebug(LOG_VariableController()) << tr("VariableController init END");
501 }
501 }
502
502
503 void VariableController::finalize()
503 void VariableController::finalize()
504 {
504 {
505 impl->m_WorkingMutex.unlock();
505 impl->m_WorkingMutex.unlock();
506 }
506 }
507
507
508 void VariableController::waitForFinish()
508 void VariableController::waitForFinish()
509 {
509 {
510 QMutexLocker locker{&impl->m_WorkingMutex};
510 QMutexLocker locker{&impl->m_WorkingMutex};
511 }
511 }
512
512
513 AcquisitionZoomType VariableController::getZoomType(const SqpRange &range, const SqpRange &oldRange)
513 AcquisitionZoomType VariableController::getZoomType(const SqpRange &range, const SqpRange &oldRange)
514 {
514 {
515 // t1.m_TStart <= t2.m_TStart && t2.m_TEnd <= t1.m_TEnd
515 // t1.m_TStart <= t2.m_TStart && t2.m_TEnd <= t1.m_TEnd
516 auto zoomType = AcquisitionZoomType::Unknown;
516 auto zoomType = AcquisitionZoomType::Unknown;
517 if (range.m_TStart <= oldRange.m_TStart && oldRange.m_TEnd <= range.m_TEnd) {
517 if (range.m_TStart <= oldRange.m_TStart && oldRange.m_TEnd <= range.m_TEnd) {
518 zoomType = AcquisitionZoomType::ZoomOut;
518 zoomType = AcquisitionZoomType::ZoomOut;
519 }
519 }
520 else if (range.m_TStart > oldRange.m_TStart && range.m_TEnd > oldRange.m_TEnd) {
520 else if (range.m_TStart > oldRange.m_TStart && range.m_TEnd > oldRange.m_TEnd) {
521 zoomType = AcquisitionZoomType::PanRight;
521 zoomType = AcquisitionZoomType::PanRight;
522 }
522 }
523 else if (range.m_TStart < oldRange.m_TStart && range.m_TEnd < oldRange.m_TEnd) {
523 else if (range.m_TStart < oldRange.m_TStart && range.m_TEnd < oldRange.m_TEnd) {
524 zoomType = AcquisitionZoomType::PanLeft;
524 zoomType = AcquisitionZoomType::PanLeft;
525 }
525 }
526 else if (range.m_TStart > oldRange.m_TStart && oldRange.m_TEnd > range.m_TEnd) {
526 else if (range.m_TStart > oldRange.m_TStart && oldRange.m_TEnd > range.m_TEnd) {
527 zoomType = AcquisitionZoomType::ZoomIn;
527 zoomType = AcquisitionZoomType::ZoomIn;
528 }
528 }
529 else {
529 else {
530 qCCritical(LOG_VariableController()) << "getZoomType: Unknown type detected";
530 qCCritical(LOG_VariableController()) << "getZoomType: Unknown type detected";
531 }
531 }
532 return zoomType;
532 return zoomType;
533 }
533 }
534
534
535 void VariableController::VariableControllerPrivate::processRequest(std::shared_ptr<Variable> var,
535 void VariableController::VariableControllerPrivate::processRequest(std::shared_ptr<Variable> var,
536 const SqpRange &rangeRequested,
536 const SqpRange &rangeRequested,
537 QUuid varRequestId)
537 QUuid varRequestId)
538 {
538 {
539
539
540 // TODO: protect at
540 // TODO: protect at
541 auto varRequest = VariableRequest{};
541 auto varRequest = VariableRequest{};
542 auto varId = m_VariableToIdentifierMap.at(var);
542 auto varId = m_VariableToIdentifierMap.at(var);
543
543
544 auto varStrategyRangesRequested
544 auto varStrategyRangesRequested
545 = m_VariableCacheStrategy->computeStrategyRanges(var->range(), rangeRequested);
545 = m_VariableCacheStrategy->computeStrategyRanges(var->range(), rangeRequested);
546 auto notInCacheRangeList = var->provideNotInCacheRangeList(varStrategyRangesRequested.second);
546 auto notInCacheRangeList = var->provideNotInCacheRangeList(varStrategyRangesRequested.second);
547 auto inCacheRangeList = var->provideInCacheRangeList(varStrategyRangesRequested.second);
547 auto inCacheRangeList = var->provideInCacheRangeList(varStrategyRangesRequested.second);
548
548
549 if (!notInCacheRangeList.empty()) {
549 if (!notInCacheRangeList.empty()) {
550 varRequest.m_RangeRequested = varStrategyRangesRequested.first;
550 varRequest.m_RangeRequested = varStrategyRangesRequested.first;
551 varRequest.m_CacheRangeRequested = varStrategyRangesRequested.second;
551 varRequest.m_CacheRangeRequested = varStrategyRangesRequested.second;
552 qCDebug(LOG_VariableAcquisitionWorker()) << tr("TORM processRequest RR ") << rangeRequested;
552 qCDebug(LOG_VariableAcquisitionWorker()) << tr("TORM processRequest RR ") << rangeRequested;
553 qCDebug(LOG_VariableAcquisitionWorker()) << tr("TORM processRequest R ")
553 qCDebug(LOG_VariableAcquisitionWorker())
554 << varStrategyRangesRequested.first;
554 << tr("TORM processRequest R ") << varStrategyRangesRequested.first;
555 qCDebug(LOG_VariableAcquisitionWorker()) << tr("TORM processRequest CR ")
555 qCDebug(LOG_VariableAcquisitionWorker())
556 << varStrategyRangesRequested.second;
556 << tr("TORM processRequest CR ") << varStrategyRangesRequested.second;
557 // store VarRequest
557 // store VarRequest
558 storeVariableRequest(varId, varRequestId, varRequest);
558 storeVariableRequest(varId, varRequestId, varRequest);
559
559
560 auto varProvider = m_VariableToProviderMap.at(var);
560 auto varProvider = m_VariableToProviderMap.at(var);
561 if (varProvider != nullptr) {
561 if (varProvider != nullptr) {
562 auto varRequestIdCanceled = m_VariableAcquisitionWorker->pushVariableRequest(
562 auto varRequestIdCanceled = m_VariableAcquisitionWorker->pushVariableRequest(
563 varRequestId, varId, varStrategyRangesRequested.first,
563 varRequestId, varId, varStrategyRangesRequested.first,
564 varStrategyRangesRequested.second,
564 varStrategyRangesRequested.second,
565 DataProviderParameters{std::move(notInCacheRangeList), var->metadata()},
565 DataProviderParameters{std::move(notInCacheRangeList), var->metadata()},
566 varProvider);
566 varProvider);
567
567
568 if (!varRequestIdCanceled.isNull()) {
568 if (!varRequestIdCanceled.isNull()) {
569 qCInfo(LOG_VariableAcquisitionWorker()) << tr("varRequestIdCanceled: ")
569 qCInfo(LOG_VariableAcquisitionWorker())
570 << varRequestIdCanceled;
570 << tr("varRequestIdCanceled: ") << varRequestIdCanceled;
571 cancelVariableRequest(varRequestIdCanceled);
571 cancelVariableRequest(varRequestIdCanceled);
572 }
572 }
573 }
573 }
574 else {
574 else {
575 qCCritical(LOG_VariableController())
575 qCCritical(LOG_VariableController())
576 << "Impossible to provide data with a null provider";
576 << "Impossible to provide data with a null provider";
577 }
577 }
578
578
579 if (!inCacheRangeList.empty()) {
579 if (!inCacheRangeList.empty()) {
580 emit q->updateVarDisplaying(var, inCacheRangeList.first());
580 emit q->updateVarDisplaying(var, inCacheRangeList.first());
581 }
581 }
582 }
582 }
583 else {
583 else {
584
584
585 varRequest.m_RangeRequested = varStrategyRangesRequested.first;
585 varRequest.m_RangeRequested = varStrategyRangesRequested.first;
586 varRequest.m_CacheRangeRequested = varStrategyRangesRequested.second;
586 varRequest.m_CacheRangeRequested = varStrategyRangesRequested.second;
587 // store VarRequest
587 // store VarRequest
588 storeVariableRequest(varId, varRequestId, varRequest);
588 storeVariableRequest(varId, varRequestId, varRequest);
589 acceptVariableRequest(varId,
589 acceptVariableRequest(varId,
590 var->dataSeries()->subDataSeries(varStrategyRangesRequested.second));
590 var->dataSeries()->subDataSeries(varStrategyRangesRequested.second));
591 }
591 }
592 }
592 }
593
593
594 std::shared_ptr<Variable>
594 std::shared_ptr<Variable>
595 VariableController::VariableControllerPrivate::findVariable(QUuid vIdentifier)
595 VariableController::VariableControllerPrivate::findVariable(QUuid vIdentifier)
596 {
596 {
597 std::shared_ptr<Variable> var;
597 std::shared_ptr<Variable> var;
598 auto findReply = [vIdentifier](const auto &entry) { return vIdentifier == entry.second; };
598 auto findReply = [vIdentifier](const auto &entry) { return vIdentifier == entry.second; };
599
599
600 auto end = m_VariableToIdentifierMap.cend();
600 auto end = m_VariableToIdentifierMap.cend();
601 auto it = std::find_if(m_VariableToIdentifierMap.cbegin(), end, findReply);
601 auto it = std::find_if(m_VariableToIdentifierMap.cbegin(), end, findReply);
602 if (it != end) {
602 if (it != end) {
603 var = it->first;
603 var = it->first;
604 }
604 }
605 else {
605 else {
606 qCCritical(LOG_VariableController())
606 qCCritical(LOG_VariableController())
607 << tr("Impossible to find the variable with the identifier: ") << vIdentifier;
607 << tr("Impossible to find the variable with the identifier: ") << vIdentifier;
608 }
608 }
609
609
610 return var;
610 return var;
611 }
611 }
612
612
613 std::shared_ptr<IDataSeries> VariableController::VariableControllerPrivate::retrieveDataSeries(
613 std::shared_ptr<IDataSeries> VariableController::VariableControllerPrivate::retrieveDataSeries(
614 const QVector<AcquisitionDataPacket> acqDataPacketVector)
614 const QVector<AcquisitionDataPacket> acqDataPacketVector)
615 {
615 {
616 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size")
616 qCDebug(LOG_VariableController())
617 << acqDataPacketVector.size();
617 << tr("TORM: retrieveDataSeries acqDataPacketVector size") << acqDataPacketVector.size();
618 std::shared_ptr<IDataSeries> dataSeries;
618 std::shared_ptr<IDataSeries> dataSeries;
619 if (!acqDataPacketVector.isEmpty()) {
619 if (!acqDataPacketVector.isEmpty()) {
620 dataSeries = acqDataPacketVector[0].m_DateSeries;
620 dataSeries = acqDataPacketVector[0].m_DateSeries;
621 for (int i = 1; i < acqDataPacketVector.size(); ++i) {
621 for (int i = 1; i < acqDataPacketVector.size(); ++i) {
622 dataSeries->merge(acqDataPacketVector[i].m_DateSeries.get());
622 dataSeries->merge(acqDataPacketVector[i].m_DateSeries.get());
623 }
623 }
624 }
624 }
625 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size END")
625 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size END")
626 << acqDataPacketVector.size();
626 << acqDataPacketVector.size();
627 return dataSeries;
627 return dataSeries;
628 }
628 }
629
629
630 void VariableController::VariableControllerPrivate::registerProvider(
630 void VariableController::VariableControllerPrivate::registerProvider(
631 std::shared_ptr<IDataProvider> provider)
631 std::shared_ptr<IDataProvider> provider)
632 {
632 {
633 if (m_ProviderSet.find(provider) == m_ProviderSet.end()) {
633 if (m_ProviderSet.find(provider) == m_ProviderSet.end()) {
634 qCDebug(LOG_VariableController()) << tr("Registering of a new provider")
634 qCDebug(LOG_VariableController())
635 << provider->objectName();
635 << tr("Registering of a new provider") << provider->objectName();
636 m_ProviderSet.insert(provider);
636 m_ProviderSet.insert(provider);
637 connect(provider.get(), &IDataProvider::dataProvided, m_VariableAcquisitionWorker.get(),
637 connect(provider.get(), &IDataProvider::dataProvided, m_VariableAcquisitionWorker.get(),
638 &VariableAcquisitionWorker::onVariableDataAcquired);
638 &VariableAcquisitionWorker::onVariableDataAcquired);
639 connect(provider.get(), &IDataProvider::dataProvidedProgress,
639 connect(provider.get(), &IDataProvider::dataProvidedProgress,
640 m_VariableAcquisitionWorker.get(),
640 m_VariableAcquisitionWorker.get(),
641 &VariableAcquisitionWorker::onVariableRetrieveDataInProgress);
641 &VariableAcquisitionWorker::onVariableRetrieveDataInProgress);
642 }
642 }
643 else {
643 else {
644 qCDebug(LOG_VariableController()) << tr("Cannot register provider, it already exists ");
644 qCDebug(LOG_VariableController()) << tr("Cannot register provider, it already exists ");
645 }
645 }
646 }
646 }
647
647
648 void VariableController::VariableControllerPrivate::storeVariableRequest(
648 void VariableController::VariableControllerPrivate::storeVariableRequest(
649 QUuid varId, QUuid varRequestId, const VariableRequest &varRequest)
649 QUuid varId, QUuid varRequestId, const VariableRequest &varRequest)
650 {
650 {
651 // First request for the variable. we can create an entry for it
651 // First request for the variable. we can create an entry for it
652 auto varIdToVarRequestIdQueueMapIt = m_VarIdToVarRequestIdQueueMap.find(varId);
652 auto varIdToVarRequestIdQueueMapIt = m_VarIdToVarRequestIdQueueMap.find(varId);
653 if (varIdToVarRequestIdQueueMapIt == m_VarIdToVarRequestIdQueueMap.cend()) {
653 if (varIdToVarRequestIdQueueMapIt == m_VarIdToVarRequestIdQueueMap.cend()) {
654 auto varRequestIdQueue = std::deque<QUuid>{};
654 auto varRequestIdQueue = std::deque<QUuid>{};
655 qCDebug(LOG_VariableController()) << tr("Store REQUEST in QUEUE");
655 qCDebug(LOG_VariableController()) << tr("Store REQUEST in QUEUE");
656 varRequestIdQueue.push_back(varRequestId);
656 varRequestIdQueue.push_back(varRequestId);
657 m_VarIdToVarRequestIdQueueMap.insert(std::make_pair(varId, std::move(varRequestIdQueue)));
657 m_VarIdToVarRequestIdQueueMap.insert(std::make_pair(varId, std::move(varRequestIdQueue)));
658 }
658 }
659 else {
659 else {
660 qCDebug(LOG_VariableController()) << tr("Store REQUEST in EXISTING QUEUE");
660 qCDebug(LOG_VariableController()) << tr("Store REQUEST in EXISTING QUEUE");
661 auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second;
661 auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second;
662 varRequestIdQueue.push_back(varRequestId);
662 varRequestIdQueue.push_back(varRequestId);
663 }
663 }
664
664
665 auto varRequestIdToVarIdVarRequestMapIt = m_VarRequestIdToVarIdVarRequestMap.find(varRequestId);
665 auto varRequestIdToVarIdVarRequestMapIt = m_VarRequestIdToVarIdVarRequestMap.find(varRequestId);
666 if (varRequestIdToVarIdVarRequestMapIt == m_VarRequestIdToVarIdVarRequestMap.cend()) {
666 if (varRequestIdToVarIdVarRequestMapIt == m_VarRequestIdToVarIdVarRequestMap.cend()) {
667 auto varIdToVarRequestMap = std::map<QUuid, VariableRequest>{};
667 auto varIdToVarRequestMap = std::map<QUuid, VariableRequest>{};
668 varIdToVarRequestMap.insert(std::make_pair(varId, varRequest));
668 varIdToVarRequestMap.insert(std::make_pair(varId, varRequest));
669 qCDebug(LOG_VariableController()) << tr("Store REQUESTID in MAP");
669 qCDebug(LOG_VariableController()) << tr("Store REQUESTID in MAP");
670 m_VarRequestIdToVarIdVarRequestMap.insert(
670 m_VarRequestIdToVarIdVarRequestMap.insert(
671 std::make_pair(varRequestId, std::move(varIdToVarRequestMap)));
671 std::make_pair(varRequestId, std::move(varIdToVarRequestMap)));
672 }
672 }
673 else {
673 else {
674 auto &varIdToVarRequestMap = varRequestIdToVarIdVarRequestMapIt->second;
674 auto &varIdToVarRequestMap = varRequestIdToVarIdVarRequestMapIt->second;
675 qCDebug(LOG_VariableController()) << tr("Store REQUESTID in EXISTING MAP");
675 qCDebug(LOG_VariableController()) << tr("Store REQUESTID in EXISTING MAP");
676 varIdToVarRequestMap.insert(std::make_pair(varId, varRequest));
676 varIdToVarRequestMap.insert(std::make_pair(varId, varRequest));
677 }
677 }
678 }
678 }
679
679
680 QUuid VariableController::VariableControllerPrivate::acceptVariableRequest(
680 QUuid VariableController::VariableControllerPrivate::acceptVariableRequest(
681 QUuid varId, std::shared_ptr<IDataSeries> dataSeries)
681 QUuid varId, std::shared_ptr<IDataSeries> dataSeries)
682 {
682 {
683 QUuid varRequestId;
683 QUuid varRequestId;
684 auto varIdToVarRequestIdQueueMapIt = m_VarIdToVarRequestIdQueueMap.find(varId);
684 auto varIdToVarRequestIdQueueMapIt = m_VarIdToVarRequestIdQueueMap.find(varId);
685 if (varIdToVarRequestIdQueueMapIt != m_VarIdToVarRequestIdQueueMap.cend()) {
685 if (varIdToVarRequestIdQueueMapIt != m_VarIdToVarRequestIdQueueMap.cend()) {
686 auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second;
686 auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second;
687 varRequestId = varRequestIdQueue.front();
687 varRequestId = varRequestIdQueue.front();
688 auto varRequestIdToVarIdVarRequestMapIt
688 auto varRequestIdToVarIdVarRequestMapIt
689 = m_VarRequestIdToVarIdVarRequestMap.find(varRequestId);
689 = m_VarRequestIdToVarIdVarRequestMap.find(varRequestId);
690 if (varRequestIdToVarIdVarRequestMapIt != m_VarRequestIdToVarIdVarRequestMap.cend()) {
690 if (varRequestIdToVarIdVarRequestMapIt != m_VarRequestIdToVarIdVarRequestMap.cend()) {
691 auto &varIdToVarRequestMap = varRequestIdToVarIdVarRequestMapIt->second;
691 auto &varIdToVarRequestMap = varRequestIdToVarIdVarRequestMapIt->second;
692 auto varIdToVarRequestMapIt = varIdToVarRequestMap.find(varId);
692 auto varIdToVarRequestMapIt = varIdToVarRequestMap.find(varId);
693 if (varIdToVarRequestMapIt != varIdToVarRequestMap.cend()) {
693 if (varIdToVarRequestMapIt != varIdToVarRequestMap.cend()) {
694 qCDebug(LOG_VariableController()) << tr("acceptVariableRequest");
694 qCDebug(LOG_VariableController()) << tr("acceptVariableRequest");
695 auto &varRequest = varIdToVarRequestMapIt->second;
695 auto &varRequest = varIdToVarRequestMapIt->second;
696 varRequest.m_DataSeries = dataSeries;
696 varRequest.m_DataSeries = dataSeries;
697 varRequest.m_CanUpdate = true;
697 varRequest.m_CanUpdate = true;
698 }
698 }
699 else {
699 else {
700 qCDebug(LOG_VariableController())
700 qCDebug(LOG_VariableController())
701 << tr("Impossible to acceptVariableRequest of a unknown variable id attached "
701 << tr("Impossible to acceptVariableRequest of a unknown variable id attached "
702 "to a variableRequestId")
702 "to a variableRequestId")
703 << varRequestId << varId;
703 << varRequestId << varId;
704 }
704 }
705 }
705 }
706 else {
706 else {
707 qCCritical(LOG_VariableController())
707 qCCritical(LOG_VariableController())
708 << tr("Impossible to acceptVariableRequest of a unknown variableRequestId")
708 << tr("Impossible to acceptVariableRequest of a unknown variableRequestId")
709 << varRequestId;
709 << varRequestId;
710 }
710 }
711
711
712 qCDebug(LOG_VariableController()) << tr("1: erase REQUEST in QUEUE ?")
712 qCDebug(LOG_VariableController())
713 << varRequestIdQueue.size();
713 << tr("1: erase REQUEST in QUEUE ?") << varRequestIdQueue.size();
714 varRequestIdQueue.pop_front();
714 varRequestIdQueue.pop_front();
715 qCDebug(LOG_VariableController()) << tr("2: erase REQUEST in QUEUE ?")
715 qCDebug(LOG_VariableController())
716 << varRequestIdQueue.size();
716 << tr("2: erase REQUEST in QUEUE ?") << varRequestIdQueue.size();
717 if (varRequestIdQueue.empty()) {
717 if (varRequestIdQueue.empty()) {
718 m_VarIdToVarRequestIdQueueMap.erase(varId);
718 m_VarIdToVarRequestIdQueueMap.erase(varId);
719 }
719 }
720 }
720 }
721 else {
721 else {
722 qCCritical(LOG_VariableController())
722 qCCritical(LOG_VariableController())
723 << tr("Impossible to acceptVariableRequest of a unknown variable id") << varId;
723 << tr("Impossible to acceptVariableRequest of a unknown variable id") << varId;
724 }
724 }
725
725
726 return varRequestId;
726 return varRequestId;
727 }
727 }
728
728
729 void VariableController::VariableControllerPrivate::updateVariableRequest(QUuid varRequestId)
729 void VariableController::VariableControllerPrivate::updateVariableRequest(QUuid varRequestId)
730 {
730 {
731
731
732 auto varRequestIdToVarIdVarRequestMapIt = m_VarRequestIdToVarIdVarRequestMap.find(varRequestId);
732 auto varRequestIdToVarIdVarRequestMapIt = m_VarRequestIdToVarIdVarRequestMap.find(varRequestId);
733 if (varRequestIdToVarIdVarRequestMapIt != m_VarRequestIdToVarIdVarRequestMap.cend()) {
733 if (varRequestIdToVarIdVarRequestMapIt != m_VarRequestIdToVarIdVarRequestMap.cend()) {
734 bool processVariableUpdate = true;
734 bool processVariableUpdate = true;
735 auto &varIdToVarRequestMap = varRequestIdToVarIdVarRequestMapIt->second;
735 auto &varIdToVarRequestMap = varRequestIdToVarIdVarRequestMapIt->second;
736 for (auto varIdToVarRequestMapIt = varIdToVarRequestMap.cbegin();
736 for (auto varIdToVarRequestMapIt = varIdToVarRequestMap.cbegin();
737 (varIdToVarRequestMapIt != varIdToVarRequestMap.cend()) && processVariableUpdate;
737 (varIdToVarRequestMapIt != varIdToVarRequestMap.cend()) && processVariableUpdate;
738 ++varIdToVarRequestMapIt) {
738 ++varIdToVarRequestMapIt) {
739 processVariableUpdate &= varIdToVarRequestMapIt->second.m_CanUpdate;
739 processVariableUpdate &= varIdToVarRequestMapIt->second.m_CanUpdate;
740 qCDebug(LOG_VariableController()) << tr("updateVariableRequest")
740 qCDebug(LOG_VariableController())
741 << processVariableUpdate;
741 << tr("updateVariableRequest") << processVariableUpdate;
742 }
742 }
743
743
744 if (processVariableUpdate) {
744 if (processVariableUpdate) {
745 for (auto varIdToVarRequestMapIt = varIdToVarRequestMap.cbegin();
745 for (auto varIdToVarRequestMapIt = varIdToVarRequestMap.cbegin();
746 varIdToVarRequestMapIt != varIdToVarRequestMap.cend(); ++varIdToVarRequestMapIt) {
746 varIdToVarRequestMapIt != varIdToVarRequestMap.cend(); ++varIdToVarRequestMapIt) {
747 if (auto var = findVariable(varIdToVarRequestMapIt->first)) {
747 if (auto var = findVariable(varIdToVarRequestMapIt->first)) {
748 auto &varRequest = varIdToVarRequestMapIt->second;
748 auto &varRequest = varIdToVarRequestMapIt->second;
749 var->setRange(varRequest.m_RangeRequested);
749 var->setRange(varRequest.m_RangeRequested);
750 var->setCacheRange(varRequest.m_CacheRangeRequested);
750 var->setCacheRange(varRequest.m_CacheRangeRequested);
751 qCDebug(LOG_VariableController()) << tr("1: onDataProvided")
751 qCDebug(LOG_VariableController())
752 << varRequest.m_RangeRequested;
752 << tr("1: onDataProvided") << varRequest.m_RangeRequested;
753 qCDebug(LOG_VariableController()) << tr("2: onDataProvided")
753 qCDebug(LOG_VariableController())
754 << varRequest.m_CacheRangeRequested;
754 << tr("2: onDataProvided") << varRequest.m_CacheRangeRequested;
755 var->mergeDataSeries(varRequest.m_DataSeries);
755 var->mergeDataSeries(varRequest.m_DataSeries);
756 qCDebug(LOG_VariableController()) << tr("3: onDataProvided")
756 qCDebug(LOG_VariableController())
757 << varRequest.m_DataSeries->range();
757 << tr("3: onDataProvided") << varRequest.m_DataSeries->range();
758 qCDebug(LOG_VariableController()) << tr("4: onDataProvided");
758 qCDebug(LOG_VariableController()) << tr("4: onDataProvided");
759
759
760 /// @todo MPL: confirm
760 /// @todo MPL: confirm
761 // Variable update is notified only if there is no pending request for it
761 // Variable update is notified only if there is no pending request for it
762 if (m_VarIdToVarRequestIdQueueMap.count(varIdToVarRequestMapIt->first) == 0) {
762 if (m_VarIdToVarRequestIdQueueMap.count(varIdToVarRequestMapIt->first) == 0) {
763 emit var->updated();
763 emit var->updated();
764 }
764 }
765 }
765 }
766 else {
766 else {
767 qCCritical(LOG_VariableController())
767 qCCritical(LOG_VariableController())
768 << tr("Impossible to update data to a null variable");
768 << tr("Impossible to update data to a null variable");
769 }
769 }
770 }
770 }
771
771
772 // cleaning varRequestId
772 // cleaning varRequestId
773 qCDebug(LOG_VariableController()) << tr("0: erase REQUEST in MAP ?")
773 qCDebug(LOG_VariableController())
774 << m_VarRequestIdToVarIdVarRequestMap.size();
774 << tr("0: erase REQUEST in MAP ?") << m_VarRequestIdToVarIdVarRequestMap.size();
775 m_VarRequestIdToVarIdVarRequestMap.erase(varRequestId);
775 m_VarRequestIdToVarIdVarRequestMap.erase(varRequestId);
776 qCDebug(LOG_VariableController()) << tr("1: erase REQUEST in MAP ?")
776 qCDebug(LOG_VariableController())
777 << m_VarRequestIdToVarIdVarRequestMap.size();
777 << tr("1: erase REQUEST in MAP ?") << m_VarRequestIdToVarIdVarRequestMap.size();
778 }
778 }
779 }
779 }
780 else {
780 else {
781 qCCritical(LOG_VariableController())
781 qCCritical(LOG_VariableController())
782 << tr("Cannot updateVariableRequest for a unknow varRequestId") << varRequestId;
782 << tr("Cannot updateVariableRequest for a unknow varRequestId") << varRequestId;
783 }
783 }
784 }
784 }
785
785
786 void VariableController::VariableControllerPrivate::cancelVariableRequest(QUuid varRequestId)
786 void VariableController::VariableControllerPrivate::cancelVariableRequest(QUuid varRequestId)
787 {
787 {
788 // cleaning varRequestId
788 // cleaning varRequestId
789 m_VarRequestIdToVarIdVarRequestMap.erase(varRequestId);
789 m_VarRequestIdToVarIdVarRequestMap.erase(varRequestId);
790
790
791 for (auto varIdToVarRequestIdQueueMapIt = m_VarIdToVarRequestIdQueueMap.begin();
791 for (auto varIdToVarRequestIdQueueMapIt = m_VarIdToVarRequestIdQueueMap.begin();
792 varIdToVarRequestIdQueueMapIt != m_VarIdToVarRequestIdQueueMap.end();) {
792 varIdToVarRequestIdQueueMapIt != m_VarIdToVarRequestIdQueueMap.end();) {
793 auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second;
793 auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second;
794 varRequestIdQueue.erase(
794 varRequestIdQueue.erase(
795 std::remove(varRequestIdQueue.begin(), varRequestIdQueue.end(), varRequestId),
795 std::remove(varRequestIdQueue.begin(), varRequestIdQueue.end(), varRequestId),
796 varRequestIdQueue.end());
796 varRequestIdQueue.end());
797 if (varRequestIdQueue.empty()) {
797 if (varRequestIdQueue.empty()) {
798 varIdToVarRequestIdQueueMapIt
798 varIdToVarRequestIdQueueMapIt
799 = m_VarIdToVarRequestIdQueueMap.erase(varIdToVarRequestIdQueueMapIt);
799 = m_VarIdToVarRequestIdQueueMap.erase(varIdToVarRequestIdQueueMapIt);
800 }
800 }
801 else {
801 else {
802 ++varIdToVarRequestIdQueueMapIt;
802 ++varIdToVarRequestIdQueueMapIt;
803 }
803 }
804 }
804 }
805 }
805 }
@@ -1,48 +1,48
1 #include <Visualization/VisualizationController.h>
1 #include <Visualization/VisualizationController.h>
2
2
3 #include <Variable/Variable.h>
3 #include <Variable/Variable.h>
4
4
5 #include <QMutex>
5 #include <QMutex>
6 #include <QThread>
6 #include <QThread>
7
7
8 #include <QDir>
8 #include <QDir>
9 #include <QStandardPaths>
9 #include <QStandardPaths>
10
10
11 Q_LOGGING_CATEGORY(LOG_VisualizationController, "VisualizationController")
11 Q_LOGGING_CATEGORY(LOG_VisualizationController, "VisualizationController")
12
12
13 class VisualizationController::VisualizationControllerPrivate {
13 class VisualizationController::VisualizationControllerPrivate {
14 public:
14 public:
15 QMutex m_WorkingMutex;
15 QMutex m_WorkingMutex;
16 };
16 };
17
17
18 VisualizationController::VisualizationController(QObject *parent)
18 VisualizationController::VisualizationController(QObject *parent)
19 : impl{spimpl::make_unique_impl<VisualizationControllerPrivate>()}
19 : impl{spimpl::make_unique_impl<VisualizationControllerPrivate>()}
20 {
20 {
21 qCDebug(LOG_VisualizationController()) << tr("VisualizationController construction")
21 qCDebug(LOG_VisualizationController())
22 << QThread::currentThread();
22 << tr("VisualizationController construction") << QThread::currentThread();
23 }
23 }
24
24
25 VisualizationController::~VisualizationController()
25 VisualizationController::~VisualizationController()
26 {
26 {
27 qCDebug(LOG_VisualizationController()) << tr("VisualizationController destruction")
27 qCDebug(LOG_VisualizationController())
28 << QThread::currentThread();
28 << tr("VisualizationController destruction") << QThread::currentThread();
29 this->waitForFinish();
29 this->waitForFinish();
30 }
30 }
31
31
32 void VisualizationController::initialize()
32 void VisualizationController::initialize()
33 {
33 {
34 qCDebug(LOG_VisualizationController()) << tr("VisualizationController init")
34 qCDebug(LOG_VisualizationController())
35 << QThread::currentThread();
35 << tr("VisualizationController init") << QThread::currentThread();
36 impl->m_WorkingMutex.lock();
36 impl->m_WorkingMutex.lock();
37 qCDebug(LOG_VisualizationController()) << tr("VisualizationController init END");
37 qCDebug(LOG_VisualizationController()) << tr("VisualizationController init END");
38 }
38 }
39
39
40 void VisualizationController::finalize()
40 void VisualizationController::finalize()
41 {
41 {
42 impl->m_WorkingMutex.unlock();
42 impl->m_WorkingMutex.unlock();
43 }
43 }
44
44
45 void VisualizationController::waitForFinish()
45 void VisualizationController::waitForFinish()
46 {
46 {
47 QMutexLocker locker{&impl->m_WorkingMutex};
47 QMutexLocker locker{&impl->m_WorkingMutex};
48 }
48 }
@@ -1,636 +1,636
1 #include "Data/DataSeries.h"
1 #include "Data/DataSeries.h"
2 #include "Data/ScalarSeries.h"
2 #include "Data/ScalarSeries.h"
3 #include "Data/VectorSeries.h"
3 #include "Data/VectorSeries.h"
4
4
5 #include <cmath>
5 #include <cmath>
6
6
7 #include <QObject>
7 #include <QObject>
8 #include <QtTest>
8 #include <QtTest>
9
9
10 Q_DECLARE_METATYPE(std::shared_ptr<ScalarSeries>)
10 Q_DECLARE_METATYPE(std::shared_ptr<ScalarSeries>)
11 Q_DECLARE_METATYPE(std::shared_ptr<VectorSeries>)
11 Q_DECLARE_METATYPE(std::shared_ptr<VectorSeries>)
12
12
13 namespace {
13 namespace {
14
14
15 using DataContainer = std::vector<double>;
15 using DataContainer = std::vector<double>;
16
16
17 void validateRange(DataSeriesIterator first, DataSeriesIterator last, const DataContainer &xData,
17 void validateRange(DataSeriesIterator first, DataSeriesIterator last, const DataContainer &xData,
18 const DataContainer &valuesData)
18 const DataContainer &valuesData)
19 {
19 {
20 QVERIFY(std::equal(first, last, xData.cbegin(), xData.cend(),
20 QVERIFY(std::equal(first, last, xData.cbegin(), xData.cend(),
21 [](const auto &it, const auto &expectedX) { return it.x() == expectedX; }));
21 [](const auto &it, const auto &expectedX) { return it.x() == expectedX; }));
22 QVERIFY(std::equal(
22 QVERIFY(std::equal(
23 first, last, valuesData.cbegin(), valuesData.cend(),
23 first, last, valuesData.cbegin(), valuesData.cend(),
24 [](const auto &it, const auto &expectedVal) { return it.value() == expectedVal; }));
24 [](const auto &it, const auto &expectedVal) { return it.value() == expectedVal; }));
25 }
25 }
26
26
27 void validateRange(DataSeriesIterator first, DataSeriesIterator last, const DataContainer &xData,
27 void validateRange(DataSeriesIterator first, DataSeriesIterator last, const DataContainer &xData,
28 const std::vector<DataContainer> &valuesData)
28 const std::vector<DataContainer> &valuesData)
29 {
29 {
30 QVERIFY(std::equal(first, last, xData.cbegin(), xData.cend(),
30 QVERIFY(std::equal(first, last, xData.cbegin(), xData.cend(),
31 [](const auto &it, const auto &expectedX) { return it.x() == expectedX; }));
31 [](const auto &it, const auto &expectedX) { return it.x() == expectedX; }));
32 for (auto i = 0; i < valuesData.size(); ++i) {
32 for (auto i = 0; i < valuesData.size(); ++i) {
33 auto componentData = valuesData.at(i);
33 auto componentData = valuesData.at(i);
34
34
35 QVERIFY(std::equal(
35 QVERIFY(std::equal(
36 first, last, componentData.cbegin(), componentData.cend(),
36 first, last, componentData.cbegin(), componentData.cend(),
37 [i](const auto &it, const auto &expectedVal) { return it.value(i) == expectedVal; }));
37 [i](const auto &it, const auto &expectedVal) { return it.value(i) == expectedVal; }));
38 }
38 }
39 }
39 }
40
40
41 } // namespace
41 } // namespace
42
42
43 class TestDataSeries : public QObject {
43 class TestDataSeries : public QObject {
44 Q_OBJECT
44 Q_OBJECT
45 private:
45 private:
46 template <typename T>
46 template <typename T>
47 void testValuesBoundsStructure()
47 void testValuesBoundsStructure()
48 {
48 {
49 // ////////////// //
49 // ////////////// //
50 // Test structure //
50 // Test structure //
51 // ////////////// //
51 // ////////////// //
52
52
53 // Data series to get values bounds
53 // Data series to get values bounds
54 QTest::addColumn<std::shared_ptr<T> >("dataSeries");
54 QTest::addColumn<std::shared_ptr<T> >("dataSeries");
55
55
56 // x-axis range
56 // x-axis range
57 QTest::addColumn<double>("minXAxis");
57 QTest::addColumn<double>("minXAxis");
58 QTest::addColumn<double>("maxXAxis");
58 QTest::addColumn<double>("maxXAxis");
59
59
60 // Expected results
60 // Expected results
61 QTest::addColumn<bool>(
61 QTest::addColumn<bool>(
62 "expectedOK"); // Test is expected to be ok (i.e. method doesn't return end iterators)
62 "expectedOK"); // Test is expected to be ok (i.e. method doesn't return end iterators)
63 QTest::addColumn<double>("expectedMinValue");
63 QTest::addColumn<double>("expectedMinValue");
64 QTest::addColumn<double>("expectedMaxValue");
64 QTest::addColumn<double>("expectedMaxValue");
65 }
65 }
66
66
67 template <typename T>
67 template <typename T>
68 void testValuesBounds()
68 void testValuesBounds()
69 {
69 {
70 QFETCH(std::shared_ptr<T>, dataSeries);
70 QFETCH(std::shared_ptr<T>, dataSeries);
71 QFETCH(double, minXAxis);
71 QFETCH(double, minXAxis);
72 QFETCH(double, maxXAxis);
72 QFETCH(double, maxXAxis);
73
73
74 QFETCH(bool, expectedOK);
74 QFETCH(bool, expectedOK);
75 QFETCH(double, expectedMinValue);
75 QFETCH(double, expectedMinValue);
76 QFETCH(double, expectedMaxValue);
76 QFETCH(double, expectedMaxValue);
77
77
78 auto minMaxIts = dataSeries->valuesBounds(minXAxis, maxXAxis);
78 auto minMaxIts = dataSeries->valuesBounds(minXAxis, maxXAxis);
79 auto end = dataSeries->cend();
79 auto end = dataSeries->cend();
80
80
81 // Checks iterators with expected result
81 // Checks iterators with expected result
82 QCOMPARE(expectedOK, minMaxIts.first != end && minMaxIts.second != end);
82 QCOMPARE(expectedOK, minMaxIts.first != end && minMaxIts.second != end);
83
83
84 if (expectedOK) {
84 if (expectedOK) {
85 auto compare = [](const auto &v1, const auto &v2) {
85 auto compare = [](const auto &v1, const auto &v2) {
86 return (std::isnan(v1) && std::isnan(v2)) || v1 == v2;
86 return (std::isnan(v1) && std::isnan(v2)) || v1 == v2;
87 };
87 };
88
88
89 QVERIFY(compare(expectedMinValue, minMaxIts.first->minValue()));
89 QVERIFY(compare(expectedMinValue, minMaxIts.first->minValue()));
90 QVERIFY(compare(expectedMaxValue, minMaxIts.second->maxValue()));
90 QVERIFY(compare(expectedMaxValue, minMaxIts.second->maxValue()));
91 }
91 }
92 }
92 }
93
93
94 template <typename T>
94 template <typename T>
95 void testPurgeStructure()
95 void testPurgeStructure()
96 {
96 {
97 // ////////////// //
97 // ////////////// //
98 // Test structure //
98 // Test structure //
99 // ////////////// //
99 // ////////////// //
100
100
101 // Data series to purge
101 // Data series to purge
102 QTest::addColumn<std::shared_ptr<T> >("dataSeries");
102 QTest::addColumn<std::shared_ptr<T> >("dataSeries");
103 QTest::addColumn<double>("min");
103 QTest::addColumn<double>("min");
104 QTest::addColumn<double>("max");
104 QTest::addColumn<double>("max");
105
105
106 // Expected values after purge
106 // Expected values after purge
107 QTest::addColumn<DataContainer>("expectedXAxisData");
107 QTest::addColumn<DataContainer>("expectedXAxisData");
108 QTest::addColumn<std::vector<DataContainer> >("expectedValuesData");
108 QTest::addColumn<std::vector<DataContainer> >("expectedValuesData");
109 }
109 }
110
110
111 template <typename T>
111 template <typename T>
112 void testPurge()
112 void testPurge()
113 {
113 {
114 QFETCH(std::shared_ptr<T>, dataSeries);
114 QFETCH(std::shared_ptr<T>, dataSeries);
115 QFETCH(double, min);
115 QFETCH(double, min);
116 QFETCH(double, max);
116 QFETCH(double, max);
117
117
118 dataSeries->purge(min, max);
118 dataSeries->purge(min, max);
119
119
120 // Validates results
120 // Validates results
121 QFETCH(DataContainer, expectedXAxisData);
121 QFETCH(DataContainer, expectedXAxisData);
122 QFETCH(std::vector<DataContainer>, expectedValuesData);
122 QFETCH(std::vector<DataContainer>, expectedValuesData);
123
123
124 validateRange(dataSeries->cbegin(), dataSeries->cend(), expectedXAxisData,
124 validateRange(dataSeries->cbegin(), dataSeries->cend(), expectedXAxisData,
125 expectedValuesData);
125 expectedValuesData);
126 }
126 }
127
127
128 private slots:
128 private slots:
129
129
130 /// Input test data
130 /// Input test data
131 /// @sa testCtor()
131 /// @sa testCtor()
132 void testCtor_data();
132 void testCtor_data();
133
133
134 /// Tests construction of a data series
134 /// Tests construction of a data series
135 void testCtor();
135 void testCtor();
136
136
137 /// Input test data
137 /// Input test data
138 /// @sa testMerge()
138 /// @sa testMerge()
139 void testMerge_data();
139 void testMerge_data();
140
140
141 /// Tests merge of two data series
141 /// Tests merge of two data series
142 void testMerge();
142 void testMerge();
143
143
144 /// Input test data
144 /// Input test data
145 /// @sa testPurgeScalar()
145 /// @sa testPurgeScalar()
146 void testPurgeScalar_data();
146 void testPurgeScalar_data();
147
147
148 /// Tests purge of a scalar series
148 /// Tests purge of a scalar series
149 void testPurgeScalar();
149 void testPurgeScalar();
150
150
151 /// Input test data
151 /// Input test data
152 /// @sa testPurgeVector()
152 /// @sa testPurgeVector()
153 void testPurgeVector_data();
153 void testPurgeVector_data();
154
154
155 /// Tests purge of a vector series
155 /// Tests purge of a vector series
156 void testPurgeVector();
156 void testPurgeVector();
157
157
158 /// Input test data
158 /// Input test data
159 /// @sa testMinXAxisData()
159 /// @sa testMinXAxisData()
160 void testMinXAxisData_data();
160 void testMinXAxisData_data();
161
161
162 /// Tests get min x-axis data of a data series
162 /// Tests get min x-axis data of a data series
163 void testMinXAxisData();
163 void testMinXAxisData();
164
164
165 /// Input test data
165 /// Input test data
166 /// @sa testMaxXAxisData()
166 /// @sa testMaxXAxisData()
167 void testMaxXAxisData_data();
167 void testMaxXAxisData_data();
168
168
169 /// Tests get max x-axis data of a data series
169 /// Tests get max x-axis data of a data series
170 void testMaxXAxisData();
170 void testMaxXAxisData();
171
171
172 /// Input test data
172 /// Input test data
173 /// @sa testXAxisRange()
173 /// @sa testXAxisRange()
174 void testXAxisRange_data();
174 void testXAxisRange_data();
175
175
176 /// Tests get x-axis range of a data series
176 /// Tests get x-axis range of a data series
177 void testXAxisRange();
177 void testXAxisRange();
178
178
179 /// Input test data
179 /// Input test data
180 /// @sa testValuesBoundsScalar()
180 /// @sa testValuesBoundsScalar()
181 void testValuesBoundsScalar_data();
181 void testValuesBoundsScalar_data();
182
182
183 /// Tests get values bounds of a scalar series
183 /// Tests get values bounds of a scalar series
184 void testValuesBoundsScalar();
184 void testValuesBoundsScalar();
185
185
186 /// Input test data
186 /// Input test data
187 /// @sa testValuesBoundsVector()
187 /// @sa testValuesBoundsVector()
188 void testValuesBoundsVector_data();
188 void testValuesBoundsVector_data();
189
189
190 /// Tests get values bounds of a vector series
190 /// Tests get values bounds of a vector series
191 void testValuesBoundsVector();
191 void testValuesBoundsVector();
192 };
192 };
193
193
194 void TestDataSeries::testCtor_data()
194 void TestDataSeries::testCtor_data()
195 {
195 {
196 // ////////////// //
196 // ////////////// //
197 // Test structure //
197 // Test structure //
198 // ////////////// //
198 // ////////////// //
199
199
200 // x-axis data
200 // x-axis data
201 QTest::addColumn<DataContainer>("xAxisData");
201 QTest::addColumn<DataContainer>("xAxisData");
202 // values data
202 // values data
203 QTest::addColumn<DataContainer>("valuesData");
203 QTest::addColumn<DataContainer>("valuesData");
204
204
205 // expected x-axis data
205 // expected x-axis data
206 QTest::addColumn<DataContainer>("expectedXAxisData");
206 QTest::addColumn<DataContainer>("expectedXAxisData");
207 // expected values data
207 // expected values data
208 QTest::addColumn<DataContainer>("expectedValuesData");
208 QTest::addColumn<DataContainer>("expectedValuesData");
209
209
210 // ////////// //
210 // ////////// //
211 // Test cases //
211 // Test cases //
212 // ////////// //
212 // ////////// //
213
213
214 QTest::newRow("invalidData (different sizes of vectors)")
214 QTest::newRow("invalidData (different sizes of vectors)")
215 << DataContainer{1., 2., 3., 4., 5.} << DataContainer{100., 200., 300.} << DataContainer{}
215 << DataContainer{1., 2., 3., 4., 5.} << DataContainer{100., 200., 300.} << DataContainer{}
216 << DataContainer{};
216 << DataContainer{};
217
217
218 QTest::newRow("sortedData") << DataContainer{1., 2., 3., 4., 5.}
218 QTest::newRow("sortedData") << DataContainer{1., 2., 3., 4., 5.}
219 << DataContainer{100., 200., 300., 400., 500.}
219 << DataContainer{100., 200., 300., 400., 500.}
220 << DataContainer{1., 2., 3., 4., 5.}
220 << DataContainer{1., 2., 3., 4., 5.}
221 << DataContainer{100., 200., 300., 400., 500.};
221 << DataContainer{100., 200., 300., 400., 500.};
222
222
223 QTest::newRow("unsortedData") << DataContainer{5., 4., 3., 2., 1.}
223 QTest::newRow("unsortedData") << DataContainer{5., 4., 3., 2., 1.}
224 << DataContainer{100., 200., 300., 400., 500.}
224 << DataContainer{100., 200., 300., 400., 500.}
225 << DataContainer{1., 2., 3., 4., 5.}
225 << DataContainer{1., 2., 3., 4., 5.}
226 << DataContainer{500., 400., 300., 200., 100.};
226 << DataContainer{500., 400., 300., 200., 100.};
227
227
228 QTest::newRow("unsortedData2")
228 QTest::newRow("unsortedData2")
229 << DataContainer{1., 4., 3., 5., 2.} << DataContainer{100., 200., 300., 400., 500.}
229 << DataContainer{1., 4., 3., 5., 2.} << DataContainer{100., 200., 300., 400., 500.}
230 << DataContainer{1., 2., 3., 4., 5.} << DataContainer{100., 500., 300., 200., 400.};
230 << DataContainer{1., 2., 3., 4., 5.} << DataContainer{100., 500., 300., 200., 400.};
231 }
231 }
232
232
233 void TestDataSeries::testCtor()
233 void TestDataSeries::testCtor()
234 {
234 {
235 // Creates series
235 // Creates series
236 QFETCH(DataContainer, xAxisData);
236 QFETCH(DataContainer, xAxisData);
237 QFETCH(DataContainer, valuesData);
237 QFETCH(DataContainer, valuesData);
238
238
239 auto series = std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData),
239 auto series = std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData),
240 Unit{}, Unit{});
240 Unit{}, Unit{});
241
241
242 // Validates results : we check that the data series is sorted on its x-axis data
242 // Validates results : we check that the data series is sorted on its x-axis data
243 QFETCH(DataContainer, expectedXAxisData);
243 QFETCH(DataContainer, expectedXAxisData);
244 QFETCH(DataContainer, expectedValuesData);
244 QFETCH(DataContainer, expectedValuesData);
245
245
246 validateRange(series->cbegin(), series->cend(), expectedXAxisData, expectedValuesData);
246 validateRange(series->cbegin(), series->cend(), expectedXAxisData, expectedValuesData);
247 }
247 }
248
248
249 namespace {
249 namespace {
250
250
251 std::shared_ptr<ScalarSeries> createScalarSeries(DataContainer xAxisData, DataContainer valuesData)
251 std::shared_ptr<ScalarSeries> createScalarSeries(DataContainer xAxisData, DataContainer valuesData)
252 {
252 {
253 return std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData), Unit{},
253 return std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData), Unit{},
254 Unit{});
254 Unit{});
255 }
255 }
256
256
257 std::shared_ptr<VectorSeries> createVectorSeries(DataContainer xAxisData, DataContainer xValuesData,
257 std::shared_ptr<VectorSeries> createVectorSeries(DataContainer xAxisData, DataContainer xValuesData,
258 DataContainer yValuesData,
258 DataContainer yValuesData,
259 DataContainer zValuesData)
259 DataContainer zValuesData)
260 {
260 {
261 return std::make_shared<VectorSeries>(std::move(xAxisData), std::move(xValuesData),
261 return std::make_shared<VectorSeries>(std::move(xAxisData), std::move(xValuesData),
262 std::move(yValuesData), std::move(zValuesData), Unit{},
262 std::move(yValuesData), std::move(zValuesData), Unit{},
263 Unit{});
263 Unit{});
264 }
264 }
265
265
266 } // namespace
266 } // namespace
267
267
268 void TestDataSeries::testMerge_data()
268 void TestDataSeries::testMerge_data()
269 {
269 {
270 // ////////////// //
270 // ////////////// //
271 // Test structure //
271 // Test structure //
272 // ////////////// //
272 // ////////////// //
273
273
274 // Data series to merge
274 // Data series to merge
275 QTest::addColumn<std::shared_ptr<ScalarSeries> >("dataSeries");
275 QTest::addColumn<std::shared_ptr<ScalarSeries> >("dataSeries");
276 QTest::addColumn<std::shared_ptr<ScalarSeries> >("dataSeries2");
276 QTest::addColumn<std::shared_ptr<ScalarSeries> >("dataSeries2");
277
277
278 // Expected values in the first data series after merge
278 // Expected values in the first data series after merge
279 QTest::addColumn<DataContainer>("expectedXAxisData");
279 QTest::addColumn<DataContainer>("expectedXAxisData");
280 QTest::addColumn<DataContainer>("expectedValuesData");
280 QTest::addColumn<DataContainer>("expectedValuesData");
281
281
282 // ////////// //
282 // ////////// //
283 // Test cases //
283 // Test cases //
284 // ////////// //
284 // ////////// //
285
285
286 QTest::newRow("sortedMerge")
286 QTest::newRow("sortedMerge")
287 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
287 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
288 << createScalarSeries({6., 7., 8., 9., 10.}, {600., 700., 800., 900., 1000.})
288 << createScalarSeries({6., 7., 8., 9., 10.}, {600., 700., 800., 900., 1000.})
289 << DataContainer{1., 2., 3., 4., 5., 6., 7., 8., 9., 10.}
289 << DataContainer{1., 2., 3., 4., 5., 6., 7., 8., 9., 10.}
290 << DataContainer{100., 200., 300., 400., 500., 600., 700., 800., 900., 1000.};
290 << DataContainer{100., 200., 300., 400., 500., 600., 700., 800., 900., 1000.};
291
291
292 QTest::newRow("unsortedMerge")
292 QTest::newRow("unsortedMerge")
293 << createScalarSeries({6., 7., 8., 9., 10.}, {600., 700., 800., 900., 1000.})
293 << createScalarSeries({6., 7., 8., 9., 10.}, {600., 700., 800., 900., 1000.})
294 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
294 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
295 << DataContainer{1., 2., 3., 4., 5., 6., 7., 8., 9., 10.}
295 << DataContainer{1., 2., 3., 4., 5., 6., 7., 8., 9., 10.}
296 << DataContainer{100., 200., 300., 400., 500., 600., 700., 800., 900., 1000.};
296 << DataContainer{100., 200., 300., 400., 500., 600., 700., 800., 900., 1000.};
297
297
298 QTest::newRow("unsortedMerge2 (merge not made because source is in the bounds of dest)")
298 QTest::newRow("unsortedMerge2 (merge not made because source is in the bounds of dest)")
299 << createScalarSeries({1., 2., 8., 9., 10}, {100., 200., 800., 900., 1000.})
299 << createScalarSeries({1., 2., 8., 9., 10}, {100., 200., 800., 900., 1000.})
300 << createScalarSeries({3., 4., 5., 6., 7.}, {300., 400., 500., 600., 700.})
300 << createScalarSeries({3., 4., 5., 6., 7.}, {300., 400., 500., 600., 700.})
301 << DataContainer{1., 2., 8., 9., 10.} << DataContainer{100., 200., 800., 900., 1000.};
301 << DataContainer{1., 2., 8., 9., 10.} << DataContainer{100., 200., 800., 900., 1000.};
302
302
303 QTest::newRow("unsortedMerge3")
303 QTest::newRow("unsortedMerge3")
304 << createScalarSeries({3., 4., 5., 7., 8}, {300., 400., 500., 700., 800.})
304 << createScalarSeries({3., 4., 5., 7., 8}, {300., 400., 500., 700., 800.})
305 << createScalarSeries({1., 2., 3., 7., 10.}, {100., 200., 333., 777., 1000.})
305 << createScalarSeries({1., 2., 3., 7., 10.}, {100., 200., 333., 777., 1000.})
306 << DataContainer{1., 2., 3., 4., 5., 7., 8., 10.}
306 << DataContainer{1., 2., 3., 4., 5., 7., 8., 10.}
307 << DataContainer{100., 200., 300., 400., 500., 700., 800., 1000.};
307 << DataContainer{100., 200., 300., 400., 500., 700., 800., 1000.};
308 }
308 }
309
309
310 void TestDataSeries::testMerge()
310 void TestDataSeries::testMerge()
311 {
311 {
312 // Merges series
312 // Merges series
313 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries);
313 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries);
314 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries2);
314 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries2);
315
315
316 dataSeries->merge(dataSeries2.get());
316 dataSeries->merge(dataSeries2.get());
317
317
318 // Validates results : we check that the merge is valid and the data series is sorted on its
318 // Validates results : we check that the merge is valid and the data series is sorted on its
319 // x-axis data
319 // x-axis data
320 QFETCH(DataContainer, expectedXAxisData);
320 QFETCH(DataContainer, expectedXAxisData);
321 QFETCH(DataContainer, expectedValuesData);
321 QFETCH(DataContainer, expectedValuesData);
322
322
323 validateRange(dataSeries->cbegin(), dataSeries->cend(), expectedXAxisData, expectedValuesData);
323 validateRange(dataSeries->cbegin(), dataSeries->cend(), expectedXAxisData, expectedValuesData);
324 }
324 }
325
325
326 void TestDataSeries::testPurgeScalar_data()
326 void TestDataSeries::testPurgeScalar_data()
327 {
327 {
328 testPurgeStructure<ScalarSeries>();
328 testPurgeStructure<ScalarSeries>();
329
329
330 // ////////// //
330 // ////////// //
331 // Test cases //
331 // Test cases //
332 // ////////// //
332 // ////////// //
333
333
334 QTest::newRow("purgeScalar") << createScalarSeries({1., 2., 3., 4., 5.},
334 QTest::newRow("purgeScalar") << createScalarSeries({1., 2., 3., 4., 5.},
335 {100., 200., 300., 400., 500.})
335 {100., 200., 300., 400., 500.})
336 << 2. << 4. << DataContainer{2., 3., 4.}
336 << 2. << 4. << DataContainer{2., 3., 4.}
337 << std::vector<DataContainer>{{200., 300., 400.}};
337 << std::vector<DataContainer>{{200., 300., 400.}};
338 QTest::newRow("purgeScalar2") << createScalarSeries({1., 2., 3., 4., 5.},
338 QTest::newRow("purgeScalar2") << createScalarSeries({1., 2., 3., 4., 5.},
339 {100., 200., 300., 400., 500.})
339 {100., 200., 300., 400., 500.})
340 << 0. << 2.5 << DataContainer{1., 2.}
340 << 0. << 2.5 << DataContainer{1., 2.}
341 << std::vector<DataContainer>{{100., 200.}};
341 << std::vector<DataContainer>{{100., 200.}};
342 QTest::newRow("purgeScalar3") << createScalarSeries({1., 2., 3., 4., 5.},
342 QTest::newRow("purgeScalar3") << createScalarSeries({1., 2., 3., 4., 5.},
343 {100., 200., 300., 400., 500.})
343 {100., 200., 300., 400., 500.})
344 << 3.5 << 7. << DataContainer{4., 5.}
344 << 3.5 << 7. << DataContainer{4., 5.}
345 << std::vector<DataContainer>{{400., 500.}};
345 << std::vector<DataContainer>{{400., 500.}};
346 QTest::newRow("purgeScalar4") << createScalarSeries({1., 2., 3., 4., 5.},
346 QTest::newRow("purgeScalar4") << createScalarSeries({1., 2., 3., 4., 5.},
347 {100., 200., 300., 400., 500.})
347 {100., 200., 300., 400., 500.})
348 << 0. << 7. << DataContainer{1., 2., 3., 4., 5.}
348 << 0. << 7. << DataContainer{1., 2., 3., 4., 5.}
349 << std::vector<DataContainer>{{100., 200., 300., 400., 500.}};
349 << std::vector<DataContainer>{{100., 200., 300., 400., 500.}};
350 QTest::newRow("purgeScalar5") << createScalarSeries({1., 2., 3., 4., 5.},
350 QTest::newRow("purgeScalar5") << createScalarSeries({1., 2., 3., 4., 5.},
351 {100., 200., 300., 400., 500.})
351 {100., 200., 300., 400., 500.})
352 << 5.5 << 7. << DataContainer{} << std::vector<DataContainer>{{}};
352 << 5.5 << 7. << DataContainer{} << std::vector<DataContainer>{{}};
353 }
353 }
354
354
355 void TestDataSeries::testPurgeScalar()
355 void TestDataSeries::testPurgeScalar()
356 {
356 {
357 testPurge<ScalarSeries>();
357 testPurge<ScalarSeries>();
358 }
358 }
359
359
360 void TestDataSeries::testPurgeVector_data()
360 void TestDataSeries::testPurgeVector_data()
361 {
361 {
362 testPurgeStructure<VectorSeries>();
362 testPurgeStructure<VectorSeries>();
363
363
364 // ////////// //
364 // ////////// //
365 // Test cases //
365 // Test cases //
366 // ////////// //
366 // ////////// //
367
367
368 QTest::newRow("purgeVector") << createVectorSeries({1., 2., 3., 4., 5.}, {6., 7., 8., 9., 10.},
368 QTest::newRow("purgeVector") << createVectorSeries({1., 2., 3., 4., 5.}, {6., 7., 8., 9., 10.},
369 {11., 12., 13., 14., 15.},
369 {11., 12., 13., 14., 15.},
370 {16., 17., 18., 19., 20.})
370 {16., 17., 18., 19., 20.})
371 << 2. << 4. << DataContainer{2., 3., 4.}
371 << 2. << 4. << DataContainer{2., 3., 4.}
372 << std::vector<DataContainer>{
372 << std::vector<DataContainer>{
373 {7., 8., 9.}, {12., 13., 14.}, {17., 18., 19.}};
373 {7., 8., 9.}, {12., 13., 14.}, {17., 18., 19.}};
374 }
374 }
375
375
376 void TestDataSeries::testPurgeVector()
376 void TestDataSeries::testPurgeVector()
377 {
377 {
378 testPurge<VectorSeries>();
378 testPurge<VectorSeries>();
379 }
379 }
380
380
381 void TestDataSeries::testMinXAxisData_data()
381 void TestDataSeries::testMinXAxisData_data()
382 {
382 {
383 // ////////////// //
383 // ////////////// //
384 // Test structure //
384 // Test structure //
385 // ////////////// //
385 // ////////////// //
386
386
387 // Data series to get min data
387 // Data series to get min data
388 QTest::addColumn<std::shared_ptr<ScalarSeries> >("dataSeries");
388 QTest::addColumn<std::shared_ptr<ScalarSeries> >("dataSeries");
389
389
390 // Min data
390 // Min data
391 QTest::addColumn<double>("min");
391 QTest::addColumn<double>("min");
392
392
393 // Expected results
393 // Expected results
394 QTest::addColumn<bool>(
394 QTest::addColumn<bool>(
395 "expectedOK"); // if true, expects to have a result (i.e. the iterator != end iterator)
395 "expectedOK"); // if true, expects to have a result (i.e. the iterator != end iterator)
396 QTest::addColumn<double>(
396 QTest::addColumn<double>(
397 "expectedMin"); // Expected value when method doesn't return end iterator
397 "expectedMin"); // Expected value when method doesn't return end iterator
398
398
399 // ////////// //
399 // ////////// //
400 // Test cases //
400 // Test cases //
401 // ////////// //
401 // ////////// //
402
402
403 QTest::newRow("minData1") << createScalarSeries({1., 2., 3., 4., 5.},
403 QTest::newRow("minData1") << createScalarSeries({1., 2., 3., 4., 5.},
404 {100., 200., 300., 400., 500.})
404 {100., 200., 300., 400., 500.})
405 << 0. << true << 1.;
405 << 0. << true << 1.;
406 QTest::newRow("minData2") << createScalarSeries({1., 2., 3., 4., 5.},
406 QTest::newRow("minData2") << createScalarSeries({1., 2., 3., 4., 5.},
407 {100., 200., 300., 400., 500.})
407 {100., 200., 300., 400., 500.})
408 << 1. << true << 1.;
408 << 1. << true << 1.;
409 QTest::newRow("minData3") << createScalarSeries({1., 2., 3., 4., 5.},
409 QTest::newRow("minData3") << createScalarSeries({1., 2., 3., 4., 5.},
410 {100., 200., 300., 400., 500.})
410 {100., 200., 300., 400., 500.})
411 << 1.1 << true << 2.;
411 << 1.1 << true << 2.;
412 QTest::newRow("minData4") << createScalarSeries({1., 2., 3., 4., 5.},
412 QTest::newRow("minData4") << createScalarSeries({1., 2., 3., 4., 5.},
413 {100., 200., 300., 400., 500.})
413 {100., 200., 300., 400., 500.})
414 << 5. << true << 5.;
414 << 5. << true << 5.;
415 QTest::newRow("minData5") << createScalarSeries({1., 2., 3., 4., 5.},
415 QTest::newRow("minData5") << createScalarSeries({1., 2., 3., 4., 5.},
416 {100., 200., 300., 400., 500.})
416 {100., 200., 300., 400., 500.})
417 << 5.1 << false << std::numeric_limits<double>::quiet_NaN();
417 << 5.1 << false << std::numeric_limits<double>::quiet_NaN();
418 QTest::newRow("minData6") << createScalarSeries({}, {}) << 1.1 << false
418 QTest::newRow("minData6") << createScalarSeries({}, {}) << 1.1 << false
419 << std::numeric_limits<double>::quiet_NaN();
419 << std::numeric_limits<double>::quiet_NaN();
420 }
420 }
421
421
422 void TestDataSeries::testMinXAxisData()
422 void TestDataSeries::testMinXAxisData()
423 {
423 {
424 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries);
424 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries);
425 QFETCH(double, min);
425 QFETCH(double, min);
426
426
427 QFETCH(bool, expectedOK);
427 QFETCH(bool, expectedOK);
428 QFETCH(double, expectedMin);
428 QFETCH(double, expectedMin);
429
429
430 auto it = dataSeries->minXAxisData(min);
430 auto it = dataSeries->minXAxisData(min);
431
431
432 QCOMPARE(expectedOK, it != dataSeries->cend());
432 QCOMPARE(expectedOK, it != dataSeries->cend());
433
433
434 // If the method doesn't return a end iterator, checks with expected value
434 // If the method doesn't return a end iterator, checks with expected value
435 if (expectedOK) {
435 if (expectedOK) {
436 QCOMPARE(expectedMin, it->x());
436 QCOMPARE(expectedMin, it->x());
437 }
437 }
438 }
438 }
439
439
440 void TestDataSeries::testMaxXAxisData_data()
440 void TestDataSeries::testMaxXAxisData_data()
441 {
441 {
442 // ////////////// //
442 // ////////////// //
443 // Test structure //
443 // Test structure //
444 // ////////////// //
444 // ////////////// //
445
445
446 // Data series to get max data
446 // Data series to get max data
447 QTest::addColumn<std::shared_ptr<ScalarSeries> >("dataSeries");
447 QTest::addColumn<std::shared_ptr<ScalarSeries> >("dataSeries");
448
448
449 // Max data
449 // Max data
450 QTest::addColumn<double>("max");
450 QTest::addColumn<double>("max");
451
451
452 // Expected results
452 // Expected results
453 QTest::addColumn<bool>(
453 QTest::addColumn<bool>(
454 "expectedOK"); // if true, expects to have a result (i.e. the iterator != end iterator)
454 "expectedOK"); // if true, expects to have a result (i.e. the iterator != end iterator)
455 QTest::addColumn<double>(
455 QTest::addColumn<double>(
456 "expectedMax"); // Expected value when method doesn't return end iterator
456 "expectedMax"); // Expected value when method doesn't return end iterator
457
457
458 // ////////// //
458 // ////////// //
459 // Test cases //
459 // Test cases //
460 // ////////// //
460 // ////////// //
461
461
462 QTest::newRow("maxData1") << createScalarSeries({1., 2., 3., 4., 5.},
462 QTest::newRow("maxData1") << createScalarSeries({1., 2., 3., 4., 5.},
463 {100., 200., 300., 400., 500.})
463 {100., 200., 300., 400., 500.})
464 << 6. << true << 5.;
464 << 6. << true << 5.;
465 QTest::newRow("maxData2") << createScalarSeries({1., 2., 3., 4., 5.},
465 QTest::newRow("maxData2") << createScalarSeries({1., 2., 3., 4., 5.},
466 {100., 200., 300., 400., 500.})
466 {100., 200., 300., 400., 500.})
467 << 5. << true << 5.;
467 << 5. << true << 5.;
468 QTest::newRow("maxData3") << createScalarSeries({1., 2., 3., 4., 5.},
468 QTest::newRow("maxData3") << createScalarSeries({1., 2., 3., 4., 5.},
469 {100., 200., 300., 400., 500.})
469 {100., 200., 300., 400., 500.})
470 << 4.9 << true << 4.;
470 << 4.9 << true << 4.;
471 QTest::newRow("maxData4") << createScalarSeries({1., 2., 3., 4., 5.},
471 QTest::newRow("maxData4") << createScalarSeries({1., 2., 3., 4., 5.},
472 {100., 200., 300., 400., 500.})
472 {100., 200., 300., 400., 500.})
473 << 1.1 << true << 1.;
473 << 1.1 << true << 1.;
474 QTest::newRow("maxData5") << createScalarSeries({1., 2., 3., 4., 5.},
474 QTest::newRow("maxData5") << createScalarSeries({1., 2., 3., 4., 5.},
475 {100., 200., 300., 400., 500.})
475 {100., 200., 300., 400., 500.})
476 << 1. << true << 1.;
476 << 1. << true << 1.;
477 QTest::newRow("maxData6") << createScalarSeries({}, {}) << 1.1 << false
477 QTest::newRow("maxData6") << createScalarSeries({}, {}) << 1.1 << false
478 << std::numeric_limits<double>::quiet_NaN();
478 << std::numeric_limits<double>::quiet_NaN();
479 }
479 }
480
480
481 void TestDataSeries::testMaxXAxisData()
481 void TestDataSeries::testMaxXAxisData()
482 {
482 {
483 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries);
483 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries);
484 QFETCH(double, max);
484 QFETCH(double, max);
485
485
486 QFETCH(bool, expectedOK);
486 QFETCH(bool, expectedOK);
487 QFETCH(double, expectedMax);
487 QFETCH(double, expectedMax);
488
488
489 auto it = dataSeries->maxXAxisData(max);
489 auto it = dataSeries->maxXAxisData(max);
490
490
491 QCOMPARE(expectedOK, it != dataSeries->cend());
491 QCOMPARE(expectedOK, it != dataSeries->cend());
492
492
493 // If the method doesn't return a end iterator, checks with expected value
493 // If the method doesn't return a end iterator, checks with expected value
494 if (expectedOK) {
494 if (expectedOK) {
495 QCOMPARE(expectedMax, it->x());
495 QCOMPARE(expectedMax, it->x());
496 }
496 }
497 }
497 }
498
498
499 void TestDataSeries::testXAxisRange_data()
499 void TestDataSeries::testXAxisRange_data()
500 {
500 {
501 // ////////////// //
501 // ////////////// //
502 // Test structure //
502 // Test structure //
503 // ////////////// //
503 // ////////////// //
504
504
505 // Data series to get x-axis range
505 // Data series to get x-axis range
506 QTest::addColumn<std::shared_ptr<ScalarSeries> >("dataSeries");
506 QTest::addColumn<std::shared_ptr<ScalarSeries> >("dataSeries");
507
507
508 // Min/max values
508 // Min/max values
509 QTest::addColumn<double>("min");
509 QTest::addColumn<double>("min");
510 QTest::addColumn<double>("max");
510 QTest::addColumn<double>("max");
511
511
512 // Expected values
512 // Expected values
513 QTest::addColumn<DataContainer>("expectedXAxisData");
513 QTest::addColumn<DataContainer>("expectedXAxisData");
514 QTest::addColumn<DataContainer>("expectedValuesData");
514 QTest::addColumn<DataContainer>("expectedValuesData");
515
515
516 // ////////// //
516 // ////////// //
517 // Test cases //
517 // Test cases //
518 // ////////// //
518 // ////////// //
519
519
520 QTest::newRow("xAxisRange1") << createScalarSeries({1., 2., 3., 4., 5.},
520 QTest::newRow("xAxisRange1") << createScalarSeries({1., 2., 3., 4., 5.},
521 {100., 200., 300., 400., 500.})
521 {100., 200., 300., 400., 500.})
522 << -1. << 3.2 << DataContainer{1., 2., 3.}
522 << -1. << 3.2 << DataContainer{1., 2., 3.}
523 << DataContainer{100., 200., 300.};
523 << DataContainer{100., 200., 300.};
524 QTest::newRow("xAxisRange2") << createScalarSeries({1., 2., 3., 4., 5.},
524 QTest::newRow("xAxisRange2") << createScalarSeries({1., 2., 3., 4., 5.},
525 {100., 200., 300., 400., 500.})
525 {100., 200., 300., 400., 500.})
526 << 1. << 4. << DataContainer{1., 2., 3., 4.}
526 << 1. << 4. << DataContainer{1., 2., 3., 4.}
527 << DataContainer{100., 200., 300., 400.};
527 << DataContainer{100., 200., 300., 400.};
528 QTest::newRow("xAxisRange3") << createScalarSeries({1., 2., 3., 4., 5.},
528 QTest::newRow("xAxisRange3") << createScalarSeries({1., 2., 3., 4., 5.},
529 {100., 200., 300., 400., 500.})
529 {100., 200., 300., 400., 500.})
530 << 1. << 3.9 << DataContainer{1., 2., 3.}
530 << 1. << 3.9 << DataContainer{1., 2., 3.}
531 << DataContainer{100., 200., 300.};
531 << DataContainer{100., 200., 300.};
532 QTest::newRow("xAxisRange4") << createScalarSeries({1., 2., 3., 4., 5.},
532 QTest::newRow("xAxisRange4") << createScalarSeries({1., 2., 3., 4., 5.},
533 {100., 200., 300., 400., 500.})
533 {100., 200., 300., 400., 500.})
534 << 0. << 0.9 << DataContainer{} << DataContainer{};
534 << 0. << 0.9 << DataContainer{} << DataContainer{};
535 QTest::newRow("xAxisRange5") << createScalarSeries({1., 2., 3., 4., 5.},
535 QTest::newRow("xAxisRange5") << createScalarSeries({1., 2., 3., 4., 5.},
536 {100., 200., 300., 400., 500.})
536 {100., 200., 300., 400., 500.})
537 << 0. << 1. << DataContainer{1.} << DataContainer{100.};
537 << 0. << 1. << DataContainer{1.} << DataContainer{100.};
538 QTest::newRow("xAxisRange6") << createScalarSeries({1., 2., 3., 4., 5.},
538 QTest::newRow("xAxisRange6") << createScalarSeries({1., 2., 3., 4., 5.},
539 {100., 200., 300., 400., 500.})
539 {100., 200., 300., 400., 500.})
540 << 2.1 << 6. << DataContainer{3., 4., 5.}
540 << 2.1 << 6. << DataContainer{3., 4., 5.}
541 << DataContainer{300., 400., 500.};
541 << DataContainer{300., 400., 500.};
542 QTest::newRow("xAxisRange7") << createScalarSeries({1., 2., 3., 4., 5.},
542 QTest::newRow("xAxisRange7") << createScalarSeries({1., 2., 3., 4., 5.},
543 {100., 200., 300., 400., 500.})
543 {100., 200., 300., 400., 500.})
544 << 6. << 9. << DataContainer{} << DataContainer{};
544 << 6. << 9. << DataContainer{} << DataContainer{};
545 QTest::newRow("xAxisRange8") << createScalarSeries({1., 2., 3., 4., 5.},
545 QTest::newRow("xAxisRange8") << createScalarSeries({1., 2., 3., 4., 5.},
546 {100., 200., 300., 400., 500.})
546 {100., 200., 300., 400., 500.})
547 << 5. << 9. << DataContainer{5.} << DataContainer{500.};
547 << 5. << 9. << DataContainer{5.} << DataContainer{500.};
548 }
548 }
549
549
550 void TestDataSeries::testXAxisRange()
550 void TestDataSeries::testXAxisRange()
551 {
551 {
552 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries);
552 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries);
553 QFETCH(double, min);
553 QFETCH(double, min);
554 QFETCH(double, max);
554 QFETCH(double, max);
555
555
556 QFETCH(DataContainer, expectedXAxisData);
556 QFETCH(DataContainer, expectedXAxisData);
557 QFETCH(DataContainer, expectedValuesData);
557 QFETCH(DataContainer, expectedValuesData);
558
558
559 auto bounds = dataSeries->xAxisRange(min, max);
559 auto bounds = dataSeries->xAxisRange(min, max);
560 validateRange(bounds.first, bounds.second, expectedXAxisData, expectedValuesData);
560 validateRange(bounds.first, bounds.second, expectedXAxisData, expectedValuesData);
561 }
561 }
562
562
563 void TestDataSeries::testValuesBoundsScalar_data()
563 void TestDataSeries::testValuesBoundsScalar_data()
564 {
564 {
565 testValuesBoundsStructure<ScalarSeries>();
565 testValuesBoundsStructure<ScalarSeries>();
566
566
567 // ////////// //
567 // ////////// //
568 // Test cases //
568 // Test cases //
569 // ////////// //
569 // ////////// //
570 auto nan = std::numeric_limits<double>::quiet_NaN();
570 auto nan = std::numeric_limits<double>::quiet_NaN();
571
571
572 QTest::newRow("scalarBounds1")
572 QTest::newRow("scalarBounds1")
573 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.}) << 0. << 6.
573 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.}) << 0. << 6.
574 << true << 100. << 500.;
574 << true << 100. << 500.;
575 QTest::newRow("scalarBounds2")
575 QTest::newRow("scalarBounds2")
576 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.}) << 2. << 4.
576 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.}) << 2. << 4.
577 << true << 200. << 400.;
577 << true << 200. << 400.;
578 QTest::newRow("scalarBounds3")
578 QTest::newRow("scalarBounds3")
579 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.}) << 0. << 0.5
579 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.}) << 0. << 0.5
580 << false << nan << nan;
580 << false << nan << nan;
581 QTest::newRow("scalarBounds4")
581 QTest::newRow("scalarBounds4")
582 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.}) << 5.1 << 6.
582 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.}) << 5.1 << 6.
583 << false << nan << nan;
583 << false << nan << nan;
584 QTest::newRow("scalarBounds5") << createScalarSeries({1.}, {100.}) << 0. << 2. << true << 100.
584 QTest::newRow("scalarBounds5")
585 << 100.;
585 << createScalarSeries({1.}, {100.}) << 0. << 2. << true << 100. << 100.;
586 QTest::newRow("scalarBounds6") << createScalarSeries({}, {}) << 0. << 2. << false << nan << nan;
586 QTest::newRow("scalarBounds6") << createScalarSeries({}, {}) << 0. << 2. << false << nan << nan;
587
587
588 // Tests with NaN values: NaN values are not included in min/max search
588 // Tests with NaN values: NaN values are not included in min/max search
589 QTest::newRow("scalarBounds7")
589 QTest::newRow("scalarBounds7")
590 << createScalarSeries({1., 2., 3., 4., 5.}, {nan, 200., 300., 400., nan}) << 0. << 6.
590 << createScalarSeries({1., 2., 3., 4., 5.}, {nan, 200., 300., 400., nan}) << 0. << 6.
591 << true << 200. << 400.;
591 << true << 200. << 400.;
592 QTest::newRow("scalarBounds8")
592 QTest::newRow("scalarBounds8")
593 << createScalarSeries({1., 2., 3., 4., 5.}, {nan, nan, nan, nan, nan}) << 0. << 6. << true
593 << createScalarSeries({1., 2., 3., 4., 5.}, {nan, nan, nan, nan, nan}) << 0. << 6. << true
594 << std::numeric_limits<double>::quiet_NaN() << std::numeric_limits<double>::quiet_NaN();
594 << std::numeric_limits<double>::quiet_NaN() << std::numeric_limits<double>::quiet_NaN();
595 }
595 }
596
596
597 void TestDataSeries::testValuesBoundsScalar()
597 void TestDataSeries::testValuesBoundsScalar()
598 {
598 {
599 testValuesBounds<ScalarSeries>();
599 testValuesBounds<ScalarSeries>();
600 }
600 }
601
601
602 void TestDataSeries::testValuesBoundsVector_data()
602 void TestDataSeries::testValuesBoundsVector_data()
603 {
603 {
604 testValuesBoundsStructure<VectorSeries>();
604 testValuesBoundsStructure<VectorSeries>();
605
605
606 // ////////// //
606 // ////////// //
607 // Test cases //
607 // Test cases //
608 // ////////// //
608 // ////////// //
609 auto nan = std::numeric_limits<double>::quiet_NaN();
609 auto nan = std::numeric_limits<double>::quiet_NaN();
610
610
611 QTest::newRow("vectorBounds1")
611 QTest::newRow("vectorBounds1")
612 << createVectorSeries({1., 2., 3., 4., 5.}, {10., 15., 20., 13., 12.},
612 << createVectorSeries({1., 2., 3., 4., 5.}, {10., 15., 20., 13., 12.},
613 {35., 24., 10., 9., 0.3}, {13., 14., 12., 9., 24.})
613 {35., 24., 10., 9., 0.3}, {13., 14., 12., 9., 24.})
614 << 0. << 6. << true << 0.3 << 35.; // min/max in same component
614 << 0. << 6. << true << 0.3 << 35.; // min/max in same component
615 QTest::newRow("vectorBounds2")
615 QTest::newRow("vectorBounds2")
616 << createVectorSeries({1., 2., 3., 4., 5.}, {2.3, 15., 20., 13., 12.},
616 << createVectorSeries({1., 2., 3., 4., 5.}, {2.3, 15., 20., 13., 12.},
617 {35., 24., 10., 9., 4.}, {13., 14., 12., 9., 24.})
617 {35., 24., 10., 9., 4.}, {13., 14., 12., 9., 24.})
618 << 0. << 6. << true << 2.3 << 35.; // min/max in same entry
618 << 0. << 6. << true << 2.3 << 35.; // min/max in same entry
619 QTest::newRow("vectorBounds3")
619 QTest::newRow("vectorBounds3")
620 << createVectorSeries({1., 2., 3., 4., 5.}, {2.3, 15., 20., 13., 12.},
620 << createVectorSeries({1., 2., 3., 4., 5.}, {2.3, 15., 20., 13., 12.},
621 {35., 24., 10., 9., 4.}, {13., 14., 12., 9., 24.})
621 {35., 24., 10., 9., 4.}, {13., 14., 12., 9., 24.})
622 << 2. << 3. << true << 10. << 24.;
622 << 2. << 3. << true << 10. << 24.;
623
623
624 // Tests with NaN values: NaN values are not included in min/max search
624 // Tests with NaN values: NaN values are not included in min/max search
625 QTest::newRow("vectorBounds4")
625 QTest::newRow("vectorBounds4")
626 << createVectorSeries({1., 2.}, {nan, nan}, {nan, nan}, {nan, nan}) << 0. << 6. << true
626 << createVectorSeries({1., 2.}, {nan, nan}, {nan, nan}, {nan, nan}) << 0. << 6. << true
627 << nan << nan;
627 << nan << nan;
628 }
628 }
629
629
630 void TestDataSeries::testValuesBoundsVector()
630 void TestDataSeries::testValuesBoundsVector()
631 {
631 {
632 testValuesBounds<VectorSeries>();
632 testValuesBounds<VectorSeries>();
633 }
633 }
634
634
635 QTEST_MAIN(TestDataSeries)
635 QTEST_MAIN(TestDataSeries)
636 #include "TestDataSeries.moc"
636 #include "TestDataSeries.moc"
@@ -1,356 +1,356
1 #include "Visualization/VisualizationGraphWidget.h"
1 #include "Visualization/VisualizationGraphWidget.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 #include "Visualization/VisualizationDefs.h"
3 #include "Visualization/VisualizationDefs.h"
4 #include "Visualization/VisualizationGraphHelper.h"
4 #include "Visualization/VisualizationGraphHelper.h"
5 #include "Visualization/VisualizationGraphRenderingDelegate.h"
5 #include "Visualization/VisualizationGraphRenderingDelegate.h"
6 #include "ui_VisualizationGraphWidget.h"
6 #include "ui_VisualizationGraphWidget.h"
7
7
8 #include <Data/ArrayData.h>
8 #include <Data/ArrayData.h>
9 #include <Data/IDataSeries.h>
9 #include <Data/IDataSeries.h>
10 #include <Settings/SqpSettingsDefs.h>
10 #include <Settings/SqpSettingsDefs.h>
11 #include <SqpApplication.h>
11 #include <SqpApplication.h>
12 #include <Variable/Variable.h>
12 #include <Variable/Variable.h>
13 #include <Variable/VariableController.h>
13 #include <Variable/VariableController.h>
14
14
15 #include <unordered_map>
15 #include <unordered_map>
16
16
17 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
17 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
18
18
19 namespace {
19 namespace {
20
20
21 /// Key pressed to enable zoom on horizontal axis
21 /// Key pressed to enable zoom on horizontal axis
22 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::NoModifier;
22 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::NoModifier;
23
23
24 /// Key pressed to enable zoom on vertical axis
24 /// Key pressed to enable zoom on vertical axis
25 const auto VERTICAL_ZOOM_MODIFIER = Qt::ControlModifier;
25 const auto VERTICAL_ZOOM_MODIFIER = Qt::ControlModifier;
26
26
27 } // namespace
27 } // namespace
28
28
29 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
29 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
30
30
31 explicit VisualizationGraphWidgetPrivate(const QString &name)
31 explicit VisualizationGraphWidgetPrivate(const QString &name)
32 : m_Name{name},
32 : m_Name{name},
33 m_DoAcquisition{true},
33 m_DoAcquisition{true},
34 m_IsCalibration{false},
34 m_IsCalibration{false},
35 m_RenderingDelegate{nullptr}
35 m_RenderingDelegate{nullptr}
36 {
36 {
37 }
37 }
38
38
39 QString m_Name;
39 QString m_Name;
40 // 1 variable -> n qcpplot
40 // 1 variable -> n qcpplot
41 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
41 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
42 bool m_DoAcquisition;
42 bool m_DoAcquisition;
43 bool m_IsCalibration;
43 bool m_IsCalibration;
44 QCPItemTracer *m_TextTracer;
44 QCPItemTracer *m_TextTracer;
45 /// Delegate used to attach rendering features to the plot
45 /// Delegate used to attach rendering features to the plot
46 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
46 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
47 };
47 };
48
48
49 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
49 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
50 : QWidget{parent},
50 : QWidget{parent},
51 ui{new Ui::VisualizationGraphWidget},
51 ui{new Ui::VisualizationGraphWidget},
52 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
52 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
53 {
53 {
54 ui->setupUi(this);
54 ui->setupUi(this);
55
55
56 // 'Close' options : widget is deleted when closed
56 // 'Close' options : widget is deleted when closed
57 setAttribute(Qt::WA_DeleteOnClose);
57 setAttribute(Qt::WA_DeleteOnClose);
58
58
59 // Set qcpplot properties :
59 // Set qcpplot properties :
60 // - Drag (on x-axis) and zoom are enabled
60 // - Drag (on x-axis) and zoom are enabled
61 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
61 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
62 ui->widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectItems);
62 ui->widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectItems);
63 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal);
63 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal);
64
64
65 // The delegate must be initialized after the ui as it uses the plot
65 // The delegate must be initialized after the ui as it uses the plot
66 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
66 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
67
67
68 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
68 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
69 connect(ui->widget, &QCustomPlot::mouseRelease, this,
69 connect(ui->widget, &QCustomPlot::mouseRelease, this,
70 &VisualizationGraphWidget::onMouseRelease);
70 &VisualizationGraphWidget::onMouseRelease);
71 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
71 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
72 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
72 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
73 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
73 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
74 &QCPAxis::rangeChanged),
74 &QCPAxis::rangeChanged),
75 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
75 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
76
76
77 // Activates menu when right clicking on the graph
77 // Activates menu when right clicking on the graph
78 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
78 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
79 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
79 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
80 &VisualizationGraphWidget::onGraphMenuRequested);
80 &VisualizationGraphWidget::onGraphMenuRequested);
81
81
82 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
82 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
83 &VariableController::onRequestDataLoading);
83 &VariableController::onRequestDataLoading);
84
84
85 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
85 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
86 &VisualizationGraphWidget::onUpdateVarDisplaying);
86 &VisualizationGraphWidget::onUpdateVarDisplaying);
87 }
87 }
88
88
89
89
90 VisualizationGraphWidget::~VisualizationGraphWidget()
90 VisualizationGraphWidget::~VisualizationGraphWidget()
91 {
91 {
92 delete ui;
92 delete ui;
93 }
93 }
94
94
95 void VisualizationGraphWidget::enableAcquisition(bool enable)
95 void VisualizationGraphWidget::enableAcquisition(bool enable)
96 {
96 {
97 impl->m_DoAcquisition = enable;
97 impl->m_DoAcquisition = enable;
98 }
98 }
99
99
100 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
100 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
101 {
101 {
102 // Uses delegate to create the qcpplot components according to the variable
102 // Uses delegate to create the qcpplot components according to the variable
103 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
103 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
104 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
104 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
105
105
106 // Set axes properties according to the units of the data series
106 // Set axes properties according to the units of the data series
107 /// @todo : for the moment, no control is performed on the axes: the units and the tickers
107 /// @todo : for the moment, no control is performed on the axes: the units and the tickers
108 /// are fixed for the default x-axis and y-axis of the plot, and according to the new graph
108 /// are fixed for the default x-axis and y-axis of the plot, and according to the new graph
109 auto xAxisUnit = Unit{};
109 auto xAxisUnit = Unit{};
110 auto valuesUnit = Unit{};
110 auto valuesUnit = Unit{};
111
111
112 if (auto dataSeries = variable->dataSeries()) {
112 if (auto dataSeries = variable->dataSeries()) {
113 dataSeries->lockRead();
113 dataSeries->lockRead();
114 xAxisUnit = dataSeries->xAxisUnit();
114 xAxisUnit = dataSeries->xAxisUnit();
115 valuesUnit = dataSeries->valuesUnit();
115 valuesUnit = dataSeries->valuesUnit();
116 dataSeries->unlock();
116 dataSeries->unlock();
117 }
117 }
118 impl->m_RenderingDelegate->setAxesProperties(xAxisUnit, valuesUnit);
118 impl->m_RenderingDelegate->setAxesProperties(xAxisUnit, valuesUnit);
119
119
120 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
120 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
121
121
122 auto varRange = variable->range();
122 auto varRange = variable->range();
123
123
124 this->enableAcquisition(false);
124 this->enableAcquisition(false);
125 this->setGraphRange(range);
125 this->setGraphRange(range);
126 this->enableAcquisition(true);
126 this->enableAcquisition(true);
127
127
128 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable, range, varRange,
128 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable, range, varRange,
129 false);
129 false);
130
130
131 emit variableAdded(variable);
131 emit variableAdded(variable);
132 }
132 }
133
133
134 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
134 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
135 {
135 {
136 // Each component associated to the variable :
136 // Each component associated to the variable :
137 // - is removed from qcpplot (which deletes it)
137 // - is removed from qcpplot (which deletes it)
138 // - is no longer referenced in the map
138 // - is no longer referenced in the map
139 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
139 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
140 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
140 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
141 emit variableAboutToBeRemoved(variable);
141 emit variableAboutToBeRemoved(variable);
142
142
143 auto &plottablesMap = variableIt->second;
143 auto &plottablesMap = variableIt->second;
144
144
145 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
145 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
146 plottableIt != plottableEnd;) {
146 plottableIt != plottableEnd;) {
147 ui->widget->removePlottable(plottableIt->second);
147 ui->widget->removePlottable(plottableIt->second);
148 plottableIt = plottablesMap.erase(plottableIt);
148 plottableIt = plottablesMap.erase(plottableIt);
149 }
149 }
150
150
151 impl->m_VariableToPlotMultiMap.erase(variableIt);
151 impl->m_VariableToPlotMultiMap.erase(variableIt);
152 }
152 }
153
153
154 // Updates graph
154 // Updates graph
155 ui->widget->replot();
155 ui->widget->replot();
156 }
156 }
157
157
158 void VisualizationGraphWidget::setRange(std::shared_ptr<Variable> variable, const SqpRange &range)
158 void VisualizationGraphWidget::setRange(std::shared_ptr<Variable> variable, const SqpRange &range)
159 {
159 {
160 // Note: in case of different axes that depends on variable, we could start with a code like
160 // Note: in case of different axes that depends on variable, we could start with a code like
161 // that:
161 // that:
162 // auto componentsIt = impl->m_VariableToPlotMultiMap.equal_range(variable);
162 // auto componentsIt = impl->m_VariableToPlotMultiMap.equal_range(variable);
163 // for (auto it = componentsIt.first; it != componentsIt.second;) {
163 // for (auto it = componentsIt.first; it != componentsIt.second;) {
164 // }
164 // }
165 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
165 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
166 ui->widget->replot();
166 ui->widget->replot();
167 }
167 }
168
168
169 void VisualizationGraphWidget::setYRange(const SqpRange &range)
169 void VisualizationGraphWidget::setYRange(const SqpRange &range)
170 {
170 {
171 ui->widget->yAxis->setRange(range.m_TStart, range.m_TEnd);
171 ui->widget->yAxis->setRange(range.m_TStart, range.m_TEnd);
172 }
172 }
173
173
174 SqpRange VisualizationGraphWidget::graphRange() const noexcept
174 SqpRange VisualizationGraphWidget::graphRange() const noexcept
175 {
175 {
176 auto graphRange = ui->widget->xAxis->range();
176 auto graphRange = ui->widget->xAxis->range();
177 return SqpRange{graphRange.lower, graphRange.upper};
177 return SqpRange{graphRange.lower, graphRange.upper};
178 }
178 }
179
179
180 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
180 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
181 {
181 {
182 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
182 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
183 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
183 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
184 ui->widget->replot();
184 ui->widget->replot();
185 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
185 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
186 }
186 }
187
187
188 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
188 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
189 {
189 {
190 if (visitor) {
190 if (visitor) {
191 visitor->visit(this);
191 visitor->visit(this);
192 }
192 }
193 else {
193 else {
194 qCCritical(LOG_VisualizationGraphWidget())
194 qCCritical(LOG_VisualizationGraphWidget())
195 << tr("Can't visit widget : the visitor is null");
195 << tr("Can't visit widget : the visitor is null");
196 }
196 }
197 }
197 }
198
198
199 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
199 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
200 {
200 {
201 /// @todo : for the moment, a graph can always accomodate a variable
201 /// @todo : for the moment, a graph can always accomodate a variable
202 Q_UNUSED(variable);
202 Q_UNUSED(variable);
203 return true;
203 return true;
204 }
204 }
205
205
206 bool VisualizationGraphWidget::contains(const Variable &variable) const
206 bool VisualizationGraphWidget::contains(const Variable &variable) const
207 {
207 {
208 // Finds the variable among the keys of the map
208 // Finds the variable among the keys of the map
209 auto variablePtr = &variable;
209 auto variablePtr = &variable;
210 auto findVariable
210 auto findVariable
211 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
211 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
212
212
213 auto end = impl->m_VariableToPlotMultiMap.cend();
213 auto end = impl->m_VariableToPlotMultiMap.cend();
214 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
214 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
215 return it != end;
215 return it != end;
216 }
216 }
217
217
218 QString VisualizationGraphWidget::name() const
218 QString VisualizationGraphWidget::name() const
219 {
219 {
220 return impl->m_Name;
220 return impl->m_Name;
221 }
221 }
222
222
223 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
223 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
224 {
224 {
225 Q_UNUSED(event);
225 Q_UNUSED(event);
226
226
227 // Prevents that all variables will be removed from graph when it will be closed
227 // Prevents that all variables will be removed from graph when it will be closed
228 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
228 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
229 emit variableAboutToBeRemoved(variableEntry.first);
229 emit variableAboutToBeRemoved(variableEntry.first);
230 }
230 }
231 }
231 }
232
232
233 void VisualizationGraphWidget::enterEvent(QEvent *event)
233 void VisualizationGraphWidget::enterEvent(QEvent *event)
234 {
234 {
235 Q_UNUSED(event);
235 Q_UNUSED(event);
236 impl->m_RenderingDelegate->showGraphOverlay(true);
236 impl->m_RenderingDelegate->showGraphOverlay(true);
237 }
237 }
238
238
239 void VisualizationGraphWidget::leaveEvent(QEvent *event)
239 void VisualizationGraphWidget::leaveEvent(QEvent *event)
240 {
240 {
241 Q_UNUSED(event);
241 Q_UNUSED(event);
242 impl->m_RenderingDelegate->showGraphOverlay(false);
242 impl->m_RenderingDelegate->showGraphOverlay(false);
243 }
243 }
244
244
245 QCustomPlot &VisualizationGraphWidget::plot() noexcept
245 QCustomPlot &VisualizationGraphWidget::plot() noexcept
246 {
246 {
247 return *ui->widget;
247 return *ui->widget;
248 }
248 }
249
249
250 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
250 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
251 {
251 {
252 QMenu graphMenu{};
252 QMenu graphMenu{};
253
253
254 // Iterates on variables (unique keys)
254 // Iterates on variables (unique keys)
255 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
255 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
256 end = impl->m_VariableToPlotMultiMap.cend();
256 end = impl->m_VariableToPlotMultiMap.cend();
257 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
257 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
258 // 'Remove variable' action
258 // 'Remove variable' action
259 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
259 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
260 [ this, var = it->first ]() { removeVariable(var); });
260 [ this, var = it->first ]() { removeVariable(var); });
261 }
261 }
262
262
263 if (!graphMenu.isEmpty()) {
263 if (!graphMenu.isEmpty()) {
264 graphMenu.exec(QCursor::pos());
264 graphMenu.exec(QCursor::pos());
265 }
265 }
266 }
266 }
267
267
268 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
268 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
269 {
269 {
270 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
270 qCDebug(LOG_VisualizationGraphWidget())
271 << QThread::currentThread()->objectName() << "DoAcqui"
271 << tr("TORM: VisualizationGraphWidget::onRangeChanged")
272 << impl->m_DoAcquisition;
272 << QThread::currentThread()->objectName() << "DoAcqui" << impl->m_DoAcquisition;
273
273
274 auto graphRange = SqpRange{t1.lower, t1.upper};
274 auto graphRange = SqpRange{t1.lower, t1.upper};
275 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
275 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
276
276
277 if (impl->m_DoAcquisition) {
277 if (impl->m_DoAcquisition) {
278 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
278 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
279
279
280 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
280 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
281 end = impl->m_VariableToPlotMultiMap.end();
281 end = impl->m_VariableToPlotMultiMap.end();
282 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
282 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
283 variableUnderGraphVector.push_back(it->first);
283 variableUnderGraphVector.push_back(it->first);
284 }
284 }
285 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange, oldGraphRange,
285 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange, oldGraphRange,
286 !impl->m_IsCalibration);
286 !impl->m_IsCalibration);
287
287
288 if (!impl->m_IsCalibration) {
288 if (!impl->m_IsCalibration) {
289 qCDebug(LOG_VisualizationGraphWidget())
289 qCDebug(LOG_VisualizationGraphWidget())
290 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
290 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
291 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
291 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
292 emit synchronize(graphRange, oldGraphRange);
292 emit synchronize(graphRange, oldGraphRange);
293 }
293 }
294 }
294 }
295 }
295 }
296
296
297 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
297 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
298 {
298 {
299 // Handles plot rendering when mouse is moving
299 // Handles plot rendering when mouse is moving
300 impl->m_RenderingDelegate->onMouseMove(event);
300 impl->m_RenderingDelegate->onMouseMove(event);
301 }
301 }
302
302
303 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
303 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
304 {
304 {
305 auto zoomOrientations = QFlags<Qt::Orientation>{};
305 auto zoomOrientations = QFlags<Qt::Orientation>{};
306
306
307 // Lambda that enables a zoom orientation if the key modifier related to this orientation
307 // Lambda that enables a zoom orientation if the key modifier related to this orientation
308 // has
308 // has
309 // been pressed
309 // been pressed
310 auto enableOrientation
310 auto enableOrientation
311 = [&zoomOrientations, event](const auto &orientation, const auto &modifier) {
311 = [&zoomOrientations, event](const auto &orientation, const auto &modifier) {
312 auto orientationEnabled = event->modifiers().testFlag(modifier);
312 auto orientationEnabled = event->modifiers().testFlag(modifier);
313 zoomOrientations.setFlag(orientation, orientationEnabled);
313 zoomOrientations.setFlag(orientation, orientationEnabled);
314 };
314 };
315 enableOrientation(Qt::Vertical, VERTICAL_ZOOM_MODIFIER);
315 enableOrientation(Qt::Vertical, VERTICAL_ZOOM_MODIFIER);
316 enableOrientation(Qt::Horizontal, HORIZONTAL_ZOOM_MODIFIER);
316 enableOrientation(Qt::Horizontal, HORIZONTAL_ZOOM_MODIFIER);
317
317
318 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
318 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
319 }
319 }
320
320
321 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
321 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
322 {
322 {
323 impl->m_IsCalibration = event->modifiers().testFlag(Qt::ControlModifier);
323 impl->m_IsCalibration = event->modifiers().testFlag(Qt::ControlModifier);
324 }
324 }
325
325
326 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
326 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
327 {
327 {
328 impl->m_IsCalibration = false;
328 impl->m_IsCalibration = false;
329 }
329 }
330
330
331 void VisualizationGraphWidget::onDataCacheVariableUpdated()
331 void VisualizationGraphWidget::onDataCacheVariableUpdated()
332 {
332 {
333 auto graphRange = ui->widget->xAxis->range();
333 auto graphRange = ui->widget->xAxis->range();
334 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
334 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
335
335
336 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
336 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
337 auto variable = variableEntry.first;
337 auto variable = variableEntry.first;
338 qCDebug(LOG_VisualizationGraphWidget())
338 qCDebug(LOG_VisualizationGraphWidget())
339 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
339 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
340 qCDebug(LOG_VisualizationGraphWidget())
340 qCDebug(LOG_VisualizationGraphWidget())
341 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
341 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
342 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
342 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
343 VisualizationGraphHelper::updateData(variableEntry.second, variable->dataSeries(),
343 VisualizationGraphHelper::updateData(variableEntry.second, variable->dataSeries(),
344 variable->range());
344 variable->range());
345 }
345 }
346 }
346 }
347 }
347 }
348
348
349 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
349 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
350 const SqpRange &range)
350 const SqpRange &range)
351 {
351 {
352 auto it = impl->m_VariableToPlotMultiMap.find(variable);
352 auto it = impl->m_VariableToPlotMultiMap.find(variable);
353 if (it != impl->m_VariableToPlotMultiMap.end()) {
353 if (it != impl->m_VariableToPlotMultiMap.end()) {
354 VisualizationGraphHelper::updateData(it->second, variable->dataSeries(), range);
354 VisualizationGraphHelper::updateData(it->second, variable->dataSeries(), range);
355 }
355 }
356 }
356 }
@@ -1,302 +1,302
1 #include "Visualization/VisualizationZoneWidget.h"
1 #include "Visualization/VisualizationZoneWidget.h"
2
2
3 #include "Visualization/IVisualizationWidgetVisitor.h"
3 #include "Visualization/IVisualizationWidgetVisitor.h"
4 #include "Visualization/QCustomPlotSynchronizer.h"
4 #include "Visualization/QCustomPlotSynchronizer.h"
5 #include "Visualization/VisualizationGraphWidget.h"
5 #include "Visualization/VisualizationGraphWidget.h"
6 #include "ui_VisualizationZoneWidget.h"
6 #include "ui_VisualizationZoneWidget.h"
7
7
8 #include <Data/SqpRange.h>
8 #include <Data/SqpRange.h>
9 #include <Variable/Variable.h>
9 #include <Variable/Variable.h>
10 #include <Variable/VariableController.h>
10 #include <Variable/VariableController.h>
11
11
12 #include <QUuid>
12 #include <QUuid>
13 #include <SqpApplication.h>
13 #include <SqpApplication.h>
14 #include <cmath>
14 #include <cmath>
15
15
16 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
16 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
17
17
18 namespace {
18 namespace {
19
19
20 /// Minimum height for graph added in zones (in pixels)
20 /// Minimum height for graph added in zones (in pixels)
21 const auto GRAPH_MINIMUM_HEIGHT = 300;
21 const auto GRAPH_MINIMUM_HEIGHT = 300;
22
22
23 /// Generates a default name for a new graph, according to the number of graphs already displayed in
23 /// Generates a default name for a new graph, according to the number of graphs already displayed in
24 /// the zone
24 /// the zone
25 QString defaultGraphName(const QLayout &layout)
25 QString defaultGraphName(const QLayout &layout)
26 {
26 {
27 auto count = 0;
27 auto count = 0;
28 for (auto i = 0; i < layout.count(); ++i) {
28 for (auto i = 0; i < layout.count(); ++i) {
29 if (dynamic_cast<VisualizationGraphWidget *>(layout.itemAt(i)->widget())) {
29 if (dynamic_cast<VisualizationGraphWidget *>(layout.itemAt(i)->widget())) {
30 count++;
30 count++;
31 }
31 }
32 }
32 }
33
33
34 return QObject::tr("Graph %1").arg(count + 1);
34 return QObject::tr("Graph %1").arg(count + 1);
35 }
35 }
36
36
37 /**
37 /**
38 * Applies a function to all graphs of the zone represented by its layout
38 * Applies a function to all graphs of the zone represented by its layout
39 * @param layout the layout that contains graphs
39 * @param layout the layout that contains graphs
40 * @param fun the function to apply to each graph
40 * @param fun the function to apply to each graph
41 */
41 */
42 template <typename Fun>
42 template <typename Fun>
43 void processGraphs(QLayout &layout, Fun fun)
43 void processGraphs(QLayout &layout, Fun fun)
44 {
44 {
45 for (auto i = 0; i < layout.count(); ++i) {
45 for (auto i = 0; i < layout.count(); ++i) {
46 if (auto item = layout.itemAt(i)) {
46 if (auto item = layout.itemAt(i)) {
47 if (auto visualizationGraphWidget
47 if (auto visualizationGraphWidget
48 = dynamic_cast<VisualizationGraphWidget *>(item->widget())) {
48 = dynamic_cast<VisualizationGraphWidget *>(item->widget())) {
49 fun(*visualizationGraphWidget);
49 fun(*visualizationGraphWidget);
50 }
50 }
51 }
51 }
52 }
52 }
53 }
53 }
54
54
55 } // namespace
55 } // namespace
56
56
57 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate {
57 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate {
58
58
59 explicit VisualizationZoneWidgetPrivate()
59 explicit VisualizationZoneWidgetPrivate()
60 : m_SynchronisationGroupId{QUuid::createUuid()},
60 : m_SynchronisationGroupId{QUuid::createUuid()},
61 m_Synchronizer{std::make_unique<QCustomPlotSynchronizer>()}
61 m_Synchronizer{std::make_unique<QCustomPlotSynchronizer>()}
62 {
62 {
63 }
63 }
64 QUuid m_SynchronisationGroupId;
64 QUuid m_SynchronisationGroupId;
65 std::unique_ptr<IGraphSynchronizer> m_Synchronizer;
65 std::unique_ptr<IGraphSynchronizer> m_Synchronizer;
66 };
66 };
67
67
68 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
68 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
69 : QWidget{parent},
69 : QWidget{parent},
70 ui{new Ui::VisualizationZoneWidget},
70 ui{new Ui::VisualizationZoneWidget},
71 impl{spimpl::make_unique_impl<VisualizationZoneWidgetPrivate>()}
71 impl{spimpl::make_unique_impl<VisualizationZoneWidgetPrivate>()}
72 {
72 {
73 ui->setupUi(this);
73 ui->setupUi(this);
74
74
75 ui->zoneNameLabel->setText(name);
75 ui->zoneNameLabel->setText(name);
76
76
77 // 'Close' options : widget is deleted when closed
77 // 'Close' options : widget is deleted when closed
78 setAttribute(Qt::WA_DeleteOnClose);
78 setAttribute(Qt::WA_DeleteOnClose);
79 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
79 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
80 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
80 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
81
81
82 // Synchronisation id
82 // Synchronisation id
83 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronizationGroupId",
83 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronizationGroupId",
84 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
84 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
85 }
85 }
86
86
87 VisualizationZoneWidget::~VisualizationZoneWidget()
87 VisualizationZoneWidget::~VisualizationZoneWidget()
88 {
88 {
89 delete ui;
89 delete ui;
90 }
90 }
91
91
92 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
92 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
93 {
93 {
94 // Synchronize new graph with others in the zone
94 // Synchronize new graph with others in the zone
95 impl->m_Synchronizer->addGraph(*graphWidget);
95 impl->m_Synchronizer->addGraph(*graphWidget);
96
96
97 ui->visualizationZoneFrame->layout()->addWidget(graphWidget);
97 ui->visualizationZoneFrame->layout()->addWidget(graphWidget);
98 }
98 }
99
99
100 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
100 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
101 {
101 {
102 auto graphWidget = new VisualizationGraphWidget{
102 auto graphWidget = new VisualizationGraphWidget{
103 defaultGraphName(*ui->visualizationZoneFrame->layout()), this};
103 defaultGraphName(*ui->visualizationZoneFrame->layout()), this};
104
104
105
105
106 // Set graph properties
106 // Set graph properties
107 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
107 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
108 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
108 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
109
109
110
110
111 // Lambda to synchronize zone widget
111 // Lambda to synchronize zone widget
112 auto synchronizeZoneWidget = [this, graphWidget](const SqpRange &graphRange,
112 auto synchronizeZoneWidget = [this, graphWidget](const SqpRange &graphRange,
113 const SqpRange &oldGraphRange) {
113 const SqpRange &oldGraphRange) {
114
114
115 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
115 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
116 auto frameLayout = ui->visualizationZoneFrame->layout();
116 auto frameLayout = ui->visualizationZoneFrame->layout();
117 for (auto i = 0; i < frameLayout->count(); ++i) {
117 for (auto i = 0; i < frameLayout->count(); ++i) {
118 auto graphChild
118 auto graphChild
119 = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
119 = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
120 if (graphChild && (graphChild != graphWidget)) {
120 if (graphChild && (graphChild != graphWidget)) {
121
121
122 auto graphChildRange = graphChild->graphRange();
122 auto graphChildRange = graphChild->graphRange();
123 switch (zoomType) {
123 switch (zoomType) {
124 case AcquisitionZoomType::ZoomIn: {
124 case AcquisitionZoomType::ZoomIn: {
125 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
125 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
126 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
126 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
127 graphChildRange.m_TStart += deltaLeft;
127 graphChildRange.m_TStart += deltaLeft;
128 graphChildRange.m_TEnd -= deltaRight;
128 graphChildRange.m_TEnd -= deltaRight;
129 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomIn");
129 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomIn");
130 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
130 qCDebug(LOG_VisualizationZoneWidget())
131 << deltaLeft;
131 << tr("TORM: deltaLeft") << deltaLeft;
132 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
132 qCDebug(LOG_VisualizationZoneWidget())
133 << deltaRight;
133 << tr("TORM: deltaRight") << deltaRight;
134 qCDebug(LOG_VisualizationZoneWidget())
134 qCDebug(LOG_VisualizationZoneWidget())
135 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
135 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
136
136
137 break;
137 break;
138 }
138 }
139
139
140 case AcquisitionZoomType::ZoomOut: {
140 case AcquisitionZoomType::ZoomOut: {
141 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomOut");
141 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomOut");
142 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
142 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
143 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
143 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
144 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
144 qCDebug(LOG_VisualizationZoneWidget())
145 << deltaLeft;
145 << tr("TORM: deltaLeft") << deltaLeft;
146 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
146 qCDebug(LOG_VisualizationZoneWidget())
147 << deltaRight;
147 << tr("TORM: deltaRight") << deltaRight;
148 qCDebug(LOG_VisualizationZoneWidget())
148 qCDebug(LOG_VisualizationZoneWidget())
149 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
149 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
150 graphChildRange.m_TStart -= deltaLeft;
150 graphChildRange.m_TStart -= deltaLeft;
151 graphChildRange.m_TEnd += deltaRight;
151 graphChildRange.m_TEnd += deltaRight;
152 break;
152 break;
153 }
153 }
154 case AcquisitionZoomType::PanRight: {
154 case AcquisitionZoomType::PanRight: {
155 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanRight");
155 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanRight");
156 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
156 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
157 graphChildRange.m_TStart += deltaRight;
157 graphChildRange.m_TStart += deltaRight;
158 graphChildRange.m_TEnd += deltaRight;
158 graphChildRange.m_TEnd += deltaRight;
159 qCDebug(LOG_VisualizationZoneWidget())
159 qCDebug(LOG_VisualizationZoneWidget())
160 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
160 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
161 break;
161 break;
162 }
162 }
163 case AcquisitionZoomType::PanLeft: {
163 case AcquisitionZoomType::PanLeft: {
164 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanLeft");
164 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanLeft");
165 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
165 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
166 graphChildRange.m_TStart -= deltaLeft;
166 graphChildRange.m_TStart -= deltaLeft;
167 graphChildRange.m_TEnd -= deltaLeft;
167 graphChildRange.m_TEnd -= deltaLeft;
168 break;
168 break;
169 }
169 }
170 case AcquisitionZoomType::Unknown: {
170 case AcquisitionZoomType::Unknown: {
171 qCDebug(LOG_VisualizationZoneWidget())
171 qCDebug(LOG_VisualizationZoneWidget())
172 << tr("Impossible to synchronize: zoom type unknown");
172 << tr("Impossible to synchronize: zoom type unknown");
173 break;
173 break;
174 }
174 }
175 default:
175 default:
176 qCCritical(LOG_VisualizationZoneWidget())
176 qCCritical(LOG_VisualizationZoneWidget())
177 << tr("Impossible to synchronize: zoom type not take into account");
177 << tr("Impossible to synchronize: zoom type not take into account");
178 // No action
178 // No action
179 break;
179 break;
180 }
180 }
181 graphChild->enableAcquisition(false);
181 graphChild->enableAcquisition(false);
182 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range before: ")
182 qCDebug(LOG_VisualizationZoneWidget())
183 << graphChild->graphRange();
183 << tr("TORM: Range before: ") << graphChild->graphRange();
184 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range after : ")
184 qCDebug(LOG_VisualizationZoneWidget())
185 << graphChildRange;
185 << tr("TORM: Range after : ") << graphChildRange;
186 qCDebug(LOG_VisualizationZoneWidget())
186 qCDebug(LOG_VisualizationZoneWidget())
187 << tr("TORM: child dt") << graphChildRange.m_TEnd - graphChildRange.m_TStart;
187 << tr("TORM: child dt") << graphChildRange.m_TEnd - graphChildRange.m_TStart;
188 graphChild->setGraphRange(graphChildRange);
188 graphChild->setGraphRange(graphChildRange);
189 graphChild->enableAcquisition(true);
189 graphChild->enableAcquisition(true);
190 }
190 }
191 }
191 }
192 };
192 };
193
193
194 // connection for synchronization
194 // connection for synchronization
195 connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
195 connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
196 connect(graphWidget, &VisualizationGraphWidget::variableAdded, this,
196 connect(graphWidget, &VisualizationGraphWidget::variableAdded, this,
197 &VisualizationZoneWidget::onVariableAdded);
197 &VisualizationZoneWidget::onVariableAdded);
198 connect(graphWidget, &VisualizationGraphWidget::variableAboutToBeRemoved, this,
198 connect(graphWidget, &VisualizationGraphWidget::variableAboutToBeRemoved, this,
199 &VisualizationZoneWidget::onVariableAboutToBeRemoved);
199 &VisualizationZoneWidget::onVariableAboutToBeRemoved);
200
200
201 auto range = SqpRange{};
201 auto range = SqpRange{};
202
202
203 // Apply visitor to graph children
203 // Apply visitor to graph children
204 auto layout = ui->visualizationZoneFrame->layout();
204 auto layout = ui->visualizationZoneFrame->layout();
205 if (layout->count() > 0) {
205 if (layout->count() > 0) {
206 // Case of a new graph in a existant zone
206 // Case of a new graph in a existant zone
207 if (auto visualizationGraphWidget
207 if (auto visualizationGraphWidget
208 = dynamic_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
208 = dynamic_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
209 range = visualizationGraphWidget->graphRange();
209 range = visualizationGraphWidget->graphRange();
210 }
210 }
211 }
211 }
212 else {
212 else {
213 // Case of a new graph as the first of the zone
213 // Case of a new graph as the first of the zone
214 range = variable->range();
214 range = variable->range();
215 }
215 }
216
216
217 this->addGraph(graphWidget);
217 this->addGraph(graphWidget);
218
218
219 graphWidget->addVariable(variable, range);
219 graphWidget->addVariable(variable, range);
220
220
221 // get y using variable range
221 // get y using variable range
222 if (auto dataSeries = variable->dataSeries()) {
222 if (auto dataSeries = variable->dataSeries()) {
223 dataSeries->lockRead();
223 dataSeries->lockRead();
224 auto valuesBounds
224 auto valuesBounds
225 = dataSeries->valuesBounds(variable->range().m_TStart, variable->range().m_TEnd);
225 = dataSeries->valuesBounds(variable->range().m_TStart, variable->range().m_TEnd);
226 auto end = dataSeries->cend();
226 auto end = dataSeries->cend();
227 if (valuesBounds.first != end && valuesBounds.second != end) {
227 if (valuesBounds.first != end && valuesBounds.second != end) {
228 auto rangeValue = [](const auto &value) { return std::isnan(value) ? 0. : value; };
228 auto rangeValue = [](const auto &value) { return std::isnan(value) ? 0. : value; };
229
229
230 auto minValue = rangeValue(valuesBounds.first->minValue());
230 auto minValue = rangeValue(valuesBounds.first->minValue());
231 auto maxValue = rangeValue(valuesBounds.second->maxValue());
231 auto maxValue = rangeValue(valuesBounds.second->maxValue());
232
232
233 graphWidget->setYRange(SqpRange{minValue, maxValue});
233 graphWidget->setYRange(SqpRange{minValue, maxValue});
234 }
234 }
235 dataSeries->unlock();
235 dataSeries->unlock();
236 }
236 }
237
237
238 return graphWidget;
238 return graphWidget;
239 }
239 }
240
240
241 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
241 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
242 {
242 {
243 if (visitor) {
243 if (visitor) {
244 visitor->visitEnter(this);
244 visitor->visitEnter(this);
245
245
246 // Apply visitor to graph children: widgets different from graphs are not visited (no
246 // Apply visitor to graph children: widgets different from graphs are not visited (no
247 // action)
247 // action)
248 processGraphs(
248 processGraphs(
249 *ui->visualizationZoneFrame->layout(),
249 *ui->visualizationZoneFrame->layout(),
250 [visitor](VisualizationGraphWidget &graphWidget) { graphWidget.accept(visitor); });
250 [visitor](VisualizationGraphWidget &graphWidget) { graphWidget.accept(visitor); });
251
251
252 visitor->visitLeave(this);
252 visitor->visitLeave(this);
253 }
253 }
254 else {
254 else {
255 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
255 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
256 }
256 }
257 }
257 }
258
258
259 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
259 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
260 {
260 {
261 // A tab can always accomodate a variable
261 // A tab can always accomodate a variable
262 Q_UNUSED(variable);
262 Q_UNUSED(variable);
263 return true;
263 return true;
264 }
264 }
265
265
266 bool VisualizationZoneWidget::contains(const Variable &variable) const
266 bool VisualizationZoneWidget::contains(const Variable &variable) const
267 {
267 {
268 Q_UNUSED(variable);
268 Q_UNUSED(variable);
269 return false;
269 return false;
270 }
270 }
271
271
272 QString VisualizationZoneWidget::name() const
272 QString VisualizationZoneWidget::name() const
273 {
273 {
274 return ui->zoneNameLabel->text();
274 return ui->zoneNameLabel->text();
275 }
275 }
276
276
277 void VisualizationZoneWidget::closeEvent(QCloseEvent *event)
277 void VisualizationZoneWidget::closeEvent(QCloseEvent *event)
278 {
278 {
279 // Closes graphs in the zone
279 // Closes graphs in the zone
280 processGraphs(*ui->visualizationZoneFrame->layout(),
280 processGraphs(*ui->visualizationZoneFrame->layout(),
281 [](VisualizationGraphWidget &graphWidget) { graphWidget.close(); });
281 [](VisualizationGraphWidget &graphWidget) { graphWidget.close(); });
282
282
283 // Delete synchronization group from variable controller
283 // Delete synchronization group from variable controller
284 QMetaObject::invokeMethod(&sqpApp->variableController(), "onRemoveSynchronizationGroupId",
284 QMetaObject::invokeMethod(&sqpApp->variableController(), "onRemoveSynchronizationGroupId",
285 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
285 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
286
286
287 QWidget::closeEvent(event);
287 QWidget::closeEvent(event);
288 }
288 }
289
289
290 void VisualizationZoneWidget::onVariableAdded(std::shared_ptr<Variable> variable)
290 void VisualizationZoneWidget::onVariableAdded(std::shared_ptr<Variable> variable)
291 {
291 {
292 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronized",
292 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronized",
293 Qt::QueuedConnection, Q_ARG(std::shared_ptr<Variable>, variable),
293 Qt::QueuedConnection, Q_ARG(std::shared_ptr<Variable>, variable),
294 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
294 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
295 }
295 }
296
296
297 void VisualizationZoneWidget::onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable)
297 void VisualizationZoneWidget::onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable)
298 {
298 {
299 QMetaObject::invokeMethod(&sqpApp->variableController(), "desynchronize", Qt::QueuedConnection,
299 QMetaObject::invokeMethod(&sqpApp->variableController(), "desynchronize", Qt::QueuedConnection,
300 Q_ARG(std::shared_ptr<Variable>, variable),
300 Q_ARG(std::shared_ptr<Variable>, variable),
301 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
301 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
302 }
302 }
@@ -1,176 +1,176
1 #include "AmdaParser.h"
1 #include "AmdaParser.h"
2
2
3 #include <DataSource/DataSourceItem.h>
3 #include <DataSource/DataSourceItem.h>
4
4
5 #include <QObject>
5 #include <QObject>
6 #include <QtTest>
6 #include <QtTest>
7
7
8 #include <QString>
8 #include <QString>
9
9
10 namespace {
10 namespace {
11
11
12 /// Path for the tests
12 /// Path for the tests
13 const auto TESTS_RESOURCES_PATH
13 const auto TESTS_RESOURCES_PATH
14 = QFileInfo{QString{AMDA_TESTS_RESOURCES_DIR}, "TestAmdaParser"}.absoluteFilePath();
14 = QFileInfo{QString{AMDA_TESTS_RESOURCES_DIR}, "TestAmdaParser"}.absoluteFilePath();
15
15
16 QString inputFilePath(const QString &inputFileName)
16 QString inputFilePath(const QString &inputFileName)
17 {
17 {
18 return QFileInfo{TESTS_RESOURCES_PATH, inputFileName}.absoluteFilePath();
18 return QFileInfo{TESTS_RESOURCES_PATH, inputFileName}.absoluteFilePath();
19 }
19 }
20
20
21 struct ExpectedResults {
21 struct ExpectedResults {
22 explicit ExpectedResults() = default;
22 explicit ExpectedResults() = default;
23 explicit ExpectedResults(std::shared_ptr<DataSourceItem> item)
23 explicit ExpectedResults(std::shared_ptr<DataSourceItem> item)
24 : m_ParsingOK{true}, m_Item{std::move(item)}
24 : m_ParsingOK{true}, m_Item{std::move(item)}
25 {
25 {
26 }
26 }
27
27
28 // Parsing was successfully completed
28 // Parsing was successfully completed
29 bool m_ParsingOK{false};
29 bool m_ParsingOK{false};
30 // Expected item after parsing
30 // Expected item after parsing
31 std::shared_ptr<DataSourceItem> m_Item{nullptr};
31 std::shared_ptr<DataSourceItem> m_Item{nullptr};
32 };
32 };
33
33
34 // ///////////////////////////////// //
34 // ///////////////////////////////// //
35 // Set of expected results for tests //
35 // Set of expected results for tests //
36 // ///////////////////////////////// //
36 // ///////////////////////////////// //
37
37
38 ExpectedResults validResults1()
38 ExpectedResults validResults1()
39 {
39 {
40 auto component1 = std::make_unique<DataSourceItem>(
40 auto component1 = std::make_unique<DataSourceItem>(
41 DataSourceItemType::COMPONENT,
41 DataSourceItemType::COMPONENT,
42 QHash<QString, QVariant>{{"name", "Bx"}, {"xml:id", "ice_b_cse(0)"}});
42 QHash<QString, QVariant>{{"name", "Bx"}, {"xml:id", "ice_b_cse(0)"}});
43 auto component2 = std::make_unique<DataSourceItem>(
43 auto component2 = std::make_unique<DataSourceItem>(
44 DataSourceItemType::COMPONENT,
44 DataSourceItemType::COMPONENT,
45 QHash<QString, QVariant>{{"name", "By"}, {"xml:id", "ice_b_cse(1)"}});
45 QHash<QString, QVariant>{{"name", "By"}, {"xml:id", "ice_b_cse(1)"}});
46 auto component3 = std::make_unique<DataSourceItem>(
46 auto component3 = std::make_unique<DataSourceItem>(
47 DataSourceItemType::COMPONENT,
47 DataSourceItemType::COMPONENT,
48 QHash<QString, QVariant>{{"name", "Bz"}, {"xml:id", "ice_b_cse(2)"}});
48 QHash<QString, QVariant>{{"name", "Bz"}, {"xml:id", "ice_b_cse(2)"}});
49 auto parameter1 = std::make_unique<DataSourceItem>(
49 auto parameter1 = std::make_unique<DataSourceItem>(
50 DataSourceItemType::PRODUCT,
50 DataSourceItemType::PRODUCT,
51 QHash<QString, QVariant>{
51 QHash<QString, QVariant>{
52 {"name", "B_cse"}, {"units", "nT"}, {"display_type", ""}, {"xml:id", "ice_b_cse"}});
52 {"name", "B_cse"}, {"units", "nT"}, {"display_type", ""}, {"xml:id", "ice_b_cse"}});
53 parameter1->appendChild(std::move(component1));
53 parameter1->appendChild(std::move(component1));
54 parameter1->appendChild(std::move(component2));
54 parameter1->appendChild(std::move(component2));
55 parameter1->appendChild(std::move(component3));
55 parameter1->appendChild(std::move(component3));
56
56
57 auto parameter2 = std::make_unique<DataSourceItem>(
57 auto parameter2 = std::make_unique<DataSourceItem>(
58 DataSourceItemType::PRODUCT,
58 DataSourceItemType::PRODUCT,
59 QHash<QString, QVariant>{
59 QHash<QString, QVariant>{
60 {"name", "|B|"}, {"units", "nT"}, {"display_type", ""}, {"xml:id", "ice_b_tot"}});
60 {"name", "|B|"}, {"units", "nT"}, {"display_type", ""}, {"xml:id", "ice_b_tot"}});
61
61
62 auto dataset = std::make_unique<DataSourceItem>(
62 auto dataset = std::make_unique<DataSourceItem>(
63 DataSourceItemType::NODE, QHash<QString, QVariant>{{"att", ""},
63 DataSourceItemType::NODE, QHash<QString, QVariant>{{"att", ""},
64 {"restricted", ""},
64 {"restricted", ""},
65 {"name", "Magnetic Field"},
65 {"name", "Magnetic Field"},
66 {"xml:id", "ice:mag:p21"},
66 {"xml:id", "ice:mag:p21"},
67 {"sampling", "0.3s"},
67 {"sampling", "0.3s"},
68 {"maxSampling", ""},
68 {"maxSampling", ""},
69 {"dataStart", "1985/09/10"},
69 {"dataStart", "1985/09/10"},
70 {"dataStop", "1985/09/14"},
70 {"dataStop", "1985/09/14"},
71 {"dataSource", "PDS"},
71 {"dataSource", "PDS"},
72 {"target", ""}});
72 {"target", ""}});
73 dataset->appendChild(std::move(parameter1));
73 dataset->appendChild(std::move(parameter1));
74 dataset->appendChild(std::move(parameter2));
74 dataset->appendChild(std::move(parameter2));
75
75
76 auto instrument = std::make_unique<DataSourceItem>(
76 auto instrument = std::make_unique<DataSourceItem>(
77 DataSourceItemType::NODE, QHash<QString, QVariant>{{"att", ""},
77 DataSourceItemType::NODE, QHash<QString, QVariant>{{"att", ""},
78 {"name", "MAG"},
78 {"name", "MAG"},
79 {"xml:id", "ICE@Giacobini-Zinner:MAG"},
79 {"xml:id", "ICE@Giacobini-Zinner:MAG"},
80 {"desc", "Vector Helium Magnetometer"},
80 {"desc", "Vector Helium Magnetometer"},
81 {"restricted", ""}});
81 {"restricted", ""}});
82 instrument->appendChild(std::move(dataset));
82 instrument->appendChild(std::move(dataset));
83
83
84 auto mission = std::make_unique<DataSourceItem>(
84 auto mission = std::make_unique<DataSourceItem>(
85 DataSourceItemType::NODE,
85 DataSourceItemType::NODE,
86 QHash<QString, QVariant>{{"att", ""},
86 QHash<QString, QVariant>{{"att", ""},
87 {"name", "ICE@Giacobini-Zinner"},
87 {"name", "ICE@Giacobini-Zinner"},
88 {"rank", "93"},
88 {"rank", "93"},
89 {"xml:id", "ICE@Giacobini-Zinner"},
89 {"xml:id", "ICE@Giacobini-Zinner"},
90 {"desc", "International Cometary Explorer"},
90 {"desc", "International Cometary Explorer"},
91 {"target", "Comet"},
91 {"target", "Comet"},
92 {"available", "1"}});
92 {"available", "1"}});
93 mission->appendChild(std::move(instrument));
93 mission->appendChild(std::move(instrument));
94
94
95 auto item = std::make_shared<DataSourceItem>(DataSourceItemType::NODE,
95 auto item = std::make_shared<DataSourceItem>(DataSourceItemType::NODE,
96 QHash<QString, QVariant>{
96 QHash<QString, QVariant>{
97 {"name", "AMDA"},
97 {"name", "AMDA"},
98 {"desc", "AMDA_Internal_Data_Base"},
98 {"desc", "AMDA_Internal_Data_Base"},
99 {"xml:id", "myLocalData-treeRootNode"},
99 {"xml:id", "myLocalData-treeRootNode"},
100 });
100 });
101 item->appendChild(std::move(mission));
101 item->appendChild(std::move(mission));
102
102
103 return ExpectedResults{item};
103 return ExpectedResults{item};
104 }
104 }
105
105
106 ExpectedResults invalidResults()
106 ExpectedResults invalidResults()
107 {
107 {
108 return ExpectedResults{};
108 return ExpectedResults{};
109 }
109 }
110
110
111 } // namespace
111 } // namespace
112
112
113 Q_DECLARE_METATYPE(ExpectedResults)
113 Q_DECLARE_METATYPE(ExpectedResults)
114
114
115 class TestAmdaParser : public QObject {
115 class TestAmdaParser : public QObject {
116 Q_OBJECT
116 Q_OBJECT
117 private slots:
117 private slots:
118 /// Input test data
118 /// Input test data
119 /// @sa testReadJson()
119 /// @sa testReadJson()
120 void testReadJson_data();
120 void testReadJson_data();
121
121
122 /// Tests parsing of a JSON file
122 /// Tests parsing of a JSON file
123 void testReadJson();
123 void testReadJson();
124 };
124 };
125
125
126 void TestAmdaParser::testReadJson_data()
126 void TestAmdaParser::testReadJson_data()
127 {
127 {
128 // ////////////// //
128 // ////////////// //
129 // Test structure //
129 // Test structure //
130 // ////////////// //
130 // ////////////// //
131
131
132 // Name of JSON file to read
132 // Name of JSON file to read
133 QTest::addColumn<QString>("inputFileName");
133 QTest::addColumn<QString>("inputFileName");
134 // Expected results
134 // Expected results
135 QTest::addColumn<ExpectedResults>("expectedResults");
135 QTest::addColumn<ExpectedResults>("expectedResults");
136
136
137 // ////////// //
137 // ////////// //
138 // Test cases //
138 // Test cases //
139 // ////////// //
139 // ////////// //
140
140
141 // Valid file
141 // Valid file
142 QTest::newRow("Valid file") << QStringLiteral("ValidFile1.json") << validResults1();
142 QTest::newRow("Valid file") << QStringLiteral("ValidFile1.json") << validResults1();
143
143
144 // Invalid files
144 // Invalid files
145 QTest::newRow("Invalid file (unexisting file)") << QStringLiteral("UnexistingFile.json")
145 QTest::newRow("Invalid file (unexisting file)")
146 << invalidResults();
146 << QStringLiteral("UnexistingFile.json") << invalidResults();
147 QTest::newRow("Invalid file (two root objects)") << QStringLiteral("TwoRootsFile.json")
147 QTest::newRow("Invalid file (two root objects)")
148 << invalidResults();
148 << QStringLiteral("TwoRootsFile.json") << invalidResults();
149 QTest::newRow("Invalid file (wrong root key)") << QStringLiteral("WrongRootKey.json")
149 QTest::newRow("Invalid file (wrong root key)")
150 << invalidResults();
150 << QStringLiteral("WrongRootKey.json") << invalidResults();
151 QTest::newRow("Invalid file (wrong root type)") << QStringLiteral("WrongRootType.json")
151 QTest::newRow("Invalid file (wrong root type)")
152 << invalidResults();
152 << QStringLiteral("WrongRootType.json") << invalidResults();
153 }
153 }
154
154
155 void TestAmdaParser::testReadJson()
155 void TestAmdaParser::testReadJson()
156 {
156 {
157 QFETCH(QString, inputFileName);
157 QFETCH(QString, inputFileName);
158 QFETCH(ExpectedResults, expectedResults);
158 QFETCH(ExpectedResults, expectedResults);
159
159
160 // Parses file
160 // Parses file
161 auto filePath = inputFilePath(inputFileName);
161 auto filePath = inputFilePath(inputFileName);
162 auto item = AmdaParser::readJson(filePath);
162 auto item = AmdaParser::readJson(filePath);
163
163
164 // Validates results
164 // Validates results
165 if (expectedResults.m_ParsingOK) {
165 if (expectedResults.m_ParsingOK) {
166 QVERIFY(item != nullptr);
166 QVERIFY(item != nullptr);
167 QVERIFY(expectedResults.m_Item != nullptr);
167 QVERIFY(expectedResults.m_Item != nullptr);
168 QVERIFY(*item == *expectedResults.m_Item);
168 QVERIFY(*item == *expectedResults.m_Item);
169 }
169 }
170 else {
170 else {
171 QVERIFY(item == nullptr);
171 QVERIFY(item == nullptr);
172 }
172 }
173 }
173 }
174
174
175 QTEST_MAIN(TestAmdaParser)
175 QTEST_MAIN(TestAmdaParser)
176 #include "TestAmdaParser.moc"
176 #include "TestAmdaParser.moc"
@@ -1,281 +1,281
1 #include "AmdaResultParser.h"
1 #include "AmdaResultParser.h"
2
2
3 #include <Data/ScalarSeries.h>
3 #include <Data/ScalarSeries.h>
4 #include <Data/VectorSeries.h>
4 #include <Data/VectorSeries.h>
5
5
6 #include <QObject>
6 #include <QObject>
7 #include <QtTest>
7 #include <QtTest>
8
8
9 namespace {
9 namespace {
10
10
11 /// Path for the tests
11 /// Path for the tests
12 const auto TESTS_RESOURCES_PATH
12 const auto TESTS_RESOURCES_PATH
13 = QFileInfo{QString{AMDA_TESTS_RESOURCES_DIR}, "TestAmdaResultParser"}.absoluteFilePath();
13 = QFileInfo{QString{AMDA_TESTS_RESOURCES_DIR}, "TestAmdaResultParser"}.absoluteFilePath();
14
14
15 QDateTime dateTime(int year, int month, int day, int hours, int minutes, int seconds)
15 QDateTime dateTime(int year, int month, int day, int hours, int minutes, int seconds)
16 {
16 {
17 return QDateTime{{year, month, day}, {hours, minutes, seconds}, Qt::UTC};
17 return QDateTime{{year, month, day}, {hours, minutes, seconds}, Qt::UTC};
18 }
18 }
19
19
20 QString inputFilePath(const QString &inputFileName)
20 QString inputFilePath(const QString &inputFileName)
21 {
21 {
22 return QFileInfo{TESTS_RESOURCES_PATH, inputFileName}.absoluteFilePath();
22 return QFileInfo{TESTS_RESOURCES_PATH, inputFileName}.absoluteFilePath();
23 }
23 }
24
24
25 template <typename T>
25 template <typename T>
26 struct ExpectedResults {
26 struct ExpectedResults {
27 explicit ExpectedResults() = default;
27 explicit ExpectedResults() = default;
28
28
29 explicit ExpectedResults(Unit xAxisUnit, Unit valuesUnit, const QVector<QDateTime> &xAxisData,
29 explicit ExpectedResults(Unit xAxisUnit, Unit valuesUnit, const QVector<QDateTime> &xAxisData,
30 QVector<double> valuesData)
30 QVector<double> valuesData)
31 : ExpectedResults(xAxisUnit, valuesUnit, xAxisData,
31 : ExpectedResults(xAxisUnit, valuesUnit, xAxisData,
32 QVector<QVector<double> >{std::move(valuesData)})
32 QVector<QVector<double> >{std::move(valuesData)})
33 {
33 {
34 }
34 }
35
35
36 /// Ctor with QVector<QDateTime> as x-axis data. Datetimes are converted to doubles
36 /// Ctor with QVector<QDateTime> as x-axis data. Datetimes are converted to doubles
37 explicit ExpectedResults(Unit xAxisUnit, Unit valuesUnit, const QVector<QDateTime> &xAxisData,
37 explicit ExpectedResults(Unit xAxisUnit, Unit valuesUnit, const QVector<QDateTime> &xAxisData,
38 QVector<QVector<double> > valuesData)
38 QVector<QVector<double> > valuesData)
39 : m_ParsingOK{true},
39 : m_ParsingOK{true},
40 m_XAxisUnit{xAxisUnit},
40 m_XAxisUnit{xAxisUnit},
41 m_ValuesUnit{valuesUnit},
41 m_ValuesUnit{valuesUnit},
42 m_XAxisData{},
42 m_XAxisData{},
43 m_ValuesData{std::move(valuesData)}
43 m_ValuesData{std::move(valuesData)}
44 {
44 {
45 // Converts QVector<QDateTime> to QVector<double>
45 // Converts QVector<QDateTime> to QVector<double>
46 std::transform(xAxisData.cbegin(), xAxisData.cend(), std::back_inserter(m_XAxisData),
46 std::transform(xAxisData.cbegin(), xAxisData.cend(), std::back_inserter(m_XAxisData),
47 [](const auto &dateTime) { return dateTime.toMSecsSinceEpoch() / 1000.; });
47 [](const auto &dateTime) { return dateTime.toMSecsSinceEpoch() / 1000.; });
48 }
48 }
49
49
50 /**
50 /**
51 * Validates a DataSeries compared to the expected results
51 * Validates a DataSeries compared to the expected results
52 * @param results the DataSeries to validate
52 * @param results the DataSeries to validate
53 */
53 */
54 void validate(std::shared_ptr<IDataSeries> results)
54 void validate(std::shared_ptr<IDataSeries> results)
55 {
55 {
56 if (m_ParsingOK) {
56 if (m_ParsingOK) {
57 auto dataSeries = dynamic_cast<T *>(results.get());
57 auto dataSeries = dynamic_cast<T *>(results.get());
58 QVERIFY(dataSeries != nullptr);
58 QVERIFY(dataSeries != nullptr);
59
59
60 // Checks units
60 // Checks units
61 QVERIFY(dataSeries->xAxisUnit() == m_XAxisUnit);
61 QVERIFY(dataSeries->xAxisUnit() == m_XAxisUnit);
62 QVERIFY(dataSeries->valuesUnit() == m_ValuesUnit);
62 QVERIFY(dataSeries->valuesUnit() == m_ValuesUnit);
63
63
64 auto verifyRange = [dataSeries](const auto &expectedData, const auto &equalFun) {
64 auto verifyRange = [dataSeries](const auto &expectedData, const auto &equalFun) {
65 QVERIFY(std::equal(dataSeries->cbegin(), dataSeries->cend(), expectedData.cbegin(),
65 QVERIFY(std::equal(dataSeries->cbegin(), dataSeries->cend(), expectedData.cbegin(),
66 expectedData.cend(),
66 expectedData.cend(),
67 [&equalFun](const auto &dataSeriesIt, const auto &expectedX) {
67 [&equalFun](const auto &dataSeriesIt, const auto &expectedX) {
68 return equalFun(dataSeriesIt, expectedX);
68 return equalFun(dataSeriesIt, expectedX);
69 }));
69 }));
70 };
70 };
71
71
72 // Checks x-axis data
72 // Checks x-axis data
73 verifyRange(m_XAxisData, [](const auto &seriesIt, const auto &value) {
73 verifyRange(m_XAxisData, [](const auto &seriesIt, const auto &value) {
74 return seriesIt.x() == value;
74 return seriesIt.x() == value;
75 });
75 });
76
76
77 // Checks values data of each component
77 // Checks values data of each component
78 for (auto i = 0; i < m_ValuesData.size(); ++i) {
78 for (auto i = 0; i < m_ValuesData.size(); ++i) {
79 verifyRange(m_ValuesData.at(i), [i](const auto &seriesIt, const auto &value) {
79 verifyRange(m_ValuesData.at(i), [i](const auto &seriesIt, const auto &value) {
80 auto itValue = seriesIt.value(i);
80 auto itValue = seriesIt.value(i);
81 return (std::isnan(itValue) && std::isnan(value)) || seriesIt.value(i) == value;
81 return (std::isnan(itValue) && std::isnan(value)) || seriesIt.value(i) == value;
82 });
82 });
83 }
83 }
84 }
84 }
85 else {
85 else {
86 QVERIFY(results == nullptr);
86 QVERIFY(results == nullptr);
87 }
87 }
88 }
88 }
89
89
90 // Parsing was successfully completed
90 // Parsing was successfully completed
91 bool m_ParsingOK{false};
91 bool m_ParsingOK{false};
92 // Expected x-axis unit
92 // Expected x-axis unit
93 Unit m_XAxisUnit{};
93 Unit m_XAxisUnit{};
94 // Expected values unit
94 // Expected values unit
95 Unit m_ValuesUnit{};
95 Unit m_ValuesUnit{};
96 // Expected x-axis data
96 // Expected x-axis data
97 QVector<double> m_XAxisData{};
97 QVector<double> m_XAxisData{};
98 // Expected values data
98 // Expected values data
99 QVector<QVector<double> > m_ValuesData{};
99 QVector<QVector<double> > m_ValuesData{};
100 };
100 };
101
101
102 } // namespace
102 } // namespace
103
103
104 Q_DECLARE_METATYPE(ExpectedResults<ScalarSeries>)
104 Q_DECLARE_METATYPE(ExpectedResults<ScalarSeries>)
105 Q_DECLARE_METATYPE(ExpectedResults<VectorSeries>)
105 Q_DECLARE_METATYPE(ExpectedResults<VectorSeries>)
106
106
107 class TestAmdaResultParser : public QObject {
107 class TestAmdaResultParser : public QObject {
108 Q_OBJECT
108 Q_OBJECT
109 private:
109 private:
110 template <typename T>
110 template <typename T>
111 void testReadDataStructure()
111 void testReadDataStructure()
112 {
112 {
113 // ////////////// //
113 // ////////////// //
114 // Test structure //
114 // Test structure //
115 // ////////////// //
115 // ////////////// //
116
116
117 // Name of TXT file to read
117 // Name of TXT file to read
118 QTest::addColumn<QString>("inputFileName");
118 QTest::addColumn<QString>("inputFileName");
119 // Expected results
119 // Expected results
120 QTest::addColumn<ExpectedResults<T> >("expectedResults");
120 QTest::addColumn<ExpectedResults<T> >("expectedResults");
121 }
121 }
122
122
123 template <typename T>
123 template <typename T>
124 void testRead(AmdaResultParser::ValueType valueType)
124 void testRead(AmdaResultParser::ValueType valueType)
125 {
125 {
126 QFETCH(QString, inputFileName);
126 QFETCH(QString, inputFileName);
127 QFETCH(ExpectedResults<T>, expectedResults);
127 QFETCH(ExpectedResults<T>, expectedResults);
128
128
129 // Parses file
129 // Parses file
130 auto filePath = inputFilePath(inputFileName);
130 auto filePath = inputFilePath(inputFileName);
131 auto results = AmdaResultParser::readTxt(filePath, valueType);
131 auto results = AmdaResultParser::readTxt(filePath, valueType);
132
132
133 // ///////////////// //
133 // ///////////////// //
134 // Validates results //
134 // Validates results //
135 // ///////////////// //
135 // ///////////////// //
136 expectedResults.validate(results);
136 expectedResults.validate(results);
137 }
137 }
138
138
139 private slots:
139 private slots:
140 /// Input test data
140 /// Input test data
141 /// @sa testReadScalarTxt()
141 /// @sa testReadScalarTxt()
142 void testReadScalarTxt_data();
142 void testReadScalarTxt_data();
143
143
144 /// Tests parsing scalar series of a TXT file
144 /// Tests parsing scalar series of a TXT file
145 void testReadScalarTxt();
145 void testReadScalarTxt();
146
146
147 /// Input test data
147 /// Input test data
148 /// @sa testReadVectorTxt()
148 /// @sa testReadVectorTxt()
149 void testReadVectorTxt_data();
149 void testReadVectorTxt_data();
150
150
151 /// Tests parsing vector series of a TXT file
151 /// Tests parsing vector series of a TXT file
152 void testReadVectorTxt();
152 void testReadVectorTxt();
153 };
153 };
154
154
155 void TestAmdaResultParser::testReadScalarTxt_data()
155 void TestAmdaResultParser::testReadScalarTxt_data()
156 {
156 {
157 testReadDataStructure<ScalarSeries>();
157 testReadDataStructure<ScalarSeries>();
158
158
159 // ////////// //
159 // ////////// //
160 // Test cases //
160 // Test cases //
161 // ////////// //
161 // ////////// //
162
162
163 // Valid files
163 // Valid files
164 QTest::newRow("Valid file")
164 QTest::newRow("Valid file")
165 << QStringLiteral("ValidScalar1.txt")
165 << QStringLiteral("ValidScalar1.txt")
166 << ExpectedResults<ScalarSeries>{
166 << ExpectedResults<ScalarSeries>{
167 Unit{QStringLiteral("nT"), true}, Unit{},
167 Unit{QStringLiteral("nT"), true}, Unit{},
168 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 0, 30), dateTime(2013, 9, 23, 9, 1, 30),
168 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 0, 30), dateTime(2013, 9, 23, 9, 1, 30),
169 dateTime(2013, 9, 23, 9, 2, 30), dateTime(2013, 9, 23, 9, 3, 30),
169 dateTime(2013, 9, 23, 9, 2, 30), dateTime(2013, 9, 23, 9, 3, 30),
170 dateTime(2013, 9, 23, 9, 4, 30), dateTime(2013, 9, 23, 9, 5, 30),
170 dateTime(2013, 9, 23, 9, 4, 30), dateTime(2013, 9, 23, 9, 5, 30),
171 dateTime(2013, 9, 23, 9, 6, 30), dateTime(2013, 9, 23, 9, 7, 30),
171 dateTime(2013, 9, 23, 9, 6, 30), dateTime(2013, 9, 23, 9, 7, 30),
172 dateTime(2013, 9, 23, 9, 8, 30), dateTime(2013, 9, 23, 9, 9, 30)},
172 dateTime(2013, 9, 23, 9, 8, 30), dateTime(2013, 9, 23, 9, 9, 30)},
173 QVector<double>{-2.83950, -2.71850, -2.52150, -2.57633, -2.58050, -2.48325, -2.63025,
173 QVector<double>{-2.83950, -2.71850, -2.52150, -2.57633, -2.58050, -2.48325, -2.63025,
174 -2.55800, -2.43250, -2.42200}};
174 -2.55800, -2.43250, -2.42200}};
175
175
176 QTest::newRow("Valid file (value of first line is invalid but it is converted to NaN")
176 QTest::newRow("Valid file (value of first line is invalid but it is converted to NaN")
177 << QStringLiteral("WrongValue.txt")
177 << QStringLiteral("WrongValue.txt")
178 << ExpectedResults<ScalarSeries>{
178 << ExpectedResults<ScalarSeries>{
179 Unit{QStringLiteral("nT"), true}, Unit{},
179 Unit{QStringLiteral("nT"), true}, Unit{},
180 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 0, 30), dateTime(2013, 9, 23, 9, 1, 30),
180 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 0, 30), dateTime(2013, 9, 23, 9, 1, 30),
181 dateTime(2013, 9, 23, 9, 2, 30)},
181 dateTime(2013, 9, 23, 9, 2, 30)},
182 QVector<double>{std::numeric_limits<double>::quiet_NaN(), -2.71850, -2.52150}};
182 QVector<double>{std::numeric_limits<double>::quiet_NaN(), -2.71850, -2.52150}};
183
183
184 QTest::newRow("Valid file that contains NaN values")
184 QTest::newRow("Valid file that contains NaN values")
185 << QStringLiteral("NaNValue.txt")
185 << QStringLiteral("NaNValue.txt")
186 << ExpectedResults<ScalarSeries>{
186 << ExpectedResults<ScalarSeries>{
187 Unit{QStringLiteral("nT"), true}, Unit{},
187 Unit{QStringLiteral("nT"), true}, Unit{},
188 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 0, 30), dateTime(2013, 9, 23, 9, 1, 30),
188 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 0, 30), dateTime(2013, 9, 23, 9, 1, 30),
189 dateTime(2013, 9, 23, 9, 2, 30)},
189 dateTime(2013, 9, 23, 9, 2, 30)},
190 QVector<double>{std::numeric_limits<double>::quiet_NaN(), -2.71850, -2.52150}};
190 QVector<double>{std::numeric_limits<double>::quiet_NaN(), -2.71850, -2.52150}};
191
191
192 // Valid files but with some invalid lines (wrong unit, wrong values, etc.)
192 // Valid files but with some invalid lines (wrong unit, wrong values, etc.)
193 QTest::newRow("No unit file") << QStringLiteral("NoUnit.txt")
193 QTest::newRow("No unit file") << QStringLiteral("NoUnit.txt")
194 << ExpectedResults<ScalarSeries>{Unit{QStringLiteral(""), true},
194 << ExpectedResults<ScalarSeries>{Unit{QStringLiteral(""), true},
195 Unit{}, QVector<QDateTime>{},
195 Unit{}, QVector<QDateTime>{},
196 QVector<double>{}};
196 QVector<double>{}};
197 QTest::newRow("Wrong unit file")
197 QTest::newRow("Wrong unit file")
198 << QStringLiteral("WrongUnit.txt")
198 << QStringLiteral("WrongUnit.txt")
199 << ExpectedResults<ScalarSeries>{Unit{QStringLiteral(""), true}, Unit{},
199 << ExpectedResults<ScalarSeries>{Unit{QStringLiteral(""), true}, Unit{},
200 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 0, 30),
200 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 0, 30),
201 dateTime(2013, 9, 23, 9, 1, 30),
201 dateTime(2013, 9, 23, 9, 1, 30),
202 dateTime(2013, 9, 23, 9, 2, 30)},
202 dateTime(2013, 9, 23, 9, 2, 30)},
203 QVector<double>{-2.83950, -2.71850, -2.52150}};
203 QVector<double>{-2.83950, -2.71850, -2.52150}};
204
204
205 QTest::newRow("Wrong results file (date of first line is invalid")
205 QTest::newRow("Wrong results file (date of first line is invalid")
206 << QStringLiteral("WrongDate.txt")
206 << QStringLiteral("WrongDate.txt")
207 << ExpectedResults<ScalarSeries>{
207 << ExpectedResults<ScalarSeries>{
208 Unit{QStringLiteral("nT"), true}, Unit{},
208 Unit{QStringLiteral("nT"), true}, Unit{},
209 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)},
209 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)},
210 QVector<double>{-2.71850, -2.52150}};
210 QVector<double>{-2.71850, -2.52150}};
211
211
212 QTest::newRow("Wrong results file (too many values for first line")
212 QTest::newRow("Wrong results file (too many values for first line")
213 << QStringLiteral("TooManyValues.txt")
213 << QStringLiteral("TooManyValues.txt")
214 << ExpectedResults<ScalarSeries>{
214 << ExpectedResults<ScalarSeries>{
215 Unit{QStringLiteral("nT"), true}, Unit{},
215 Unit{QStringLiteral("nT"), true}, Unit{},
216 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)},
216 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)},
217 QVector<double>{-2.71850, -2.52150}};
217 QVector<double>{-2.71850, -2.52150}};
218
218
219 QTest::newRow("Wrong results file (x of first line is NaN")
219 QTest::newRow("Wrong results file (x of first line is NaN")
220 << QStringLiteral("NaNX.txt")
220 << QStringLiteral("NaNX.txt")
221 << ExpectedResults<ScalarSeries>{
221 << ExpectedResults<ScalarSeries>{
222 Unit{QStringLiteral("nT"), true}, Unit{},
222 Unit{QStringLiteral("nT"), true}, Unit{},
223 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)},
223 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)},
224 QVector<double>{-2.71850, -2.52150}};
224 QVector<double>{-2.71850, -2.52150}};
225
225
226 QTest::newRow("Invalid file type (vector)")
226 QTest::newRow("Invalid file type (vector)")
227 << QStringLiteral("ValidVector1.txt")
227 << QStringLiteral("ValidVector1.txt")
228 << ExpectedResults<ScalarSeries>{Unit{QStringLiteral("nT"), true}, Unit{},
228 << ExpectedResults<ScalarSeries>{Unit{QStringLiteral("nT"), true}, Unit{},
229 QVector<QDateTime>{}, QVector<double>{}};
229 QVector<QDateTime>{}, QVector<double>{}};
230
230
231 // Invalid files
231 // Invalid files
232 QTest::newRow("Invalid file (unexisting file)") << QStringLiteral("UnexistingFile.txt")
232 QTest::newRow("Invalid file (unexisting file)")
233 << ExpectedResults<ScalarSeries>{};
233 << QStringLiteral("UnexistingFile.txt") << ExpectedResults<ScalarSeries>{};
234
234
235 QTest::newRow("Invalid file (file not found on server)") << QStringLiteral("FileNotFound.txt")
235 QTest::newRow("Invalid file (file not found on server)")
236 << ExpectedResults<ScalarSeries>{};
236 << QStringLiteral("FileNotFound.txt") << ExpectedResults<ScalarSeries>{};
237 }
237 }
238
238
239 void TestAmdaResultParser::testReadScalarTxt()
239 void TestAmdaResultParser::testReadScalarTxt()
240 {
240 {
241 testRead<ScalarSeries>(AmdaResultParser::ValueType::SCALAR);
241 testRead<ScalarSeries>(AmdaResultParser::ValueType::SCALAR);
242 }
242 }
243
243
244 void TestAmdaResultParser::testReadVectorTxt_data()
244 void TestAmdaResultParser::testReadVectorTxt_data()
245 {
245 {
246 testReadDataStructure<VectorSeries>();
246 testReadDataStructure<VectorSeries>();
247
247
248 // ////////// //
248 // ////////// //
249 // Test cases //
249 // Test cases //
250 // ////////// //
250 // ////////// //
251
251
252 // Valid files
252 // Valid files
253 QTest::newRow("Valid file")
253 QTest::newRow("Valid file")
254 << QStringLiteral("ValidVector1.txt")
254 << QStringLiteral("ValidVector1.txt")
255 << ExpectedResults<VectorSeries>{
255 << ExpectedResults<VectorSeries>{
256 Unit{QStringLiteral("nT"), true}, Unit{},
256 Unit{QStringLiteral("nT"), true}, Unit{},
257 QVector<QDateTime>{dateTime(2013, 7, 2, 9, 13, 50), dateTime(2013, 7, 2, 9, 14, 6),
257 QVector<QDateTime>{dateTime(2013, 7, 2, 9, 13, 50), dateTime(2013, 7, 2, 9, 14, 6),
258 dateTime(2013, 7, 2, 9, 14, 22), dateTime(2013, 7, 2, 9, 14, 38),
258 dateTime(2013, 7, 2, 9, 14, 22), dateTime(2013, 7, 2, 9, 14, 38),
259 dateTime(2013, 7, 2, 9, 14, 54), dateTime(2013, 7, 2, 9, 15, 10),
259 dateTime(2013, 7, 2, 9, 14, 54), dateTime(2013, 7, 2, 9, 15, 10),
260 dateTime(2013, 7, 2, 9, 15, 26), dateTime(2013, 7, 2, 9, 15, 42),
260 dateTime(2013, 7, 2, 9, 15, 26), dateTime(2013, 7, 2, 9, 15, 42),
261 dateTime(2013, 7, 2, 9, 15, 58), dateTime(2013, 7, 2, 9, 16, 14)},
261 dateTime(2013, 7, 2, 9, 15, 58), dateTime(2013, 7, 2, 9, 16, 14)},
262 QVector<QVector<double> >{
262 QVector<QVector<double> >{
263 {-0.332, -1.011, -1.457, -1.293, -1.217, -1.443, -1.278, -1.202, -1.22, -1.259},
263 {-0.332, -1.011, -1.457, -1.293, -1.217, -1.443, -1.278, -1.202, -1.22, -1.259},
264 {3.206, 2.999, 2.785, 2.736, 2.612, 2.564, 2.892, 2.862, 2.859, 2.764},
264 {3.206, 2.999, 2.785, 2.736, 2.612, 2.564, 2.892, 2.862, 2.859, 2.764},
265 {0.058, 0.496, 1.018, 1.485, 1.662, 1.505, 1.168, 1.244, 1.15, 1.358}}};
265 {0.058, 0.496, 1.018, 1.485, 1.662, 1.505, 1.168, 1.244, 1.15, 1.358}}};
266
266
267 // Valid files but with some invalid lines (wrong unit, wrong values, etc.)
267 // Valid files but with some invalid lines (wrong unit, wrong values, etc.)
268 QTest::newRow("Invalid file type (scalar)")
268 QTest::newRow("Invalid file type (scalar)")
269 << QStringLiteral("ValidScalar1.txt")
269 << QStringLiteral("ValidScalar1.txt")
270 << ExpectedResults<VectorSeries>{Unit{QStringLiteral("nT"), true}, Unit{},
270 << ExpectedResults<VectorSeries>{Unit{QStringLiteral("nT"), true}, Unit{},
271 QVector<QDateTime>{},
271 QVector<QDateTime>{},
272 QVector<QVector<double> >{{}, {}, {}}};
272 QVector<QVector<double> >{{}, {}, {}}};
273 }
273 }
274
274
275 void TestAmdaResultParser::testReadVectorTxt()
275 void TestAmdaResultParser::testReadVectorTxt()
276 {
276 {
277 testRead<VectorSeries>(AmdaResultParser::ValueType::VECTOR);
277 testRead<VectorSeries>(AmdaResultParser::ValueType::VECTOR);
278 }
278 }
279
279
280 QTEST_MAIN(TestAmdaResultParser)
280 QTEST_MAIN(TestAmdaResultParser)
281 #include "TestAmdaResultParser.moc"
281 #include "TestAmdaResultParser.moc"
@@ -1,109 +1,109
1 #include "CosinusProvider.h"
1 #include "CosinusProvider.h"
2
2
3 #include <Data/DataProviderParameters.h>
3 #include <Data/DataProviderParameters.h>
4 #include <Data/ScalarSeries.h>
4 #include <Data/ScalarSeries.h>
5
5
6 #include <cmath>
6 #include <cmath>
7
7
8 #include <QFuture>
8 #include <QFuture>
9 #include <QThread>
9 #include <QThread>
10 #include <QtConcurrent/QtConcurrent>
10 #include <QtConcurrent/QtConcurrent>
11
11
12 Q_LOGGING_CATEGORY(LOG_CosinusProvider, "CosinusProvider")
12 Q_LOGGING_CATEGORY(LOG_CosinusProvider, "CosinusProvider")
13
13
14 std::shared_ptr<IDataProvider> CosinusProvider::clone() const
14 std::shared_ptr<IDataProvider> CosinusProvider::clone() const
15 {
15 {
16 // No copy is made in clone
16 // No copy is made in clone
17 return std::make_shared<CosinusProvider>();
17 return std::make_shared<CosinusProvider>();
18 }
18 }
19
19
20 std::shared_ptr<IDataSeries> CosinusProvider::retrieveData(QUuid acqIdentifier,
20 std::shared_ptr<IDataSeries> CosinusProvider::retrieveData(QUuid acqIdentifier,
21 const SqpRange &dataRangeRequested)
21 const SqpRange &dataRangeRequested)
22 {
22 {
23 // TODO: Add Mutex
23 // TODO: Add Mutex
24 auto dataIndex = 0;
24 auto dataIndex = 0;
25
25
26 // Gets the timerange from the parameters
26 // Gets the timerange from the parameters
27 double freq = 100.0;
27 double freq = 1.0;
28 double start = std::ceil(dataRangeRequested.m_TStart * freq); // 100 htz
28 double start = std::ceil(dataRangeRequested.m_TStart * freq); // 100 htz
29 double end = std::floor(dataRangeRequested.m_TEnd * freq); // 100 htz
29 double end = std::floor(dataRangeRequested.m_TEnd * freq); // 100 htz
30
30
31 // We assure that timerange is valid
31 // We assure that timerange is valid
32 if (end < start) {
32 if (end < start) {
33 std::swap(start, end);
33 std::swap(start, end);
34 }
34 }
35
35
36 // Generates scalar series containing cosinus values (one value per second)
36 // Generates scalar series containing cosinus values (one value per second)
37 auto dataCount = end - start;
37 auto dataCount = end - start;
38
38
39 auto xAxisData = std::vector<double>{};
39 auto xAxisData = std::vector<double>{};
40 xAxisData.resize(dataCount);
40 xAxisData.resize(dataCount);
41
41
42 auto valuesData = std::vector<double>{};
42 auto valuesData = std::vector<double>{};
43 valuesData.resize(dataCount);
43 valuesData.resize(dataCount);
44
44
45 int progress = 0;
45 int progress = 0;
46 auto progressEnd = dataCount;
46 auto progressEnd = dataCount;
47 for (auto time = start; time < end; ++time, ++dataIndex) {
47 for (auto time = start; time < end; ++time, ++dataIndex) {
48 auto it = m_VariableToEnableProvider.find(acqIdentifier);
48 auto it = m_VariableToEnableProvider.find(acqIdentifier);
49 if (it != m_VariableToEnableProvider.end() && it.value()) {
49 if (it != m_VariableToEnableProvider.end() && it.value()) {
50 const auto timeOnFreq = time / freq;
50 const auto timeOnFreq = time / freq;
51
51
52 xAxisData[dataIndex] = timeOnFreq;
52 xAxisData[dataIndex] = timeOnFreq;
53 valuesData[dataIndex] = std::cos(timeOnFreq);
53 valuesData[dataIndex] = std::cos(timeOnFreq);
54
54
55 // progression
55 // progression
56 int currentProgress = (time - start) * 100.0 / progressEnd;
56 int currentProgress = (time - start) * 100.0 / progressEnd;
57 if (currentProgress != progress) {
57 if (currentProgress != progress) {
58 progress = currentProgress;
58 progress = currentProgress;
59
59
60 emit dataProvidedProgress(acqIdentifier, progress);
60 emit dataProvidedProgress(acqIdentifier, progress);
61 }
61 }
62 }
62 }
63 else {
63 else {
64 if (!it.value()) {
64 if (!it.value()) {
65 qCDebug(LOG_CosinusProvider())
65 qCDebug(LOG_CosinusProvider())
66 << "CosinusProvider::retrieveData: ARRET De l'acquisition detectΓ©"
66 << "CosinusProvider::retrieveData: ARRET De l'acquisition detectΓ©"
67 << end - time;
67 << end - time;
68 }
68 }
69 }
69 }
70 }
70 }
71 emit dataProvidedProgress(acqIdentifier, 0.0);
71 emit dataProvidedProgress(acqIdentifier, 0.0);
72
72
73 return std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData),
73 return std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData),
74 Unit{QStringLiteral("t"), true}, Unit{});
74 Unit{QStringLiteral("t"), true}, Unit{});
75 }
75 }
76
76
77 void CosinusProvider::requestDataLoading(QUuid acqIdentifier,
77 void CosinusProvider::requestDataLoading(QUuid acqIdentifier,
78 const DataProviderParameters &parameters)
78 const DataProviderParameters &parameters)
79 {
79 {
80 // TODO: Add Mutex
80 // TODO: Add Mutex
81 m_VariableToEnableProvider[acqIdentifier] = true;
81 m_VariableToEnableProvider[acqIdentifier] = true;
82 qCDebug(LOG_CosinusProvider()) << "TORM: CosinusProvider::requestDataLoading"
82 qCDebug(LOG_CosinusProvider())
83 << QThread::currentThread()->objectName();
83 << "TORM: CosinusProvider::requestDataLoading" << QThread::currentThread()->objectName();
84 // NOTE: Try to use multithread if possible
84 // NOTE: Try to use multithread if possible
85 const auto times = parameters.m_Times;
85 const auto times = parameters.m_Times;
86
86
87 for (const auto &dateTime : qAsConst(times)) {
87 for (const auto &dateTime : qAsConst(times)) {
88 if (m_VariableToEnableProvider[acqIdentifier]) {
88 if (m_VariableToEnableProvider[acqIdentifier]) {
89 auto scalarSeries = this->retrieveData(acqIdentifier, dateTime);
89 auto scalarSeries = this->retrieveData(acqIdentifier, dateTime);
90 qCDebug(LOG_CosinusProvider()) << "TORM: CosinusProvider::dataProvided";
90 qCDebug(LOG_CosinusProvider()) << "TORM: CosinusProvider::dataProvided";
91 emit dataProvided(acqIdentifier, scalarSeries, dateTime);
91 emit dataProvided(acqIdentifier, scalarSeries, dateTime);
92 }
92 }
93 }
93 }
94 }
94 }
95
95
96 void CosinusProvider::requestDataAborting(QUuid acqIdentifier)
96 void CosinusProvider::requestDataAborting(QUuid acqIdentifier)
97 {
97 {
98 // TODO: Add Mutex
98 // TODO: Add Mutex
99 qCDebug(LOG_CosinusProvider()) << "CosinusProvider::requestDataAborting" << acqIdentifier
99 qCDebug(LOG_CosinusProvider()) << "CosinusProvider::requestDataAborting" << acqIdentifier
100 << QThread::currentThread()->objectName();
100 << QThread::currentThread()->objectName();
101 auto it = m_VariableToEnableProvider.find(acqIdentifier);
101 auto it = m_VariableToEnableProvider.find(acqIdentifier);
102 if (it != m_VariableToEnableProvider.end()) {
102 if (it != m_VariableToEnableProvider.end()) {
103 it.value() = false;
103 it.value() = false;
104 }
104 }
105 else {
105 else {
106 qCWarning(LOG_CosinusProvider())
106 qCWarning(LOG_CosinusProvider())
107 << tr("Aborting progression of inexistant identifier detected !!!");
107 << tr("Aborting progression of inexistant identifier detected !!!");
108 }
108 }
109 }
109 }
General Comments 0
You need to be logged in to leave comments. Login now