##// END OF EJS Templates
Some WIP refactoring, trying to remove TimeController object...
jeandet -
r1345:ce477e992869
parent child
Show More
@@ -1,48 +1,48
1 1 #ifndef SCIQLOP_TIMECONTROLLER_H
2 2 #define SCIQLOP_TIMECONTROLLER_H
3 3
4 4 #include "CoreGlobal.h"
5 5
6 6 #include <Data/SqpRange.h>
7 7
8 8 #include <QLoggingCategory>
9 9 #include <QObject>
10 10
11 11 #include <Common/spimpl.h>
12 12
13 13
14 14 Q_DECLARE_LOGGING_CATEGORY(LOG_TimeController)
15 15
16 16 /**
17 17 * @brief The TimeController class aims to handle the Time parameters notification in SciQlop.
18 18 */
19 19 class SCIQLOP_CORE_EXPORT TimeController : public QObject {
20 20 Q_OBJECT
21 21 public:
22 22 explicit TimeController(QObject *parent = 0);
23 23
24 24 SqpRange dateTime() const noexcept;
25 25
26 26 /// Returns the MIME data associated to a time range
27 27 static QByteArray mimeDataForTimeRange(const SqpRange &timeRange);
28 28
29 29 /// Returns the time range contained in a MIME data
30 30 static SqpRange timeRangeForMimeData(const QByteArray &mimeData);
31 31
32 32 signals:
33 33 /// Signal emitted to notify that time parameters has beed updated
34 34 void timeUpdated(SqpRange time);
35 35
36 36 public slots:
37 37 /// Slot called when a new dateTime has been defined.
38 void onTimeToUpdate(SqpRange dateTime);
38 void setDateTimeRange(SqpRange dateTime);
39 39
40 40 /// Slot called when the dateTime has to be notified. Call timeUpdated signal
41 41 void onTimeNotify();
42 42
43 43 private:
44 44 class TimeControllerPrivate;
45 45 spimpl::unique_impl_ptr<TimeControllerPrivate> impl;
46 46 };
47 47
48 48 #endif // SCIQLOP_TIMECONTROLLER_H
@@ -1,148 +1,147
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 #include <QUuid>
12 12
13 13 #include <Common/spimpl.h>
14 14
15 15 class IDataProvider;
16 16 class QItemSelectionModel;
17 17 class TimeController;
18 18 class Variable;
19 19 class VariableModel;
20 20
21 21 Q_DECLARE_LOGGING_CATEGORY(LOG_VariableController)
22 22
23 23
24 24 /**
25 25 * Possible types of zoom operation
26 26 */
27 27 enum class AcquisitionZoomType { ZoomOut, ZoomIn, PanRight, PanLeft, Unknown };
28 28
29 29
30 30 /**
31 31 * @brief The VariableController class aims to handle the variables in SciQlop.
32 32 */
33 33 class SCIQLOP_CORE_EXPORT VariableController : public QObject {
34 34 Q_OBJECT
35 35 public:
36 36 explicit VariableController(QObject *parent = 0);
37 37 virtual ~VariableController();
38 38
39 39 VariableModel *variableModel() noexcept;
40 40 QItemSelectionModel *variableSelectionModel() noexcept;
41 41
42 void setTimeController(TimeController *timeController) noexcept;
43 42
44 43 /**
45 44 * Clones the variable passed in parameter and adds the duplicate to the controller
46 45 * @param variable the variable to duplicate
47 46 * @return the duplicate created, nullptr if the variable couldn't be created
48 47 */
49 48 std::shared_ptr<Variable> cloneVariable(std::shared_ptr<Variable> variable) noexcept;
50 49
51 50 /// Returns the MIME data associated to a list of variables
52 51 QByteArray mimeDataForVariables(const QList<std::shared_ptr<Variable> > &variables) const;
53 52
54 53 /// Returns the list of variables contained in a MIME data
55 54 QList<std::shared_ptr<Variable> > variablesForMimeData(const QByteArray &mimeData) const;
56 55
57 56 static AcquisitionZoomType getZoomType(const SqpRange &range, const SqpRange &oldRange);
58 57
59 58 /// Returns True if there are pending downloads
60 59 bool hasPendingDownloads();
61 60 signals:
62 61 /// Signal emitted when a variable is about to be deleted from the controller
63 62 void variableAboutToBeDeleted(std::shared_ptr<Variable> variable);
64 63
65 64 /// Signal emitted when a data acquisition is requested on a range for a variable
66 65 void rangeChanged(std::shared_ptr<Variable> variable, const SqpRange &range);
67 66
68 67 /// Signal emitted when a sub range of the cacheRange of the variable can be displayed
69 68 void updateVarDisplaying(std::shared_ptr<Variable> variable, const SqpRange &range);
70 69
71 70 /// Signal emitted when all acquisitions related to the variables have been completed (whether
72 71 /// validated, canceled, or failed)
73 72 void acquisitionFinished();
74 73
75 74 void variableAdded(const std::shared_ptr<Variable> &variable);
76 75
77 76 public slots:
78 77 /**
79 78 * Deletes from the controller the variable passed in parameter.
80 79 *
81 80 * Delete a variable includes:
82 81 * - the deletion of the various references to the variable in SciQlop
83 82 * - the deletion of the model variable
84 83 * - the deletion of the provider associated with the variable
85 84 * - removing the cache associated with the variable
86 85 *
87 86 * @param variable the variable to delete from the controller.
88 87 */
89 88 void deleteVariable(std::shared_ptr<Variable> variable) noexcept;
90 89
91 90 /**
92 91 * Deletes from the controller the variables passed in parameter.
93 92 * @param variables the variables to delete from the controller.
94 93 * @sa deleteVariable()
95 94 */
96 95 void deleteVariables(const QVector<std::shared_ptr<Variable> > &variables) noexcept;
97 96
98 97 /// Request the data loading of the variable whithin range
99 98 void onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables, const SqpRange &range,
100 99 bool synchronise);
101 100 /**
102 101 * Creates a new variable and adds it to the model
103 102 * @param name the name of the new variable
104 103 * @param metadata the metadata of the new variable
105 104 * @param provider the data provider for the new variable
106 105 * @return the pointer to the new variable or nullptr if the creation failed
107 106 */
108 107 std::shared_ptr<Variable> createVariable(const QString &name, const QVariantHash &metadata,
109 std::shared_ptr<IDataProvider> provider) noexcept;
108 std::shared_ptr<IDataProvider> provider, const SqpRange &range) noexcept;
110 109
111 110 /// Update the temporal parameters of every selected variable to dateTime
112 111 void onDateTimeOnSelection(const SqpRange &dateTime);
113 112
114 113 /// Update the temporal parameters of the specified variable
115 114 void onUpdateDateTime(std::shared_ptr<Variable> variable, const SqpRange &dateTime);
116 115
117 116
118 117 void onDataProvided(QUuid vIdentifier, const SqpRange &rangeRequested,
119 118 const SqpRange &cacheRangeRequested,
120 119 QVector<AcquisitionDataPacket> dataAcquired);
121 120
122 121 void onVariableRetrieveDataInProgress(QUuid identifier, double progress);
123 122
124 123 /// Cancel the current request for the variable
125 124 void onAbortProgressRequested(std::shared_ptr<Variable> variable);
126 125 void onAbortAcquisitionRequested(QUuid vIdentifier);
127 126
128 127 // synchronization group methods
129 128 void onAddSynchronizationGroupId(QUuid synchronizationGroupId);
130 129 void onRemoveSynchronizationGroupId(QUuid synchronizationGroupId);
131 130 void onAddSynchronized(std::shared_ptr<Variable> variable, QUuid synchronizationGroupId);
132 131
133 132 /// Desynchronizes the variable of the group whose identifier is passed in parameter
134 133 /// @remarks the method does nothing if the variable is not part of the group
135 134 void desynchronize(std::shared_ptr<Variable> variable, QUuid synchronizationGroupId);
136 135
137 136 void initialize();
138 137 void finalize();
139 138
140 139 private:
141 140 void waitForFinish();
142 141
143 142 class VariableControllerPrivate;
144 143 spimpl::unique_impl_ptr<VariableControllerPrivate> impl;
145 144 };
146 145
147 146
148 147 #endif // SCIQLOP_VARIABLECONTROLLER_H
@@ -1,51 +1,51
1 1 #include "Time/TimeController.h"
2 2
3 3 #include <QDataStream>
4 4
5 5 Q_LOGGING_CATEGORY(LOG_TimeController, "TimeController")
6 6
7 7 struct TimeController::TimeControllerPrivate {
8 8
9 9 SqpRange m_DateTime;
10 10 };
11 11
12 12 TimeController::TimeController(QObject *parent)
13 13 : QObject{parent}, impl{spimpl::make_unique_impl<TimeControllerPrivate>()}
14 14 {
15 15 qCDebug(LOG_TimeController()) << tr("TimeController construction");
16 16 }
17 17
18 18 SqpRange TimeController::dateTime() const noexcept
19 19 {
20 20 return impl->m_DateTime;
21 21 }
22 22
23 23 QByteArray TimeController::mimeDataForTimeRange(const SqpRange &timeRange)
24 24 {
25 25 QByteArray encodedData;
26 26 QDataStream stream{&encodedData, QIODevice::WriteOnly};
27 27
28 28 stream << timeRange.m_TStart << timeRange.m_TEnd;
29 29
30 30 return encodedData;
31 31 }
32 32
33 33 SqpRange TimeController::timeRangeForMimeData(const QByteArray &mimeData)
34 34 {
35 35 QDataStream stream{mimeData};
36 36
37 37 SqpRange timeRange;
38 38 stream >> timeRange.m_TStart >> timeRange.m_TEnd;
39 39
40 40 return timeRange;
41 41 }
42 42
43 void TimeController::onTimeToUpdate(SqpRange dateTime)
43 void TimeController::setDateTimeRange(SqpRange dateTime)
44 44 {
45 45 impl->m_DateTime = dateTime;
46 46 }
47 47
48 48 void TimeController::onTimeNotify()
49 49 {
50 50 emit timeUpdated(impl->m_DateTime);
51 51 }
@@ -1,1114 +1,1108
1 1 #include <Variable/Variable.h>
2 2 #include <Variable/VariableAcquisitionWorker.h>
3 3 #include <Variable/VariableCacheStrategy.h>
4 4 #include <Variable/VariableCacheStrategyFactory.h>
5 5 #include <Variable/VariableController.h>
6 6 #include <Variable/VariableModel.h>
7 7 #include <Variable/VariableSynchronizationGroup.h>
8 8
9 9 #include <Data/DataProviderParameters.h>
10 10 #include <Data/IDataProvider.h>
11 11 #include <Data/IDataSeries.h>
12 12 #include <Data/VariableRequest.h>
13 13 #include <Time/TimeController.h>
14 14
15 15 #include <QDataStream>
16 16 #include <QMutex>
17 17 #include <QThread>
18 18 #include <QUuid>
19 19 #include <QtCore/QItemSelectionModel>
20 20
21 21 #include <deque>
22 22 #include <set>
23 23 #include <unordered_map>
24 24
25 25 Q_LOGGING_CATEGORY(LOG_VariableController, "VariableController")
26 26
27 27 namespace {
28 28
29 29 SqpRange computeSynchroRangeRequested(const SqpRange &varRange, const SqpRange &graphRange,
30 30 const SqpRange &oldGraphRange)
31 31 {
32 32 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
33 33
34 34 auto varRangeRequested = varRange;
35 35 switch (zoomType) {
36 36 case AcquisitionZoomType::ZoomIn: {
37 37 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
38 38 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
39 39 varRangeRequested.m_TStart += deltaLeft;
40 40 varRangeRequested.m_TEnd -= deltaRight;
41 41 break;
42 42 }
43 43
44 44 case AcquisitionZoomType::ZoomOut: {
45 45 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
46 46 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
47 47 varRangeRequested.m_TStart -= deltaLeft;
48 48 varRangeRequested.m_TEnd += deltaRight;
49 49 break;
50 50 }
51 51 case AcquisitionZoomType::PanRight: {
52 52 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
53 53 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
54 54 varRangeRequested.m_TStart += deltaLeft;
55 55 varRangeRequested.m_TEnd += deltaRight;
56 56 break;
57 57 }
58 58 case AcquisitionZoomType::PanLeft: {
59 59 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
60 60 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
61 61 varRangeRequested.m_TStart -= deltaLeft;
62 62 varRangeRequested.m_TEnd -= deltaRight;
63 63 break;
64 64 }
65 65 case AcquisitionZoomType::Unknown: {
66 66 qCCritical(LOG_VariableController())
67 67 << VariableController::tr("Impossible to synchronize: zoom type unknown");
68 68 break;
69 69 }
70 70 default:
71 71 qCCritical(LOG_VariableController()) << VariableController::tr(
72 72 "Impossible to synchronize: zoom type not take into account");
73 73 // No action
74 74 break;
75 75 }
76 76
77 77 return varRangeRequested;
78 78 }
79 79 }
80 80
81 81 enum class VariableRequestHandlerState { OFF, RUNNING, PENDING };
82 82
83 83 struct VariableRequestHandler {
84 84
85 85 VariableRequestHandler()
86 86 {
87 87 m_CanUpdate = false;
88 88 m_State = VariableRequestHandlerState::OFF;
89 89 }
90 90
91 91 QUuid m_VarId;
92 92 VariableRequest m_RunningVarRequest;
93 93 VariableRequest m_PendingVarRequest;
94 94 VariableRequestHandlerState m_State;
95 95 bool m_CanUpdate;
96 96 };
97 97
98 98 struct VariableController::VariableControllerPrivate {
99 99 explicit VariableControllerPrivate(VariableController *parent)
100 100 : m_WorkingMutex{},
101 101 m_VariableModel{new VariableModel{parent}},
102 102 m_VariableSelectionModel{new QItemSelectionModel{m_VariableModel, parent}},
103 103 // m_VariableCacheStrategy{std::make_unique<VariableCacheStrategy>()},
104 104 m_VariableCacheStrategy{VariableCacheStrategyFactory::createCacheStrategy(
105 105 CacheStrategy::SingleThreshold)},
106 106 m_VariableAcquisitionWorker{std::make_unique<VariableAcquisitionWorker>()},
107 107 q{parent}
108 108 {
109 109
110 110 m_VariableAcquisitionWorker->moveToThread(&m_VariableAcquisitionWorkerThread);
111 111 m_VariableAcquisitionWorkerThread.setObjectName("VariableAcquisitionWorkerThread");
112 112 }
113 113
114 114
115 115 virtual ~VariableControllerPrivate()
116 116 {
117 117 qCDebug(LOG_VariableController()) << tr("VariableControllerPrivate destruction");
118 118 m_VariableAcquisitionWorkerThread.quit();
119 119 m_VariableAcquisitionWorkerThread.wait();
120 120 }
121 121
122 122
123 123 void processRequest(std::shared_ptr<Variable> var, const SqpRange &rangeRequested,
124 124 QUuid varRequestId);
125 125
126 126 std::shared_ptr<Variable> findVariable(QUuid vIdentifier);
127 127 std::shared_ptr<IDataSeries>
128 128 retrieveDataSeries(const QVector<AcquisitionDataPacket> acqDataPacketVector);
129 129
130 130 void registerProvider(std::shared_ptr<IDataProvider> provider);
131 131
132 132 void storeVariableRequest(QUuid varId, QUuid varRequestId, const VariableRequest &varRequest);
133 133 QUuid acceptVariableRequest(QUuid varId, std::shared_ptr<IDataSeries> dataSeries);
134 134 void updateVariables(QUuid varRequestId);
135 135 void updateVariableRequest(QUuid varRequestId);
136 136 void cancelVariableRequest(QUuid varRequestId);
137 137 void executeVarRequest(std::shared_ptr<Variable> var, VariableRequest &varRequest);
138 138 bool hasPendingDownloads();
139 139 template <typename VariableIterator>
140 140 void desynchronize(VariableIterator variableIt, const QUuid &syncGroupId);
141 141
142 142 QMutex m_WorkingMutex;
143 143 /// Variable model. The VariableController has the ownership
144 144 VariableModel *m_VariableModel;
145 145 QItemSelectionModel *m_VariableSelectionModel;
146 146
147 147
148 TimeController *m_TimeController{nullptr};
149 148 std::unique_ptr<VariableCacheStrategy> m_VariableCacheStrategy;
150 149 std::unique_ptr<VariableAcquisitionWorker> m_VariableAcquisitionWorker;
151 150 QThread m_VariableAcquisitionWorkerThread;
152 151
153 152 std::unordered_map<std::shared_ptr<Variable>, std::shared_ptr<IDataProvider> >
154 153 m_VariableToProviderMap;
155 154 std::unordered_map<std::shared_ptr<Variable>, QUuid> m_VariableToIdentifierMap;
156 155 std::map<QUuid, std::shared_ptr<VariableSynchronizationGroup> >
157 156 m_GroupIdToVariableSynchronizationGroupMap;
158 157 std::map<QUuid, QUuid> m_VariableIdGroupIdMap;
159 158 std::set<std::shared_ptr<IDataProvider> > m_ProviderSet;
160 159
161 160 std::map<QUuid, std::list<QUuid> > m_VarGroupIdToVarIds;
162 161 std::map<QUuid, std::unique_ptr<VariableRequestHandler> > m_VarIdToVarRequestHandler;
163 162
164 163 VariableController *q;
165 164 };
166 165
167 166
168 167 VariableController::VariableController(QObject *parent)
169 168 : QObject{parent}, impl{spimpl::make_unique_impl<VariableControllerPrivate>(this)}
170 169 {
171 170 qCDebug(LOG_VariableController()) << tr("VariableController construction")
172 171 << QThread::currentThread();
173 172
174 173 connect(impl->m_VariableModel, &VariableModel::abortProgessRequested, this,
175 174 &VariableController::onAbortProgressRequested);
176 175
177 176 connect(impl->m_VariableAcquisitionWorker.get(),
178 177 &VariableAcquisitionWorker::variableCanceledRequested, this,
179 178 &VariableController::onAbortAcquisitionRequested);
180 179
181 180 connect(impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::dataProvided, this,
182 181 &VariableController::onDataProvided);
183 182 connect(impl->m_VariableAcquisitionWorker.get(),
184 183 &VariableAcquisitionWorker::variableRequestInProgress, this,
185 184 &VariableController::onVariableRetrieveDataInProgress);
186 185
187 186
188 187 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::started,
189 188 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::initialize);
190 189 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::finished,
191 190 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::finalize);
192 191
193 192 connect(impl->m_VariableModel, &VariableModel::requestVariableRangeUpdate, this,
194 193 &VariableController::onUpdateDateTime);
195 194
196 195 impl->m_VariableAcquisitionWorkerThread.start();
197 196 }
198 197
199 198 VariableController::~VariableController()
200 199 {
201 200 qCDebug(LOG_VariableController()) << tr("VariableController destruction")
202 201 << QThread::currentThread();
203 202 this->waitForFinish();
204 203 }
205 204
206 205 VariableModel *VariableController::variableModel() noexcept
207 206 {
208 207 return impl->m_VariableModel;
209 208 }
210 209
211 210 QItemSelectionModel *VariableController::variableSelectionModel() noexcept
212 211 {
213 212 return impl->m_VariableSelectionModel;
214 213 }
215 214
216 void VariableController::setTimeController(TimeController *timeController) noexcept
217 {
218 impl->m_TimeController = timeController;
219 }
220
221 215 std::shared_ptr<Variable>
222 216 VariableController::cloneVariable(std::shared_ptr<Variable> variable) noexcept
223 217 {
224 218 if (impl->m_VariableModel->containsVariable(variable)) {
225 219 // Clones variable
226 220 auto duplicate = variable->clone();
227 221
228 222 // Adds clone to model
229 223 impl->m_VariableModel->addVariable(duplicate);
230 224
231 225 // Generates clone identifier
232 226 impl->m_VariableToIdentifierMap[duplicate] = QUuid::createUuid();
233 227
234 228 // Registers provider
235 229 auto variableProvider = impl->m_VariableToProviderMap.at(variable);
236 230 auto duplicateProvider = variableProvider != nullptr ? variableProvider->clone() : nullptr;
237 231
238 232 impl->m_VariableToProviderMap[duplicate] = duplicateProvider;
239 233 if (duplicateProvider) {
240 234 impl->registerProvider(duplicateProvider);
241 235 }
242 236
243 237 return duplicate;
244 238 }
245 239 else {
246 240 qCCritical(LOG_VariableController())
247 241 << tr("Can't create duplicate of variable %1: variable not registered in the model")
248 242 .arg(variable->name());
249 243 return nullptr;
250 244 }
251 245 }
252 246
253 247 void VariableController::deleteVariable(std::shared_ptr<Variable> variable) noexcept
254 248 {
255 249 if (!variable) {
256 250 qCCritical(LOG_VariableController()) << "Can't delete variable: variable is null";
257 251 return;
258 252 }
259 253
260 254 // Spreads in SciQlop that the variable will be deleted, so that potential receivers can
261 255 // make some treatments before the deletion
262 256 emit variableAboutToBeDeleted(variable);
263 257
264 258 auto variableIt = impl->m_VariableToIdentifierMap.find(variable);
265 259 Q_ASSERT(variableIt != impl->m_VariableToIdentifierMap.cend());
266 260
267 261 auto variableId = variableIt->second;
268 262
269 263 // Removes variable's handler
270 264 impl->m_VarIdToVarRequestHandler.erase(variableId);
271 265
272 266 // Desynchronizes variable (if the variable is in a sync group)
273 267 auto syncGroupIt = impl->m_VariableIdGroupIdMap.find(variableId);
274 268 if (syncGroupIt != impl->m_VariableIdGroupIdMap.cend()) {
275 269 impl->desynchronize(variableIt, syncGroupIt->second);
276 270 }
277 271
278 272 // Deletes identifier
279 273 impl->m_VariableToIdentifierMap.erase(variableIt);
280 274
281 275 // Deletes provider
282 276 auto nbProvidersDeleted = impl->m_VariableToProviderMap.erase(variable);
283 277 qCDebug(LOG_VariableController())
284 278 << tr("Number of providers deleted for variable %1: %2")
285 279 .arg(variable->name(), QString::number(nbProvidersDeleted));
286 280
287 281
288 282 // Deletes from model
289 283 impl->m_VariableModel->deleteVariable(variable);
290 284 }
291 285
292 286 void VariableController::deleteVariables(
293 287 const QVector<std::shared_ptr<Variable> > &variables) noexcept
294 288 {
295 289 for (auto variable : qAsConst(variables)) {
296 290 deleteVariable(variable);
297 291 }
298 292 }
299 293
300 294 QByteArray
301 295 VariableController::mimeDataForVariables(const QList<std::shared_ptr<Variable> > &variables) const
302 296 {
303 297 auto encodedData = QByteArray{};
304 298
305 299 QVariantList ids;
306 300 for (auto &var : variables) {
307 301 auto itVar = impl->m_VariableToIdentifierMap.find(var);
308 302 if (itVar == impl->m_VariableToIdentifierMap.cend()) {
309 303 qCCritical(LOG_VariableController())
310 304 << tr("Impossible to find the data for an unknown variable.");
311 305 }
312 306
313 307 ids << itVar->second.toByteArray();
314 308 }
315 309
316 310 QDataStream stream{&encodedData, QIODevice::WriteOnly};
317 311 stream << ids;
318 312
319 313 return encodedData;
320 314 }
321 315
322 316 QList<std::shared_ptr<Variable> >
323 317 VariableController::variablesForMimeData(const QByteArray &mimeData) const
324 318 {
325 319 auto variables = QList<std::shared_ptr<Variable> >{};
326 320 QDataStream stream{mimeData};
327 321
328 322 QVariantList ids;
329 323 stream >> ids;
330 324
331 325 for (auto id : ids) {
332 326 auto uuid = QUuid{id.toByteArray()};
333 327 auto var = impl->findVariable(uuid);
334 328 variables << var;
335 329 }
336 330
337 331 return variables;
338 332 }
339 333
340 334 std::shared_ptr<Variable>
341 335 VariableController::createVariable(const QString &name, const QVariantHash &metadata,
342 std::shared_ptr<IDataProvider> provider) noexcept
336 std::shared_ptr<IDataProvider> provider, const SqpRange& range) noexcept
343 337 {
344 if (!impl->m_TimeController) {
345 qCCritical(LOG_VariableController())
346 << tr("Impossible to create variable: The time controller is null");
347 return nullptr;
348 }
338 // if (!impl->m_TimeController) {
339 // qCCritical(LOG_VariableController())
340 // << tr("Impossible to create variable: The time controller is null");
341 // return nullptr;
342 // }
349 343
350 auto range = impl->m_TimeController->dateTime();
344 // auto range = impl->m_TimeController->dateTime();
351 345
352 346 if (auto newVariable = impl->m_VariableModel->createVariable(name, metadata)) {
353 347 auto varId = QUuid::createUuid();
354 348
355 349 // Create the handler
356 350 auto varRequestHandler = std::make_unique<VariableRequestHandler>();
357 351 varRequestHandler->m_VarId = varId;
358 352
359 353 impl->m_VarIdToVarRequestHandler.insert(
360 354 std::make_pair(varId, std::move(varRequestHandler)));
361 355
362 356 // store the provider
363 357 impl->registerProvider(provider);
364 358
365 359 // Associate the provider
366 360 impl->m_VariableToProviderMap[newVariable] = provider;
367 361 impl->m_VariableToIdentifierMap[newVariable] = varId;
368 362
369 363 this->onRequestDataLoading(QVector<std::shared_ptr<Variable> >{newVariable}, range, false);
370 364
371 365 // auto varRequestId = QUuid::createUuid();
372 366 // qCInfo(LOG_VariableController()) << "createVariable: " << varId << varRequestId;
373 367 // impl->processRequest(newVariable, range, varRequestId);
374 368 // impl->updateVariableRequest(varRequestId);
375 369
376 370 emit variableAdded(newVariable);
377 371
378 372 return newVariable;
379 373 }
380 374
381 375 qCCritical(LOG_VariableController()) << tr("Impossible to create variable");
382 376 return nullptr;
383 377 }
384 378
385 379 void VariableController::onDateTimeOnSelection(const SqpRange &dateTime)
386 380 {
387 381 // NOTE: Even if acquisition request is aborting, the graphe range will be changed
388 382 qCDebug(LOG_VariableController()) << "VariableController::onDateTimeOnSelection"
389 383 << QThread::currentThread()->objectName();
390 384 auto selectedRows = impl->m_VariableSelectionModel->selectedRows();
391 385
392 386 // NOTE we only permit the time modification for one variable
393 387 // DEPRECATED
394 388 // auto variables = QVector<std::shared_ptr<Variable> >{};
395 389 // for (const auto &selectedRow : qAsConst(selectedRows)) {
396 390 // if (auto selectedVariable =
397 391 // impl->m_VariableModel->variable(selectedRow.row())) {
398 392 // variables << selectedVariable;
399 393
400 394 // // notify that rescale operation has to be done
401 395 // emit rangeChanged(selectedVariable, dateTime);
402 396 // }
403 397 // }
404 398 // if (!variables.isEmpty()) {
405 399 // this->onRequestDataLoading(variables, dateTime, synchro);
406 400 // }
407 401 if (selectedRows.size() == 1) {
408 402
409 403 if (auto selectedVariable
410 404 = impl->m_VariableModel->variable(qAsConst(selectedRows).first().row())) {
411 405
412 406 onUpdateDateTime(selectedVariable, dateTime);
413 407 }
414 408 }
415 409 else if (selectedRows.size() > 1) {
416 410 qCCritical(LOG_VariableController())
417 411 << tr("Impossible to set time for more than 1 variable in the same time");
418 412 }
419 413 else {
420 414 qCWarning(LOG_VariableController())
421 415 << tr("There is no variable selected to set the time one");
422 416 }
423 417 }
424 418
425 419 void VariableController::onUpdateDateTime(std::shared_ptr<Variable> variable,
426 420 const SqpRange &dateTime)
427 421 {
428 422 auto itVar = impl->m_VariableToIdentifierMap.find(variable);
429 423 if (itVar == impl->m_VariableToIdentifierMap.cend()) {
430 424 qCCritical(LOG_VariableController())
431 425 << tr("Impossible to onDateTimeOnSelection request for unknown variable");
432 426 return;
433 427 }
434 428
435 429 // notify that rescale operation has to be done
436 430 emit rangeChanged(variable, dateTime);
437 431
438 432 auto synchro
439 433 = impl->m_VariableIdGroupIdMap.find(itVar->second) != impl->m_VariableIdGroupIdMap.cend();
440 434
441 435 this->onRequestDataLoading(QVector<std::shared_ptr<Variable> >{variable}, dateTime, synchro);
442 436 }
443 437
444 438 void VariableController::onDataProvided(QUuid vIdentifier, const SqpRange &rangeRequested,
445 439 const SqpRange &cacheRangeRequested,
446 440 QVector<AcquisitionDataPacket> dataAcquired)
447 441 {
448 442 qCDebug(LOG_VariableController()) << tr("onDataProvided") << QThread::currentThread();
449 443 auto retrievedDataSeries = impl->retrieveDataSeries(dataAcquired);
450 444 auto varRequestId = impl->acceptVariableRequest(vIdentifier, retrievedDataSeries);
451 445 if (!varRequestId.isNull()) {
452 446 impl->updateVariables(varRequestId);
453 447 }
454 448 }
455 449
456 450 void VariableController::onVariableRetrieveDataInProgress(QUuid identifier, double progress)
457 451 {
458 452 qCDebug(LOG_VariableController())
459 453 << "TORM: variableController::onVariableRetrieveDataInProgress"
460 454 << QThread::currentThread()->objectName() << progress;
461 455 if (auto var = impl->findVariable(identifier)) {
462 456 impl->m_VariableModel->setDataProgress(var, progress);
463 457 }
464 458 else {
465 459 qCCritical(LOG_VariableController())
466 460 << tr("Impossible to notify progression of a null variable");
467 461 }
468 462 }
469 463
470 464 void VariableController::onAbortProgressRequested(std::shared_ptr<Variable> variable)
471 465 {
472 466 qCDebug(LOG_VariableController()) << "TORM: variableController::onAbortProgressRequested"
473 467 << QThread::currentThread()->objectName() << variable->name();
474 468
475 469 auto itVar = impl->m_VariableToIdentifierMap.find(variable);
476 470 if (itVar == impl->m_VariableToIdentifierMap.cend()) {
477 471 qCCritical(LOG_VariableController())
478 472 << tr("Impossible to onAbortProgressRequested request for unknown variable");
479 473 return;
480 474 }
481 475
482 476 auto varId = itVar->second;
483 477
484 478 auto itVarHandler = impl->m_VarIdToVarRequestHandler.find(varId);
485 479 if (itVarHandler == impl->m_VarIdToVarRequestHandler.cend()) {
486 480 qCCritical(LOG_VariableController())
487 481 << tr("Impossible to onAbortProgressRequested for variable with unknown handler");
488 482 return;
489 483 }
490 484
491 485 auto varHandler = itVarHandler->second.get();
492 486
493 487 // case where a variable has a running request
494 488 if (varHandler->m_State != VariableRequestHandlerState::OFF) {
495 489 impl->cancelVariableRequest(varHandler->m_RunningVarRequest.m_VariableGroupId);
496 490 }
497 491 }
498 492
499 493 void VariableController::onAbortAcquisitionRequested(QUuid vIdentifier)
500 494 {
501 495 qCDebug(LOG_VariableController()) << "TORM: variableController::onAbortAcquisitionRequested"
502 496 << QThread::currentThread()->objectName() << vIdentifier;
503 497
504 498 if (auto var = impl->findVariable(vIdentifier)) {
505 499 this->onAbortProgressRequested(var);
506 500 }
507 501 else {
508 502 qCCritical(LOG_VariableController())
509 503 << tr("Impossible to abort Acquisition Requestof a null variable");
510 504 }
511 505 }
512 506
513 507 void VariableController::onAddSynchronizationGroupId(QUuid synchronizationGroupId)
514 508 {
515 509 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronizationGroupId"
516 510 << QThread::currentThread()->objectName()
517 511 << synchronizationGroupId;
518 512 auto vSynchroGroup = std::make_shared<VariableSynchronizationGroup>();
519 513 impl->m_GroupIdToVariableSynchronizationGroupMap.insert(
520 514 std::make_pair(synchronizationGroupId, vSynchroGroup));
521 515 }
522 516
523 517 void VariableController::onRemoveSynchronizationGroupId(QUuid synchronizationGroupId)
524 518 {
525 519 impl->m_GroupIdToVariableSynchronizationGroupMap.erase(synchronizationGroupId);
526 520 }
527 521
528 522 void VariableController::onAddSynchronized(std::shared_ptr<Variable> variable,
529 523 QUuid synchronizationGroupId)
530 524
531 525 {
532 526 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronized"
533 527 << synchronizationGroupId;
534 528 auto varToVarIdIt = impl->m_VariableToIdentifierMap.find(variable);
535 529 if (varToVarIdIt != impl->m_VariableToIdentifierMap.cend()) {
536 530 auto groupIdToVSGIt
537 531 = impl->m_GroupIdToVariableSynchronizationGroupMap.find(synchronizationGroupId);
538 532 if (groupIdToVSGIt != impl->m_GroupIdToVariableSynchronizationGroupMap.cend()) {
539 533 impl->m_VariableIdGroupIdMap.insert(
540 534 std::make_pair(varToVarIdIt->second, synchronizationGroupId));
541 535 groupIdToVSGIt->second->addVariableId(varToVarIdIt->second);
542 536 }
543 537 else {
544 538 qCCritical(LOG_VariableController())
545 539 << tr("Impossible to synchronize a variable with an unknown sycnhronization group")
546 540 << variable->name();
547 541 }
548 542 }
549 543 else {
550 544 qCCritical(LOG_VariableController())
551 545 << tr("Impossible to synchronize a variable with no identifier") << variable->name();
552 546 }
553 547 }
554 548
555 549 void VariableController::desynchronize(std::shared_ptr<Variable> variable,
556 550 QUuid synchronizationGroupId)
557 551 {
558 552 // Gets variable id
559 553 auto variableIt = impl->m_VariableToIdentifierMap.find(variable);
560 554 if (variableIt == impl->m_VariableToIdentifierMap.cend()) {
561 555 qCCritical(LOG_VariableController())
562 556 << tr("Can't desynchronize variable %1: variable identifier not found")
563 557 .arg(variable->name());
564 558 return;
565 559 }
566 560
567 561 impl->desynchronize(variableIt, synchronizationGroupId);
568 562 }
569 563
570 564 void VariableController::onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables,
571 565 const SqpRange &range, bool synchronise)
572 566 {
573 567 // variables is assumed synchronized
574 568 // TODO: Asser variables synchronization
575 569 // we want to load data of the variable for the dateTime.
576 570 if (variables.isEmpty()) {
577 571 return;
578 572 }
579 573
580 574 auto varRequestId = QUuid::createUuid();
581 575 qCDebug(LOG_VariableController()) << "VariableController::onRequestDataLoading"
582 576 << QThread::currentThread()->objectName() << varRequestId
583 577 << range << synchronise;
584 578
585 579 if (!synchronise) {
586 580 auto varIds = std::list<QUuid>{};
587 581 for (const auto &var : variables) {
588 582 auto vId = impl->m_VariableToIdentifierMap.at(var);
589 583 varIds.push_back(vId);
590 584 }
591 585 impl->m_VarGroupIdToVarIds.insert(std::make_pair(varRequestId, varIds));
592 586 for (const auto &var : variables) {
593 587 qCDebug(LOG_VariableController()) << "processRequest for" << var->name() << varRequestId
594 588 << varIds.size();
595 589 impl->processRequest(var, range, varRequestId);
596 590 }
597 591 }
598 592 else {
599 593 auto vId = impl->m_VariableToIdentifierMap.at(variables.first());
600 594 auto varIdToGroupIdIt = impl->m_VariableIdGroupIdMap.find(vId);
601 595 if (varIdToGroupIdIt != impl->m_VariableIdGroupIdMap.cend()) {
602 596 auto groupId = varIdToGroupIdIt->second;
603 597
604 598 auto vSynchronizationGroup
605 599 = impl->m_GroupIdToVariableSynchronizationGroupMap.at(groupId);
606 600 auto vSyncIds = vSynchronizationGroup->getIds();
607 601
608 602 auto varIds = std::list<QUuid>{};
609 603 for (auto vId : vSyncIds) {
610 604 varIds.push_back(vId);
611 605 }
612 606 impl->m_VarGroupIdToVarIds.insert(std::make_pair(varRequestId, varIds));
613 607
614 608 for (auto vId : vSyncIds) {
615 609 auto var = impl->findVariable(vId);
616 610
617 611 // Don't process already processed var
618 612 if (var != nullptr) {
619 613 qCDebug(LOG_VariableController()) << "processRequest synchro for" << var->name()
620 614 << varRequestId;
621 615 auto vSyncRangeRequested
622 616 = variables.contains(var)
623 617 ? range
624 618 : computeSynchroRangeRequested(var->range(), range,
625 619 variables.first()->range());
626 620 qCDebug(LOG_VariableController()) << "synchro RR" << vSyncRangeRequested;
627 621 impl->processRequest(var, vSyncRangeRequested, varRequestId);
628 622 }
629 623 else {
630 624 qCCritical(LOG_VariableController())
631 625
632 626 << tr("Impossible to synchronize a null variable");
633 627 }
634 628 }
635 629 }
636 630 }
637 631
638 632 impl->updateVariables(varRequestId);
639 633 }
640 634
641 635
642 636 void VariableController::initialize()
643 637 {
644 638 qCDebug(LOG_VariableController()) << tr("VariableController init") << QThread::currentThread();
645 639 impl->m_WorkingMutex.lock();
646 640 qCDebug(LOG_VariableController()) << tr("VariableController init END");
647 641 }
648 642
649 643 void VariableController::finalize()
650 644 {
651 645 impl->m_WorkingMutex.unlock();
652 646 }
653 647
654 648 void VariableController::waitForFinish()
655 649 {
656 650 QMutexLocker locker{&impl->m_WorkingMutex};
657 651 }
658 652
659 653 bool VariableController::hasPendingDownloads()
660 654 {
661 655 return impl->hasPendingDownloads();
662 656 }
663 657
664 658 AcquisitionZoomType VariableController::getZoomType(const SqpRange &range, const SqpRange &oldRange)
665 659 {
666 660 // t1.m_TStart <= t2.m_TStart && t2.m_TEnd <= t1.m_TEnd
667 661 auto zoomType = AcquisitionZoomType::Unknown;
668 662 if (range.m_TStart <= oldRange.m_TStart && oldRange.m_TEnd <= range.m_TEnd) {
669 663 qCDebug(LOG_VariableController()) << "zoomtype: ZoomOut";
670 664 zoomType = AcquisitionZoomType::ZoomOut;
671 665 }
672 666 else if (range.m_TStart > oldRange.m_TStart && range.m_TEnd > oldRange.m_TEnd) {
673 667 qCDebug(LOG_VariableController()) << "zoomtype: PanRight";
674 668 zoomType = AcquisitionZoomType::PanRight;
675 669 }
676 670 else if (range.m_TStart < oldRange.m_TStart && range.m_TEnd < oldRange.m_TEnd) {
677 671 qCDebug(LOG_VariableController()) << "zoomtype: PanLeft";
678 672 zoomType = AcquisitionZoomType::PanLeft;
679 673 }
680 674 else if (range.m_TStart >= oldRange.m_TStart && oldRange.m_TEnd >= range.m_TEnd) {
681 675 qCDebug(LOG_VariableController()) << "zoomtype: ZoomIn";
682 676 zoomType = AcquisitionZoomType::ZoomIn;
683 677 }
684 678 else {
685 679 qCDebug(LOG_VariableController()) << "getZoomType: Unknown type detected";
686 680 }
687 681 return zoomType;
688 682 }
689 683
690 684 void VariableController::VariableControllerPrivate::processRequest(std::shared_ptr<Variable> var,
691 685 const SqpRange &rangeRequested,
692 686 QUuid varRequestId)
693 687 {
694 688 auto itVar = m_VariableToIdentifierMap.find(var);
695 689 if (itVar == m_VariableToIdentifierMap.cend()) {
696 690 qCCritical(LOG_VariableController())
697 691 << tr("Impossible to process request for unknown variable");
698 692 return;
699 693 }
700 694
701 695 auto varId = itVar->second;
702 696
703 697 auto itVarHandler = m_VarIdToVarRequestHandler.find(varId);
704 698 if (itVarHandler == m_VarIdToVarRequestHandler.cend()) {
705 699 qCCritical(LOG_VariableController())
706 700 << tr("Impossible to process request for variable with unknown handler");
707 701 return;
708 702 }
709 703
710 704 auto oldRange = var->range();
711 705
712 706 auto varHandler = itVarHandler->second.get();
713 707
714 708 if (varHandler->m_State != VariableRequestHandlerState::OFF) {
715 709 oldRange = varHandler->m_RunningVarRequest.m_RangeRequested;
716 710 }
717 711
718 712 auto varRequest = VariableRequest{};
719 713 varRequest.m_VariableGroupId = varRequestId;
720 714 auto varStrategyRangesRequested
721 715 = m_VariableCacheStrategy->computeRange(oldRange, rangeRequested);
722 716 varRequest.m_RangeRequested = varStrategyRangesRequested.first;
723 717 varRequest.m_CacheRangeRequested = varStrategyRangesRequested.second;
724 718
725 719 switch (varHandler->m_State) {
726 720 case VariableRequestHandlerState::OFF: {
727 721 qCDebug(LOG_VariableController()) << tr("Process Request OFF")
728 722 << varRequest.m_RangeRequested
729 723 << varRequest.m_CacheRangeRequested;
730 724 varHandler->m_RunningVarRequest = varRequest;
731 725 varHandler->m_State = VariableRequestHandlerState::RUNNING;
732 726 executeVarRequest(var, varRequest);
733 727 break;
734 728 }
735 729 case VariableRequestHandlerState::RUNNING: {
736 730 qCDebug(LOG_VariableController()) << tr("Process Request RUNNING")
737 731 << varRequest.m_RangeRequested
738 732 << varRequest.m_CacheRangeRequested;
739 733 varHandler->m_State = VariableRequestHandlerState::PENDING;
740 734 varHandler->m_PendingVarRequest = varRequest;
741 735 break;
742 736 }
743 737 case VariableRequestHandlerState::PENDING: {
744 738 qCDebug(LOG_VariableController()) << tr("Process Request PENDING")
745 739 << varRequest.m_RangeRequested
746 740 << varRequest.m_CacheRangeRequested;
747 741 auto variableGroupIdToCancel = varHandler->m_PendingVarRequest.m_VariableGroupId;
748 742 cancelVariableRequest(variableGroupIdToCancel);
749 743 // Cancel variable can make state downgrade
750 744 varHandler->m_State = VariableRequestHandlerState::PENDING;
751 745 varHandler->m_PendingVarRequest = varRequest;
752 746
753 747 break;
754 748 }
755 749 default:
756 750 qCCritical(LOG_VariableController())
757 751 << QObject::tr("Unknown VariableRequestHandlerState");
758 752 }
759 753 }
760 754
761 755 std::shared_ptr<Variable>
762 756 VariableController::VariableControllerPrivate::findVariable(QUuid vIdentifier)
763 757 {
764 758 std::shared_ptr<Variable> var;
765 759 auto findReply = [vIdentifier](const auto &entry) { return vIdentifier == entry.second; };
766 760
767 761 auto end = m_VariableToIdentifierMap.cend();
768 762 auto it = std::find_if(m_VariableToIdentifierMap.cbegin(), end, findReply);
769 763 if (it != end) {
770 764 var = it->first;
771 765 }
772 766 else {
773 767 qCCritical(LOG_VariableController())
774 768 << tr("Impossible to find the variable with the identifier: ") << vIdentifier;
775 769 }
776 770
777 771 return var;
778 772 }
779 773
780 774 std::shared_ptr<IDataSeries> VariableController::VariableControllerPrivate::retrieveDataSeries(
781 775 const QVector<AcquisitionDataPacket> acqDataPacketVector)
782 776 {
783 777 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size")
784 778 << acqDataPacketVector.size();
785 779 std::shared_ptr<IDataSeries> dataSeries;
786 780 if (!acqDataPacketVector.isEmpty()) {
787 781 dataSeries = acqDataPacketVector[0].m_DateSeries;
788 782 for (int i = 1; i < acqDataPacketVector.size(); ++i) {
789 783 dataSeries->merge(acqDataPacketVector[i].m_DateSeries.get());
790 784 }
791 785 }
792 786 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size END")
793 787 << acqDataPacketVector.size();
794 788 return dataSeries;
795 789 }
796 790
797 791 void VariableController::VariableControllerPrivate::registerProvider(
798 792 std::shared_ptr<IDataProvider> provider)
799 793 {
800 794 if (m_ProviderSet.find(provider) == m_ProviderSet.end()) {
801 795 qCDebug(LOG_VariableController()) << tr("Registering of a new provider")
802 796 << provider->objectName();
803 797 m_ProviderSet.insert(provider);
804 798 connect(provider.get(), &IDataProvider::dataProvided, m_VariableAcquisitionWorker.get(),
805 799 &VariableAcquisitionWorker::onVariableDataAcquired);
806 800 connect(provider.get(), &IDataProvider::dataProvidedProgress,
807 801 m_VariableAcquisitionWorker.get(),
808 802 &VariableAcquisitionWorker::onVariableRetrieveDataInProgress);
809 803 connect(provider.get(), &IDataProvider::dataProvidedFailed,
810 804 m_VariableAcquisitionWorker.get(),
811 805 &VariableAcquisitionWorker::onVariableAcquisitionFailed);
812 806 }
813 807 else {
814 808 qCDebug(LOG_VariableController()) << tr("Cannot register provider, it already exists ");
815 809 }
816 810 }
817 811
818 812 QUuid VariableController::VariableControllerPrivate::acceptVariableRequest(
819 813 QUuid varId, std::shared_ptr<IDataSeries> dataSeries)
820 814 {
821 815 auto itVarHandler = m_VarIdToVarRequestHandler.find(varId);
822 816 if (itVarHandler == m_VarIdToVarRequestHandler.cend()) {
823 817 return QUuid();
824 818 }
825 819
826 820 auto varHandler = itVarHandler->second.get();
827 821 if (varHandler->m_State == VariableRequestHandlerState::OFF) {
828 822 qCCritical(LOG_VariableController())
829 823 << tr("acceptVariableRequest impossible on a variable with OFF state");
830 824 }
831 825
832 826 varHandler->m_RunningVarRequest.m_DataSeries = dataSeries;
833 827 varHandler->m_CanUpdate = true;
834 828
835 829 // Element traitΓ©, on a dΓ©jΓ  toutes les donnΓ©es necessaires
836 830 auto varGroupId = varHandler->m_RunningVarRequest.m_VariableGroupId;
837 831 qCDebug(LOG_VariableController()) << "Variable::acceptVariableRequest" << varGroupId
838 832 << m_VarGroupIdToVarIds.size();
839 833
840 834 return varHandler->m_RunningVarRequest.m_VariableGroupId;
841 835 }
842 836
843 837 void VariableController::VariableControllerPrivate::updateVariables(QUuid varRequestId)
844 838 {
845 839 qCDebug(LOG_VariableController()) << "VariableControllerPrivate::updateVariables"
846 840 << QThread::currentThread()->objectName() << varRequestId;
847 841
848 842 auto varGroupIdToVarIdsIt = m_VarGroupIdToVarIds.find(varRequestId);
849 843 if (varGroupIdToVarIdsIt == m_VarGroupIdToVarIds.end()) {
850 844 qCWarning(LOG_VariableController())
851 845 << tr("Impossible to updateVariables of unknown variables") << varRequestId;
852 846 return;
853 847 }
854 848
855 849 auto &varIds = varGroupIdToVarIdsIt->second;
856 850 auto varIdsEnd = varIds.end();
857 851 bool processVariableUpdate = true;
858 852 qCDebug(LOG_VariableController()) << "VariableControllerPrivate::updateVariables"
859 853 << varRequestId << varIds.size();
860 854 for (auto varIdsIt = varIds.begin(); (varIdsIt != varIdsEnd) && processVariableUpdate;
861 855 ++varIdsIt) {
862 856 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
863 857 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
864 858 processVariableUpdate &= itVarHandler->second->m_CanUpdate;
865 859 }
866 860 }
867 861
868 862 if (processVariableUpdate) {
869 863 qCDebug(LOG_VariableController()) << "Final update OK for the var request" << varIds.size();
870 864 for (auto varIdsIt = varIds.begin(); varIdsIt != varIdsEnd; ++varIdsIt) {
871 865 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
872 866 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
873 867 if (auto var = findVariable(*varIdsIt)) {
874 868 auto &varRequest = itVarHandler->second->m_RunningVarRequest;
875 869 var->setRange(varRequest.m_RangeRequested);
876 870 var->setCacheRange(varRequest.m_CacheRangeRequested);
877 871 qCDebug(LOG_VariableController()) << tr("1: onDataProvided")
878 872 << varRequest.m_RangeRequested
879 873 << varRequest.m_CacheRangeRequested;
880 874 qCDebug(LOG_VariableController()) << tr("2: onDataProvided var points before")
881 875 << var->nbPoints()
882 876 << varRequest.m_DataSeries->nbPoints();
883 877 var->mergeDataSeries(varRequest.m_DataSeries);
884 878 qCDebug(LOG_VariableController()) << tr("3: onDataProvided var points after")
885 879 << var->nbPoints();
886 880
887 881 emit var->updated();
888 882 qCDebug(LOG_VariableController()) << tr("Update OK");
889 883 }
890 884 else {
891 885 qCCritical(LOG_VariableController())
892 886 << tr("Impossible to update data to a null variable");
893 887 }
894 888 }
895 889 }
896 890 updateVariableRequest(varRequestId);
897 891
898 892 // cleaning varRequestId
899 893 qCDebug(LOG_VariableController()) << tr("m_VarGroupIdToVarIds erase") << varRequestId;
900 894 m_VarGroupIdToVarIds.erase(varRequestId);
901 895 if (m_VarGroupIdToVarIds.empty()) {
902 896 emit q->acquisitionFinished();
903 897 }
904 898 }
905 899 }
906 900
907 901
908 902 void VariableController::VariableControllerPrivate::updateVariableRequest(QUuid varRequestId)
909 903 {
910 904 auto varGroupIdToVarIdsIt = m_VarGroupIdToVarIds.find(varRequestId);
911 905 if (varGroupIdToVarIdsIt == m_VarGroupIdToVarIds.end()) {
912 906 qCCritical(LOG_VariableController()) << QObject::tr(
913 907 "Impossible to updateVariableRequest since varGroupdId isn't here anymore");
914 908
915 909 return;
916 910 }
917 911
918 912 auto &varIds = varGroupIdToVarIdsIt->second;
919 913 auto varIdsEnd = varIds.end();
920 914 for (auto varIdsIt = varIds.begin(); (varIdsIt != varIdsEnd); ++varIdsIt) {
921 915 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
922 916 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
923 917
924 918 auto varHandler = itVarHandler->second.get();
925 919 varHandler->m_CanUpdate = false;
926 920
927 921
928 922 switch (varHandler->m_State) {
929 923 case VariableRequestHandlerState::OFF: {
930 924 qCCritical(LOG_VariableController())
931 925 << QObject::tr("Impossible to update a variable with handler in OFF state");
932 926 } break;
933 927 case VariableRequestHandlerState::RUNNING: {
934 928 varHandler->m_State = VariableRequestHandlerState::OFF;
935 929 varHandler->m_RunningVarRequest = VariableRequest{};
936 930 break;
937 931 }
938 932 case VariableRequestHandlerState::PENDING: {
939 933 varHandler->m_State = VariableRequestHandlerState::RUNNING;
940 934 varHandler->m_RunningVarRequest = varHandler->m_PendingVarRequest;
941 935 varHandler->m_PendingVarRequest = VariableRequest{};
942 936 auto var = findVariable(itVarHandler->first);
943 937 executeVarRequest(var, varHandler->m_RunningVarRequest);
944 938 updateVariables(varHandler->m_RunningVarRequest.m_VariableGroupId);
945 939 break;
946 940 }
947 941 default:
948 942 qCCritical(LOG_VariableController())
949 943 << QObject::tr("Unknown VariableRequestHandlerState");
950 944 }
951 945 }
952 946 }
953 947 }
954 948
955 949
956 950 void VariableController::VariableControllerPrivate::cancelVariableRequest(QUuid varRequestId)
957 951 {
958 952 qCDebug(LOG_VariableController()) << tr("cancelVariableRequest") << varRequestId;
959 953
960 954 auto varGroupIdToVarIdsIt = m_VarGroupIdToVarIds.find(varRequestId);
961 955 if (varGroupIdToVarIdsIt == m_VarGroupIdToVarIds.end()) {
962 956 qCCritical(LOG_VariableController())
963 957 << tr("Impossible to cancelVariableRequest for unknown varGroupdId") << varRequestId;
964 958 return;
965 959 }
966 960
967 961 auto &varIds = varGroupIdToVarIdsIt->second;
968 962 auto varIdsEnd = varIds.end();
969 963 for (auto varIdsIt = varIds.begin(); (varIdsIt != varIdsEnd); ++varIdsIt) {
970 964 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
971 965 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
972 966
973 967 auto varHandler = itVarHandler->second.get();
974 968 varHandler->m_VarId = QUuid{};
975 969 switch (varHandler->m_State) {
976 970 case VariableRequestHandlerState::OFF: {
977 971 qCWarning(LOG_VariableController())
978 972 << QObject::tr("Impossible to cancel a variable with no running request");
979 973 break;
980 974 }
981 975 case VariableRequestHandlerState::RUNNING: {
982 976
983 977 if (varHandler->m_RunningVarRequest.m_VariableGroupId == varRequestId) {
984 978 auto var = findVariable(itVarHandler->first);
985 979 auto varProvider = m_VariableToProviderMap.at(var);
986 980 if (varProvider != nullptr) {
987 981 m_VariableAcquisitionWorker->abortProgressRequested(
988 982 itVarHandler->first);
989 983 }
990 984 m_VariableModel->setDataProgress(var, 0.0);
991 985 varHandler->m_CanUpdate = false;
992 986 varHandler->m_State = VariableRequestHandlerState::OFF;
993 987 varHandler->m_RunningVarRequest = VariableRequest{};
994 988 }
995 989 else {
996 990 // TODO: log Impossible to cancel the running variable request beacause its
997 991 // varRequestId isn't not the canceled one
998 992 }
999 993 break;
1000 994 }
1001 995 case VariableRequestHandlerState::PENDING: {
1002 996 if (varHandler->m_RunningVarRequest.m_VariableGroupId == varRequestId) {
1003 997 auto var = findVariable(itVarHandler->first);
1004 998 auto varProvider = m_VariableToProviderMap.at(var);
1005 999 if (varProvider != nullptr) {
1006 1000 m_VariableAcquisitionWorker->abortProgressRequested(
1007 1001 itVarHandler->first);
1008 1002 }
1009 1003 m_VariableModel->setDataProgress(var, 0.0);
1010 1004 varHandler->m_CanUpdate = false;
1011 1005 varHandler->m_State = VariableRequestHandlerState::RUNNING;
1012 1006 varHandler->m_RunningVarRequest = varHandler->m_PendingVarRequest;
1013 1007 varHandler->m_PendingVarRequest = VariableRequest{};
1014 1008 executeVarRequest(var, varHandler->m_RunningVarRequest);
1015 1009 }
1016 1010 else if (varHandler->m_PendingVarRequest.m_VariableGroupId == varRequestId) {
1017 1011 varHandler->m_State = VariableRequestHandlerState::RUNNING;
1018 1012 varHandler->m_PendingVarRequest = VariableRequest{};
1019 1013 }
1020 1014 else {
1021 1015 // TODO: log Impossible to cancel the variable request beacause its
1022 1016 // varRequestId isn't not the canceled one
1023 1017 }
1024 1018 break;
1025 1019 }
1026 1020 default:
1027 1021 qCCritical(LOG_VariableController())
1028 1022 << QObject::tr("Unknown VariableRequestHandlerState");
1029 1023 }
1030 1024 }
1031 1025 }
1032 1026 qCDebug(LOG_VariableController()) << tr("cancelVariableRequest: erase") << varRequestId;
1033 1027 m_VarGroupIdToVarIds.erase(varRequestId);
1034 1028 if (m_VarGroupIdToVarIds.empty()) {
1035 1029 emit q->acquisitionFinished();
1036 1030 }
1037 1031 }
1038 1032
1039 1033 void VariableController::VariableControllerPrivate::executeVarRequest(std::shared_ptr<Variable> var,
1040 1034 VariableRequest &varRequest)
1041 1035 {
1042 1036 qCDebug(LOG_VariableController()) << tr("TORM: executeVarRequest");
1043 1037
1044 1038 auto varIdIt = m_VariableToIdentifierMap.find(var);
1045 1039 if (varIdIt == m_VariableToIdentifierMap.cend()) {
1046 1040 qCWarning(LOG_VariableController()) << tr(
1047 1041 "Can't execute request of a variable that is not registered (may has been deleted)");
1048 1042 return;
1049 1043 }
1050 1044
1051 1045 auto varId = varIdIt->second;
1052 1046
1053 1047 auto varCacheRange = var->cacheRange();
1054 1048 auto varCacheRangeRequested = varRequest.m_CacheRangeRequested;
1055 1049 auto notInCacheRangeList
1056 1050 = Variable::provideNotInCacheRangeList(varCacheRange, varCacheRangeRequested);
1057 1051 auto inCacheRangeList
1058 1052 = Variable::provideInCacheRangeList(varCacheRange, varCacheRangeRequested);
1059 1053
1060 1054 if (!notInCacheRangeList.empty()) {
1061 1055
1062 1056 auto varProvider = m_VariableToProviderMap.at(var);
1063 1057 if (varProvider != nullptr) {
1064 1058 qCDebug(LOG_VariableController()) << "executeVarRequest " << varRequest.m_RangeRequested
1065 1059 << varRequest.m_CacheRangeRequested;
1066 1060 m_VariableAcquisitionWorker->pushVariableRequest(
1067 1061 varRequest.m_VariableGroupId, varId, varRequest.m_RangeRequested,
1068 1062 varRequest.m_CacheRangeRequested,
1069 1063 DataProviderParameters{std::move(notInCacheRangeList), var->metadata()},
1070 1064 varProvider);
1071 1065 }
1072 1066 else {
1073 1067 qCCritical(LOG_VariableController())
1074 1068 << "Impossible to provide data with a null provider";
1075 1069 }
1076 1070
1077 1071 if (!inCacheRangeList.empty()) {
1078 1072 emit q->updateVarDisplaying(var, inCacheRangeList.first());
1079 1073 }
1080 1074 }
1081 1075 else {
1082 1076 acceptVariableRequest(varId,
1083 1077 var->dataSeries()->subDataSeries(varRequest.m_CacheRangeRequested));
1084 1078 }
1085 1079 }
1086 1080
1087 1081 bool VariableController::VariableControllerPrivate::hasPendingDownloads()
1088 1082 {
1089 1083 return !m_VarGroupIdToVarIds.empty();
1090 1084 }
1091 1085
1092 1086 template <typename VariableIterator>
1093 1087 void VariableController::VariableControllerPrivate::desynchronize(VariableIterator variableIt,
1094 1088 const QUuid &syncGroupId)
1095 1089 {
1096 1090 const auto &variable = variableIt->first;
1097 1091 const auto &variableId = variableIt->second;
1098 1092
1099 1093 // Gets synchronization group
1100 1094 auto groupIt = m_GroupIdToVariableSynchronizationGroupMap.find(syncGroupId);
1101 1095 if (groupIt == m_GroupIdToVariableSynchronizationGroupMap.cend()) {
1102 1096 qCCritical(LOG_VariableController())
1103 1097 << tr("Can't desynchronize variable %1: unknown synchronization group")
1104 1098 .arg(variable->name());
1105 1099 return;
1106 1100 }
1107 1101
1108 1102 // Removes variable from synchronization group
1109 1103 auto synchronizationGroup = groupIt->second;
1110 1104 synchronizationGroup->removeVariableId(variableId);
1111 1105
1112 1106 // Removes link between variable and synchronization group
1113 1107 m_VariableIdGroupIdMap.erase(variableId);
1114 1108 }
@@ -1,74 +1,74
1 1 #include <QObject>
2 2 #include <QtTest>
3 3
4 4 #include <Data/IDataProvider.h>
5 5 #include <Time/TimeController.h>
6 6 #include <Variable/Variable.h>
7 7 #include <Variable/VariableController.h>
8 8
9 9 #include <memory>
10 10
11 11 namespace {
12 12
13 13 /// Provider used for the tests
14 14 class TestProvider : public IDataProvider {
15 15 std::shared_ptr<IDataProvider> clone() const { return std::make_shared<TestProvider>(); }
16 16
17 17 void requestDataLoading(QUuid acqIdentifier, const DataProviderParameters &parameters) override
18 18 {
19 19 // Does nothing
20 20 }
21 21
22 22 void requestDataAborting(QUuid acqIdentifier) override
23 23 {
24 24 // Does nothing
25 25 }
26 26 };
27 27
28 28 /// Generates a time controller for the tests
29 29 std::unique_ptr<TimeController> defaultTimeController()
30 30 {
31 31 auto timeController = std::make_unique<TimeController>();
32 32
33 33 QDateTime start{QDate{2017, 01, 01}, QTime{0, 0, 0, 0}};
34 34 QDateTime end{QDate{2017, 01, 02}, QTime{0, 0, 0, 0}};
35 timeController->onTimeToUpdate(
35 timeController->setDateTimeRange(
36 36 SqpRange{DateUtils::secondsSinceEpoch(start), DateUtils::secondsSinceEpoch(end)});
37 37
38 38 return timeController;
39 39 }
40 40
41 41 } // namespace
42 42
43 43 class TestVariableController : public QObject {
44 44 Q_OBJECT
45 45
46 46 private slots:
47 47 /// Test removes variable from controller
48 48 void testDeleteVariable();
49 49 };
50 50
51 51 void TestVariableController::testDeleteVariable()
52 52 {
53 53 // Creates variable controller
54 54 auto timeController = defaultTimeController();
55 55 VariableController variableController{};
56 variableController.setTimeController(timeController.get());
56 //variableController.setTimeController(timeController.get());
57 57
58 58 // Creates a variable from the controller
59 59 auto variable
60 = variableController.createVariable("variable", {}, std::make_shared<TestProvider>());
60 = variableController.createVariable("variable", {}, std::make_shared<TestProvider>(), timeController->dateTime());
61 61
62 62 qDebug() << QString::number(variable.use_count());
63 63
64 64 // Removes the variable from the controller
65 65 variableController.deleteVariable(variable);
66 66
67 67 // Verifies that the variable has been deleted: this implies that the number of shared_ptr
68 68 // objects referring to the variable is 1 (the reference of this scope). Otherwise, the deletion
69 69 // is considered invalid since the variable is still referenced in the controller
70 70 QVERIFY(variable.use_count() == 1);
71 71 }
72 72
73 73 QTEST_MAIN(TestVariableController)
74 74 #include "TestVariableController.moc"
@@ -1,508 +1,508
1 1 #include <QObject>
2 2 #include <QtTest>
3 3
4 4 #include <memory>
5 5
6 6 #include <Data/DataProviderParameters.h>
7 7 #include <Data/IDataProvider.h>
8 8 #include <Data/ScalarSeries.h>
9 9 #include <Time/TimeController.h>
10 10 #include <Variable/Variable.h>
11 11 #include <Variable/VariableController.h>
12 12 #include <Variable/VariableModel.h>
13 13
14 14 namespace {
15 15
16 16 /// Delay after each operation on the variable before validating it (in ms)
17 17 const auto OPERATION_DELAY = 100;
18 18
19 19 /**
20 20 * Generates values according to a range. The value generated for a time t is the number of seconds
21 21 * of difference between t and a reference value (which is midnight -> 00:00:00)
22 22 *
23 23 * Example: For a range between 00:00:10 and 00:00:20, the generated values are
24 24 * {10,11,12,13,14,15,16,17,18,19,20}
25 25 */
26 26 std::vector<double> values(const SqpRange &range)
27 27 {
28 28 QTime referenceTime{0, 0};
29 29
30 30 std::vector<double> result{};
31 31
32 32 for (auto i = range.m_TStart; i <= range.m_TEnd; ++i) {
33 33 auto time = DateUtils::dateTime(i).time();
34 34 result.push_back(referenceTime.secsTo(time));
35 35 }
36 36
37 37 return result;
38 38 }
39 39
40 40 void validateRanges(VariableController &variableController,
41 41 const std::map<int, SqpRange> &expectedRanges)
42 42 {
43 43 for (const auto &expectedRangeEntry : expectedRanges) {
44 44 auto variableIndex = expectedRangeEntry.first;
45 45 auto expectedRange = expectedRangeEntry.second;
46 46
47 47 // Gets the variable in the controller
48 48 auto variable = variableController.variableModel()->variable(variableIndex);
49 49
50 50 // Compares variable's range to the expected range
51 51 QVERIFY(variable != nullptr);
52 52 auto range = variable->range();
53 53 qInfo() << "range vs expected range" << range << expectedRange;
54 54 QCOMPARE(range, expectedRange);
55 55
56 56 // Compares variable's data with values expected for its range
57 57 auto dataSeries = variable->dataSeries();
58 58 QVERIFY(dataSeries != nullptr);
59 59
60 60 auto it = dataSeries->xAxisRange(range.m_TStart, range.m_TEnd);
61 61 auto expectedValues = values(range);
62 62 qInfo() << std::distance(it.first, it.second) << expectedValues.size();
63 63 QVERIFY(std::equal(it.first, it.second, expectedValues.cbegin(), expectedValues.cend(),
64 64 [](const auto &dataSeriesIt, const auto &expectedValue) {
65 65 return dataSeriesIt.value() == expectedValue;
66 66 }));
67 67 }
68 68 }
69 69
70 70 /// Provider used for the tests
71 71 class TestProvider : public IDataProvider {
72 72 std::shared_ptr<IDataProvider> clone() const { return std::make_shared<TestProvider>(); }
73 73
74 74 void requestDataLoading(QUuid acqIdentifier, const DataProviderParameters &parameters) override
75 75 {
76 76 const auto &ranges = parameters.m_Times;
77 77
78 78 for (const auto &range : ranges) {
79 79 // Generates data series
80 80 auto valuesData = values(range);
81 81
82 82 std::vector<double> xAxisData{};
83 83 for (auto i = range.m_TStart; i <= range.m_TEnd; ++i) {
84 84 xAxisData.push_back(i);
85 85 }
86 86
87 87 auto dataSeries = std::make_shared<ScalarSeries>(
88 88 std::move(xAxisData), std::move(valuesData), Unit{"t", true}, Unit{});
89 89
90 90 emit dataProvided(acqIdentifier, dataSeries, range);
91 91 }
92 92 }
93 93
94 94 void requestDataAborting(QUuid acqIdentifier) override
95 95 {
96 96 // Does nothing
97 97 }
98 98 };
99 99
100 100 /**
101 101 * Interface representing an operation performed on a variable controller.
102 102 * This interface is used in tests to apply a set of operations and check the status of the
103 103 * controller after each operation
104 104 */
105 105 struct IOperation {
106 106 virtual ~IOperation() = default;
107 107 /// Executes the operation on the variable controller
108 108 virtual void exec(VariableController &variableController) const = 0;
109 109 };
110 110
111 111 /**
112 112 *Variable creation operation in the controller
113 113 */
114 114 struct Create : public IOperation {
115 explicit Create(int index) : m_Index{index} {}
115 explicit Create(int index, const SqpRange &range) : m_Index{index},m_range(range) {}
116 116
117 117 void exec(VariableController &variableController) const override
118 118 {
119 119 auto variable = variableController.createVariable(QString::number(m_Index), {},
120 std::make_unique<TestProvider>());
120 std::make_unique<TestProvider>(), m_range);
121 121 }
122
123 122 int m_Index; ///< The index of the variable to create in the controller
123 SqpRange m_range;
124 124 };
125 125
126 126 /**
127 127 * Variable move/shift operation in the controller
128 128 */
129 129 struct Move : public IOperation {
130 130 explicit Move(int index, const SqpRange &newRange, bool shift = false, int delayMS = 10)
131 131 : m_Index{index}, m_NewRange{newRange}, m_Shift{shift}, m_DelayMs{delayMS}
132 132 {
133 133 }
134 134
135 135 void exec(VariableController &variableController) const override
136 136 {
137 137 if (auto variable = variableController.variableModel()->variable(m_Index)) {
138 138 variableController.onRequestDataLoading({variable}, m_NewRange, !m_Shift);
139 139 QTest::qWait(m_DelayMs);
140 140 }
141 141 }
142 142
143 143 int m_Index; ///< The index of the variable to move
144 144 SqpRange m_NewRange; ///< The new range of the variable
145 145 bool m_Shift; ///< Performs a shift (
146 146 int m_DelayMs; ///< wait the delay after running the request (
147 147 };
148 148
149 149 /**
150 150 * Variable synchronization/desynchronization operation in the controller
151 151 */
152 152 struct Synchronize : public IOperation {
153 153 explicit Synchronize(int index, QUuid syncId, bool synchronize = true)
154 154 : m_Index{index}, m_SyncId{syncId}, m_Synchronize{synchronize}
155 155 {
156 156 }
157 157
158 158 void exec(VariableController &variableController) const override
159 159 {
160 160 if (auto variable = variableController.variableModel()->variable(m_Index)) {
161 161 if (m_Synchronize) {
162 162 variableController.onAddSynchronized(variable, m_SyncId);
163 163 }
164 164 else {
165 165 variableController.desynchronize(variable, m_SyncId);
166 166 }
167 167 }
168 168 }
169 169
170 170 int m_Index; ///< The index of the variable to sync/desync
171 171 QUuid m_SyncId; ///< The synchronization group of the variable
172 172 bool m_Synchronize; ///< Performs sync or desync operation
173 173 };
174 174
175 175 /**
176 176 * Test Iteration
177 177 *
178 178 * A test iteration includes an operation to be performed, and a set of expected ranges after each
179 179 * operation. Each range is tested after the operation to ensure that:
180 180 * - the range of the variable is the expected range
181 181 * - the data of the variable are those generated for the expected range
182 182 */
183 183 struct Iteration {
184 184 std::shared_ptr<IOperation> m_Operation; ///< Operation to perform
185 185 std::map<int, SqpRange> m_ExpectedRanges; ///< Expected ranges (by variable index)
186 186 };
187 187
188 188 using Iterations = std::vector<Iteration>;
189 189
190 190 } // namespace
191 191
192 192 Q_DECLARE_METATYPE(Iterations)
193 193
194 194 class TestVariableSync : public QObject {
195 195 Q_OBJECT
196 196
197 197 private slots:
198 198 void initTestCase() { QSKIP("Temporarily disables TestVariableSync"); }
199 199
200 200 /// Input data for @sa testSync()
201 201 void testSync_data();
202 202
203 203 /// Input data for @sa testSyncOneVar()
204 204 void testSyncOneVar_data();
205 205
206 206 /// Tests synchronization between variables through several operations
207 207 void testSync();
208 208
209 209 /// Tests synchronization between variables through several operations
210 210 void testSyncOneVar();
211 211 };
212 212
213 213 namespace {
214 214
215 215 void testSyncCase1()
216 216 {
217 217 // Id used to synchronize variables in the controller
218 218 auto syncId = QUuid::createUuid();
219 219
220 220 /// Generates a range according to a start time and a end time (the date is the same)
221 221 auto range = [](const QTime &startTime, const QTime &endTime) {
222 222 return SqpRange{DateUtils::secondsSinceEpoch(QDateTime{{2017, 1, 1}, startTime, Qt::UTC}),
223 223 DateUtils::secondsSinceEpoch(QDateTime{{2017, 1, 1}, endTime, Qt::UTC})};
224 224 };
225 225
226 226 auto initialRange = range({12, 0}, {13, 0});
227 227
228 228 Iterations iterations{};
229 229 // Creates variables var0, var1 and var2
230 iterations.push_back({std::make_shared<Create>(0), {{0, initialRange}}});
231 iterations.push_back({std::make_shared<Create>(1), {{0, initialRange}, {1, initialRange}}});
230 iterations.push_back({std::make_shared<Create>(0, initialRange), {{0, initialRange}}});
231 iterations.push_back({std::make_shared<Create>(1, initialRange), {{0, initialRange}, {1, initialRange}}});
232 232 iterations.push_back(
233 {std::make_shared<Create>(2), {{0, initialRange}, {1, initialRange}, {2, initialRange}}});
233 {std::make_shared<Create>(2, initialRange), {{0, initialRange}, {1, initialRange}, {2, initialRange}}});
234 234
235 235 // Adds variables into the sync group (ranges don't need to be tested here)
236 236 iterations.push_back({std::make_shared<Synchronize>(0, syncId)});
237 237 iterations.push_back({std::make_shared<Synchronize>(1, syncId)});
238 238 iterations.push_back({std::make_shared<Synchronize>(2, syncId)});
239 239
240 240 // Moves var0: ranges of var0, var1 and var2 change
241 241 auto newRange = range({12, 30}, {13, 30});
242 242 iterations.push_back(
243 243 {std::make_shared<Move>(0, newRange), {{0, newRange}, {1, newRange}, {2, newRange}}});
244 244
245 245 // Moves var1: ranges of var0, var1 and var2 change
246 246 newRange = range({13, 0}, {14, 0});
247 247 iterations.push_back(
248 248 {std::make_shared<Move>(0, newRange), {{0, newRange}, {1, newRange}, {2, newRange}}});
249 249
250 250 // Moves var2: ranges of var0, var1 and var2 change
251 251 newRange = range({13, 30}, {14, 30});
252 252 iterations.push_back(
253 253 {std::make_shared<Move>(0, newRange), {{0, newRange}, {1, newRange}, {2, newRange}}});
254 254
255 255 // Desyncs var2 and moves var0:
256 256 // - ranges of var0 and var1 change
257 257 // - range of var2 doesn't change anymore
258 258 auto var2Range = newRange;
259 259 newRange = range({13, 45}, {14, 45});
260 260 iterations.push_back({std::make_shared<Synchronize>(2, syncId, false)});
261 261 iterations.push_back(
262 262 {std::make_shared<Move>(0, newRange), {{0, newRange}, {1, newRange}, {2, var2Range}}});
263 263
264 264 // Shifts var0: although var1 is synchronized with var0, its range doesn't change
265 265 auto var1Range = newRange;
266 266 newRange = range({14, 45}, {15, 45});
267 267 iterations.push_back({std::make_shared<Move>(0, newRange, true),
268 268 {{0, newRange}, {1, var1Range}, {2, var2Range}}});
269 269
270 270 // Moves var0 through several operations:
271 271 // - range of var0 changes
272 272 // - range or var1 changes according to the previous shift (one hour)
273 273 auto moveVar0 = [&iterations](const auto &var0NewRange, const auto &var1ExpectedRange) {
274 274 iterations.push_back(
275 275 {std::make_shared<Move>(0, var0NewRange), {{0, var0NewRange}, {1, var1ExpectedRange}}});
276 276 };
277 277
278 278 // Pan left
279 279 moveVar0(range({14, 30}, {15, 30}), range({13, 30}, {14, 30}));
280 280 // Pan right
281 281 moveVar0(range({16, 0}, {17, 0}), range({15, 0}, {16, 0}));
282 282 // Zoom in
283 283 moveVar0(range({16, 30}, {16, 45}), range({15, 30}, {15, 45}));
284 284 // Zoom out
285 285 moveVar0(range({16, 15}, {17, 0}), range({15, 15}, {16, 0}));
286 286
287 287 QTest::newRow("sync1") << syncId << initialRange << std::move(iterations) << 200;
288 288 }
289 289
290 290 void testSyncCase2()
291 291 {
292 292 // Id used to synchronize variables in the controller
293 293 auto syncId = QUuid::createUuid();
294 294
295 295 /// Generates a range according to a start time and a end time (the date is the same)
296 296 auto dateTime = [](int year, int month, int day, int hours, int minutes, int seconds) {
297 297 return DateUtils::secondsSinceEpoch(
298 298 QDateTime{{year, month, day}, QTime{hours, minutes, seconds}, Qt::UTC});
299 299 };
300 300
301 301 auto initialRange = SqpRange{dateTime(2017, 1, 1, 12, 0, 0), dateTime(2017, 1, 1, 13, 0, 0)};
302 302
303 303 Iterations iterations{};
304 304 // Creates variables var0 and var1
305 iterations.push_back({std::make_shared<Create>(0), {{0, initialRange}}});
306 iterations.push_back({std::make_shared<Create>(1), {{0, initialRange}, {1, initialRange}}});
305 iterations.push_back({std::make_shared<Create>(0, initialRange), {{0, initialRange}}});
306 iterations.push_back({std::make_shared<Create>(1, initialRange), {{0, initialRange}, {1, initialRange}}});
307 307
308 308 // Adds variables into the sync group (ranges don't need to be tested here)
309 309 iterations.push_back({std::make_shared<Synchronize>(0, syncId)});
310 310 iterations.push_back({std::make_shared<Synchronize>(1, syncId)});
311 311
312 312
313 313 // Moves var0 through several operations:
314 314 // - range of var0 changes
315 315 // - range or var1 changes according to the previous shift (one hour)
316 316 auto moveVar0 = [&iterations](const auto &var0NewRange) {
317 317 iterations.push_back(
318 318 {std::make_shared<Move>(0, var0NewRange), {{0, var0NewRange}, {1, var0NewRange}}});
319 319 };
320 320 moveVar0(SqpRange{dateTime(2017, 1, 1, 12, 0, 0), dateTime(2017, 1, 1, 13, 0, 0)});
321 321 moveVar0(SqpRange{dateTime(2017, 1, 1, 14, 0, 0), dateTime(2017, 1, 1, 15, 0, 0)});
322 322 moveVar0(SqpRange{dateTime(2017, 1, 1, 8, 0, 0), dateTime(2017, 1, 1, 9, 0, 0)});
323 323 // moveVar0(SqpRange{dateTime(2017, 1, 1, 7, 30, 0), dateTime(2017, 1, 1, 9, 30, 0)});
324 324 moveVar0(SqpRange{dateTime(2017, 1, 1, 2, 0, 0), dateTime(2017, 1, 1, 4, 0, 0)});
325 325 moveVar0(SqpRange{dateTime(2017, 1, 1, 6, 0, 0), dateTime(2017, 1, 1, 8, 0, 0)});
326 326
327 327 moveVar0(SqpRange{dateTime(2017, 1, 10, 6, 0, 0), dateTime(2017, 1, 15, 8, 0, 0)});
328 328 moveVar0(SqpRange{dateTime(2017, 1, 17, 6, 0, 0), dateTime(2017, 1, 25, 8, 0, 0)});
329 329 moveVar0(SqpRange{dateTime(2017, 1, 2, 6, 0, 0), dateTime(2017, 1, 8, 8, 0, 0)});
330 330
331 331 moveVar0(SqpRange{dateTime(2017, 4, 10, 6, 0, 0), dateTime(2017, 6, 15, 8, 0, 0)});
332 332 moveVar0(SqpRange{dateTime(2017, 1, 17, 6, 0, 0), dateTime(2017, 2, 25, 8, 0, 0)});
333 333 moveVar0(SqpRange{dateTime(2017, 7, 2, 6, 0, 0), dateTime(2017, 10, 8, 8, 0, 0)});
334 334 moveVar0(SqpRange{dateTime(2017, 4, 10, 6, 0, 0), dateTime(2017, 6, 15, 8, 0, 0)});
335 335 moveVar0(SqpRange{dateTime(2017, 1, 17, 6, 0, 0), dateTime(2017, 2, 25, 8, 0, 0)});
336 336 moveVar0(SqpRange{dateTime(2017, 7, 2, 6, 0, 0), dateTime(2017, 10, 8, 8, 0, 0)});
337 337 moveVar0(SqpRange{dateTime(2017, 4, 10, 6, 0, 0), dateTime(2017, 6, 15, 8, 0, 0)});
338 338 moveVar0(SqpRange{dateTime(2017, 1, 17, 6, 0, 0), dateTime(2017, 2, 25, 8, 0, 0)});
339 339 moveVar0(SqpRange{dateTime(2017, 7, 2, 6, 0, 0), dateTime(2017, 10, 8, 8, 0, 0)});
340 340 moveVar0(SqpRange{dateTime(2017, 4, 10, 6, 0, 0), dateTime(2017, 6, 15, 8, 0, 0)});
341 341 moveVar0(SqpRange{dateTime(2017, 1, 17, 6, 0, 0), dateTime(2017, 2, 25, 8, 0, 0)});
342 342 moveVar0(SqpRange{dateTime(2017, 7, 2, 6, 0, 0), dateTime(2017, 10, 8, 8, 0, 0)});
343 343
344 344
345 345 QTest::newRow("sync2") << syncId << initialRange << iterations << 4000;
346 346 // QTest::newRow("sync3") << syncId << initialRange << iterations << 5000;
347 347 }
348 348
349 349 void testSyncOnVarCase1()
350 350 {
351 351 // Id used to synchronize variables in the controller
352 352 auto syncId = QUuid::createUuid();
353 353
354 354 /// Generates a range according to a start time and a end time (the date is the same)
355 355 auto range = [](const QTime &startTime, const QTime &endTime) {
356 356 return SqpRange{DateUtils::secondsSinceEpoch(QDateTime{{2017, 1, 1}, startTime, Qt::UTC}),
357 357 DateUtils::secondsSinceEpoch(QDateTime{{2017, 1, 1}, endTime, Qt::UTC})};
358 358 };
359 359
360 360 auto initialRange = range({12, 0}, {13, 0});
361 361
362 362 Iterations creations{};
363 363 // Creates variables var0, var1 and var2
364 creations.push_back({std::make_shared<Create>(0), {{0, initialRange}}});
364 creations.push_back({std::make_shared<Create>(0, initialRange), {{0, initialRange}}});
365 365
366 366 Iterations synchronization{};
367 367 // Adds variables into the sync group (ranges don't need to be tested here)
368 368 synchronization.push_back({std::make_shared<Synchronize>(0, syncId)});
369 369
370 370 Iterations iterations{};
371 371
372 372 // Moves var0 through several operations
373 373 auto moveOp = [&iterations](const auto &requestedRange, const auto &expectedRange, auto delay) {
374 374 iterations.push_back(
375 375 {std::make_shared<Move>(0, requestedRange, true, delay), {{0, expectedRange}}});
376 376 };
377 377
378 378 // we assume here 300 ms is enough to finsh a operation
379 379 int delayToFinish = 300;
380 380 // jump to right, let's the operation time to finish
381 381 moveOp(range({14, 30}, {15, 30}), range({14, 30}, {15, 30}), delayToFinish);
382 382 // pan to right, let's the operation time to finish
383 383 moveOp(range({14, 45}, {15, 45}), range({14, 45}, {15, 45}), delayToFinish);
384 384 // jump to left, let's the operation time to finish
385 385 moveOp(range({03, 30}, {04, 30}), range({03, 30}, {04, 30}), delayToFinish);
386 386 // Pan to left, let's the operation time to finish
387 387 moveOp(range({03, 10}, {04, 10}), range({03, 10}, {04, 10}), delayToFinish);
388 388 // Zoom in, let's the operation time to finish
389 389 moveOp(range({03, 30}, {04, 00}), range({03, 30}, {04, 00}), delayToFinish);
390 390 // Zoom out left, let's the operation time to finish
391 391 moveOp(range({01, 10}, {18, 10}), range({01, 10}, {18, 10}), delayToFinish);
392 392 // Go back to initial range
393 393 moveOp(initialRange, initialRange, delayToFinish);
394 394
395 395
396 396 // jump to right, let's the operation time to finish
397 397 // moveOp(range({14, 30}, {15, 30}), initialRange, delayToFinish);
398 398 // Zoom out left, let's the operation time to finish
399 399 moveOp(range({01, 10}, {18, 10}), initialRange, delayToFinish);
400 400 // Go back to initial range
401 401 moveOp(initialRange, initialRange, 300);
402 402
403 403 QTest::newRow("syncOnVarCase1") << syncId << initialRange << std::move(creations)
404 404 << std::move(iterations);
405 405 }
406 406 }
407 407
408 408 void TestVariableSync::testSync_data()
409 409 {
410 410 // ////////////// //
411 411 // Test structure //
412 412 // ////////////// //
413 413
414 414 QTest::addColumn<QUuid>("syncId");
415 415 QTest::addColumn<SqpRange>("initialRange");
416 416 QTest::addColumn<Iterations>("iterations");
417 417 QTest::addColumn<int>("operationDelay");
418 418
419 419 // ////////// //
420 420 // Test cases //
421 421 // ////////// //
422 422
423 423 testSyncCase1();
424 424 testSyncCase2();
425 425 }
426 426
427 427 void TestVariableSync::testSyncOneVar_data()
428 428 {
429 429 // ////////////// //
430 430 // Test structure //
431 431 // ////////////// //
432 432
433 433 QTest::addColumn<QUuid>("syncId");
434 434 QTest::addColumn<SqpRange>("initialRange");
435 435 QTest::addColumn<Iterations>("creations");
436 436 QTest::addColumn<Iterations>("iterations");
437 437
438 438 // ////////// //
439 439 // Test cases //
440 440 // ////////// //
441 441
442 442 testSyncOnVarCase1();
443 443 }
444 444
445 445 void TestVariableSync::testSync()
446 446 {
447 447 // Inits controllers
448 448 TimeController timeController{};
449 449 VariableController variableController{};
450 variableController.setTimeController(&timeController);
450 //variableController.setTimeController(&timeController);
451 451
452 452 QFETCH(QUuid, syncId);
453 453 QFETCH(SqpRange, initialRange);
454 timeController.onTimeToUpdate(initialRange);
454 timeController.setDateTimeRange(initialRange);
455 455
456 456 // Synchronization group used
457 457 variableController.onAddSynchronizationGroupId(syncId);
458 458
459 459 // For each iteration:
460 460 // - execute operation
461 461 // - compare the variables' state to the expected states
462 462 QFETCH(Iterations, iterations);
463 463 QFETCH(int, operationDelay);
464 464 for (const auto &iteration : iterations) {
465 465 iteration.m_Operation->exec(variableController);
466 466 QTest::qWait(operationDelay);
467 467
468 468 validateRanges(variableController, iteration.m_ExpectedRanges);
469 469 }
470 470 }
471 471
472 472 void TestVariableSync::testSyncOneVar()
473 473 {
474 474 // Inits controllers
475 475 TimeController timeController{};
476 476 VariableController variableController{};
477 variableController.setTimeController(&timeController);
477 //variableController.setTimeController(&timeController);
478 478
479 479 QFETCH(QUuid, syncId);
480 480 QFETCH(SqpRange, initialRange);
481 timeController.onTimeToUpdate(initialRange);
481 timeController.setDateTimeRange(initialRange);
482 482
483 483 // Synchronization group used
484 484 variableController.onAddSynchronizationGroupId(syncId);
485 485
486 486 // For each iteration:
487 487 // - execute operation
488 488 // - compare the variables' state to the expected states
489 489 QFETCH(Iterations, iterations);
490 490 QFETCH(Iterations, creations);
491 491
492 492 for (const auto &creation : creations) {
493 493 creation.m_Operation->exec(variableController);
494 494 QTest::qWait(300);
495 495 }
496 496
497 497 for (const auto &iteration : iterations) {
498 498 iteration.m_Operation->exec(variableController);
499 499 }
500 500
501 501 if (!iterations.empty()) {
502 502 validateRanges(variableController, iterations.back().m_ExpectedRanges);
503 503 }
504 504 }
505 505
506 506 QTEST_MAIN(TestVariableSync)
507 507
508 508 #include "TestVariableSync.moc"
@@ -1,207 +1,207
1 1 #include "SqpApplication.h"
2 2
3 3 #include <Actions/ActionsGuiController.h>
4 4 #include <Catalogue/CatalogueController.h>
5 5 #include <Data/IDataProvider.h>
6 6 #include <DataSource/DataSourceController.h>
7 7 #include <DragAndDrop/DragDropGuiController.h>
8 8 #include <Network/NetworkController.h>
9 9 #include <QThread>
10 10 #include <Time/TimeController.h>
11 11 #include <Variable/Variable.h>
12 12 #include <Variable/VariableController.h>
13 13 #include <Variable/VariableModel.h>
14 14 #include <Visualization/VisualizationController.h>
15 15
16 16 Q_LOGGING_CATEGORY(LOG_SqpApplication, "SqpApplication")
17 17
18 18 class SqpApplication::SqpApplicationPrivate {
19 19 public:
20 20 SqpApplicationPrivate()
21 21 : m_DataSourceController{std::make_unique<DataSourceController>()},
22 22 m_VariableController{std::make_unique<VariableController>()},
23 23 m_TimeController{std::make_unique<TimeController>()},
24 24 m_NetworkController{std::make_unique<NetworkController>()},
25 25 m_VisualizationController{std::make_unique<VisualizationController>()},
26 26 m_DragDropGuiController{std::make_unique<DragDropGuiController>()},
27 27 m_CatalogueController{std::make_unique<CatalogueController>()},
28 28 m_ActionsGuiController{std::make_unique<ActionsGuiController>()},
29 29 m_PlotInterractionMode(SqpApplication::PlotsInteractionMode::None),
30 30 m_PlotCursorMode(SqpApplication::PlotsCursorMode::NoCursor)
31 31 {
32 32 // /////////////////////////////// //
33 33 // Connections between controllers //
34 34 // /////////////////////////////// //
35 35
36 36 // VariableController <-> DataSourceController
37 37 connect(m_DataSourceController.get(),
38 38 SIGNAL(variableCreationRequested(const QString &, const QVariantHash &,
39 39 std::shared_ptr<IDataProvider>)),
40 40 m_VariableController.get(),
41 41 SLOT(createVariable(const QString &, const QVariantHash &,
42 42 std::shared_ptr<IDataProvider>)));
43 43
44 44 connect(m_VariableController->variableModel(), &VariableModel::requestVariable,
45 45 m_DataSourceController.get(), &DataSourceController::requestVariable);
46 46
47 47 // VariableController <-> VisualizationController
48 48 connect(m_VariableController.get(),
49 49 SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)),
50 50 m_VisualizationController.get(),
51 51 SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)), Qt::DirectConnection);
52 52
53 53 connect(m_VariableController.get(),
54 54 SIGNAL(rangeChanged(std::shared_ptr<Variable>, const SqpRange &)),
55 55 m_VisualizationController.get(),
56 56 SIGNAL(rangeChanged(std::shared_ptr<Variable>, const SqpRange &)));
57 57
58 58
59 59 m_DataSourceController->moveToThread(&m_DataSourceControllerThread);
60 60 m_DataSourceControllerThread.setObjectName("DataSourceControllerThread");
61 61 m_NetworkController->moveToThread(&m_NetworkControllerThread);
62 62 m_NetworkControllerThread.setObjectName("NetworkControllerThread");
63 63 m_VariableController->moveToThread(&m_VariableControllerThread);
64 64 m_VariableControllerThread.setObjectName("VariableControllerThread");
65 65 m_VisualizationController->moveToThread(&m_VisualizationControllerThread);
66 66 m_VisualizationControllerThread.setObjectName("VsualizationControllerThread");
67 67
68 68 // Additionnal init
69 m_VariableController->setTimeController(m_TimeController.get());
69 //m_VariableController->setTimeController(m_TimeController.get());
70 70 }
71 71
72 72 virtual ~SqpApplicationPrivate()
73 73 {
74 74 m_DataSourceControllerThread.quit();
75 75 m_DataSourceControllerThread.wait();
76 76
77 77 m_NetworkControllerThread.quit();
78 78 m_NetworkControllerThread.wait();
79 79
80 80 m_VariableControllerThread.quit();
81 81 m_VariableControllerThread.wait();
82 82
83 83 m_VisualizationControllerThread.quit();
84 84 m_VisualizationControllerThread.wait();
85 85 }
86 86
87 87 std::unique_ptr<DataSourceController> m_DataSourceController;
88 88 std::unique_ptr<VariableController> m_VariableController;
89 89 std::unique_ptr<TimeController> m_TimeController;
90 90 std::unique_ptr<NetworkController> m_NetworkController;
91 91 std::unique_ptr<VisualizationController> m_VisualizationController;
92 92 std::unique_ptr<CatalogueController> m_CatalogueController;
93 93
94 94 QThread m_DataSourceControllerThread;
95 95 QThread m_NetworkControllerThread;
96 96 QThread m_VariableControllerThread;
97 97 QThread m_VisualizationControllerThread;
98 98
99 99 std::unique_ptr<DragDropGuiController> m_DragDropGuiController;
100 100 std::unique_ptr<ActionsGuiController> m_ActionsGuiController;
101 101
102 102 SqpApplication::PlotsInteractionMode m_PlotInterractionMode;
103 103 SqpApplication::PlotsCursorMode m_PlotCursorMode;
104 104 };
105 105
106 106
107 107 SqpApplication::SqpApplication(int &argc, char **argv)
108 108 : QApplication{argc, argv}, impl{spimpl::make_unique_impl<SqpApplicationPrivate>()}
109 109 {
110 110 qCDebug(LOG_SqpApplication()) << tr("SqpApplication construction") << QThread::currentThread();
111 111
112 112 QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
113 113
114 114 connect(&impl->m_DataSourceControllerThread, &QThread::started,
115 115 impl->m_DataSourceController.get(), &DataSourceController::initialize);
116 116 connect(&impl->m_DataSourceControllerThread, &QThread::finished,
117 117 impl->m_DataSourceController.get(), &DataSourceController::finalize);
118 118
119 119 connect(&impl->m_NetworkControllerThread, &QThread::started, impl->m_NetworkController.get(),
120 120 &NetworkController::initialize);
121 121 connect(&impl->m_NetworkControllerThread, &QThread::finished, impl->m_NetworkController.get(),
122 122 &NetworkController::finalize);
123 123
124 124 connect(&impl->m_VariableControllerThread, &QThread::started, impl->m_VariableController.get(),
125 125 &VariableController::initialize);
126 126 connect(&impl->m_VariableControllerThread, &QThread::finished, impl->m_VariableController.get(),
127 127 &VariableController::finalize);
128 128
129 129 connect(&impl->m_VisualizationControllerThread, &QThread::started,
130 130 impl->m_VisualizationController.get(), &VisualizationController::initialize);
131 131 connect(&impl->m_VisualizationControllerThread, &QThread::finished,
132 132 impl->m_VisualizationController.get(), &VisualizationController::finalize);
133 133
134 134 impl->m_DataSourceControllerThread.start();
135 135 impl->m_NetworkControllerThread.start();
136 136 impl->m_VariableControllerThread.start();
137 137 impl->m_VisualizationControllerThread.start();
138 138 impl->m_CatalogueController->initialize();
139 139 }
140 140
141 141 SqpApplication::~SqpApplication()
142 142 {
143 143 }
144 144
145 145 void SqpApplication::initialize()
146 146 {
147 147 }
148 148
149 149 DataSourceController &SqpApplication::dataSourceController() noexcept
150 150 {
151 151 return *impl->m_DataSourceController;
152 152 }
153 153
154 154 NetworkController &SqpApplication::networkController() noexcept
155 155 {
156 156 return *impl->m_NetworkController;
157 157 }
158 158
159 159 TimeController &SqpApplication::timeController() noexcept
160 160 {
161 161 return *impl->m_TimeController;
162 162 }
163 163
164 164 VariableController &SqpApplication::variableController() noexcept
165 165 {
166 166 return *impl->m_VariableController;
167 167 }
168 168
169 169 VisualizationController &SqpApplication::visualizationController() noexcept
170 170 {
171 171 return *impl->m_VisualizationController;
172 172 }
173 173
174 174 CatalogueController &SqpApplication::catalogueController() noexcept
175 175 {
176 176 return *impl->m_CatalogueController;
177 177 }
178 178
179 179 DragDropGuiController &SqpApplication::dragDropGuiController() noexcept
180 180 {
181 181 return *impl->m_DragDropGuiController;
182 182 }
183 183
184 184 ActionsGuiController &SqpApplication::actionsGuiController() noexcept
185 185 {
186 186 return *impl->m_ActionsGuiController;
187 187 }
188 188
189 189 SqpApplication::PlotsInteractionMode SqpApplication::plotsInteractionMode() const
190 190 {
191 191 return impl->m_PlotInterractionMode;
192 192 }
193 193
194 194 void SqpApplication::setPlotsInteractionMode(SqpApplication::PlotsInteractionMode mode)
195 195 {
196 196 impl->m_PlotInterractionMode = mode;
197 197 }
198 198
199 199 SqpApplication::PlotsCursorMode SqpApplication::plotsCursorMode() const
200 200 {
201 201 return impl->m_PlotCursorMode;
202 202 }
203 203
204 204 void SqpApplication::setPlotsCursorMode(SqpApplication::PlotsCursorMode mode)
205 205 {
206 206 impl->m_PlotCursorMode = mode;
207 207 }
@@ -1,154 +1,154
1 1 #include "TimeWidget/TimeWidget.h"
2 2 #include "ui_TimeWidget.h"
3 3
4 4 #include <Common/DateUtils.h>
5 5 #include <Common/MimeTypesDef.h>
6 6
7 7 #include <DragAndDrop/DragDropGuiController.h>
8 8 #include <SqpApplication.h>
9 9 #include <Time/TimeController.h>
10 10
11 11 #include <QDrag>
12 12 #include <QDragEnterEvent>
13 13 #include <QDropEvent>
14 14 #include <QMimeData>
15 15
16 16
17 17 struct TimeWidget::TimeWidgetPrivate {
18 18
19 19 explicit TimeWidgetPrivate() {}
20 20
21 21 QPoint m_DragStartPosition;
22 22 };
23 23
24 24 TimeWidget::TimeWidget(QWidget *parent)
25 25 : QWidget{parent},
26 26 ui{new Ui::TimeWidget},
27 27 impl{spimpl::make_unique_impl<TimeWidgetPrivate>()}
28 28 {
29 29 ui->setupUi(this);
30 30
31 31 ui->applyToolButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_DialogApplyButton));
32 32
33 33 // Connection
34 34 connect(ui->startDateTimeEdit, &QDateTimeEdit::dateTimeChanged, this,
35 35 &TimeWidget::onTimeUpdateRequested);
36 36
37 37 connect(ui->endDateTimeEdit, &QDateTimeEdit::dateTimeChanged, this,
38 38 &TimeWidget::onTimeUpdateRequested);
39 39
40 40
41 41 connect(ui->applyToolButton, &QToolButton::clicked, &sqpApp->timeController(),
42 42 &TimeController::onTimeNotify);
43 43
44 44 // Initialisation
45 45 auto endDateTime = QDateTime::currentDateTimeUtc();
46 46 auto startDateTime = endDateTime.addSecs(-3600); // one hour before
47 47
48 48 ui->startDateTimeEdit->setDateTime(startDateTime);
49 49 ui->endDateTimeEdit->setDateTime(endDateTime);
50 50
51 51 auto dateTime = SqpRange{DateUtils::secondsSinceEpoch(startDateTime),
52 52 DateUtils::secondsSinceEpoch(endDateTime)};
53 53
54 sqpApp->timeController().onTimeToUpdate(dateTime);
54 sqpApp->timeController().setDateTimeRange(dateTime);
55 55 }
56 56
57 57
58 58 TimeWidget::~TimeWidget()
59 59 {
60 60 delete ui;
61 61 }
62 62
63 63 void TimeWidget::setTimeRange(SqpRange time)
64 64 {
65 65 auto startDateTime = DateUtils::dateTime(time.m_TStart);
66 66 auto endDateTime = DateUtils::dateTime(time.m_TEnd);
67 67
68 68 ui->startDateTimeEdit->setDateTime(startDateTime);
69 69 ui->endDateTimeEdit->setDateTime(endDateTime);
70 70 }
71 71
72 72 SqpRange TimeWidget::timeRange() const
73 73 {
74 74 return SqpRange{DateUtils::secondsSinceEpoch(ui->startDateTimeEdit->dateTime()),
75 75 DateUtils::secondsSinceEpoch(ui->endDateTimeEdit->dateTime())};
76 76 }
77 77
78 78 void TimeWidget::onTimeUpdateRequested()
79 79 {
80 80 auto dateTime = timeRange();
81 81 emit timeUpdated(std::move(dateTime));
82 82 }
83 83
84 84 void TimeWidget::dragEnterEvent(QDragEnterEvent *event)
85 85 {
86 86 if (event->mimeData()->hasFormat(MIME_TYPE_TIME_RANGE)) {
87 87 event->acceptProposedAction();
88 88 setStyleSheet("QDateTimeEdit{background-color: #BBD5EE; border:2px solid #2A7FD4}");
89 89 }
90 90 else {
91 91 event->ignore();
92 92 }
93 93 }
94 94
95 95 void TimeWidget::dragLeaveEvent(QDragLeaveEvent *event)
96 96 {
97 97 setStyleSheet(QString{});
98 98 }
99 99
100 100 void TimeWidget::dropEvent(QDropEvent *event)
101 101 {
102 102 if (event->mimeData()->hasFormat(MIME_TYPE_TIME_RANGE)) {
103 103 auto mimeData = event->mimeData()->data(MIME_TYPE_TIME_RANGE);
104 104 auto timeRange = TimeController::timeRangeForMimeData(mimeData);
105 105
106 106 setTimeRange(timeRange);
107 107 }
108 108 else {
109 109 event->ignore();
110 110 }
111 111
112 112 setStyleSheet(QString{});
113 113 }
114 114
115 115
116 116 void TimeWidget::mousePressEvent(QMouseEvent *event)
117 117 {
118 118 if (event->button() == Qt::LeftButton) {
119 119 impl->m_DragStartPosition = event->pos();
120 120 }
121 121
122 122 QWidget::mousePressEvent(event);
123 123 }
124 124
125 125 void TimeWidget::mouseMoveEvent(QMouseEvent *event)
126 126 {
127 127 if (!(event->buttons() & Qt::LeftButton)) {
128 128 return;
129 129 }
130 130
131 131 if ((event->pos() - impl->m_DragStartPosition).manhattanLength()
132 132 < QApplication::startDragDistance()) {
133 133 return;
134 134 }
135 135
136 136 // Note: The management of the drag object is done by Qt
137 137 auto drag = new QDrag{this};
138 138
139 139 auto mimeData = new QMimeData;
140 140 auto timeData = TimeController::mimeDataForTimeRange(timeRange());
141 141 mimeData->setData(MIME_TYPE_TIME_RANGE, timeData);
142 142
143 143 drag->setMimeData(mimeData);
144 144
145 145 auto pixmap = QPixmap{":/icones/time.png"};
146 146 drag->setPixmap(pixmap.scaledToWidth(22));
147 147
148 148 sqpApp->dragDropGuiController().resetDragAndDrop();
149 149
150 150 // Note: The exec() is blocking on windows but not on linux and macOS
151 151 drag->exec(Qt::MoveAction | Qt::CopyAction);
152 152
153 153 QWidget::mouseMoveEvent(event);
154 154 }
@@ -1,268 +1,268
1 1 #include "FuzzingOperations.h"
2 2 #include "FuzzingUtils.h"
3 3
4 4 #include <Data/IDataProvider.h>
5 5
6 6 #include <Variable/Variable.h>
7 7 #include <Variable/VariableController.h>
8 8
9 9 #include <QUuid>
10 10
11 11 #include <functional>
12 12
13 13 Q_LOGGING_CATEGORY(LOG_FuzzingOperations, "FuzzingOperations")
14 14
15 15 namespace {
16 16
17 17 struct CreateOperation : public IFuzzingOperation {
18 18 bool canExecute(VariableId variableId, const FuzzingState &fuzzingState) const override
19 19 {
20 20 // A variable can be created only if it doesn't exist yet
21 21 return fuzzingState.variableState(variableId).m_Variable == nullptr;
22 22 }
23 23
24 24 void execute(VariableId variableId, FuzzingState &fuzzingState,
25 25 VariableController &variableController,
26 26 const Properties &properties) const override
27 27 {
28 28 // Retrieves metadata pool from properties, and choose one of the metadata entries to
29 29 // associate it with the variable
30 30 auto metaDataPool = properties.value(METADATA_POOL_PROPERTY).value<MetadataPool>();
31 31 auto variableMetadata = RandomGenerator::instance().randomChoice(metaDataPool);
32 32
33 33 // Retrieves provider
34 34 auto variableProvider
35 35 = properties.value(PROVIDER_PROPERTY).value<std::shared_ptr<IDataProvider> >();
36 36
37 37 auto variableName = QString{"Var_%1"}.arg(QUuid::createUuid().toString());
38 38 qCInfo(LOG_FuzzingOperations()).noquote() << "Creating variable" << variableName
39 39 << "(metadata:" << variableMetadata << ")...";
40 40
41 41 auto newVariable
42 = variableController.createVariable(variableName, variableMetadata, variableProvider);
42 = variableController.createVariable(variableName, variableMetadata, variableProvider, properties.value(INITIAL_RANGE_PROPERTY).value<SqpRange>());
43 43
44 44 // Updates variable's state
45 45 auto &variableState = fuzzingState.variableState(variableId);
46 46 variableState.m_Range = properties.value(INITIAL_RANGE_PROPERTY).value<SqpRange>();
47 47 std::swap(variableState.m_Variable, newVariable);
48 48 }
49 49 };
50 50
51 51 struct DeleteOperation : public IFuzzingOperation {
52 52 bool canExecute(VariableId variableId, const FuzzingState &fuzzingState) const override
53 53 {
54 54 // A variable can be delete only if it exists
55 55 return fuzzingState.variableState(variableId).m_Variable != nullptr;
56 56 }
57 57
58 58 void execute(VariableId variableId, FuzzingState &fuzzingState,
59 59 VariableController &variableController, const Properties &) const override
60 60 {
61 61 auto &variableState = fuzzingState.variableState(variableId);
62 62
63 63 qCInfo(LOG_FuzzingOperations()).noquote() << "Deleting variable"
64 64 << variableState.m_Variable->name() << "...";
65 65 variableController.deleteVariable(variableState.m_Variable);
66 66
67 67 // Updates variable's state
68 68 variableState.m_Range = INVALID_RANGE;
69 69 variableState.m_Variable = nullptr;
70 70
71 71 // Desynchronizes the variable if it was in a sync group
72 72 auto syncGroupId = fuzzingState.syncGroupId(variableId);
73 73 fuzzingState.desynchronizeVariable(variableId, syncGroupId);
74 74 }
75 75 };
76 76
77 77 /**
78 78 * Defines a move operation through a range.
79 79 *
80 80 * A move operation is determined by three functions:
81 81 * - Two 'move' functions, used to indicate in which direction the beginning and the end of a range
82 82 * are going during the operation. These functions will be:
83 83 * -- {<- / <-} for pan left
84 84 * -- {-> / ->} for pan right
85 85 * -- {-> / <-} for zoom in
86 86 * -- {<- / ->} for zoom out
87 87 * - One 'max move' functions, used to compute the max delta at which the operation can move a
88 88 * range, according to a max range. For exemple, for a range of {1, 5} and a max range of {0, 10},
89 89 * max deltas will be:
90 90 * -- {0, 4} for pan left
91 91 * -- {6, 10} for pan right
92 92 * -- {3, 3} for zoom in
93 93 * -- {0, 6} for zoom out (same spacing left and right)
94 94 */
95 95 struct MoveOperation : public IFuzzingOperation {
96 96 using MoveFunction = std::function<double(double currentValue, double maxValue)>;
97 97 using MaxMoveFunction = std::function<double(const SqpRange &range, const SqpRange &maxRange)>;
98 98
99 99 explicit MoveOperation(MoveFunction rangeStartMoveFun, MoveFunction rangeEndMoveFun,
100 100 MaxMoveFunction maxMoveFun,
101 101 const QString &label = QStringLiteral("Move operation"))
102 102 : m_RangeStartMoveFun{std::move(rangeStartMoveFun)},
103 103 m_RangeEndMoveFun{std::move(rangeEndMoveFun)},
104 104 m_MaxMoveFun{std::move(maxMoveFun)},
105 105 m_Label{label}
106 106 {
107 107 }
108 108
109 109 bool canExecute(VariableId variableId, const FuzzingState &fuzzingState) const override
110 110 {
111 111 return fuzzingState.variableState(variableId).m_Variable != nullptr;
112 112 }
113 113
114 114 void execute(VariableId variableId, FuzzingState &fuzzingState,
115 115 VariableController &variableController,
116 116 const Properties &properties) const override
117 117 {
118 118 auto &variableState = fuzzingState.variableState(variableId);
119 119 auto variable = variableState.m_Variable;
120 120
121 121 // Gets the max range defined
122 122 auto maxRange = properties.value(MAX_RANGE_PROPERTY, QVariant::fromValue(INVALID_RANGE))
123 123 .value<SqpRange>();
124 124 auto variableRange = variableState.m_Range;
125 125
126 126 if (maxRange == INVALID_RANGE || variableRange.m_TStart < maxRange.m_TStart
127 127 || variableRange.m_TEnd > maxRange.m_TEnd) {
128 128 qCWarning(LOG_FuzzingOperations()) << "Can't execute operation: invalid max range";
129 129 return;
130 130 }
131 131
132 132 // Computes the max delta at which the variable can move, up to the limits of the max range
133 133 auto deltaMax = m_MaxMoveFun(variableRange, maxRange);
134 134
135 135 // Generates random delta that will be used to move variable
136 136 auto delta = RandomGenerator::instance().generateDouble(0, deltaMax);
137 137
138 138 // Moves variable to its new range
139 139 auto isSynchronized = !fuzzingState.syncGroupId(variableId).isNull();
140 140 auto newVariableRange = SqpRange{m_RangeStartMoveFun(variableRange.m_TStart, delta),
141 141 m_RangeEndMoveFun(variableRange.m_TEnd, delta)};
142 142 qCInfo(LOG_FuzzingOperations()).noquote() << "Performing" << m_Label << "on"
143 143 << variable->name() << "(from" << variableRange
144 144 << "to" << newVariableRange << ")...";
145 145 variableController.onRequestDataLoading({variable}, newVariableRange, isSynchronized);
146 146
147 147 // Updates state
148 148 fuzzingState.updateRanges(variableId, newVariableRange);
149 149 }
150 150
151 151 MoveFunction m_RangeStartMoveFun;
152 152 MoveFunction m_RangeEndMoveFun;
153 153 MaxMoveFunction m_MaxMoveFun;
154 154 QString m_Label;
155 155 };
156 156
157 157 struct SynchronizeOperation : public IFuzzingOperation {
158 158 bool canExecute(VariableId variableId, const FuzzingState &fuzzingState) const override
159 159 {
160 160 auto variable = fuzzingState.variableState(variableId).m_Variable;
161 161 return variable != nullptr && !fuzzingState.m_SyncGroupsPool.empty()
162 162 && fuzzingState.syncGroupId(variableId).isNull();
163 163 }
164 164
165 165 void execute(VariableId variableId, FuzzingState &fuzzingState,
166 166 VariableController &variableController, const Properties &) const override
167 167 {
168 168 auto &variableState = fuzzingState.variableState(variableId);
169 169
170 170 // Chooses a random synchronization group and adds the variable into sync group
171 171 auto syncGroupId = RandomGenerator::instance().randomChoice(fuzzingState.syncGroupsIds());
172 172 qCInfo(LOG_FuzzingOperations()).noquote() << "Adding" << variableState.m_Variable->name()
173 173 << "into synchronization group" << syncGroupId
174 174 << "...";
175 175 variableController.onAddSynchronized(variableState.m_Variable, syncGroupId);
176 176
177 177 // Updates state
178 178 fuzzingState.synchronizeVariable(variableId, syncGroupId);
179 179
180 180 variableController.onRequestDataLoading({variableState.m_Variable}, variableState.m_Range,
181 181 false);
182 182 }
183 183 };
184 184
185 185 struct DesynchronizeOperation : public IFuzzingOperation {
186 186 bool canExecute(VariableId variableId, const FuzzingState &fuzzingState) const override
187 187 {
188 188 auto variable = fuzzingState.variableState(variableId).m_Variable;
189 189 return variable != nullptr && !fuzzingState.syncGroupId(variableId).isNull();
190 190 }
191 191
192 192 void execute(VariableId variableId, FuzzingState &fuzzingState,
193 193 VariableController &variableController, const Properties &) const override
194 194 {
195 195 auto &variableState = fuzzingState.variableState(variableId);
196 196
197 197 // Gets the sync group of the variable
198 198 auto syncGroupId = fuzzingState.syncGroupId(variableId);
199 199
200 200 qCInfo(LOG_FuzzingOperations()).noquote() << "Removing" << variableState.m_Variable->name()
201 201 << "from synchronization group" << syncGroupId
202 202 << "...";
203 203 variableController.desynchronize(variableState.m_Variable, syncGroupId);
204 204
205 205 // Updates state
206 206 fuzzingState.desynchronizeVariable(variableId, syncGroupId);
207 207 }
208 208 };
209 209
210 210 struct UnknownOperation : public IFuzzingOperation {
211 211 bool canExecute(VariableId, const FuzzingState &) const override { return false; }
212 212
213 213 void execute(VariableId, FuzzingState &, VariableController &,
214 214 const Properties &) const override
215 215 {
216 216 }
217 217 };
218 218
219 219 } // namespace
220 220
221 221 std::unique_ptr<IFuzzingOperation> FuzzingOperationFactory::create(FuzzingOperationType type)
222 222 {
223 223 switch (type) {
224 224 case FuzzingOperationType::CREATE:
225 225 return std::make_unique<CreateOperation>();
226 226 case FuzzingOperationType::DELETE:
227 227 return std::make_unique<DeleteOperation>();
228 228 case FuzzingOperationType::PAN_LEFT:
229 229 return std::make_unique<MoveOperation>(
230 230 std::minus<double>(), std::minus<double>(),
231 231 [](const SqpRange &range, const SqpRange &maxRange) {
232 232 return range.m_TStart - maxRange.m_TStart;
233 233 },
234 234 QStringLiteral("Pan left operation"));
235 235 case FuzzingOperationType::PAN_RIGHT:
236 236 return std::make_unique<MoveOperation>(
237 237 std::plus<double>(), std::plus<double>(),
238 238 [](const SqpRange &range, const SqpRange &maxRange) {
239 239 return maxRange.m_TEnd - range.m_TEnd;
240 240 },
241 241 QStringLiteral("Pan right operation"));
242 242 case FuzzingOperationType::ZOOM_IN:
243 243 return std::make_unique<MoveOperation>(
244 244 std::plus<double>(), std::minus<double>(),
245 245 [](const SqpRange &range, const SqpRange &maxRange) {
246 246 Q_UNUSED(maxRange)
247 247 return range.m_TEnd - (range.m_TStart + range.m_TEnd) / 2.;
248 248 },
249 249 QStringLiteral("Zoom in operation"));
250 250 case FuzzingOperationType::ZOOM_OUT:
251 251 return std::make_unique<MoveOperation>(
252 252 std::minus<double>(), std::plus<double>(),
253 253 [](const SqpRange &range, const SqpRange &maxRange) {
254 254 return std::min(range.m_TStart - maxRange.m_TStart,
255 255 maxRange.m_TEnd - range.m_TEnd);
256 256 },
257 257 QStringLiteral("Zoom out operation"));
258 258 case FuzzingOperationType::SYNCHRONIZE:
259 259 return std::make_unique<SynchronizeOperation>();
260 260 case FuzzingOperationType::DESYNCHRONIZE:
261 261 return std::make_unique<DesynchronizeOperation>();
262 262 default:
263 263 // Default case returns unknown operation
264 264 break;
265 265 }
266 266
267 267 return std::make_unique<UnknownOperation>();
268 268 }
@@ -1,135 +1,135
1 1 /*------------------------------------------------------------------------------
2 2 -- This file is a part of the SciQLOP Software
3 3 -- Copyright (C) 2018, Plasma Physics Laboratory - CNRS
4 4 --
5 5 -- This program is free software; you can redistribute it and/or modify
6 6 -- it under the terms of the GNU General Public License as published by
7 7 -- the Free Software Foundation; either version 2 of the License, or
8 8 -- (at your option) any later version.
9 9 --
10 10 -- This program is distributed in the hope that it will be useful,
11 11 -- but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 13 -- GNU General Public License for more details.
14 14 --
15 15 -- You should have received a copy of the GNU General Public License
16 16 -- along with this program; if not, write to the Free Software
17 17 -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 18 -------------------------------------------------------------------------------*/
19 19 /*-- Author : Alexis Jeandet
20 20 -- Mail : alexis.jeandet@member.fsf.org
21 21 ----------------------------------------------------------------------------*/
22 22 #include <string>
23 23 #include <sstream>
24 24 #include <memory>
25 25
26 26 #include <pybind11/pybind11.h>
27 27 #include <pybind11/operators.h>
28 28 #include <pybind11/embed.h>
29 29 #include <pybind11/numpy.h>
30 30 #include <pybind11/chrono.h>
31 31
32 32 #include <SqpApplication.h>
33 33 #include <Variable/VariableController.h>
34 34 #include <Time/TimeController.h>
35 35 #include <Data/SqpRange.h>
36 36 #include <Data/DataSeriesType.h>
37 37 #include <Common/DateUtils.h>
38 38 #include <Variable/Variable.h>
39 39 #include <Data/ScalarSeries.h>
40 40 #include <Data/VectorSeries.h>
41 41
42 42 #include <AmdaProvider.h>
43 43 #include <AmdaResultParser.h>
44 44
45 45 //#include <QDate>
46 46 //#include <QTime>
47 47 //#include <QUuid>
48 48 //#include <QString>
49 49 #include <QFile>
50 50
51 51 #include <pywrappers_common.h>
52 52 #include <CoreWrappers.h>
53 53
54 54
55 55 using namespace std::chrono;
56 56 namespace py = pybind11;
57 57
58 58
59 59
60 60
61 61 PYBIND11_MODULE(pytestamda, m){
62 62
63 63 int argc = 0;
64 64 char ** argv=nullptr;
65 65 SqpApplication::setOrganizationName("LPP");
66 66 SqpApplication::setOrganizationDomain("lpp.fr");
67 67 SqpApplication::setApplicationName("SciQLop");
68 68 static SqpApplication app(argc, argv);
69 69
70 70 auto qtmod = py::module::import("sciqlopqt");
71 71 auto sciqlopmod = py::module::import("pysciqlopcore");
72 72
73 73 m.doc() = "hello";
74 74
75 75 py::class_<VariableController>(m, "VariableController")
76 76 .def_static("createVariable",[](const QString &name,
77 std::shared_ptr<IDataProvider> provider){
78 return sqpApp->variableController().createVariable(name, {{"dataType", "vector"}, {"xml:id", "c1_b"}}, provider);
77 std::shared_ptr<IDataProvider> provider, const SqpRange& range){
78 return sqpApp->variableController().createVariable(name, {{"dataType", "vector"}, {"xml:id", "c1_b"}}, provider, range);
79 79 })
80 80 .def_static("hasPendingDownloads",
81 81 [](){return sqpApp->variableController().hasPendingDownloads();}
82 82 )
83 83 .def_static("addSynchronizationGroup",
84 84 [](QUuid uuid){sqpApp->variableController().onAddSynchronizationGroupId(uuid);}
85 85 )
86 86 .def_static("removeSynchronizationGroup",
87 87 [](QUuid uuid){sqpApp->variableController().onRemoveSynchronizationGroupId(uuid);}
88 88 )
89 89 .def_static("synchronizeVar",
90 90 [](std::shared_ptr<Variable> variable, QUuid uuid){sqpApp->variableController().onAddSynchronized(variable, uuid);}
91 91 )
92 92 .def_static("deSynchronizeVar",
93 93 [](std::shared_ptr<Variable> variable, QUuid uuid){sqpApp->variableController().desynchronize(variable, uuid);}
94 94 )
95 95 .def_static("deleteVariable",
96 96 [](std::shared_ptr<Variable> variable){
97 97 sqpApp->variableController().deleteVariable(variable);}
98 98 )
99 99 .def_static("update_range",[](std::shared_ptr<Variable> variable, const SqpRange &range, bool synchronise){
100 100 sqpApp->variableController().onRequestDataLoading({variable}, range, synchronise);
101 101 })
102 102 .def_static("wait_for_downloads",[](){
103 103 while (sqpApp->variableController().hasPendingDownloads()) {
104 104 usleep(100);
105 105 }
106 106 });
107 107
108 108 py::class_<TimeController>(m,"TimeController")
109 .def_static("setTime", [](SqpRange range){sqpApp->timeController().onTimeToUpdate(range);});
109 .def_static("setTime", [](SqpRange range){sqpApp->timeController().setDateTimeRange(range);});
110 110
111 111
112 112 auto amda_provider = std::make_shared<AmdaProvider>();
113 113 m.def("amda_provider",[amda_provider](){return amda_provider;}, py::return_value_policy::copy);
114 114
115 115 py::class_<AmdaProvider, std::shared_ptr<AmdaProvider>, IDataProvider>(m, "AmdaProvider");
116 116
117 117 py::class_<AmdaResultParser>(m, "AmdaResultParser")
118 118 .def_static("readTxt", AmdaResultParser::readTxt)
119 119 .def("readScalarTxt", [](const QString& path){
120 120 return std::dynamic_pointer_cast<ScalarSeries>(AmdaResultParser::readTxt(path, DataSeriesType::SCALAR));
121 121 }, py::return_value_policy::copy);
122 122
123 123
124 124 }
125 125
126 126
127 127 int pytestamda_test(const char* testScriptPath )
128 128 {
129 129 py::scoped_interpreter guard{};
130 130 py::globals()["__file__"] = py::str(testScriptPath);
131 131 py::eval_file(testScriptPath);
132 132 return 0;
133 133 }
134 134
135 135
@@ -1,164 +1,164
1 1 #include "AmdaProvider.h"
2 2 #include "AmdaResultParser.h"
3 3
4 4 #include "SqpApplication.h"
5 5 #include <Data/DataSeries.h>
6 6 #include <Data/IDataSeries.h>
7 7 #include <Data/ScalarSeries.h>
8 8 #include <Time/TimeController.h>
9 9 #include <Variable/Variable.h>
10 10 #include <Variable/VariableController.h>
11 11
12 12 #include <QObject>
13 13 #include <QtTest>
14 14
15 15 #include <memory>
16 16
17 17 // TEST with REF:
18 18 // AmdaData-2012-01-01-12-00-00_2012-01-03-12-00-00
19 19 // imf(0) - Type : Local Parameter @ CDPP/AMDA -
20 20 // Name : bx_gse - Units : nT - Size : 1 -
21 21 // Frame : GSE - Mission : ACE -
22 22 // Instrument : MFI - Dataset : mfi_final-prelim
23 23 // REFERENCE DOWNLOAD FILE =
24 24 // http://amdatest.irap.omp.eu/php/rest/getParameter.php?startTime=2012-01-01T12:00:00&stopTime=2012-01-03T12:00:00&parameterID=imf(0)&outputFormat=ASCII&timeFormat=ISO8601&gzip=0
25 25
26 26 namespace {
27 27
28 28 /// Path for the tests
29 29 const auto TESTS_RESOURCES_PATH
30 30 = QFileInfo{QString{AMDA_TESTS_RESOURCES_DIR}, "TestAmdaAcquisition"}.absoluteFilePath();
31 31
32 32 /// Delay after each operation on the variable before validating it (in ms)
33 33 const auto OPERATION_DELAY = 10000;
34 34
35 35 template <typename T>
36 36 bool compareDataSeries(std::shared_ptr<IDataSeries> candidate, SqpRange candidateCacheRange,
37 37 std::shared_ptr<IDataSeries> reference)
38 38 {
39 39 auto compareLambda = [](const auto &it1, const auto &it2) {
40 40 return (it1.x() == it2.x()) && (it1.value() == it2.value());
41 41 };
42 42
43 43 auto candidateDS = std::dynamic_pointer_cast<T>(candidate);
44 44 auto referenceDS = std::dynamic_pointer_cast<T>(reference);
45 45
46 46 if (candidateDS && referenceDS) {
47 47
48 48 auto itRefs
49 49 = referenceDS->xAxisRange(candidateCacheRange.m_TStart, candidateCacheRange.m_TEnd);
50 50 qDebug() << " DISTANCE" << std::distance(candidateDS->cbegin(), candidateDS->cend())
51 51 << std::distance(itRefs.first, itRefs.second);
52 52
53 53 return std::equal(candidateDS->cbegin(), candidateDS->cend(), itRefs.first, itRefs.second,
54 54 compareLambda);
55 55 }
56 56 else {
57 57 return false;
58 58 }
59 59 }
60 60 }
61 61
62 62 class TestAmdaAcquisition : public QObject {
63 63 Q_OBJECT
64 64
65 65 private slots:
66 66 /// Input data for @sa testAcquisition()
67 67 void testAcquisition_data();
68 68 void testAcquisition();
69 69 };
70 70
71 71 void TestAmdaAcquisition::testAcquisition_data()
72 72 {
73 73 // ////////////// //
74 74 // Test structure //
75 75 // ////////////// //
76 76
77 77 QTest::addColumn<QString>("dataFilename"); // File containing expected data of acquisitions
78 78 QTest::addColumn<SqpRange>("initialRange"); // First acquisition
79 79 QTest::addColumn<std::vector<SqpRange> >("operations"); // Acquisitions to make
80 80
81 81 // ////////// //
82 82 // Test cases //
83 83 // ////////// //
84 84
85 85 auto dateTime = [](int year, int month, int day, int hours, int minutes, int seconds) {
86 86 return DateUtils::secondsSinceEpoch(
87 87 QDateTime{{year, month, day}, {hours, minutes, seconds}, Qt::UTC});
88 88 };
89 89
90 90
91 91 QTest::newRow("amda")
92 92 << "AmdaData-2012-01-01-12-00-00_2012-01-03-12-00-00.txt"
93 93 << SqpRange{dateTime(2012, 1, 2, 2, 3, 0), dateTime(2012, 1, 2, 2, 4, 0)}
94 94 << std::vector<SqpRange>{
95 95 // 2 : pan (jump) left for two min
96 96 SqpRange{dateTime(2012, 1, 2, 2, 1, 0), dateTime(2012, 1, 2, 2, 2, 0)},
97 97 // 3 : pan (jump) right for four min
98 98 SqpRange{dateTime(2012, 1, 2, 2, 5, 0), dateTime(2012, 1, 2, 2, 6, 0)},
99 99 // 4 : pan (overlay) right for 30 sec
100 100 /*SqpRange{dateTime(2012, 1, 2, 2, 5, 30), dateTime(2012, 1, 2, 2, 6, 30)},
101 101 // 5 : pan (overlay) left for 30 sec
102 102 SqpRange{dateTime(2012, 1, 2, 2, 5, 0), dateTime(2012, 1, 2, 2, 6, 0)},
103 103 // 6 : pan (overlay) left for 30 sec - BIS
104 104 SqpRange{dateTime(2012, 1, 2, 2, 4, 30), dateTime(2012, 1, 2, 2, 5, 30)},
105 105 // 7 : Zoom in Inside 20 sec range
106 106 SqpRange{dateTime(2012, 1, 2, 2, 4, 50), dateTime(2012, 1, 2, 2, 5, 10)},
107 107 // 8 : Zoom out Inside 20 sec range
108 108 SqpRange{dateTime(2012, 1, 2, 2, 4, 30), dateTime(2012, 1, 2, 2, 5, 30)}*/};
109 109 }
110 110
111 111 void TestAmdaAcquisition::testAcquisition()
112 112 {
113 113 /// @todo: update test to be compatible with AMDA v2
114 114
115 115 // Retrieves data file
116 116 QFETCH(QString, dataFilename);
117 117 auto filePath = QFileInfo{TESTS_RESOURCES_PATH, dataFilename}.absoluteFilePath();
118 118 auto results = AmdaResultParser::readTxt(filePath, DataSeriesType::SCALAR);
119 119
120 120 /// Lambda used to validate a variable at each step
121 121 auto validateVariable = [results](std::shared_ptr<Variable> variable, const SqpRange &range) {
122 122 // Checks that the variable's range has changed
123 123 qInfo() << tr("Compare var range vs range") << variable->range() << range;
124 124 QCOMPARE(variable->range(), range);
125 125
126 126 // Checks the variable's data series
127 127 QVERIFY(compareDataSeries<ScalarSeries>(variable->dataSeries(), variable->cacheRange(),
128 128 results));
129 129 qInfo() << "\n";
130 130 };
131 131
132 132 // Creates variable
133 133 QFETCH(SqpRange, initialRange);
134 sqpApp->timeController().onTimeToUpdate(initialRange);
134 sqpApp->timeController().setDateTimeRange(initialRange);
135 135 auto provider = std::make_shared<AmdaProvider>();
136 136 auto variable = sqpApp->variableController().createVariable(
137 "bx_gse", {{"dataType", "scalar"}, {"xml:id", "imf(0)"}}, provider);
137 "bx_gse", {{"dataType", "scalar"}, {"xml:id", "imf(0)"}}, provider, initialRange);
138 138
139 139 QTest::qWait(OPERATION_DELAY);
140 140 validateVariable(variable, initialRange);
141 141
142 142 // Makes operations on the variable
143 143 QFETCH(std::vector<SqpRange>, operations);
144 144 for (const auto &operation : operations) {
145 145 // Asks request on the variable and waits during its execution
146 146 sqpApp->variableController().onRequestDataLoading({variable}, operation, false);
147 147
148 148 QTest::qWait(OPERATION_DELAY);
149 149 validateVariable(variable, operation);
150 150 }
151 151 }
152 152
153 153 int main(int argc, char *argv[])
154 154 {
155 155 SqpApplication app(argc, argv);
156 156 app.setAttribute(Qt::AA_Use96Dpi, true);
157 157 TestAmdaAcquisition tc;
158 158 QTEST_SET_MAIN_SOURCE_PATH
159 159 return QTest::qExec(&tc, argc, argv);
160 160 }
161 161
162 162 // QTEST_MAIN(TestAmdaAcquisition)
163 163
164 164 #include "TestAmdaAcquisition.moc"
@@ -1,395 +1,395
1 1 #include "FuzzingDefs.h"
2 2 #include "FuzzingOperations.h"
3 3 #include "FuzzingUtils.h"
4 4 #include "FuzzingValidators.h"
5 5
6 6 #include "AmdaProvider.h"
7 7
8 8 #include <Common/SignalWaiter.h>
9 9 #include <Network/NetworkController.h>
10 10 #include <Settings/SqpSettingsDefs.h>
11 11 #include <SqpApplication.h>
12 12 #include <Time/TimeController.h>
13 13 #include <Variable/Variable.h>
14 14 #include <Variable/VariableController.h>
15 15
16 16 #include <QLoggingCategory>
17 17 #include <QObject>
18 18 #include <QtTest>
19 19
20 20 #include <memory>
21 21
22 22 Q_LOGGING_CATEGORY(LOG_TestAmdaFuzzing, "TestAmdaFuzzing")
23 23
24 24 /**
25 25 * Macro used to generate a getter for a property in @sa FuzzingTest. The macro generates a static
26 26 * attribute that is initialized by searching in properties the property and use a default value if
27 27 * it's not present. Macro arguments are:
28 28 * - GETTER_NAME : name of the getter
29 29 * - PROPERTY_NAME: used to generate constants for property's name ({PROPERTY_NAME}_PROPERTY) and
30 30 * default value ({PROPERTY_NAME}_DEFAULT_VALUE)
31 31 * - TYPE : return type of the getter
32 32 */
33 33 // clang-format off
34 34 #define DECLARE_PROPERTY_GETTER(GETTER_NAME, PROPERTY_NAME, TYPE) \
35 35 TYPE GETTER_NAME() const \
36 36 { \
37 37 static auto result = m_Properties.value(PROPERTY_NAME##_PROPERTY, PROPERTY_NAME##_DEFAULT_VALUE).value<TYPE>(); \
38 38 return result; \
39 39 } \
40 40 // clang-format on
41 41
42 42 namespace {
43 43
44 44 // /////// //
45 45 // Aliases //
46 46 // /////// //
47 47
48 48 using IntPair = std::pair<int, int>;
49 49 using Weight = double;
50 50 using Weights = std::vector<Weight>;
51 51
52 52 struct OperationProperty {
53 53 Weight m_Weight{1.};
54 54 bool m_WaitAcquisition{false};
55 55 };
56 56
57 57 using VariableOperation = std::pair<VariableId, std::shared_ptr<IFuzzingOperation> >;
58 58 using VariablesOperations = std::vector<VariableOperation>;
59 59
60 60 using OperationsTypes = std::map<FuzzingOperationType, OperationProperty>;
61 61 using OperationsPool = std::map<std::shared_ptr<IFuzzingOperation>, OperationProperty>;
62 62
63 63 using Validators = std::vector<std::shared_ptr<IFuzzingValidator> >;
64 64
65 65 // ///////// //
66 66 // Constants //
67 67 // ///////// //
68 68
69 69 // Defaults values used when the associated properties have not been set for the test
70 70 const auto ACQUISITION_TIMEOUT_DEFAULT_VALUE = 30000;
71 71 const auto NB_MAX_OPERATIONS_DEFAULT_VALUE = 100;
72 72 const auto NB_MAX_SYNC_GROUPS_DEFAULT_VALUE = 1;
73 73 const auto NB_MAX_VARIABLES_DEFAULT_VALUE = 1;
74 74 const auto AVAILABLE_OPERATIONS_DEFAULT_VALUE = QVariant::fromValue(
75 75 OperationsTypes{{FuzzingOperationType::CREATE, {1., true}},
76 76 {FuzzingOperationType::DELETE, {0.1}}, // Delete operation is less frequent
77 77 {FuzzingOperationType::PAN_LEFT, {1.}},
78 78 {FuzzingOperationType::PAN_RIGHT, {1.}},
79 79 {FuzzingOperationType::ZOOM_IN, {1.}},
80 80 {FuzzingOperationType::ZOOM_OUT, {1.}},
81 81 {FuzzingOperationType::SYNCHRONIZE, {0.8}},
82 82 {FuzzingOperationType::DESYNCHRONIZE, {0.4}}});
83 83 const auto CACHE_TOLERANCE_DEFAULT_VALUE = 0.2;
84 84
85 85 /// Min/max delays between each operation (in ms)
86 86 const auto OPERATION_DELAY_BOUNDS_DEFAULT_VALUE = QVariant::fromValue(std::make_pair(100, 3000));
87 87
88 88 /// Validators for the tests (executed in the order in which they're defined)
89 89 const auto VALIDATORS_DEFAULT_VALUE = QVariant::fromValue(
90 90 ValidatorsTypes{{FuzzingValidatorType::RANGE, FuzzingValidatorType::DATA}});
91 91
92 92 /// Min/max number of operations to execute before calling validation
93 93 const auto VALIDATION_FREQUENCY_BOUNDS_DEFAULT_VALUE = QVariant::fromValue(std::make_pair(1, 10));
94 94
95 95 // /////// //
96 96 // Methods //
97 97 // /////// //
98 98
99 99 /// Goes through the variables pool and operations pool to determine the set of {variable/operation}
100 100 /// pairs that are valid (i.e. operation that can be executed on variable)
101 101 std::pair<VariablesOperations, Weights> availableOperations(const FuzzingState &fuzzingState,
102 102 const OperationsPool &operationsPool)
103 103 {
104 104 VariablesOperations result{};
105 105 Weights weights{};
106 106
107 107 for (const auto &variablesPoolEntry : fuzzingState.m_VariablesPool) {
108 108 auto variableId = variablesPoolEntry.first;
109 109
110 110 for (const auto &operationsPoolEntry : operationsPool) {
111 111 auto operation = operationsPoolEntry.first;
112 112 auto operationProperty = operationsPoolEntry.second;
113 113
114 114 // A pair is valid if the current operation can be executed on the current variable
115 115 if (operation->canExecute(variableId, fuzzingState)) {
116 116 result.push_back({variableId, operation});
117 117 weights.push_back(operationProperty.m_Weight);
118 118 }
119 119 }
120 120 }
121 121
122 122 return {result, weights};
123 123 }
124 124
125 125 OperationsPool createOperationsPool(const OperationsTypes &types)
126 126 {
127 127 OperationsPool result{};
128 128
129 129 std::transform(
130 130 types.cbegin(), types.cend(), std::inserter(result, result.end()), [](const auto &type) {
131 131 return std::make_pair(FuzzingOperationFactory::create(type.first), type.second);
132 132 });
133 133
134 134 return result;
135 135 }
136 136
137 137 Validators createValidators(const ValidatorsTypes &types)
138 138 {
139 139 Validators result{};
140 140
141 141 std::transform(types.cbegin(), types.cend(), std::inserter(result, result.end()),
142 142 [](const auto &type) { return FuzzingValidatorFactory::create(type); });
143 143
144 144 return result;
145 145 }
146 146
147 147 /**
148 148 * Validates all the variables' states passed in parameter, according to a set of validators
149 149 * @param variablesPool the variables' states
150 150 * @param validators the validators used for validation
151 151 */
152 152 void validate(const VariablesPool &variablesPool, const Validators &validators)
153 153 {
154 154 for (const auto &variablesPoolEntry : variablesPool) {
155 155 auto variableId = variablesPoolEntry.first;
156 156 const auto &variableState = variablesPoolEntry.second;
157 157
158 158 auto variableMessage = variableState.m_Variable ? variableState.m_Variable->name()
159 159 : QStringLiteral("null variable");
160 160 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Validating state of variable at index"
161 161 << variableId << "(" << variableMessage << ")...";
162 162
163 163 for (const auto &validator : validators) {
164 164 validator->validate(VariableState{variableState});
165 165 }
166 166
167 167 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Validation completed.";
168 168 }
169 169 }
170 170
171 171 /**
172 172 * Class to run random tests
173 173 */
174 174 class FuzzingTest {
175 175 public:
176 176 explicit FuzzingTest(VariableController &variableController, Properties properties)
177 177 : m_VariableController{variableController},
178 178 m_Properties{std::move(properties)},
179 179 m_FuzzingState{}
180 180 {
181 181 // Inits variables pool: at init, all variables are null
182 182 for (auto variableId = 0; variableId < nbMaxVariables(); ++variableId) {
183 183 m_FuzzingState.m_VariablesPool[variableId] = VariableState{};
184 184 }
185 185
186 186 // Inits sync groups and registers them into the variable controller
187 187 for (auto i = 0; i < nbMaxSyncGroups(); ++i) {
188 188 auto syncGroupId = SyncGroupId::createUuid();
189 189 variableController.onAddSynchronizationGroupId(syncGroupId);
190 190 m_FuzzingState.m_SyncGroupsPool[syncGroupId] = SyncGroup{};
191 191 }
192 192 }
193 193
194 194 void execute()
195 195 {
196 196 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Running" << nbMaxOperations() << "operations on"
197 197 << nbMaxVariables() << "variable(s)...";
198 198
199 199
200 200 // Inits the count of the number of operations before the next validation
201 201 int nextValidationCounter = 0;
202 202 auto updateValidationCounter = [this, &nextValidationCounter]() {
203 203 nextValidationCounter = RandomGenerator::instance().generateInt(
204 204 validationFrequencies().first, validationFrequencies().second);
205 205 qCInfo(LOG_TestAmdaFuzzing()).noquote()
206 206 << "Next validation in " << nextValidationCounter << "operation(s)...";
207 207 };
208 208 updateValidationCounter();
209 209
210 210 auto canExecute = true;
211 211 for (auto i = 0; i < nbMaxOperations() && canExecute; ++i) {
212 212 // Retrieves all operations that can be executed in the current context
213 213 VariablesOperations variableOperations{};
214 214 Weights weights{};
215 215 std::tie(variableOperations, weights)
216 216 = availableOperations(m_FuzzingState, operationsPool());
217 217
218 218 canExecute = !variableOperations.empty();
219 219 if (canExecute) {
220 220 --nextValidationCounter;
221 221
222 222 // Of the operations available, chooses a random operation and executes it
223 223 auto variableOperation
224 224 = RandomGenerator::instance().randomChoice(variableOperations, weights);
225 225
226 226 auto variableId = variableOperation.first;
227 227 auto fuzzingOperation = variableOperation.second;
228 228
229 229 auto waitAcquisition = nextValidationCounter == 0
230 230 || operationsPool().at(fuzzingOperation).m_WaitAcquisition;
231 231
232 232 fuzzingOperation->execute(variableId, m_FuzzingState, m_VariableController,
233 233 m_Properties);
234 234
235 235 if (waitAcquisition) {
236 236 qCDebug(LOG_TestAmdaFuzzing()) << "Waiting for acquisition to finish...";
237 237 SignalWaiter{m_VariableController, SIGNAL(acquisitionFinished())}.wait(
238 238 acquisitionTimeout());
239 239
240 240 // Validates variables
241 241 if (nextValidationCounter == 0) {
242 242 validate(m_FuzzingState.m_VariablesPool, validators());
243 243 updateValidationCounter();
244 244 }
245 245 }
246 246 else {
247 247 // Delays the next operation with a randomly generated time
248 248 auto delay = RandomGenerator::instance().generateInt(operationDelays().first,
249 249 operationDelays().second);
250 250 qCDebug(LOG_TestAmdaFuzzing())
251 251 << "Waiting " << delay << "ms before the next operation...";
252 252 QTest::qWait(delay);
253 253 }
254 254 }
255 255 else {
256 256 qCInfo(LOG_TestAmdaFuzzing()).noquote()
257 257 << "No more operations are available, the execution of the test will stop...";
258 258 }
259 259 }
260 260
261 261 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Execution of the test completed.";
262 262 }
263 263
264 264 private:
265 265 OperationsPool operationsPool() const
266 266 {
267 267 static auto result = createOperationsPool(
268 268 m_Properties.value(AVAILABLE_OPERATIONS_PROPERTY, AVAILABLE_OPERATIONS_DEFAULT_VALUE)
269 269 .value<OperationsTypes>());
270 270 return result;
271 271 }
272 272
273 273 Validators validators() const
274 274 {
275 275 static auto result
276 276 = createValidators(m_Properties.value(VALIDATORS_PROPERTY, VALIDATORS_DEFAULT_VALUE)
277 277 .value<ValidatorsTypes>());
278 278 return result;
279 279 }
280 280
281 281 DECLARE_PROPERTY_GETTER(nbMaxOperations, NB_MAX_OPERATIONS, int)
282 282 DECLARE_PROPERTY_GETTER(nbMaxSyncGroups, NB_MAX_SYNC_GROUPS, int)
283 283 DECLARE_PROPERTY_GETTER(nbMaxVariables, NB_MAX_VARIABLES, int)
284 284 DECLARE_PROPERTY_GETTER(operationDelays, OPERATION_DELAY_BOUNDS, IntPair)
285 285 DECLARE_PROPERTY_GETTER(validationFrequencies, VALIDATION_FREQUENCY_BOUNDS, IntPair)
286 286 DECLARE_PROPERTY_GETTER(acquisitionTimeout, ACQUISITION_TIMEOUT, int)
287 287
288 288 VariableController &m_VariableController;
289 289 Properties m_Properties;
290 290 FuzzingState m_FuzzingState;
291 291 };
292 292
293 293 } // namespace
294 294
295 295 Q_DECLARE_METATYPE(OperationsTypes)
296 296
297 297 class TestAmdaFuzzing : public QObject {
298 298 Q_OBJECT
299 299
300 300 private slots:
301 301 /// Input data for @sa testFuzzing()
302 302 void testFuzzing_data();
303 303 void testFuzzing();
304 304 };
305 305
306 306 void TestAmdaFuzzing::testFuzzing_data()
307 307 {
308 308 // Note: Comment this line to run fuzzing tests
309 309 QSKIP("Fuzzing tests are disabled by default");
310 310
311 311 // ////////////// //
312 312 // Test structure //
313 313 // ////////////// //
314 314
315 315 QTest::addColumn<Properties>("properties"); // Properties for random test
316 316
317 317 // ////////// //
318 318 // Test cases //
319 319 // ////////// //
320 320
321 321 auto maxRange = SqpRange::fromDateTime({2017, 1, 1}, {0, 0}, {2017, 1, 5}, {0, 0});
322 322 MetadataPool metadataPool{{{"dataType", "vector"}, {"xml:id", "imf"}}};
323 323
324 324 // Note: we don't use auto here as we want to pass std::shared_ptr<IDataProvider> as is in the
325 325 // QVariant
326 326 std::shared_ptr<IDataProvider> provider = std::make_shared<AmdaProvider>();
327 327
328 328 QTest::newRow("fuzzingTest") << Properties{
329 329 {MAX_RANGE_PROPERTY, QVariant::fromValue(maxRange)},
330 330 {METADATA_POOL_PROPERTY, QVariant::fromValue(metadataPool)},
331 331 {PROVIDER_PROPERTY, QVariant::fromValue(provider)}};
332 332 }
333 333
334 334 void TestAmdaFuzzing::testFuzzing()
335 335 {
336 336 QFETCH(Properties, properties);
337 337
338 338 // Sets cache property
339 339 QSettings settings{};
340 340 auto cacheTolerance = properties.value(CACHE_TOLERANCE_PROPERTY, CACHE_TOLERANCE_DEFAULT_VALUE);
341 341 settings.setValue(GENERAL_TOLERANCE_AT_INIT_KEY, cacheTolerance);
342 342 settings.setValue(GENERAL_TOLERANCE_AT_UPDATE_KEY, cacheTolerance);
343 343
344 344 auto &variableController = sqpApp->variableController();
345 345 auto &timeController = sqpApp->timeController();
346 346
347 347 // Generates random initial range (bounded to max range)
348 348 auto maxRange = properties.value(MAX_RANGE_PROPERTY, QVariant::fromValue(INVALID_RANGE))
349 349 .value<SqpRange>();
350 350
351 351 QVERIFY(maxRange != INVALID_RANGE);
352 352
353 353 auto initialRangeStart
354 354 = RandomGenerator::instance().generateDouble(maxRange.m_TStart, maxRange.m_TEnd);
355 355 auto initialRangeEnd
356 356 = RandomGenerator::instance().generateDouble(maxRange.m_TStart, maxRange.m_TEnd);
357 357 if (initialRangeStart > initialRangeEnd) {
358 358 std::swap(initialRangeStart, initialRangeEnd);
359 359 }
360 360
361 361 // Sets initial range on time controller
362 362 SqpRange initialRange{initialRangeStart, initialRangeEnd};
363 363 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Setting initial range to" << initialRange << "...";
364 timeController.onTimeToUpdate(initialRange);
364 timeController.setDateTimeRange(initialRange);
365 365 properties.insert(INITIAL_RANGE_PROPERTY, QVariant::fromValue(initialRange));
366 366
367 367 FuzzingTest test{variableController, properties};
368 368 test.execute();
369 369 }
370 370
371 371 int main(int argc, char *argv[])
372 372 {
373 373 // Increases the test function timeout (which is 5 minutes by default) to 12 hours
374 374 // https://stackoverflow.com/questions/42655932/setting-timeout-to-qt-test
375 375 qputenv("QTEST_FUNCTION_TIMEOUT", QByteArray::number(12*60*60*1000));
376 376
377 377 QLoggingCategory::setFilterRules(
378 378 "*.warning=false\n"
379 379 "*.info=false\n"
380 380 "*.debug=false\n"
381 381 "FuzzingOperations.info=true\n"
382 382 "FuzzingValidators.info=true\n"
383 383 "TestAmdaFuzzing.info=true\n");
384 384
385 385 SqpApplication app{argc, argv};
386 386 SqpApplication::setOrganizationName("LPP");
387 387 SqpApplication::setOrganizationDomain("lpp.fr");
388 388 SqpApplication::setApplicationName("SciQLop-TestFuzzing");
389 389 app.setAttribute(Qt::AA_Use96Dpi, true);
390 390 TestAmdaFuzzing testObject{};
391 391 QTEST_SET_MAIN_SOURCE_PATH
392 392 return QTest::qExec(&testObject, argc, argv);
393 393 }
394 394
395 395 #include "TestAmdaFuzzing.moc"
@@ -1,119 +1,119
1 1 #include "MockPlugin.h"
2 2 #include "CosinusProvider.h"
3 3 #include "MockDefs.h"
4 4
5 5 #include <DataSource/DataSourceController.h>
6 6 #include <DataSource/DataSourceItem.h>
7 7 #include <DataSource/DataSourceItemAction.h>
8 8
9 9 #include <SqpApplication.h>
10 10
11 11 Q_LOGGING_CATEGORY(LOG_MockPlugin, "MockPlugin")
12 12
13 13 namespace {
14 14
15 15 /// Name of the data source
16 16 const auto DATA_SOURCE_NAME = QStringLiteral("MMS");
17 17
18 18 /// Creates the data provider relative to the plugin
19 19 std::unique_ptr<IDataProvider> createDataProvider() noexcept
20 20 {
21 21 return std::make_unique<CosinusProvider>();
22 22 }
23 23
24 std::unique_ptr<DataSourceItem> createProductItem(const QVariantHash &data,
24 std::unique_ptr<DataSourceItem> createProductItem(const QVariantHash &metaData,
25 25 const QUuid &dataSourceUid)
26 26 {
27 auto result = std::make_unique<DataSourceItem>(DataSourceItemType::PRODUCT, data);
27 auto result = std::make_unique<DataSourceItem>(DataSourceItemType::PRODUCT, metaData);
28 28
29 29 // Adds plugin name to product metadata
30 30 result->setData(DataSourceItem::PLUGIN_DATA_KEY, DATA_SOURCE_NAME);
31 result->setData(DataSourceItem::ID_DATA_KEY, data.value(DataSourceItem::NAME_DATA_KEY));
31 result->setData(DataSourceItem::ID_DATA_KEY, metaData.value(DataSourceItem::NAME_DATA_KEY));
32 32
33 auto productName = data.value(DataSourceItem::NAME_DATA_KEY).toString();
33 auto productName = metaData.value(DataSourceItem::NAME_DATA_KEY).toString();
34 34
35 35 // Add action to load product from DataSourceController
36 36 result->addAction(std::make_unique<DataSourceItemAction>(
37 37 QObject::tr("Load %1 product").arg(productName),
38 38 [productName, dataSourceUid](DataSourceItem &item) {
39 39 if (auto app = sqpApp) {
40 40 app->dataSourceController().loadProductItem(dataSourceUid, item);
41 41 }
42 42 }));
43 43
44 44 return result;
45 45 }
46 46
47 47 /// Creates the data source item relative to the plugin
48 48 std::unique_ptr<DataSourceItem> createDataSourceItem(const QUuid &dataSourceUid) noexcept
49 49 {
50 50 // Magnetic field products
51 51 auto magneticFieldFolder = std::make_unique<DataSourceItem>(DataSourceItemType::NODE,
52 52 QStringLiteral("_Magnetic field"));
53 53 magneticFieldFolder->appendChild(
54 54 createProductItem({{DataSourceItem::NAME_DATA_KEY, QStringLiteral("Scalar 10 Hz")},
55 55 {COSINUS_TYPE_KEY, "scalar"},
56 56 {COSINUS_FREQUENCY_KEY, 10.}},
57 57 dataSourceUid));
58 58 magneticFieldFolder->appendChild(
59 59 createProductItem({{DataSourceItem::NAME_DATA_KEY, QStringLiteral("Scalar 60 Hz")},
60 60 {COSINUS_TYPE_KEY, "scalar"},
61 61 {COSINUS_FREQUENCY_KEY, 60.}},
62 62 dataSourceUid));
63 63 magneticFieldFolder->appendChild(
64 64 createProductItem({{DataSourceItem::NAME_DATA_KEY, QStringLiteral("Scalar 100 Hz")},
65 65 {COSINUS_TYPE_KEY, "scalar"},
66 66 {COSINUS_FREQUENCY_KEY, 100.}},
67 67 dataSourceUid));
68 68 magneticFieldFolder->appendChild(
69 69 createProductItem({{DataSourceItem::NAME_DATA_KEY, QStringLiteral("Vector 10 Hz")},
70 70 {COSINUS_TYPE_KEY, "vector"},
71 71 {COSINUS_FREQUENCY_KEY, 10.}},
72 72 dataSourceUid));
73 73 magneticFieldFolder->appendChild(
74 74 createProductItem({{DataSourceItem::NAME_DATA_KEY, QStringLiteral("Vector 60 Hz")},
75 75 {COSINUS_TYPE_KEY, "vector"},
76 76 {COSINUS_FREQUENCY_KEY, 60.}},
77 77 dataSourceUid));
78 78 magneticFieldFolder->appendChild(
79 79 createProductItem({{DataSourceItem::NAME_DATA_KEY, QStringLiteral("Vector 100 Hz")},
80 80 {COSINUS_TYPE_KEY, "vector"},
81 81 {COSINUS_FREQUENCY_KEY, 100.}},
82 82 dataSourceUid));
83 83 magneticFieldFolder->appendChild(
84 84 createProductItem({{DataSourceItem::NAME_DATA_KEY, QStringLiteral("Spectrogram 1 Hz")},
85 85 {COSINUS_TYPE_KEY, "spectrogram"},
86 86 {COSINUS_FREQUENCY_KEY, 1.}},
87 87 dataSourceUid));
88 88
89 89 // Electric field products
90 90 auto electricFieldFolder = std::make_unique<DataSourceItem>(DataSourceItemType::NODE,
91 91 QStringLiteral("_Electric field"));
92 92
93 93 // Root
94 94 auto root = std::make_unique<DataSourceItem>(DataSourceItemType::NODE, DATA_SOURCE_NAME);
95 95 root->appendChild(std::move(magneticFieldFolder));
96 96 root->appendChild(std::move(electricFieldFolder));
97 97
98 98 return root;
99 99 }
100 100
101 101 } // namespace
102 102
103 103 void MockPlugin::initialize()
104 104 {
105 105 if (auto app = sqpApp) {
106 106 // Registers to the data source controller
107 107 auto &dataSourceController = app->dataSourceController();
108 108 auto dataSourceUid = dataSourceController.registerDataSource(DATA_SOURCE_NAME);
109 109
110 110 // Sets data source tree
111 111 dataSourceController.setDataSourceItem(dataSourceUid, createDataSourceItem(dataSourceUid));
112 112
113 113 // Sets data provider
114 114 dataSourceController.setDataProvider(dataSourceUid, createDataProvider());
115 115 }
116 116 else {
117 117 qCWarning(LOG_MockPlugin()) << tr("Can't access to SciQlop application");
118 118 }
119 119 }
@@ -1,195 +1,195
1 1 #include "CosinusProvider.h"
2 2 #include "MockDefs.h"
3 3
4 4 #include <Data/DataProviderParameters.h>
5 5 #include <Data/ScalarSeries.h>
6 6 #include <SqpApplication.h>
7 7 #include <Time/TimeController.h>
8 8 #include <Variable/Variable.h>
9 9 #include <Variable/VariableController.h>
10 10
11 11 #include <QObject>
12 12 #include <QtTest>
13 13
14 14 #include <cmath>
15 15 #include <memory>
16 16
17 17 namespace {
18 18
19 19 /// Path for the tests
20 20 const auto TESTS_RESOURCES_PATH = QFileInfo{
21 21 QString{MOCKPLUGIN_TESTS_RESOURCES_DIR},
22 22 "TestCosinusAcquisition"}.absoluteFilePath();
23 23
24 24 /// Format of dates in data files
25 25 const auto DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd hh:mm:ss:zzz");
26 26
27 27 /**
28 28 * Verifies that the data in the candidate series are identical to the data in the reference series
29 29 * in a specific range
30 30 * @param candidate the candidate data series
31 31 * @param range the range to check
32 32 * @param reference the reference data series
33 33 * @return true if the data of the candidate series and the reference series are identical in the
34 34 * range, false otherwise
35 35 */
36 36 bool checkDataSeries(std::shared_ptr<IDataSeries> candidate, const SqpRange &range,
37 37 std::shared_ptr<IDataSeries> reference)
38 38 {
39 39 if (candidate == nullptr || reference == nullptr) {
40 40 return candidate == reference;
41 41 }
42 42
43 43 auto referenceIt = reference->xAxisRange(range.m_TStart, range.m_TEnd);
44 44
45 45 qInfo() << "candidateSize" << std::distance(candidate->cbegin(), candidate->cend());
46 46 qInfo() << "refSize" << std::distance(referenceIt.first, referenceIt.second);
47 47
48 48 return std::equal(candidate->cbegin(), candidate->cend(), referenceIt.first, referenceIt.second,
49 49 [](const auto &it1, const auto &it2) {
50 50 // - milliseconds precision for time
51 51 // - 1e-6 precision for value
52 52 return std::abs(it1.x() - it2.x()) < 1e-3
53 53 && std::abs(it1.value() - it2.value()) < 1e-6;
54 54 });
55 55 }
56 56
57 57 } // namespace
58 58
59 59 /**
60 60 * @brief The TestCosinusAcquisition class tests acquisition in SciQlop (operations like zooms in,
61 61 * zooms out, pans) of data from CosinusProvider
62 62 * @sa CosinusProvider
63 63 */
64 64 class TestCosinusAcquisition : public QObject {
65 65 Q_OBJECT
66 66
67 67 private slots:
68 68 /// Input data for @sa testAcquisition()
69 69 void testAcquisition_data();
70 70 void testAcquisition();
71 71 };
72 72
73 73 void TestCosinusAcquisition::testAcquisition_data()
74 74 {
75 75 // ////////////// //
76 76 // Test structure //
77 77 // ////////////// //
78 78
79 79 QTest::addColumn<SqpRange>("referenceRange"); // Range for generating reference series
80 80 QTest::addColumn<SqpRange>("initialRange"); // First acquisition
81 81 QTest::addColumn<int>("operationDelay"); // Acquisitions to make
82 82 QTest::addColumn<std::vector<SqpRange> >("operations"); // Acquisitions to make
83 83
84 84 // ////////// //
85 85 // Test cases //
86 86 // ////////// //
87 87
88 88 auto dateTime = [](int year, int month, int day, int hours, int minutes, int seconds) {
89 89 return DateUtils::secondsSinceEpoch(
90 90 QDateTime{{year, month, day}, {hours, minutes, seconds}, Qt::UTC});
91 91 };
92 92
93 93 QTest::newRow("cosinus")
94 94 << SqpRange{dateTime(2017, 1, 1, 12, 0, 0), dateTime(2017, 1, 1, 13, 0, 0)}
95 95 << SqpRange{dateTime(2017, 1, 1, 12, 30, 0), dateTime(2017, 1, 1, 12, 35, 1)} << 250
96 96 << std::vector<SqpRange>{
97 97 // Pan (jump) left
98 98 SqpRange{dateTime(2017, 1, 1, 12, 45, 0), dateTime(2017, 1, 1, 12, 50, 0)},
99 99 // Pan (jump) right
100 100 SqpRange{dateTime(2017, 1, 1, 12, 15, 0), dateTime(2017, 1, 1, 12, 20, 0)},
101 101 // Pan (overlay) right
102 102 SqpRange{dateTime(2017, 1, 1, 12, 14, 0), dateTime(2017, 1, 1, 12, 19, 0)},
103 103 // Pan (overlay) left
104 104 SqpRange{dateTime(2017, 1, 1, 12, 15, 0), dateTime(2017, 1, 1, 12, 20, 0)},
105 105 // Pan (overlay) left
106 106 SqpRange{dateTime(2017, 1, 1, 12, 16, 0), dateTime(2017, 1, 1, 12, 21, 0)},
107 107 // Zoom in
108 108 SqpRange{dateTime(2017, 1, 1, 12, 17, 30), dateTime(2017, 1, 1, 12, 19, 30)},
109 109 // Zoom out
110 110 SqpRange{dateTime(2017, 1, 1, 12, 12, 30), dateTime(2017, 1, 1, 12, 24, 30)}};
111 111
112 112 QTest::newRow("cosinus_big")
113 113 << SqpRange{dateTime(2017, 1, 1, 1, 0, 0), dateTime(2017, 1, 5, 13, 0, 0)}
114 114 << SqpRange{dateTime(2017, 1, 2, 6, 30, 0), dateTime(2017, 1, 2, 18, 30, 0)} << 5000
115 115 << std::vector<SqpRange>{
116 116 // Pan (jump) left
117 117 SqpRange{dateTime(2017, 1, 1, 13, 30, 0), dateTime(2017, 1, 1, 18, 30, 0)},
118 118 // Pan (jump) right
119 119 SqpRange{dateTime(2017, 1, 3, 4, 30, 0), dateTime(2017, 1, 3, 10, 30, 0)},
120 120 // Pan (overlay) right
121 121 SqpRange{dateTime(2017, 1, 3, 8, 30, 0), dateTime(2017, 1, 3, 12, 30, 0)},
122 122 // Pan (overlay) left
123 123 SqpRange{dateTime(2017, 1, 2, 8, 30, 0), dateTime(2017, 1, 3, 10, 30, 0)},
124 124 // Pan (overlay) left
125 125 SqpRange{dateTime(2017, 1, 1, 12, 30, 0), dateTime(2017, 1, 3, 5, 30, 0)},
126 126 // Zoom in
127 127 SqpRange{dateTime(2017, 1, 2, 2, 30, 0), dateTime(2017, 1, 2, 8, 30, 0)},
128 128 // Zoom out
129 129 SqpRange{dateTime(2017, 1, 1, 14, 30, 0), dateTime(2017, 1, 3, 12, 30, 0)}};
130 130 }
131 131
132 132 void TestCosinusAcquisition::testAcquisition()
133 133 {
134 134 // Retrieves reference range
135 135 QFETCH(SqpRange, referenceRange);
136 136 CosinusProvider referenceProvider{};
137 137 auto dataSeries = referenceProvider.provideDataSeries(
138 138 referenceRange, {{COSINUS_TYPE_KEY, "scalar"}, {COSINUS_FREQUENCY_KEY, 10.}});
139 139
140 140 auto end = dataSeries->cend() - 1;
141 141 qInfo() << dataSeries->nbPoints() << dataSeries->cbegin()->x() << end->x();
142 142
143 143 /// Lambda used to validate a variable at each step
144 144 auto validateVariable
145 145 = [dataSeries](std::shared_ptr<Variable> variable, const SqpRange &range) {
146 146 // Checks that the variable's range has changed
147 147 qInfo() << "range vs expected range" << variable->range() << range;
148 148 QCOMPARE(variable->range(), range);
149 149
150 150 // Checks the variable's data series
151 151 QVERIFY(checkDataSeries(variable->dataSeries(), variable->cacheRange(), dataSeries));
152 152 };
153 153
154 154 // Creates variable
155 155 QFETCH(SqpRange, initialRange);
156 sqpApp->timeController().onTimeToUpdate(initialRange);
156 sqpApp->timeController().setDateTimeRange(initialRange);
157 157 auto provider = std::make_shared<CosinusProvider>();
158 158 auto variable = sqpApp->variableController().createVariable(
159 "MMS", {{COSINUS_TYPE_KEY, "scalar"}, {COSINUS_FREQUENCY_KEY, 10.}}, provider);
159 "MMS", {{COSINUS_TYPE_KEY, "scalar"}, {COSINUS_FREQUENCY_KEY, 10.}}, provider, initialRange);
160 160
161 161
162 162 QFETCH(int, operationDelay);
163 163 QTest::qWait(operationDelay);
164 164 validateVariable(variable, initialRange);
165 165
166 166 QTest::qWait(operationDelay);
167 167 // Makes operations on the variable
168 168 QFETCH(std::vector<SqpRange>, operations);
169 169 for (const auto &operation : operations) {
170 170 // Asks request on the variable and waits during its execution
171 171 sqpApp->variableController().onRequestDataLoading({variable}, operation, false);
172 172
173 173 QTest::qWait(operationDelay);
174 174 validateVariable(variable, operation);
175 175 }
176 176
177 177
178 178 for (const auto &operation : operations) {
179 179 // Asks request on the variable and waits during its execution
180 180 sqpApp->variableController().onRequestDataLoading({variable}, operation, false);
181 181 }
182 182 QTest::qWait(operationDelay);
183 183 validateVariable(variable, operations.back());
184 184 }
185 185
186 186 int main(int argc, char *argv[])
187 187 {
188 188 SqpApplication app{argc, argv};
189 189 app.setAttribute(Qt::AA_Use96Dpi, true);
190 190 TestCosinusAcquisition testObject{};
191 191 QTEST_SET_MAIN_SOURCE_PATH
192 192 return QTest::qExec(&testObject, argc, argv);
193 193 }
194 194
195 195 #include "TestCosinusAcquisition.moc"
General Comments 0
You need to be logged in to leave comments. Login now