##// END OF EJS Templates
Add synchronization part of v5 acquisition
perrinel -
r511:bf486b19bffa
parent child
Show More
@@ -1,116 +1,117
1 1 #ifndef SCIQLOP_VARIABLECONTROLLER_H
2 2 #define SCIQLOP_VARIABLECONTROLLER_H
3 3
4 4 #include "CoreGlobal.h"
5 5
6 6 #include <Data/AcquisitionDataPacket.h>
7 7 #include <Data/SqpRange.h>
8 8
9 9 #include <QLoggingCategory>
10 10 #include <QObject>
11 11
12 12 #include <Common/spimpl.h>
13 13
14 14 class IDataProvider;
15 15 class QItemSelectionModel;
16 16 class TimeController;
17 17 class Variable;
18 18 class VariableModel;
19 19
20 20 Q_DECLARE_LOGGING_CATEGORY(LOG_VariableController)
21 21
22 22
23 23 /**
24 24 * Possible types of zoom operation
25 25 */
26 26 enum class AcquisitionZoomType { ZoomOut, ZoomIn, PanRight, PanLeft, Unknown };
27 27
28 28
29 29 /**
30 30 * @brief The VariableController class aims to handle the variables in SciQlop.
31 31 */
32 32 class SCIQLOP_CORE_EXPORT VariableController : public QObject {
33 33 Q_OBJECT
34 34 public:
35 35 explicit VariableController(QObject *parent = 0);
36 36 virtual ~VariableController();
37 37
38 38 VariableModel *variableModel() noexcept;
39 39 QItemSelectionModel *variableSelectionModel() noexcept;
40 40
41 41 void setTimeController(TimeController *timeController) noexcept;
42 42
43 43 /**
44 44 * Deletes from the controller the variable passed in parameter.
45 45 *
46 46 * Delete a variable includes:
47 47 * - the deletion of the various references to the variable in SciQlop
48 48 * - the deletion of the model variable
49 49 * - the deletion of the provider associated with the variable
50 50 * - removing the cache associated with the variable
51 51 *
52 52 * @param variable the variable to delete from the controller.
53 53 */
54 54 void deleteVariable(std::shared_ptr<Variable> variable) noexcept;
55 55
56 56 /**
57 57 * Deletes from the controller the variables passed in parameter.
58 58 * @param variables the variables to delete from the controller.
59 59 * @sa deleteVariable()
60 60 */
61 61 void deleteVariables(const QVector<std::shared_ptr<Variable> > &variables) noexcept;
62 62
63 63 /**
64 64 * @brief abort the variable retrieve data progression
65 65 */
66 66 void abortProgress(std::shared_ptr<Variable> variable);
67 67
68 68 static AcquisitionZoomType getZoomType(const SqpRange &range, const SqpRange &oldRange);
69 69 signals:
70 70 /// Signal emitted when a variable is about to be deleted from the controller
71 71 void variableAboutToBeDeleted(std::shared_ptr<Variable> variable);
72 72
73 73 /// Signal emitted when a data acquisition is requested on a range for a variable
74 74 void rangeChanged(std::shared_ptr<Variable> variable, const SqpRange &range);
75 75
76 76 public slots:
77 77 /// Request the data loading of the variable whithin range
78 78 void onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables, const SqpRange &range,
79 79 const SqpRange &oldRange, bool synchronise);
80 80 /**
81 81 * Creates a new variable and adds it to the model
82 82 * @param name the name of the new variable
83 83 * @param metadata the metadata of the new variable
84 84 * @param provider the data provider for the new variable
85 85 */
86 86 void createVariable(const QString &name, const QVariantHash &metadata,
87 87 std::shared_ptr<IDataProvider> provider) noexcept;
88 88
89 89 /// Update the temporal parameters of every selected variable to dateTime
90 90 void onDateTimeOnSelection(const SqpRange &dateTime);
91 91
92 92
93 93 void onDataProvided(QUuid vIdentifier, const SqpRange &rangeRequested,
94 94 const SqpRange &cacheRangeRequested,
95 95 QVector<AcquisitionDataPacket> dataAcquired);
96 96
97 97 void onVariableRetrieveDataInProgress(QUuid identifier, double progress);
98 98
99 99 /// Cancel the current request for the variable
100 100 void onAbortProgressRequested(std::shared_ptr<Variable> variable);
101 101
102 102 /// synchronization group methods
103 103 void onAddSynchronizationGroupId(QUuid synchronizationGroupId);
104 104 void onRemoveSynchronizationGroupId(QUuid synchronizationGroupId);
105 void onAddSynchronized(std::shared_ptr<Variable> variable, QUuid synchronizationGroupId);
105 106
106 107 void initialize();
107 108 void finalize();
108 109
109 110 private:
110 111 void waitForFinish();
111 112
112 113 class VariableControllerPrivate;
113 114 spimpl::unique_impl_ptr<VariableControllerPrivate> impl;
114 115 };
115 116
116 117 #endif // SCIQLOP_VARIABLECONTROLLER_H
@@ -1,508 +1,543
1 1 #include <Variable/Variable.h>
2 2 #include <Variable/VariableAcquisitionWorker.h>
3 3 #include <Variable/VariableCacheController.h>
4 4 #include <Variable/VariableCacheStrategy.h>
5 5 #include <Variable/VariableController.h>
6 6 #include <Variable/VariableModel.h>
7 7 #include <Variable/VariableSynchronizationGroup.h>
8 8
9 9 #include <Data/DataProviderParameters.h>
10 10 #include <Data/IDataProvider.h>
11 11 #include <Data/IDataSeries.h>
12 12 #include <Time/TimeController.h>
13 13
14 14 #include <QMutex>
15 15 #include <QThread>
16 16 #include <QUuid>
17 17 #include <QtCore/QItemSelectionModel>
18 18
19 19 #include <set>
20 20 #include <unordered_map>
21 21
22 22 Q_LOGGING_CATEGORY(LOG_VariableController, "VariableController")
23 23
24 24 namespace {
25 25
26 26 SqpRange computeSynchroRangeRequested(const SqpRange &varRange, const SqpRange &grapheRange,
27 27 const SqpRange &oldGraphRange)
28 28 {
29 29 auto zoomType = VariableController::getZoomType(grapheRange, oldGraphRange);
30 30
31 31 auto varRangeRequested = varRange;
32 32 switch (zoomType) {
33 33 case AcquisitionZoomType::ZoomIn: {
34 34 auto deltaLeft = grapheRange.m_TStart - oldGraphRange.m_TStart;
35 35 auto deltaRight = oldGraphRange.m_TEnd - grapheRange.m_TEnd;
36 36 varRangeRequested.m_TStart += deltaLeft;
37 37 varRangeRequested.m_TEnd -= deltaRight;
38 38 break;
39 39 }
40 40
41 41 case AcquisitionZoomType::ZoomOut: {
42 42 auto deltaLeft = oldGraphRange.m_TStart - grapheRange.m_TStart;
43 43 auto deltaRight = grapheRange.m_TEnd - oldGraphRange.m_TEnd;
44 44 varRangeRequested.m_TStart -= deltaLeft;
45 45 varRangeRequested.m_TEnd += deltaRight;
46 46 break;
47 47 }
48 48 case AcquisitionZoomType::PanRight: {
49 49 auto deltaRight = grapheRange.m_TEnd - oldGraphRange.m_TEnd;
50 50 varRangeRequested.m_TStart += deltaRight;
51 51 varRangeRequested.m_TEnd += deltaRight;
52 52 break;
53 53 }
54 54 case AcquisitionZoomType::PanLeft: {
55 55 auto deltaLeft = oldGraphRange.m_TStart - grapheRange.m_TStart;
56 56 varRangeRequested.m_TStart -= deltaLeft;
57 57 varRangeRequested.m_TEnd -= deltaLeft;
58 58 break;
59 59 }
60 60 case AcquisitionZoomType::Unknown: {
61 61 qCCritical(LOG_VariableController())
62 62 << VariableController::tr("Impossible to synchronize: zoom type unknown");
63 63 break;
64 64 }
65 65 default:
66 66 qCCritical(LOG_VariableController()) << VariableController::tr(
67 67 "Impossible to synchronize: zoom type not take into account");
68 68 // No action
69 69 break;
70 70 }
71 71
72 72 return varRangeRequested;
73 73 }
74 74 }
75 75
76 76 struct VariableController::VariableControllerPrivate {
77 77 explicit VariableControllerPrivate(VariableController *parent)
78 78 : m_WorkingMutex{},
79 79 m_VariableModel{new VariableModel{parent}},
80 80 m_VariableSelectionModel{new QItemSelectionModel{m_VariableModel, parent}},
81 81 m_VariableCacheController{std::make_unique<VariableCacheController>()},
82 82 m_VariableCacheStrategy{std::make_unique<VariableCacheStrategy>()},
83 83 m_VariableAcquisitionWorker{std::make_unique<VariableAcquisitionWorker>()}
84 84 {
85 85
86 86 m_VariableAcquisitionWorker->moveToThread(&m_VariableAcquisitionWorkerThread);
87 87 m_VariableAcquisitionWorkerThread.setObjectName("VariableAcquisitionWorkerThread");
88 88 }
89 89
90 90
91 91 virtual ~VariableControllerPrivate()
92 92 {
93 93 qCDebug(LOG_VariableController()) << tr("VariableControllerPrivate destruction");
94 94 m_VariableAcquisitionWorkerThread.quit();
95 95 m_VariableAcquisitionWorkerThread.wait();
96 96 }
97 97
98 98
99 99 void processRequest(std::shared_ptr<Variable> var, const SqpRange &rangeRequested);
100 100
101 101 QVector<SqpRange> provideNotInCacheDateTimeList(std::shared_ptr<Variable> variable,
102 102 const SqpRange &dateTime);
103 103
104 104 std::shared_ptr<Variable> findVariable(QUuid vIdentifier);
105 105 std::shared_ptr<IDataSeries>
106 106 retrieveDataSeries(const QVector<AcquisitionDataPacket> acqDataPacketVector);
107 107
108 108 void registerProvider(std::shared_ptr<IDataProvider> provider);
109 109
110 110 QMutex m_WorkingMutex;
111 111 /// Variable model. The VariableController has the ownership
112 112 VariableModel *m_VariableModel;
113 113 QItemSelectionModel *m_VariableSelectionModel;
114 114
115 115
116 116 TimeController *m_TimeController{nullptr};
117 117 std::unique_ptr<VariableCacheController> m_VariableCacheController;
118 118 std::unique_ptr<VariableCacheStrategy> m_VariableCacheStrategy;
119 119 std::unique_ptr<VariableAcquisitionWorker> m_VariableAcquisitionWorker;
120 120 QThread m_VariableAcquisitionWorkerThread;
121 121
122 122 std::unordered_map<std::shared_ptr<Variable>, std::shared_ptr<IDataProvider> >
123 123 m_VariableToProviderMap;
124 124 std::unordered_map<std::shared_ptr<Variable>, QUuid> m_VariableToIdentifierMap;
125 125 std::map<QUuid, std::shared_ptr<VariableSynchronizationGroup> >
126 126 m_GroupIdToVariableSynchronizationGroupMap;
127 127 std::map<QUuid, QUuid> m_VariableIdGroupIdMap;
128 128 std::set<std::shared_ptr<IDataProvider> > m_ProviderSet;
129 129 };
130 130
131 131
132 132 VariableController::VariableController(QObject *parent)
133 133 : QObject{parent}, impl{spimpl::make_unique_impl<VariableControllerPrivate>(this)}
134 134 {
135 135 qCDebug(LOG_VariableController()) << tr("VariableController construction")
136 136 << QThread::currentThread();
137 137
138 138 connect(impl->m_VariableModel, &VariableModel::abortProgessRequested, this,
139 139 &VariableController::onAbortProgressRequested);
140 140
141 141 connect(impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::dataProvided, this,
142 142 &VariableController::onDataProvided);
143 143 connect(impl->m_VariableAcquisitionWorker.get(),
144 144 &VariableAcquisitionWorker::variableRequestInProgress, this,
145 145 &VariableController::onVariableRetrieveDataInProgress);
146 146
147 147 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::started,
148 148 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::initialize);
149 149 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::finished,
150 150 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::finalize);
151 151
152 152
153 153 impl->m_VariableAcquisitionWorkerThread.start();
154 154 }
155 155
156 156 VariableController::~VariableController()
157 157 {
158 158 qCDebug(LOG_VariableController()) << tr("VariableController destruction")
159 159 << QThread::currentThread();
160 160 this->waitForFinish();
161 161 }
162 162
163 163 VariableModel *VariableController::variableModel() noexcept
164 164 {
165 165 return impl->m_VariableModel;
166 166 }
167 167
168 168 QItemSelectionModel *VariableController::variableSelectionModel() noexcept
169 169 {
170 170 return impl->m_VariableSelectionModel;
171 171 }
172 172
173 173 void VariableController::setTimeController(TimeController *timeController) noexcept
174 174 {
175 175 impl->m_TimeController = timeController;
176 176 }
177 177
178 178 void VariableController::deleteVariable(std::shared_ptr<Variable> variable) noexcept
179 179 {
180 180 if (!variable) {
181 181 qCCritical(LOG_VariableController()) << "Can't delete variable: variable is null";
182 182 return;
183 183 }
184 184
185 185 // Spreads in SciQlop that the variable will be deleted, so that potential receivers can
186 186 // make some treatments before the deletion
187 187 emit variableAboutToBeDeleted(variable);
188 188
189 189 // Deletes identifier
190 190 impl->m_VariableToIdentifierMap.erase(variable);
191 191
192 192 // Deletes provider
193 193 auto nbProvidersDeleted = impl->m_VariableToProviderMap.erase(variable);
194 194 qCDebug(LOG_VariableController())
195 195 << tr("Number of providers deleted for variable %1: %2")
196 196 .arg(variable->name(), QString::number(nbProvidersDeleted));
197 197
198 198 // Clears cache
199 199 impl->m_VariableCacheController->clear(variable);
200 200
201 201 // Deletes from model
202 202 impl->m_VariableModel->deleteVariable(variable);
203 203 }
204 204
205 205 void VariableController::deleteVariables(
206 206 const QVector<std::shared_ptr<Variable> > &variables) noexcept
207 207 {
208 208 for (auto variable : qAsConst(variables)) {
209 209 deleteVariable(variable);
210 210 }
211 211 }
212 212
213 213 void VariableController::abortProgress(std::shared_ptr<Variable> variable)
214 214 {
215 215 }
216 216
217 217 void VariableController::createVariable(const QString &name, const QVariantHash &metadata,
218 218 std::shared_ptr<IDataProvider> provider) noexcept
219 219 {
220 220
221 221 if (!impl->m_TimeController) {
222 222 qCCritical(LOG_VariableController())
223 223 << tr("Impossible to create variable: The time controller is null");
224 224 return;
225 225 }
226 226
227 227 auto range = impl->m_TimeController->dateTime();
228 228
229 229 if (auto newVariable = impl->m_VariableModel->createVariable(name, range, metadata)) {
230 230 auto identifier = QUuid::createUuid();
231 231
232 232 // store the provider
233 233 impl->registerProvider(provider);
234 234
235 235 // Associate the provider
236 236 impl->m_VariableToProviderMap[newVariable] = provider;
237 237 impl->m_VariableToIdentifierMap[newVariable] = identifier;
238 238
239 239
240 240 impl->processRequest(newVariable, range);
241 241 }
242 242 }
243 243
244 244 void VariableController::onDateTimeOnSelection(const SqpRange &dateTime)
245 245 {
246 246 // TODO check synchronisation
247 247 qCDebug(LOG_VariableController()) << "VariableController::onDateTimeOnSelection"
248 248 << QThread::currentThread()->objectName();
249 249 auto selectedRows = impl->m_VariableSelectionModel->selectedRows();
250 250
251 251 for (const auto &selectedRow : qAsConst(selectedRows)) {
252 252 if (auto selectedVariable = impl->m_VariableModel->variable(selectedRow.row())) {
253 253 selectedVariable->setRange(dateTime);
254 254 impl->processRequest(selectedVariable, dateTime);
255 255
256 256 // notify that rescale operation has to be done
257 257 emit rangeChanged(selectedVariable, dateTime);
258 258 }
259 259 }
260 260 }
261 261
262 262 void VariableController::onDataProvided(QUuid vIdentifier, const SqpRange &rangeRequested,
263 263 const SqpRange &cacheRangeRequested,
264 264 QVector<AcquisitionDataPacket> dataAcquired)
265 265 {
266 qCCritical(LOG_VariableController()) << tr("onDataProvided") << dataAcquired.isEmpty();
267
268 266 auto var = impl->findVariable(vIdentifier);
269 267 if (var != nullptr) {
270 268 var->setRange(rangeRequested);
271 269 var->setCacheRange(cacheRangeRequested);
272 qCCritical(LOG_VariableController()) << tr("1: onDataProvided") << rangeRequested;
273 qCCritical(LOG_VariableController()) << tr("2: onDataProvided") << cacheRangeRequested;
270 qCDebug(LOG_VariableController()) << tr("1: onDataProvided") << rangeRequested;
271 qCDebug(LOG_VariableController()) << tr("2: onDataProvided") << cacheRangeRequested;
274 272
275 273 auto retrievedDataSeries = impl->retrieveDataSeries(dataAcquired);
276 qCCritical(LOG_VariableController()) << tr("3: onDataProvided")
277 << retrievedDataSeries->range();
274 qCDebug(LOG_VariableController()) << tr("3: onDataProvided")
275 << retrievedDataSeries->range();
278 276 var->mergeDataSeries(retrievedDataSeries);
279 277 emit var->updated();
280 278 }
281 279 else {
282 280 qCCritical(LOG_VariableController()) << tr("Impossible to provide data to a null variable");
283 281 }
284 282 }
285 283
286 284 void VariableController::onVariableRetrieveDataInProgress(QUuid identifier, double progress)
287 285 {
288 286 auto var = impl->findVariable(identifier);
289 287 if (var != nullptr) {
290 288 impl->m_VariableModel->setDataProgress(var, progress);
291 289 }
292 290 else {
293 291 qCCritical(LOG_VariableController())
294 292 << tr("Impossible to notify progression of a null variable");
295 293 }
296 294 }
297 295
298 296 void VariableController::onAbortProgressRequested(std::shared_ptr<Variable> variable)
299 297 {
300 298 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAbortProgressRequested"
301 299 << QThread::currentThread()->objectName();
302 300
303 301 auto it = impl->m_VariableToIdentifierMap.find(variable);
304 302 if (it != impl->m_VariableToIdentifierMap.cend()) {
305 303 impl->m_VariableToProviderMap.at(variable)->requestDataAborting(it->second);
306 304 }
307 305 else {
308 306 qCWarning(LOG_VariableController())
309 307 << tr("Aborting progression of inexistant variable detected !!!")
310 308 << QThread::currentThread()->objectName();
311 309 }
312 310 }
313 311
314 312 void VariableController::onAddSynchronizationGroupId(QUuid synchronizationGroupId)
315 313 {
314 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronizationGroupId"
315 << QThread::currentThread()->objectName()
316 << synchronizationGroupId;
316 317 auto vSynchroGroup = std::make_shared<VariableSynchronizationGroup>();
317 318 impl->m_GroupIdToVariableSynchronizationGroupMap.insert(
318 319 std::make_pair(synchronizationGroupId, vSynchroGroup));
319 320 }
320 321
321 322 void VariableController::onRemoveSynchronizationGroupId(QUuid synchronizationGroupId)
322 323 {
323 324 impl->m_GroupIdToVariableSynchronizationGroupMap.erase(synchronizationGroupId);
324 325 }
325 326
327 void VariableController::onAddSynchronized(std::shared_ptr<Variable> variable,
328 QUuid synchronizationGroupId)
329
330 {
331 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronized"
332 << synchronizationGroupId;
333 auto vToVIdit = impl->m_VariableToIdentifierMap.find(variable);
note

ok

334 if (vToVIdit != impl->m_VariableToIdentifierMap.cend()) {
335 auto itSynchroGroup
336 = impl->m_GroupIdToVariableSynchronizationGroupMap.find(synchronizationGroupId);
337 if (itSynchroGroup != impl->m_GroupIdToVariableSynchronizationGroupMap.cend()) {
338 impl->m_VariableIdGroupIdMap.insert(
339 std::make_pair(vToVIdit->second, synchronizationGroupId));
340 itSynchroGroup->second->addVariableId(vToVIdit->second);
341 }
342 else {
343 qCCritical(LOG_VariableController())
344 << tr("Impossible to synchronize a variable with an unknown sycnhronization group")
345 << variable->name();
346 }
347 }
348 else {
349 qCCritical(LOG_VariableController())
350 << tr("Impossible to synchronize a variable with no identifier") << variable->name();
351 }
352 }
353
326 354
327 355 void VariableController::onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables,
328 356 const SqpRange &range, const SqpRange &oldRange,
329 357 bool synchronise)
330 358 {
331 359 // NOTE: oldRange isn't really necessary since oldRange == variable->range().
332 360
333 361 qCDebug(LOG_VariableController()) << "VariableController::onRequestDataLoading"
334 362 << QThread::currentThread()->objectName();
335 363 // we want to load data of the variable for the dateTime.
336 364 // First we check if the cache contains some of them.
337 365 // For the other, we ask the provider to give them.
338 366
339 367 foreach (auto var, variables) {
340 qCInfo(LOG_VariableController()) << "processRequest for" << var->name();
368 qCDebug(LOG_VariableController()) << "processRequest for" << var->name();
341 369 impl->processRequest(var, range);
342 370 }
343 371
344 372 if (synchronise) {
345 373 // Get the group ids
346 qCInfo(LOG_VariableController())
374 qCDebug(LOG_VariableController())
347 375 << "VariableController::onRequestDataLoading for synchro var ENABLE";
348 376 auto groupIds = std::set<QUuid>();
349 377 foreach (auto var, variables) {
350 auto vToVIdit = impl->m_VariableToIdentifierMap.find(var);
351 if (vToVIdit != impl->m_VariableToIdentifierMap.cend()) {
352 auto vId = vToVIdit->second;
353
354 auto vIdToGIdit = impl->m_VariableIdGroupIdMap.find(vId);
355 if (vIdToGIdit != impl->m_VariableIdGroupIdMap.cend()) {
356 auto gId = vToVIdit->second;
378 auto varToVarIdIt = impl->m_VariableToIdentifierMap.find(var);
379 if (varToVarIdIt != impl->m_VariableToIdentifierMap.cend()) {
380 auto vId = varToVarIdIt->second;
381 auto varIdToGroupIdIt = impl->m_VariableIdGroupIdMap.find(vId);
382 if (varIdToGroupIdIt != impl->m_VariableIdGroupIdMap.cend()) {
383 auto gId = varIdToGroupIdIt->second;
357 384 if (groupIds.find(gId) == groupIds.cend()) {
385 qCDebug(LOG_VariableController()) << "Synchro detect group " << gId;
358 386 groupIds.insert(gId);
359 387 }
360 388 }
361 389 }
362 390 }
363 391
364 392 // We assume here all group ids exist
365 393 foreach (auto gId, groupIds) {
366 394 auto vSynchronizationGroup = impl->m_GroupIdToVariableSynchronizationGroupMap.at(gId);
367 395 auto vSyncIds = vSynchronizationGroup->getIds();
396 qCDebug(LOG_VariableController()) << "Var in synchro group ";
368 397 for (auto vId : vSyncIds) {
369 398 auto var = impl->findVariable(vId);
370 if (var != nullptr) {
371 qCInfo(LOG_VariableController()) << "processRequest synchro for" << var->name();
372 auto vSyncRangeRequested
373 = computeSynchroRangeRequested(var->range(), range, oldRange);
374 impl->processRequest(var, vSyncRangeRequested);
375 }
376 else {
377 qCCritical(LOG_VariableController())
378 << tr("Impossible to synchronize a null variable");
399
400 // Don't process already processed var
401 if (!variables.contains(var)) {
402 if (var != nullptr) {
403 qCDebug(LOG_VariableController()) << "processRequest synchro for"
404 << var->name();
405 auto vSyncRangeRequested
406 = computeSynchroRangeRequested(var->range(), range, oldRange);
407 impl->processRequest(var, vSyncRangeRequested);
408 }
409 else {
410 qCCritical(LOG_VariableController())
411
412 << tr("Impossible to synchronize a null variable");
413 }
379 414 }
380 415 }
381 416 }
382 417 }
383 418 }
384 419
385 420
386 421 void VariableController::initialize()
387 422 {
388 423 qCDebug(LOG_VariableController()) << tr("VariableController init") << QThread::currentThread();
389 424 impl->m_WorkingMutex.lock();
390 425 qCDebug(LOG_VariableController()) << tr("VariableController init END");
391 426 }
392 427
393 428 void VariableController::finalize()
394 429 {
395 430 impl->m_WorkingMutex.unlock();
396 431 }
397 432
398 433 void VariableController::waitForFinish()
399 434 {
400 435 QMutexLocker locker{&impl->m_WorkingMutex};
401 436 }
402 437
403 438 AcquisitionZoomType VariableController::getZoomType(const SqpRange &range, const SqpRange &oldRange)
404 439 {
405 440 // t1.m_TStart <= t2.m_TStart && t2.m_TEnd <= t1.m_TEnd
406 441 auto zoomType = AcquisitionZoomType::Unknown;
407 442 if (range.m_TStart <= oldRange.m_TStart && oldRange.m_TEnd <= range.m_TEnd) {
408 443 zoomType = AcquisitionZoomType::ZoomOut;
409 444 }
410 445 else if (range.m_TStart > oldRange.m_TStart && range.m_TEnd > oldRange.m_TEnd) {
411 446 zoomType = AcquisitionZoomType::PanRight;
412 447 }
413 448 else if (range.m_TStart < oldRange.m_TStart && range.m_TEnd < oldRange.m_TEnd) {
414 449 zoomType = AcquisitionZoomType::PanLeft;
415 450 }
416 451 else if (range.m_TStart > oldRange.m_TStart && oldRange.m_TEnd > range.m_TEnd) {
417 452 zoomType = AcquisitionZoomType::ZoomIn;
418 453 }
419 454 else {
420 455 qCCritical(LOG_VariableController()) << "getZoomType: Unknown type detected";
421 456 }
422 457 return zoomType;
423 458 }
424 459
425 460 void VariableController::VariableControllerPrivate::processRequest(std::shared_ptr<Variable> var,
426 461 const SqpRange &rangeRequested)
427 462 {
428 463
429 464 auto varRangesRequested
430 465 = m_VariableCacheStrategy->computeCacheRange(var->range(), rangeRequested);
431 466 auto notInCacheRangeList = var->provideNotInCacheRangeList(varRangesRequested.second);
432 467
433 468 if (!notInCacheRangeList.empty()) {
434 469 // Display part of data which are already there
435 470 // Ask the provider for each data on the dateTimeListNotInCache
436 471 auto identifier = m_VariableToIdentifierMap.at(var);
437 472 auto varProvider = m_VariableToProviderMap.at(var);
438 473 if (varProvider != nullptr) {
439 474 m_VariableAcquisitionWorker->pushVariableRequest(
440 475 identifier, varRangesRequested.first, varRangesRequested.second,
441 476 DataProviderParameters{std::move(notInCacheRangeList), var->metadata()},
442 477 varProvider);
443 478 }
444 479 else {
445 480 qCCritical(LOG_VariableController())
446 481 << "Impossible to provide data with a null provider";
447 482 }
448 483 }
449 484 else {
450 485 var->setRange(rangeRequested);
451 486 var->setCacheRange(varRangesRequested.second);
452 487 var->setDataSeries(var->dataSeries()->subData(varRangesRequested.second));
453 488 emit var->updated();
454 489 }
455 490 }
456 491
457 492 std::shared_ptr<Variable>
458 493 VariableController::VariableControllerPrivate::findVariable(QUuid vIdentifier)
459 494 {
460 495 std::shared_ptr<Variable> var;
461 496 auto findReply = [vIdentifier](const auto &entry) { return vIdentifier == entry.second; };
462 497
463 498 auto end = m_VariableToIdentifierMap.cend();
464 499 auto it = std::find_if(m_VariableToIdentifierMap.cbegin(), end, findReply);
465 500 if (it != end) {
466 501 var = it->first;
467 502 }
468 503 else {
469 504 qCCritical(LOG_VariableController())
470 505 << tr("Impossible to find the variable with the identifier: ") << vIdentifier;
471 506 }
472 507
473 508 return var;
474 509 }
475 510
476 511 std::shared_ptr<IDataSeries> VariableController::VariableControllerPrivate::retrieveDataSeries(
477 512 const QVector<AcquisitionDataPacket> acqDataPacketVector)
478 513 {
479 514 qCInfo(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size")
480 515 << acqDataPacketVector.size();
481 516 std::shared_ptr<IDataSeries> dataSeries;
482 517 if (!acqDataPacketVector.isEmpty()) {
483 518 dataSeries = acqDataPacketVector[0].m_DateSeries;
484 519 for (int i = 1; i < acqDataPacketVector.size(); ++i) {
485 520 dataSeries->merge(acqDataPacketVector[i].m_DateSeries.get());
486 521 }
487 522 }
488 523
489 524 return dataSeries;
490 525 }
491 526
492 527 void VariableController::VariableControllerPrivate::registerProvider(
493 528 std::shared_ptr<IDataProvider> provider)
494 529 {
495 530 if (m_ProviderSet.find(provider) == m_ProviderSet.end()) {
496 531 qCInfo(LOG_VariableController()) << tr("Registering of a new provider")
497 532 << provider->objectName();
498 533 m_ProviderSet.insert(provider);
499 534 connect(provider.get(), &IDataProvider::dataProvided, m_VariableAcquisitionWorker.get(),
500 535 &VariableAcquisitionWorker::onVariableDataAcquired);
501 536 connect(provider.get(), &IDataProvider::dataProvidedProgress,
502 537 m_VariableAcquisitionWorker.get(),
503 538 &VariableAcquisitionWorker::onVariableRetrieveDataInProgress);
504 539 }
505 540 else {
506 qCInfo(LOG_VariableController()) << tr("Cannot register provider, it already exists ");
541 qCDebug(LOG_VariableController()) << tr("Cannot register provider, it already exists ");
507 542 }
508 543 }
@@ -1,199 +1,199
1 1 #include "Data/ArrayData.h"
2 2 #include <QObject>
3 3 #include <QtTest>
4 4
5 5 class TestOneDimArrayData : public QObject {
6 6 Q_OBJECT
7 7 private slots:
8 8 /// Tests @sa ArrayData::data()
9 9 void testData_data();
10 10 void testData();
11 11
12 12 /// Tests @sa ArrayData::data(int componentIndex)
13 13 void testDataByComponentIndex_data();
14 14 void testDataByComponentIndex();
15 15
16 16 /// Tests @sa ArrayData::add()
17 17 void testAdd_data();
18 18 void testAdd();
19 19
20 20 /// Tests @sa ArrayData::at(int index)
21 21 void testAt_data();
22 22 void testAt();
23 23
24 24 /// Tests @sa ArrayData::clear()
25 25 void testClear_data();
26 26 void testClear();
27 27
28 28 /// Tests @sa ArrayData::size()
29 29 void testSize_data();
30 30 void testSize();
31 31
32 32 /// Tests @sa ArrayData::sort()
33 33 void testSort_data();
34 34 void testSort();
35 35 };
36 36
37 37 void TestOneDimArrayData::testData_data()
38 38 {
39 39 // Test structure
40 40 QTest::addColumn<QVector<double> >("inputData"); // array's data input
41 41 QTest::addColumn<QVector<double> >("expectedData"); // expected data
42 42
43 43 // Test cases
44 44 QTest::newRow("data1") << QVector<double>{1., 2., 3., 4., 5.}
45 45 << QVector<double>{1., 2., 3., 4., 5.};
46 46 }
47 47
48 48 void TestOneDimArrayData::testData()
49 49 {
50 50 QFETCH(QVector<double>, inputData);
51 51 QFETCH(QVector<double>, expectedData);
52 52
53 53 ArrayData<1> arrayData{inputData};
54 54 QVERIFY(arrayData.data() == expectedData);
55 55 }
56 56
57 57 void TestOneDimArrayData::testDataByComponentIndex_data()
58 58 {
59 59 // Test structure
60 60 QTest::addColumn<QVector<double> >("inputData"); // array data's input
61 61 QTest::addColumn<int>("componentIndex"); // component index to test
62 62 QTest::addColumn<QVector<double> >("expectedData"); // expected data
63 63
64 64 // Test cases
65 65 QTest::newRow("validIndex") << QVector<double>{1., 2., 3., 4., 5.} << 0
66 66 << QVector<double>{1., 2., 3., 4., 5.};
67 QTest::newRow("invalidIndex1")
68 << QVector<double>{1., 2., 3., 4., 5.} << -1 << QVector<double>{};
67 QTest::newRow("invalidIndex1") << QVector<double>{1., 2., 3., 4., 5.} << -1
68 << QVector<double>{};
69 69 QTest::newRow("invalidIndex2") << QVector<double>{1., 2., 3., 4., 5.} << 1 << QVector<double>{};
70 70 }
71 71
72 72 void TestOneDimArrayData::testDataByComponentIndex()
73 73 {
74 74 QFETCH(QVector<double>, inputData);
75 75 QFETCH(int, componentIndex);
76 76 QFETCH(QVector<double>, expectedData);
77 77
78 78 ArrayData<1> arrayData{inputData};
79 79 QVERIFY(arrayData.data(componentIndex) == expectedData);
80 80 }
81 81
82 82 void TestOneDimArrayData::testAdd_data()
83 83 {
84 84 // Test structure
85 85 QTest::addColumn<QVector<double> >("inputData"); // array's data input
86 86 QTest::addColumn<QVector<double> >("otherData"); // array data's input to merge with
87 87 QTest::addColumn<bool>("prepend"); // prepend or append merge
88 88 QTest::addColumn<QVector<double> >("expectedData"); // expected data after merge
89 89
90 90 // Test cases
91 91 QTest::newRow("appendMerge") << QVector<double>{1., 2., 3., 4., 5.}
92 92 << QVector<double>{6., 7., 8.} << false
93 93 << QVector<double>{1., 2., 3., 4., 5., 6., 7., 8.};
94 94 QTest::newRow("prependMerge") << QVector<double>{1., 2., 3., 4., 5.}
95 95 << QVector<double>{6., 7., 8.} << true
96 96 << QVector<double>{6., 7., 8., 1., 2., 3., 4., 5.};
97 97 }
98 98
99 99 void TestOneDimArrayData::testAdd()
100 100 {
101 101 QFETCH(QVector<double>, inputData);
102 102 QFETCH(QVector<double>, otherData);
103 103 QFETCH(bool, prepend);
104 104 QFETCH(QVector<double>, expectedData);
105 105
106 106 ArrayData<1> arrayData{inputData};
107 107 ArrayData<1> other{otherData};
108 108
109 109 arrayData.add(other, prepend);
110 110 QVERIFY(arrayData.data() == expectedData);
111 111 }
112 112
113 113 void TestOneDimArrayData::testAt_data()
114 114 {
115 115 // Test structure
116 116 QTest::addColumn<QVector<double> >("inputData"); // array data's input
117 117 QTest::addColumn<int>("index"); // index to retrieve data
118 118 QTest::addColumn<double>("expectedData"); // expected data at index
119 119
120 120 // Test cases
121 121 QTest::newRow("data1") << QVector<double>{1., 2., 3., 4., 5.} << 0 << 1.;
122 122 QTest::newRow("data2") << QVector<double>{1., 2., 3., 4., 5.} << 3 << 4.;
123 123 }
124 124
125 125 void TestOneDimArrayData::testAt()
126 126 {
127 127 QFETCH(QVector<double>, inputData);
128 128 QFETCH(int, index);
129 129 QFETCH(double, expectedData);
130 130
131 131 ArrayData<1> arrayData{inputData};
132 132 QVERIFY(arrayData.at(index) == expectedData);
133 133 }
134 134
135 135 void TestOneDimArrayData::testClear_data()
136 136 {
137 137 // Test structure
138 138 QTest::addColumn<QVector<double> >("inputData"); // array data's input
139 139
140 140 // Test cases
141 141 QTest::newRow("data1") << QVector<double>{1., 2., 3., 4., 5.};
142 142 }
143 143
144 144 void TestOneDimArrayData::testClear()
145 145 {
146 146 QFETCH(QVector<double>, inputData);
147 147
148 148 ArrayData<1> arrayData{inputData};
149 149 arrayData.clear();
150 150 QVERIFY(arrayData.data() == QVector<double>{});
151 151 }
152 152
153 153 void TestOneDimArrayData::testSize_data()
154 154 {
155 155 // Test structure
156 156 QTest::addColumn<QVector<double> >("inputData"); // array data's input
157 157 QTest::addColumn<int>("expectedSize"); // expected array data size
158 158
159 159 // Test cases
160 160 QTest::newRow("data1") << QVector<double>{1., 2., 3., 4., 5.} << 5;
161 161 }
162 162
163 163 void TestOneDimArrayData::testSize()
164 164 {
165 165 QFETCH(QVector<double>, inputData);
166 166 QFETCH(int, expectedSize);
167 167
168 168 ArrayData<1> arrayData{inputData};
169 169 QVERIFY(arrayData.size() == expectedSize);
170 170 }
171 171
172 172 void TestOneDimArrayData::testSort_data()
173 173 {
174 174 // Test structure
175 175 QTest::addColumn<QVector<double> >("inputData"); // array data's input
176 176 QTest::addColumn<std::vector<int> >("sortPermutation"); // permutation used to sort data
177 177 QTest::addColumn<QVector<double> >("expectedData"); // expected data after sorting
178 178
179 179 // Test cases
180 180 QTest::newRow("data1") << QVector<double>{1., 2., 3., 4., 5.} << std::vector<int>{0, 2, 3, 1, 4}
181 181 << QVector<double>{1., 3., 4., 2., 5.};
182 182 QTest::newRow("data2") << QVector<double>{1., 2., 3., 4., 5.} << std::vector<int>{4, 1, 2, 3, 0}
183 183 << QVector<double>{5., 2., 3., 4., 1.};
184 184 }
185 185
186 186 void TestOneDimArrayData::testSort()
187 187 {
188 188 QFETCH(QVector<double>, inputData);
189 189 QFETCH(std::vector<int>, sortPermutation);
190 190 QFETCH(QVector<double>, expectedData);
191 191
192 192 ArrayData<1> arrayData{inputData};
193 193 auto sortedArrayData = arrayData.sort(sortPermutation);
194 194 QVERIFY(sortedArrayData != nullptr);
195 195 QVERIFY(sortedArrayData->data() == expectedData);
196 196 }
197 197
198 198 QTEST_MAIN(TestOneDimArrayData)
199 199 #include "TestOneDimArrayData.moc"
@@ -1,224 +1,224
1 1 #include "Data/ArrayData.h"
2 2 #include <QObject>
3 3 #include <QtTest>
4 4
5 5 using DataContainer = QVector<QVector<double> >;
6 6
7 7 class TestTwoDimArrayData : public QObject {
8 8 Q_OBJECT
9 9 private slots:
10 10 /// Tests @sa ArrayData::data(int componentIndex)
11 11 void testDataByComponentIndex_data();
12 12 void testDataByComponentIndex();
13 13
14 14 /// Tests @sa ArrayData ctor
15 15 void testCtor_data();
16 16 void testCtor();
17 17
18 18 /// Tests @sa ArrayData::add()
19 19 void testAdd_data();
20 20 void testAdd();
21 21
22 22 /// Tests @sa ArrayData::clear()
23 23 void testClear_data();
24 24 void testClear();
25 25
26 26 /// Tests @sa ArrayData::size()
27 27 void testSize_data();
28 28 void testSize();
29 29
30 30 /// Tests @sa ArrayData::sort()
31 31 void testSort_data();
32 32 void testSort();
33 33 };
34 34
35 35 void TestTwoDimArrayData::testDataByComponentIndex_data()
36 36 {
37 37 // Test structure
38 38 QTest::addColumn<DataContainer>("inputData"); // array data's input
39 39 QTest::addColumn<int>("componentIndex"); // component index to test
40 40 QTest::addColumn<QVector<double> >("expectedData"); // expected data
41 41
42 42 // Test cases
43 43 auto inputData
44 44 = DataContainer{{1., 2., 3., 4., 5.}, {6., 7., 8., 9., 10.}, {11., 12., 13., 14., 15.}};
45 45
46 46 QTest::newRow("validIndex1") << inputData << 0 << QVector<double>{1., 2., 3., 4., 5.};
47 47 QTest::newRow("validIndex2") << inputData << 1 << QVector<double>{6., 7., 8., 9., 10.};
48 48 QTest::newRow("validIndex3") << inputData << 2 << QVector<double>{11., 12., 13., 14., 15.};
49 49 QTest::newRow("invalidIndex1") << inputData << -1 << QVector<double>{};
50 50 QTest::newRow("invalidIndex2") << inputData << 3 << QVector<double>{};
51 51 }
52 52
53 53 void TestTwoDimArrayData::testDataByComponentIndex()
54 54 {
55 55 QFETCH(DataContainer, inputData);
56 56 QFETCH(int, componentIndex);
57 57 QFETCH(QVector<double>, expectedData);
58 58
59 59 ArrayData<2> arrayData{inputData};
60 60 QVERIFY(arrayData.data(componentIndex) == expectedData);
61 61 }
62 62
63 63 void TestTwoDimArrayData::testCtor_data()
64 64 {
65 65 // Test structure
66 66 QTest::addColumn<DataContainer>("inputData"); // array data's input
67 67 QTest::addColumn<bool>("success"); // array data has been successfully constructed
68 68 QTest::addColumn<DataContainer>("expectedData"); // expected array data (when success)
69 69
70 70 // Test cases
71 71 QTest::newRow("validInput")
72 72 << DataContainer{{1., 2., 3., 4., 5.}, {6., 7., 8., 9., 10.}, {11., 12., 13., 14., 15.}}
73 73 << true
74 74 << DataContainer{{1., 2., 3., 4., 5.}, {6., 7., 8., 9., 10.}, {11., 12., 13., 14., 15.}};
75 75 QTest::newRow("malformedInput (components of the array data haven't the same size")
76 76 << DataContainer{{1., 2., 3., 4., 5.}, {6., 7., 8.}, {11., 12.}} << true
77 77 << DataContainer{{}, {}, {}};
78 QTest::newRow("invalidInput (less than tow components")
79 << DataContainer{{1., 2., 3., 4., 5.}} << false << DataContainer{{}, {}, {}};
78 QTest::newRow("invalidInput (less than tow components") << DataContainer{{1., 2., 3., 4., 5.}}
79 << false << DataContainer{{}, {}, {}};
80 80 }
81 81
82 82 void TestTwoDimArrayData::testCtor()
83 83 {
84 84 QFETCH(DataContainer, inputData);
85 85 QFETCH(bool, success);
86 86
87 87 if (success) {
88 88 QFETCH(DataContainer, expectedData);
89 89
90 90 ArrayData<2> arrayData{inputData};
91 91
92 92 for (auto i = 0; i < expectedData.size(); ++i) {
93 93 QVERIFY(arrayData.data(i) == expectedData.at(i));
94 94 }
95 95 }
96 96 else {
97 97 QVERIFY_EXCEPTION_THROWN(ArrayData<2> arrayData{inputData}, std::invalid_argument);
98 98 }
99 99 }
100 100
101 101 void TestTwoDimArrayData::testAdd_data()
102 102 {
103 103 // Test structure
104 104 QTest::addColumn<DataContainer>("inputData"); // array's data input
105 105 QTest::addColumn<DataContainer>("otherData"); // array data's input to merge with
106 106 QTest::addColumn<bool>("prepend"); // prepend or append merge
107 107 QTest::addColumn<DataContainer>("expectedData"); // expected data after merge
108 108
109 109 // Test cases
110 110 auto inputData
111 111 = DataContainer{{1., 2., 3., 4., 5.}, {11., 12., 13., 14., 15.}, {21., 22., 23., 24., 25.}};
112 112
113 113 auto vectorContainer = DataContainer{{6., 7., 8.}, {16., 17., 18.}, {26., 27., 28}};
114 114 auto tensorContainer = DataContainer{{6., 7., 8.}, {16., 17., 18.}, {26., 27., 28},
115 115 {36., 37., 38.}, {46., 47., 48.}, {56., 57., 58}};
116 116
117 117 QTest::newRow("appendMerge") << inputData << vectorContainer << false
118 118 << DataContainer{{1., 2., 3., 4., 5., 6., 7., 8.},
119 119 {11., 12., 13., 14., 15., 16., 17., 18.},
120 120 {21., 22., 23., 24., 25., 26., 27., 28}};
121 121 QTest::newRow("prependMerge") << inputData << vectorContainer << true
122 122 << DataContainer{{6., 7., 8., 1., 2., 3., 4., 5.},
123 123 {16., 17., 18., 11., 12., 13., 14., 15.},
124 124 {26., 27., 28, 21., 22., 23., 24., 25.}};
125 125 QTest::newRow("invalidMerge") << inputData << tensorContainer << false << inputData;
126 126 }
127 127
128 128 void TestTwoDimArrayData::testAdd()
129 129 {
130 130 QFETCH(DataContainer, inputData);
131 131 QFETCH(DataContainer, otherData);
132 132 QFETCH(bool, prepend);
133 133 QFETCH(DataContainer, expectedData);
134 134
135 135 ArrayData<2> arrayData{inputData};
136 136 ArrayData<2> other{otherData};
137 137
138 138 arrayData.add(other, prepend);
139 139
140 140 for (auto i = 0; i < expectedData.size(); ++i) {
141 141 QVERIFY(arrayData.data(i) == expectedData.at(i));
142 142 }
143 143 }
144 144
145 145 void TestTwoDimArrayData::testClear_data()
146 146 {
147 147 // Test structure
148 148 QTest::addColumn<DataContainer>("inputData"); // array data's input
149 149
150 150 // Test cases
151 151 QTest::newRow("data1") << DataContainer{
152 152 {1., 2., 3., 4., 5.}, {6., 7., 8., 9., 10.}, {11., 12., 13., 14., 15.}};
153 153 }
154 154
155 155 void TestTwoDimArrayData::testClear()
156 156 {
157 157 QFETCH(DataContainer, inputData);
158 158
159 159 ArrayData<2> arrayData{inputData};
160 160 arrayData.clear();
161 161
162 162 for (auto i = 0; i < inputData.size(); ++i) {
163 163 QVERIFY(arrayData.data(i) == QVector<double>{});
164 164 }
165 165 }
166 166
167 167 void TestTwoDimArrayData::testSize_data()
168 168 {
169 169 // Test structure
170 170 QTest::addColumn<QVector<QVector<double> > >("inputData"); // array data's input
171 171 QTest::addColumn<int>("expectedSize"); // expected array data size
172 172
173 173 // Test cases
174 174 QTest::newRow("data1") << DataContainer{{1., 2., 3., 4., 5.}, {6., 7., 8., 9., 10.}} << 5;
175 175 QTest::newRow("data2") << DataContainer{{1., 2., 3., 4., 5.},
176 176 {6., 7., 8., 9., 10.},
177 177 {11., 12., 13., 14., 15.}}
178 178 << 5;
179 179 }
180 180
181 181 void TestTwoDimArrayData::testSize()
182 182 {
183 183 QFETCH(DataContainer, inputData);
184 184 QFETCH(int, expectedSize);
185 185
186 186 ArrayData<2> arrayData{inputData};
187 187 QVERIFY(arrayData.size() == expectedSize);
188 188 }
189 189
190 190 void TestTwoDimArrayData::testSort_data()
191 191 {
192 192 // Test structure
193 193 QTest::addColumn<DataContainer>("inputData"); // array data's input
194 194 QTest::addColumn<std::vector<int> >("sortPermutation"); // permutation used to sort data
195 195 QTest::addColumn<DataContainer>("expectedData"); // expected data after sorting
196 196
197 197 // Test cases
198 198 QTest::newRow("data1")
199 199 << DataContainer{{1., 2., 3., 4., 5.}, {6., 7., 8., 9., 10.}, {11., 12., 13., 14., 15.}}
200 200 << std::vector<int>{0, 2, 3, 1, 4}
201 201 << DataContainer{{1., 3., 4., 2., 5.}, {6., 8., 9., 7., 10.}, {11., 13., 14., 12., 15.}};
202 202 QTest::newRow("data2")
203 203 << DataContainer{{1., 2., 3., 4., 5.}, {6., 7., 8., 9., 10.}, {11., 12., 13., 14., 15.}}
204 204 << std::vector<int>{2, 4, 3, 0, 1}
205 205 << DataContainer{{3., 5., 4., 1., 2.}, {8., 10., 9., 6., 7.}, {13., 15., 14., 11., 12.}};
206 206 }
207 207
208 208 void TestTwoDimArrayData::testSort()
209 209 {
210 210 QFETCH(DataContainer, inputData);
211 211 QFETCH(std::vector<int>, sortPermutation);
212 212 QFETCH(DataContainer, expectedData);
213 213
214 214 ArrayData<2> arrayData{inputData};
215 215 auto sortedArrayData = arrayData.sort(sortPermutation);
216 216 QVERIFY(sortedArrayData != nullptr);
217 217
218 218 for (auto i = 0; i < expectedData.size(); ++i) {
219 219 QVERIFY(sortedArrayData->data(i) == expectedData.at(i));
220 220 }
221 221 }
222 222
223 223 QTEST_MAIN(TestTwoDimArrayData)
224 224 #include "TestTwoDimArrayData.moc"
@@ -1,80 +1,83
1 1 #ifndef SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
2 2 #define SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
3 3
4 4 #include "Visualization/IVisualizationWidget.h"
5 5
6 6 #include <QLoggingCategory>
7 7 #include <QWidget>
8 8
9 9 #include <memory>
10 10
11 11 #include <Common/spimpl.h>
12 12
13 13 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationGraphWidget)
14 14
15 15 class QCPRange;
16 16 class SqpRange;
17 17 class Variable;
18 18
19 19 namespace Ui {
20 20 class VisualizationGraphWidget;
21 21 } // namespace Ui
22 22
23 23 class VisualizationGraphWidget : public QWidget, public IVisualizationWidget {
24 24 Q_OBJECT
25 25
26 26 public:
27 27 explicit VisualizationGraphWidget(const QString &name = {}, QWidget *parent = 0);
28 28 virtual ~VisualizationGraphWidget();
29 29
30 30 /// If acquisition isn't enable, requestDataLoading signal cannot be emit
31 31 void enableAcquisition(bool enable);
32 32
33 33 void addVariable(std::shared_ptr<Variable> variable);
34 34 void addVariableUsingGraph(std::shared_ptr<Variable> variable);
35 35 /// Removes a variable from the graph
36 36 void removeVariable(std::shared_ptr<Variable> variable) noexcept;
37 37
38 38 void setRange(std::shared_ptr<Variable> variable, const SqpRange &range);
39 39 SqpRange graphRange() const noexcept;
40 40 void setGraphRange(const SqpRange &range);
41 41
42 42 // IVisualizationWidget interface
43 43 void accept(IVisualizationWidgetVisitor *visitor) override;
44 44 bool canDrop(const Variable &variable) const override;
45 45 bool contains(const Variable &variable) const override;
46 46 QString name() const override;
47 47
48 48
49 49 signals:
50 50 void synchronize(const SqpRange &range, const SqpRange &oldRange);
51 51 void requestDataLoading(QVector<std::shared_ptr<Variable> > variable, const SqpRange &range,
52 52 const SqpRange &oldRange, bool synchronise);
53 53
54 54
55 void variableAdded(std::shared_ptr<Variable> var);
56
57
55 58 private:
56 59 Ui::VisualizationGraphWidget *ui;
57 60
58 61 class VisualizationGraphWidgetPrivate;
59 62 spimpl::unique_impl_ptr<VisualizationGraphWidgetPrivate> impl;
60 63
61 64 private slots:
62 65 /// Slot called when right clicking on the graph (displays a menu)
63 66 void onGraphMenuRequested(const QPoint &pos) noexcept;
64 67
65 68 /// Rescale the X axe to range parameter
66 69 void onRangeChanged(const QCPRange &t1, const QCPRange &t2);
67 70
68 71 /// Slot called when a mouse move was made
69 72 void onMouseMove(QMouseEvent *event) noexcept;
70 73 /// Slot called when a mouse wheel was made, to perform some processing before the zoom is done
71 74 void onMouseWheel(QWheelEvent *event) noexcept;
72 75 /// Slot called when a mouse press was made, to activate the calibration of a graph
73 76 void onMousePress(QMouseEvent *event) noexcept;
74 77 /// Slot called when a mouse release was made, to deactivate the calibration of a graph
75 78 void onMouseRelease(QMouseEvent *event) noexcept;
76 79
77 80 void onDataCacheVariableUpdated();
78 81 };
79 82
80 83 #endif // SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
@@ -1,52 +1,56
1 1 #ifndef SCIQLOP_VISUALIZATIONZONEWIDGET_H
2 2 #define SCIQLOP_VISUALIZATIONZONEWIDGET_H
3 3
4 4 #include "Visualization/IVisualizationWidget.h"
5 5
6 6 #include <QLoggingCategory>
7 7 #include <QWidget>
8 8
9 9 #include <memory>
10 10
11 11 #include <Common/spimpl.h>
12 12
13 13 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationZoneWidget)
14 14
15 15 namespace Ui {
16 16 class VisualizationZoneWidget;
17 17 } // Ui
18 18
19 19 class Variable;
20 20 class VisualizationGraphWidget;
21 21
22 22 class VisualizationZoneWidget : public QWidget, public IVisualizationWidget {
23 23 Q_OBJECT
24 24
25 25 public:
26 26 explicit VisualizationZoneWidget(const QString &name = {}, QWidget *parent = 0);
27 27 virtual ~VisualizationZoneWidget();
28 28
29 29 /// Add a graph widget
30 30 void addGraph(VisualizationGraphWidget *graphWidget);
31 31
32 32 /**
33 33 * Creates a graph using a variable. The variable will be displayed in the new graph.
34 34 * @param variable the variable for which to create the graph
35 35 * @return the pointer to the created graph
36 36 */
37 37 VisualizationGraphWidget *createGraph(std::shared_ptr<Variable> variable);
38 38
39 39 // IVisualizationWidget interface
40 40 void accept(IVisualizationWidgetVisitor *visitor) override;
41 41 bool canDrop(const Variable &variable) const override;
42 42 bool contains(const Variable &variable) const override;
43 43 QString name() const override;
44 44
45
46 private slots:
47 void onVariableAdded(std::shared_ptr<Variable> variable);
48
45 49 private:
46 50 Ui::VisualizationZoneWidget *ui;
47 51
48 52 class VisualizationZoneWidgetPrivate;
49 53 spimpl::unique_impl_ptr<VisualizationZoneWidgetPrivate> impl;
50 54 };
51 55
52 56 #endif // SCIQLOP_VISUALIZATIONZONEWIDGET_H
@@ -1,321 +1,307
1 1 #include "Visualization/VisualizationGraphWidget.h"
2 2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 3 #include "Visualization/VisualizationGraphHelper.h"
4 4 #include "Visualization/VisualizationGraphRenderingDelegate.h"
5 5 #include "ui_VisualizationGraphWidget.h"
6 6
7 7 #include <Data/ArrayData.h>
8 8 #include <Data/IDataSeries.h>
9 9 #include <Settings/SqpSettingsDefs.h>
10 10 #include <SqpApplication.h>
11 11 #include <Variable/Variable.h>
12 12 #include <Variable/VariableController.h>
13 13
14 14 #include <unordered_map>
15 15
16 16 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
17 17
18 18 namespace {
19 19
20 20 /// Key pressed to enable zoom on horizontal axis
21 21 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::NoModifier;
22 22
23 23 /// Key pressed to enable zoom on vertical axis
24 24 const auto VERTICAL_ZOOM_MODIFIER = Qt::ControlModifier;
25 25
26 26 } // namespace
27 27
28 28 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
29 29
30 30 explicit VisualizationGraphWidgetPrivate()
31 31 : m_DoAcquisition{true}, m_IsCalibration{false}, m_RenderingDelegate{nullptr}
32 32 {
33 33 }
34 34
35 35 // 1 variable -> n qcpplot
36 36 std::multimap<std::shared_ptr<Variable>, QCPAbstractPlottable *> m_VariableToPlotMultiMap;
37 37 bool m_DoAcquisition;
38 38 bool m_IsCalibration;
39 39 QCPItemTracer *m_TextTracer;
40 40 /// Delegate used to attach rendering features to the plot
41 41 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
42 42 };
43 43
44 44 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
45 45 : QWidget{parent},
46 46 ui{new Ui::VisualizationGraphWidget},
47 47 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>()}
48 48 {
49 49 ui->setupUi(this);
50 50
51 51 // The delegate must be initialized after the ui as it uses the plot
52 52 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*ui->widget);
53 53
54 54 ui->graphNameLabel->setText(name);
55 55
56 56 // 'Close' options : widget is deleted when closed
57 57 setAttribute(Qt::WA_DeleteOnClose);
58 58 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationGraphWidget::close);
59 59 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
60 60
61 61 // Set qcpplot properties :
62 62 // - Drag (on x-axis) and zoom are enabled
63 63 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
64 64 ui->widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);
65 65 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal);
66 66
67 67 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
68 68 connect(ui->widget, &QCustomPlot::mouseRelease, this,
69 69 &VisualizationGraphWidget::onMouseRelease);
70 70 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
71 71 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
72 72 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
73 73 &QCPAxis::rangeChanged),
74 74 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
75 75
76 76 // Activates menu when right clicking on the graph
77 77 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
78 78 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
79 79 &VisualizationGraphWidget::onGraphMenuRequested);
80 80
81 81 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
82 82 &VariableController::onRequestDataLoading);
83 83 }
84 84
85 85
86 86 VisualizationGraphWidget::~VisualizationGraphWidget()
87 87 {
88 88 delete ui;
89 89 }
90 90
91 91 void VisualizationGraphWidget::enableAcquisition(bool enable)
92 92 {
93 93 impl->m_DoAcquisition = enable;
94 94 }
95 95
96 96 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable)
97 97 {
98 auto calibrationState = impl->m_IsCalibration;
99 impl->m_IsCalibration = true;
98 100 // Uses delegate to create the qcpplot components according to the variable
99 101 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
102 impl->m_IsCalibration = calibrationState;
100 103
101 104 for (auto createdPlottable : qAsConst(createdPlottables)) {
102 105 impl->m_VariableToPlotMultiMap.insert({variable, createdPlottable});
103 106 }
104 107
105 108 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
109
110 emit variableAdded(variable);
106 111 }
107 112 void VisualizationGraphWidget::addVariableUsingGraph(std::shared_ptr<Variable> variable)
108 113 {
109 // TODO
110 // // when adding a variable, we need to set its time range to the current graph range
111 // auto grapheRange = ui->widget->xAxis->range();
112 // auto dateTime = SqpRange{grapheRange.lower, grapheRange.upper};
113 // variable->setDateTime(dateTime);
114
115 // auto variableDateTimeWithTolerance = dateTime;
116
117 // // add tolerance for each side
118 // auto toleranceFactor
119 // = toleranceValue(GENERAL_TOLERANCE_AT_INIT_KEY,
120 // GENERAL_TOLERANCE_AT_INIT_DEFAULT_VALUE);
121 // auto tolerance = toleranceFactor * (dateTime.m_TEnd - dateTime.m_TStart);
122 // variableDateTimeWithTolerance.m_TStart -= tolerance;
123 // variableDateTimeWithTolerance.m_TEnd += tolerance;
124
125 // // Uses delegate to create the qcpplot components according to the variable
126 // auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
127
128 // for (auto createdPlottable : qAsConst(createdPlottables)) {
129 // impl->m_VariableToPlotMultiMap.insert({variable, createdPlottable});
130 // }
114 // Uses delegate to create the qcpplot components according to the variable
115 this->addVariable(variable);
131 116
132 // connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
117 // Request range for the variable
118 auto graphRange = ui->widget->xAxis->range();
133 119
134 // // CHangement detected, we need to ask controller to request data loading
135 // emit requestDataLoading(variable, variableDateTimeWithTolerance);
120 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable,
121 SqpRange{graphRange.lower, graphRange.upper}, variable->range(), false);
136 122 }
137 123
138 124 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
139 125 {
140 126 // Each component associated to the variable :
141 127 // - is removed from qcpplot (which deletes it)
142 128 // - is no longer referenced in the map
143 129 auto componentsIt = impl->m_VariableToPlotMultiMap.equal_range(variable);
144 130 for (auto it = componentsIt.first; it != componentsIt.second;) {
145 131 ui->widget->removePlottable(it->second);
146 132 it = impl->m_VariableToPlotMultiMap.erase(it);
147 133 }
148 134
149 135 // Updates graph
150 136 ui->widget->replot();
151 137 }
152 138
153 139 void VisualizationGraphWidget::setRange(std::shared_ptr<Variable> variable, const SqpRange &range)
154 140 {
155 141 // Note: in case of different axes that depends on variable, we could start with a code like
156 142 // that:
157 143 // auto componentsIt = impl->m_VariableToPlotMultiMap.equal_range(variable);
158 144 // for (auto it = componentsIt.first; it != componentsIt.second;) {
159 145 // }
160 146 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
161 147 ui->widget->replot();
162 148 }
163 149
164 150 SqpRange VisualizationGraphWidget::graphRange() const noexcept
165 151 {
166 152 auto grapheRange = ui->widget->xAxis->range();
167 153 return SqpRange{grapheRange.lower, grapheRange.upper};
168 154 }
169 155
170 156 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
171 157 {
172 158 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
173 159 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
174 160 ui->widget->replot();
175 161 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
176 162 }
177 163
178 164 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
179 165 {
180 166 if (visitor) {
181 167 visitor->visit(this);
182 168 }
183 169 else {
184 170 qCCritical(LOG_VisualizationGraphWidget())
185 171 << tr("Can't visit widget : the visitor is null");
186 172 }
187 173 }
188 174
189 175 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
190 176 {
191 177 /// @todo : for the moment, a graph can always accomodate a variable
192 178 Q_UNUSED(variable);
193 179 return true;
194 180 }
195 181
196 182 bool VisualizationGraphWidget::contains(const Variable &variable) const
197 183 {
198 184 // Finds the variable among the keys of the map
199 185 auto variablePtr = &variable;
200 186 auto findVariable
201 187 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
202 188
203 189 auto end = impl->m_VariableToPlotMultiMap.cend();
204 190 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
205 191 return it != end;
206 192 }
207 193
208 194 QString VisualizationGraphWidget::name() const
209 195 {
210 196 return ui->graphNameLabel->text();
211 197 }
212 198
213 199 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
214 200 {
215 201 QMenu graphMenu{};
216 202
217 203 // Iterates on variables (unique keys)
218 204 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
219 205 end = impl->m_VariableToPlotMultiMap.cend();
220 206 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
221 207 // 'Remove variable' action
222 208 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
223 209 [ this, var = it->first ]() { removeVariable(var); });
224 210 }
225 211
226 212 if (!graphMenu.isEmpty()) {
227 213 graphMenu.exec(mapToGlobal(pos));
228 214 }
229 215 }
230 216
231 217 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
232 218 {
233 219 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
234 220 << QThread::currentThread()->objectName() << "DoAcqui"
235 221 << impl->m_DoAcquisition;
236 222
237 223 auto graphRange = SqpRange{t1.lower, t1.upper};
238 224 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
239 225
240 226 if (impl->m_DoAcquisition) {
241 227 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
242 228
243 229 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
244 230 end = impl->m_VariableToPlotMultiMap.end();
245 231 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
246 232 variableUnderGraphVector.push_back(it->first);
247 233 }
248 234 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange, oldGraphRange,
249 235 !impl->m_IsCalibration);
250 236
251 237 if (!impl->m_IsCalibration) {
252 qCDebug(LOG_VisualizationGraphWidget())
238 qCInfo(LOG_VisualizationGraphWidget())
253 239 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
254 << QThread::currentThread()->objectName();
240 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
255 241 emit synchronize(graphRange, oldGraphRange);
256 242 }
257 243 }
258 244 }
259 245
260 246 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
261 247 {
262 248 // Handles plot rendering when mouse is moving
263 249 impl->m_RenderingDelegate->onMouseMove(event);
264 250 }
265 251
266 252 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
267 253 {
268 254 auto zoomOrientations = QFlags<Qt::Orientation>{};
269 255
270 256 // Lambda that enables a zoom orientation if the key modifier related to this orientation
271 257 // has
272 258 // been pressed
273 259 auto enableOrientation
274 260 = [&zoomOrientations, event](const auto &orientation, const auto &modifier) {
275 261 auto orientationEnabled = event->modifiers().testFlag(modifier);
276 262 zoomOrientations.setFlag(orientation, orientationEnabled);
277 263 };
278 264 enableOrientation(Qt::Vertical, VERTICAL_ZOOM_MODIFIER);
279 265 enableOrientation(Qt::Horizontal, HORIZONTAL_ZOOM_MODIFIER);
280 266
281 267 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
282 268 }
283 269
284 270 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
285 271 {
286 272 impl->m_IsCalibration = event->modifiers().testFlag(Qt::ControlModifier);
287 273 }
288 274
289 275 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
290 276 {
291 277 impl->m_IsCalibration = false;
292 278 }
293 279
294 280 void VisualizationGraphWidget::onDataCacheVariableUpdated()
295 281 {
296 282 // NOTE:
297 283 // We don't want to call the method for each component of a variable unitarily, but for
298 284 // all
299 285 // its components at once (eg its three components in the case of a vector).
300 286
301 287 // The unordered_multimap does not do this easily, so the question is whether to:
302 288 // - use an ordered_multimap and the algos of std to group the values by key
303 289 // - use a map (unique keys) and store as values directly the list of components
304 290
305 291 auto grapheRange = ui->widget->xAxis->range();
306 292 auto dateTime = SqpRange{grapheRange.lower, grapheRange.upper};
307 293
308 294 for (auto it = impl->m_VariableToPlotMultiMap.cbegin();
309 295 it != impl->m_VariableToPlotMultiMap.cend(); ++it) {
310 296 auto variable = it->first;
311 297 qCDebug(LOG_VisualizationGraphWidget())
312 298 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
313 299 qCDebug(LOG_VisualizationGraphWidget())
314 300 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
315 301 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
316 302
317 303 VisualizationGraphHelper::updateData(QVector<QCPAbstractPlottable *>{} << it->second,
318 304 variable->dataSeries(), variable->range());
319 305 }
320 306 }
321 307 }
@@ -1,215 +1,225
1 1 #include "Visualization/VisualizationZoneWidget.h"
2 2
3 3
4 4 #include "Visualization/IVisualizationWidgetVisitor.h"
5 5 #include "Visualization/VisualizationGraphWidget.h"
6 6 #include "ui_VisualizationZoneWidget.h"
7 7
8 8 #include <Data/SqpRange.h>
9 9 #include <Variable/VariableController.h>
10 10
11 11 #include <QUuid>
12 12 #include <SqpApplication.h>
13 13
14 14 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
15 15
16 16 namespace {
17 17
18 18 /// Minimum height for graph added in zones (in pixels)
19 19 const auto GRAPH_MINIMUM_HEIGHT = 300;
20 20
21 21 /// Generates a default name for a new graph, according to the number of graphs already displayed in
22 22 /// the zone
23 23 QString defaultGraphName(const QLayout &layout)
24 24 {
25 25 auto count = 0;
26 26 for (auto i = 0; i < layout.count(); ++i) {
27 27 if (dynamic_cast<VisualizationGraphWidget *>(layout.itemAt(i)->widget())) {
28 28 count++;
29 29 }
30 30 }
31 31
32 32 return QObject::tr("Graph %1").arg(count + 1);
33 33 }
34 34
35 35 } // namespace
36 36
37 37 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate {
38 38
39 39 explicit VisualizationZoneWidgetPrivate() : m_SynchronisationGroupId{QUuid::createUuid()} {}
40 40 QUuid m_SynchronisationGroupId;
41 41 };
42 42
43 43 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
44 44 : QWidget{parent},
45 45 ui{new Ui::VisualizationZoneWidget},
46 46 impl{spimpl::make_unique_impl<VisualizationZoneWidgetPrivate>()}
47 47 {
48 48 ui->setupUi(this);
49 49
50 50 ui->zoneNameLabel->setText(name);
51 51
52 52 // 'Close' options : widget is deleted when closed
53 53 setAttribute(Qt::WA_DeleteOnClose);
54 54 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
55 55 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
56 56
57 57 // Synchronisation id
58 58 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronizationGroupId",
59 59 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
60 60 }
61 61
62 62 VisualizationZoneWidget::~VisualizationZoneWidget()
63 63 {
64 64 delete ui;
65 65 }
66 66
67 67 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
68 68 {
69 69 ui->visualizationZoneFrame->layout()->addWidget(graphWidget);
70 70 }
71 71
72 72 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
73 73 {
74 74 auto graphWidget = new VisualizationGraphWidget{
75 75 defaultGraphName(*ui->visualizationZoneFrame->layout()), this};
76 76
77 77
78 78 // Set graph properties
79 79 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
80 80 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
81 81
82 this->addGraph(graphWidget);
83
84 graphWidget->addVariable(variable);
85 82
86 83 // Lambda to synchronize zone widget
87 84 auto synchronizeZoneWidget = [this, graphWidget](const SqpRange &grapheRange,
88 85 const SqpRange &oldGraphRange) {
89 86
90 87 auto zoomType = VariableController::getZoomType(grapheRange, oldGraphRange);
91 88 auto frameLayout = ui->visualizationZoneFrame->layout();
92 89 for (auto i = 0; i < frameLayout->count(); ++i) {
93 90 auto graphChild
94 91 = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
95 92 if (graphChild && (graphChild != graphWidget)) {
96 93
97 94 auto graphChildRange = graphChild->graphRange();
98 95 switch (zoomType) {
99 96 case AcquisitionZoomType::ZoomIn: {
100 97 auto deltaLeft = grapheRange.m_TStart - oldGraphRange.m_TStart;
101 98 auto deltaRight = oldGraphRange.m_TEnd - grapheRange.m_TEnd;
102 99 graphChildRange.m_TStart += deltaLeft;
103 100 graphChildRange.m_TEnd -= deltaRight;
104 101 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomIn");
105 102 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
106 103 << deltaLeft;
107 104 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
108 105 << deltaRight;
109 106 qCCritical(LOG_VisualizationZoneWidget())
110 107 << tr("TORM: dt") << grapheRange.m_TEnd - grapheRange.m_TStart;
111 108
112 109 break;
113 110 }
114 111
115 112 case AcquisitionZoomType::ZoomOut: {
116 113 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomOut");
117 114 auto deltaLeft = oldGraphRange.m_TStart - grapheRange.m_TStart;
118 115 auto deltaRight = grapheRange.m_TEnd - oldGraphRange.m_TEnd;
119 116 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
120 117 << deltaLeft;
121 118 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
122 119 << deltaRight;
123 120 qCCritical(LOG_VisualizationZoneWidget())
124 121 << tr("TORM: dt") << grapheRange.m_TEnd - grapheRange.m_TStart;
125 122 graphChildRange.m_TStart -= deltaLeft;
126 123 graphChildRange.m_TEnd += deltaRight;
127 124 break;
128 125 }
129 126 case AcquisitionZoomType::PanRight: {
130 127 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: PanRight");
131 128 auto deltaRight = grapheRange.m_TEnd - oldGraphRange.m_TEnd;
132 129 graphChildRange.m_TStart += deltaRight;
133 130 graphChildRange.m_TEnd += deltaRight;
134 131 qCCritical(LOG_VisualizationZoneWidget())
135 132 << tr("TORM: dt") << grapheRange.m_TEnd - grapheRange.m_TStart;
136 133 break;
137 134 }
138 135 case AcquisitionZoomType::PanLeft: {
139 136 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: PanLeft");
140 137 auto deltaLeft = oldGraphRange.m_TStart - grapheRange.m_TStart;
141 138 graphChildRange.m_TStart -= deltaLeft;
142 139 graphChildRange.m_TEnd -= deltaLeft;
143 140 break;
144 141 }
145 142 case AcquisitionZoomType::Unknown: {
146 143 qCCritical(LOG_VisualizationZoneWidget())
147 144 << tr("Impossible to synchronize: zoom type unknown");
148 145 break;
149 146 }
150 147 default:
151 148 qCCritical(LOG_VisualizationZoneWidget())
152 149 << tr("Impossible to synchronize: zoom type not take into account");
153 150 // No action
154 151 break;
155 152 }
156 153 graphChild->enableAcquisition(false);
157 154 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: Range before: ")
158 155 << graphChild->graphRange();
159 156 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: Range after : ")
160 157 << graphChildRange;
161 158 qCCritical(LOG_VisualizationZoneWidget())
162 159 << tr("TORM: child dt") << graphChildRange.m_TEnd - graphChildRange.m_TStart;
163 160 graphChild->setGraphRange(graphChildRange);
164 161 graphChild->enableAcquisition(true);
165 162 }
166 163 }
167 164 };
168 165
169 166 // connection for synchronization
170 167 connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
168 connect(graphWidget, &VisualizationGraphWidget::variableAdded, this,
169 &VisualizationZoneWidget::onVariableAdded);
170
171 this->addGraph(graphWidget);
172
173 graphWidget->addVariable(variable);
171 174
172 175 return graphWidget;
173 176 }
174 177
175 178 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
176 179 {
177 180 if (visitor) {
178 181 visitor->visitEnter(this);
179 182
180 183 // Apply visitor to graph children
181 184 auto layout = ui->visualizationZoneFrame->layout();
182 185 for (auto i = 0; i < layout->count(); ++i) {
183 186 if (auto item = layout->itemAt(i)) {
184 187 // Widgets different from graphs are not visited (no action)
185 188 if (auto visualizationGraphWidget
186 189 = dynamic_cast<VisualizationGraphWidget *>(item->widget())) {
187 190 visualizationGraphWidget->accept(visitor);
188 191 }
189 192 }
190 193 }
191 194
192 195 visitor->visitLeave(this);
193 196 }
194 197 else {
195 198 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
196 199 }
197 200 }
198 201
199 202 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
200 203 {
201 204 // A tab can always accomodate a variable
202 205 Q_UNUSED(variable);
203 206 return true;
204 207 }
205 208
206 209 bool VisualizationZoneWidget::contains(const Variable &variable) const
207 210 {
208 211 Q_UNUSED(variable);
209 212 return false;
210 213 }
211 214
212 215 QString VisualizationZoneWidget::name() const
213 216 {
214 217 return ui->zoneNameLabel->text();
215 218 }
219
220 void VisualizationZoneWidget::onVariableAdded(std::shared_ptr<Variable> variable)
221 {
222 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronized",
223 Qt::QueuedConnection, Q_ARG(std::shared_ptr<Variable>, variable),
224 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
225 }
@@ -1,147 +1,148
1 1 #include "AmdaProvider.h"
2 2 #include "AmdaDefs.h"
3 3 #include "AmdaResultParser.h"
4 4
5 5 #include <Common/DateUtils.h>
6 6 #include <Data/DataProviderParameters.h>
7 7 #include <Network/NetworkController.h>
8 8 #include <SqpApplication.h>
9 9 #include <Variable/Variable.h>
10 10
11 11 #include <QNetworkAccessManager>
12 12 #include <QNetworkReply>
13 13 #include <QTemporaryFile>
14 14 #include <QThread>
15 15
16 16 Q_LOGGING_CATEGORY(LOG_AmdaProvider, "AmdaProvider")
17 17
18 18 namespace {
19 19
20 20 /// URL format for a request on AMDA server. The parameters are as follows:
21 21 /// - %1: start date
22 22 /// - %2: end date
23 23 /// - %3: parameter id
24 24 const auto AMDA_URL_FORMAT = QStringLiteral(
25 25 "http://amda.irap.omp.eu/php/rest/"
26 26 "getParameter.php?startTime=%1&stopTime=%2&parameterID=%3&outputFormat=ASCII&"
27 27 "timeFormat=ISO8601&gzip=0");
28 28
29 29 /// Dates format passed in the URL (e.g 2013-09-23T09:00)
30 30 const auto AMDA_TIME_FORMAT = QStringLiteral("yyyy-MM-ddThh:mm:ss");
31 31
32 32 /// Formats a time to a date that can be passed in URL
33 33 QString dateFormat(double sqpRange) noexcept
34 34 {
35 35 auto dateTime = DateUtils::dateTime(sqpRange);
36 36 return dateTime.toString(AMDA_TIME_FORMAT);
37 37 }
38 38
39 39 } // namespace
40 40
41 41 AmdaProvider::AmdaProvider()
42 42 {
43 43 qCDebug(LOG_AmdaProvider()) << tr("AmdaProvider::AmdaProvider") << QThread::currentThread();
44 44 if (auto app = sqpApp) {
45 45 auto &networkController = app->networkController();
46 46 connect(this, SIGNAL(requestConstructed(QNetworkRequest, QUuid,
47 47 std::function<void(QNetworkReply *, QUuid)>)),
48 48 &networkController,
49 49 SLOT(onProcessRequested(QNetworkRequest, QUuid,
50 50 std::function<void(QNetworkReply *, QUuid)>)));
51 51
52 52
53 53 connect(&sqpApp->networkController(), SIGNAL(replyDownloadProgress(QUuid, double)), this,
54 54 SIGNAL(dataProvidedProgress(QUuid, double)));
55 55 }
56 56 }
57 57
58 58 void AmdaProvider::requestDataLoading(QUuid acqIdentifier, const DataProviderParameters &parameters)
59 59 {
60 60 // NOTE: Try to use multithread if possible
61 61 const auto times = parameters.m_Times;
62 62 const auto data = parameters.m_Data;
63 63 for (const auto &dateTime : qAsConst(times)) {
64 retrieveData(acqIdentifier, dateTime, data);
64 this->retrieveData(acqIdentifier, dateTime, data);
65 QThread::msleep(200);
note

ok

65 66 }
66 67 }
67 68
68 69 void AmdaProvider::requestDataAborting(QUuid acqIdentifier)
69 70 {
70 71 if (auto app = sqpApp) {
71 72 auto &networkController = app->networkController();
72 73 networkController.onReplyCanceled(acqIdentifier);
73 74 }
74 75 }
75 76
76 77 void AmdaProvider::retrieveData(QUuid token, const SqpRange &dateTime, const QVariantHash &data)
77 78 {
78 79 // Retrieves product ID from data: if the value is invalid, no request is made
79 80 auto productId = data.value(AMDA_XML_ID_KEY).toString();
80 81 if (productId.isNull()) {
81 82 qCCritical(LOG_AmdaProvider()) << tr("Can't retrieve data: unknown product id");
82 83 return;
83 84 }
84 85 qCDebug(LOG_AmdaProvider()) << tr("AmdaProvider::retrieveData") << dateTime;
85 86
86 87 // /////////// //
87 88 // Creates URL //
88 89 // /////////// //
89 90
90 91 auto startDate = dateFormat(dateTime.m_TStart);
91 92 auto endDate = dateFormat(dateTime.m_TEnd);
92 93
93 94 auto url = QUrl{QString{AMDA_URL_FORMAT}.arg(startDate, endDate, productId)};
94 95 qCInfo(LOG_AmdaProvider()) << tr("AmdaProvider::retrieveData url:") << url;
95 96 auto tempFile = std::make_shared<QTemporaryFile>();
96 97
97 98 // LAMBDA
98 99 auto httpDownloadFinished
99 100 = [this, dateTime, tempFile](QNetworkReply *reply, QUuid dataId) noexcept {
100 101
101 102 // Don't do anything if the reply was abort
102 103 if (reply->error() != QNetworkReply::OperationCanceledError) {
103 104
104 105 if (tempFile) {
105 106 auto replyReadAll = reply->readAll();
106 107 if (!replyReadAll.isEmpty()) {
107 108 tempFile->write(replyReadAll);
108 109 }
109 110 tempFile->close();
110 111
111 112 // Parse results file
112 113 if (auto dataSeries = AmdaResultParser::readTxt(tempFile->fileName())) {
113 114 emit dataProvided(dataId, dataSeries, dateTime);
114 115 }
115 116 else {
116 117 /// @todo ALX : debug
117 118 }
118 119 }
119 120 }
120 121
121 122 };
122 123 auto httpFinishedLambda
123 124 = [this, httpDownloadFinished, tempFile](QNetworkReply *reply, QUuid dataId) noexcept {
124 125
125 126 // Don't do anything if the reply was abort
126 127 if (reply->error() != QNetworkReply::OperationCanceledError) {
127 128 auto downloadFileUrl = QUrl{QString{reply->readAll()}};
128 129
129 130
130 131 qCInfo(LOG_AmdaProvider()) << tr("AmdaProvider::retrieveData downloadFileUrl:")
131 132 << downloadFileUrl;
132 133 // Executes request for downloading file //
133 134
134 135 // Creates destination file
135 136 if (tempFile->open()) {
136 137 // Executes request
137 138 emit requestConstructed(QNetworkRequest{downloadFileUrl}, dataId,
138 139 httpDownloadFinished);
139 140 }
140 141 }
141 142 };
142 143
143 144 // //////////////// //
144 145 // Executes request //
145 146 // //////////////// //
146 147 emit requestConstructed(QNetworkRequest{url}, token, httpFinishedLambda);
147 148 }
General Comments 1
Under Review
author

Auto status change to "Under Review"

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