##// END OF EJS Templates
Merge branch 'feature/GraphFixes' into develop
Alexandre Leroux -
r679:c3be9e8d665b merge
parent child
Show More
@@ -0,0 +1,42
1 #ifndef SCIQLOP_FINDVARIABLEOPERATION_H
2 #define SCIQLOP_FINDVARIABLEOPERATION_H
3
4 #include "Visualization/IVisualizationWidgetVisitor.h"
5
6 #include <Common/spimpl.h>
7
8 #include <set>
9
10 class IVisualizationWidget;
11 class Variable;
12
13 /**
14 * @brief The FindVariableOperation class defines an operation that traverses all of visualization
15 * widgets to determine which ones contain the variable passed as parameter. The result of the
16 * operation is the list of widgets that contain the variable.
17 */
18 class FindVariableOperation : public IVisualizationWidgetVisitor {
19 public:
20 /**
21 * Ctor
22 * @param variable the variable to find
23 */
24 explicit FindVariableOperation(std::shared_ptr<Variable> variable);
25
26 void visitEnter(VisualizationWidget *widget) override final;
27 void visitLeave(VisualizationWidget *widget) override final;
28 void visitEnter(VisualizationTabWidget *tabWidget) override final;
29 void visitLeave(VisualizationTabWidget *tabWidget) override final;
30 void visitEnter(VisualizationZoneWidget *zoneWidget) override final;
31 void visitLeave(VisualizationZoneWidget *zoneWidget) override final;
32 void visit(VisualizationGraphWidget *graphWidget) override final;
33
34 /// @return the widgets that contain the variable
35 std::set<IVisualizationWidget *> result() const noexcept;
36
37 private:
38 class FindVariableOperationPrivate;
39 spimpl::unique_impl_ptr<FindVariableOperationPrivate> impl;
40 };
41
42 #endif // SCIQLOP_FINDVARIABLEOPERATION_H
@@ -0,0 +1,72
1 #include "Visualization/operations/FindVariableOperation.h"
2
3 #include "Visualization/VisualizationGraphWidget.h"
4 #include "Visualization/VisualizationTabWidget.h"
5 #include "Visualization/VisualizationWidget.h"
6 #include "Visualization/VisualizationZoneWidget.h"
7
8 #include <Variable/Variable.h>
9
10 struct FindVariableOperation::FindVariableOperationPrivate {
11 explicit FindVariableOperationPrivate(std::shared_ptr<Variable> variable) : m_Variable{variable}
12 {
13 }
14
15 void visit(IVisualizationWidget *widget)
16 {
17 if (m_Variable && widget && widget->contains(*m_Variable)) {
18 m_Containers.insert(widget);
19 }
20 }
21
22 std::shared_ptr<Variable> m_Variable; ///< Variable to find
23 std::set<IVisualizationWidget *> m_Containers; ///< Containers found for the variable
24 };
25
26 FindVariableOperation::FindVariableOperation(std::shared_ptr<Variable> variable)
27 : impl{spimpl::make_unique_impl<FindVariableOperationPrivate>(variable)}
28 {
29 }
30
31 void FindVariableOperation::visitEnter(VisualizationWidget *widget)
32 {
33 impl->visit(widget);
34 }
35
36 void FindVariableOperation::visitLeave(VisualizationWidget *widget)
37 {
38 // Does nothing
39 Q_UNUSED(widget);
40 }
41
42 void FindVariableOperation::visitEnter(VisualizationTabWidget *tabWidget)
43 {
44 impl->visit(tabWidget);
45 }
46
47 void FindVariableOperation::visitLeave(VisualizationTabWidget *tabWidget)
48 {
49 // Does nothing
50 Q_UNUSED(tabWidget);
51 }
52
53 void FindVariableOperation::visitEnter(VisualizationZoneWidget *zoneWidget)
54 {
55 impl->visit(zoneWidget);
56 }
57
58 void FindVariableOperation::visitLeave(VisualizationZoneWidget *zoneWidget)
59 {
60 // Does nothing
61 Q_UNUSED(zoneWidget);
62 }
63
64 void FindVariableOperation::visit(VisualizationGraphWidget *graphWidget)
65 {
66 impl->visit(graphWidget);
67 }
68
69 std::set<IVisualizationWidget *> FindVariableOperation::result() const noexcept
70 {
71 return impl->m_Containers;
72 }
@@ -1,129 +1,133
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 42 void setTimeController(TimeController *timeController) noexcept;
43 43
44 44 /**
45 45 * Clones the variable passed in parameter and adds the duplicate to the controller
46 46 * @param variable the variable to duplicate
47 47 * @return the duplicate created, nullptr if the variable couldn't be created
48 48 */
49 49 std::shared_ptr<Variable> cloneVariable(std::shared_ptr<Variable> variable) noexcept;
50 50
51 51 /**
52 52 * Deletes from the controller the variable passed in parameter.
53 53 *
54 54 * Delete a variable includes:
55 55 * - the deletion of the various references to the variable in SciQlop
56 56 * - the deletion of the model variable
57 57 * - the deletion of the provider associated with the variable
58 58 * - removing the cache associated with the variable
59 59 *
60 60 * @param variable the variable to delete from the controller.
61 61 */
62 62 void deleteVariable(std::shared_ptr<Variable> variable) noexcept;
63 63
64 64 /**
65 65 * Deletes from the controller the variables passed in parameter.
66 66 * @param variables the variables to delete from the controller.
67 67 * @sa deleteVariable()
68 68 */
69 69 void deleteVariables(const QVector<std::shared_ptr<Variable> > &variables) noexcept;
70 70
71 71 /**
72 72 * @brief abort the variable retrieve data progression
73 73 */
74 74 void abortProgress(std::shared_ptr<Variable> variable);
75 75
76 76 static AcquisitionZoomType getZoomType(const SqpRange &range, const SqpRange &oldRange);
77 77 signals:
78 78 /// Signal emitted when a variable is about to be deleted from the controller
79 79 void variableAboutToBeDeleted(std::shared_ptr<Variable> variable);
80 80
81 81 /// Signal emitted when a data acquisition is requested on a range for a variable
82 82 void rangeChanged(std::shared_ptr<Variable> variable, const SqpRange &range);
83 83
84 84 /// Signal emitted when a sub range of the cacheRange of the variable can be displayed
85 85 void updateVarDisplaying(std::shared_ptr<Variable> variable, const SqpRange &range);
86 86
87 87 public slots:
88 88 /// Request the data loading of the variable whithin range
89 89 void onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables, const SqpRange &range,
90 90 const SqpRange &oldRange, bool synchronise);
91 91 /**
92 92 * Creates a new variable and adds it to the model
93 93 * @param name the name of the new variable
94 94 * @param metadata the metadata of the new variable
95 95 * @param provider the data provider for the new variable
96 96 * @return the pointer to the new variable or nullptr if the creation failed
97 97 */
98 98 std::shared_ptr<Variable> createVariable(const QString &name, const QVariantHash &metadata,
99 99 std::shared_ptr<IDataProvider> provider) noexcept;
100 100
101 101 /// Update the temporal parameters of every selected variable to dateTime
102 102 void onDateTimeOnSelection(const SqpRange &dateTime);
103 103
104 104
105 105 void onDataProvided(QUuid vIdentifier, const SqpRange &rangeRequested,
106 106 const SqpRange &cacheRangeRequested,
107 107 QVector<AcquisitionDataPacket> dataAcquired);
108 108
109 109 void onVariableRetrieveDataInProgress(QUuid identifier, double progress);
110 110
111 111 /// Cancel the current request for the variable
112 112 void onAbortProgressRequested(std::shared_ptr<Variable> variable);
113 113
114 /// synchronization group methods
114 // synchronization group methods
115 115 void onAddSynchronizationGroupId(QUuid synchronizationGroupId);
116 116 void onRemoveSynchronizationGroupId(QUuid synchronizationGroupId);
117 117 void onAddSynchronized(std::shared_ptr<Variable> variable, QUuid synchronizationGroupId);
118 118
119 /// Desynchronizes the variable of the group whose identifier is passed in parameter
120 /// @remarks the method does nothing if the variable is not part of the group
121 void desynchronize(std::shared_ptr<Variable> variable, QUuid synchronizationGroupId);
122
119 123 void initialize();
120 124 void finalize();
121 125
122 126 private:
123 127 void waitForFinish();
124 128
125 129 class VariableControllerPrivate;
126 130 spimpl::unique_impl_ptr<VariableControllerPrivate> impl;
127 131 };
128 132
129 133 #endif // SCIQLOP_VARIABLECONTROLLER_H
@@ -1,775 +1,805
1 1 #include <Variable/Variable.h>
2 2 #include <Variable/VariableAcquisitionWorker.h>
3 3 #include <Variable/VariableCacheStrategy.h>
4 4 #include <Variable/VariableController.h>
5 5 #include <Variable/VariableModel.h>
6 6 #include <Variable/VariableSynchronizationGroup.h>
7 7
8 8 #include <Data/DataProviderParameters.h>
9 9 #include <Data/IDataProvider.h>
10 10 #include <Data/IDataSeries.h>
11 11 #include <Data/VariableRequest.h>
12 12 #include <Time/TimeController.h>
13 13
14 14 #include <QMutex>
15 15 #include <QThread>
16 16 #include <QUuid>
17 17 #include <QtCore/QItemSelectionModel>
18 18
19 19 #include <deque>
20 20 #include <set>
21 21 #include <unordered_map>
22 22
23 23 Q_LOGGING_CATEGORY(LOG_VariableController, "VariableController")
24 24
25 25 namespace {
26 26
27 27 SqpRange computeSynchroRangeRequested(const SqpRange &varRange, const SqpRange &graphRange,
28 28 const SqpRange &oldGraphRange)
29 29 {
30 30 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
31 31
32 32 auto varRangeRequested = varRange;
33 33 switch (zoomType) {
34 34 case AcquisitionZoomType::ZoomIn: {
35 35 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
36 36 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
37 37 varRangeRequested.m_TStart += deltaLeft;
38 38 varRangeRequested.m_TEnd -= deltaRight;
39 39 break;
40 40 }
41 41
42 42 case AcquisitionZoomType::ZoomOut: {
43 43 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
44 44 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
45 45 varRangeRequested.m_TStart -= deltaLeft;
46 46 varRangeRequested.m_TEnd += deltaRight;
47 47 break;
48 48 }
49 49 case AcquisitionZoomType::PanRight: {
50 50 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
51 51 varRangeRequested.m_TStart += deltaRight;
52 52 varRangeRequested.m_TEnd += deltaRight;
53 53 break;
54 54 }
55 55 case AcquisitionZoomType::PanLeft: {
56 56 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
57 57 varRangeRequested.m_TStart -= deltaLeft;
58 58 varRangeRequested.m_TEnd -= deltaLeft;
59 59 break;
60 60 }
61 61 case AcquisitionZoomType::Unknown: {
62 62 qCCritical(LOG_VariableController())
63 63 << VariableController::tr("Impossible to synchronize: zoom type unknown");
64 64 break;
65 65 }
66 66 default:
67 67 qCCritical(LOG_VariableController()) << VariableController::tr(
68 68 "Impossible to synchronize: zoom type not take into account");
69 69 // No action
70 70 break;
71 71 }
72 72
73 73 return varRangeRequested;
74 74 }
75 75 }
76 76
77 77 struct VariableController::VariableControllerPrivate {
78 78 explicit VariableControllerPrivate(VariableController *parent)
79 79 : m_WorkingMutex{},
80 80 m_VariableModel{new VariableModel{parent}},
81 81 m_VariableSelectionModel{new QItemSelectionModel{m_VariableModel, parent}},
82 82 m_VariableCacheStrategy{std::make_unique<VariableCacheStrategy>()},
83 83 m_VariableAcquisitionWorker{std::make_unique<VariableAcquisitionWorker>()},
84 84 q{parent}
85 85 {
86 86
87 87 m_VariableAcquisitionWorker->moveToThread(&m_VariableAcquisitionWorkerThread);
88 88 m_VariableAcquisitionWorkerThread.setObjectName("VariableAcquisitionWorkerThread");
89 89 }
90 90
91 91
92 92 virtual ~VariableControllerPrivate()
93 93 {
94 94 qCDebug(LOG_VariableController()) << tr("VariableControllerPrivate destruction");
95 95 m_VariableAcquisitionWorkerThread.quit();
96 96 m_VariableAcquisitionWorkerThread.wait();
97 97 }
98 98
99 99
100 100 void processRequest(std::shared_ptr<Variable> var, const SqpRange &rangeRequested,
101 101 QUuid varRequestId);
102 102
103 103 QVector<SqpRange> provideNotInCacheDateTimeList(std::shared_ptr<Variable> variable,
104 104 const SqpRange &dateTime);
105 105
106 106 std::shared_ptr<Variable> findVariable(QUuid vIdentifier);
107 107 std::shared_ptr<IDataSeries>
108 108 retrieveDataSeries(const QVector<AcquisitionDataPacket> acqDataPacketVector);
109 109
110 110 void registerProvider(std::shared_ptr<IDataProvider> provider);
111 111
112 112 void storeVariableRequest(QUuid varId, QUuid varRequestId, const VariableRequest &varRequest);
113 113 QUuid acceptVariableRequest(QUuid varId, std::shared_ptr<IDataSeries> dataSeries);
114 114 void updateVariableRequest(QUuid varRequestId);
115 115 void cancelVariableRequest(QUuid varRequestId);
116 116
117 117 QMutex m_WorkingMutex;
118 118 /// Variable model. The VariableController has the ownership
119 119 VariableModel *m_VariableModel;
120 120 QItemSelectionModel *m_VariableSelectionModel;
121 121
122 122
123 123 TimeController *m_TimeController{nullptr};
124 124 std::unique_ptr<VariableCacheStrategy> m_VariableCacheStrategy;
125 125 std::unique_ptr<VariableAcquisitionWorker> m_VariableAcquisitionWorker;
126 126 QThread m_VariableAcquisitionWorkerThread;
127 127
128 128 std::unordered_map<std::shared_ptr<Variable>, std::shared_ptr<IDataProvider> >
129 129 m_VariableToProviderMap;
130 130 std::unordered_map<std::shared_ptr<Variable>, QUuid> m_VariableToIdentifierMap;
131 131 std::map<QUuid, std::shared_ptr<VariableSynchronizationGroup> >
132 132 m_GroupIdToVariableSynchronizationGroupMap;
133 133 std::map<QUuid, QUuid> m_VariableIdGroupIdMap;
134 134 std::set<std::shared_ptr<IDataProvider> > m_ProviderSet;
135 135
136 136 std::map<QUuid, std::map<QUuid, VariableRequest> > m_VarRequestIdToVarIdVarRequestMap;
137 137
138 138 std::map<QUuid, std::deque<QUuid> > m_VarIdToVarRequestIdQueueMap;
139 139
140 140
141 141 VariableController *q;
142 142 };
143 143
144 144
145 145 VariableController::VariableController(QObject *parent)
146 146 : QObject{parent}, impl{spimpl::make_unique_impl<VariableControllerPrivate>(this)}
147 147 {
148 148 qCDebug(LOG_VariableController()) << tr("VariableController construction")
149 149 << QThread::currentThread();
150 150
151 151 connect(impl->m_VariableModel, &VariableModel::abortProgessRequested, this,
152 152 &VariableController::onAbortProgressRequested);
153 153
154 154 connect(impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::dataProvided, this,
155 155 &VariableController::onDataProvided);
156 156 connect(impl->m_VariableAcquisitionWorker.get(),
157 157 &VariableAcquisitionWorker::variableRequestInProgress, this,
158 158 &VariableController::onVariableRetrieveDataInProgress);
159 159
160 160 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::started,
161 161 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::initialize);
162 162 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::finished,
163 163 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::finalize);
164 164
165 165
166 166 impl->m_VariableAcquisitionWorkerThread.start();
167 167 }
168 168
169 169 VariableController::~VariableController()
170 170 {
171 171 qCDebug(LOG_VariableController()) << tr("VariableController destruction")
172 172 << QThread::currentThread();
173 173 this->waitForFinish();
174 174 }
175 175
176 176 VariableModel *VariableController::variableModel() noexcept
177 177 {
178 178 return impl->m_VariableModel;
179 179 }
180 180
181 181 QItemSelectionModel *VariableController::variableSelectionModel() noexcept
182 182 {
183 183 return impl->m_VariableSelectionModel;
184 184 }
185 185
186 186 void VariableController::setTimeController(TimeController *timeController) noexcept
187 187 {
188 188 impl->m_TimeController = timeController;
189 189 }
190 190
191 191 std::shared_ptr<Variable>
192 192 VariableController::cloneVariable(std::shared_ptr<Variable> variable) noexcept
193 193 {
194 194 if (impl->m_VariableModel->containsVariable(variable)) {
195 195 // Clones variable
196 196 auto duplicate = variable->clone();
197 197
198 198 // Adds clone to model
199 199 impl->m_VariableModel->addVariable(duplicate);
200 200
201 201 // Generates clone identifier
202 202 impl->m_VariableToIdentifierMap[duplicate] = QUuid::createUuid();
203 203
204 204 // Registers provider
205 205 auto variableProvider = impl->m_VariableToProviderMap.at(variable);
206 206 auto duplicateProvider = variableProvider != nullptr ? variableProvider->clone() : nullptr;
207 207
208 208 impl->m_VariableToProviderMap[duplicate] = duplicateProvider;
209 209 if (duplicateProvider) {
210 210 impl->registerProvider(duplicateProvider);
211 211 }
212 212
213 213 return duplicate;
214 214 }
215 215 else {
216 216 qCCritical(LOG_VariableController())
217 217 << tr("Can't create duplicate of variable %1: variable not registered in the model")
218 218 .arg(variable->name());
219 219 return nullptr;
220 220 }
221 221 }
222 222
223 223 void VariableController::deleteVariable(std::shared_ptr<Variable> variable) noexcept
224 224 {
225 225 if (!variable) {
226 226 qCCritical(LOG_VariableController()) << "Can't delete variable: variable is null";
227 227 return;
228 228 }
229 229
230 230 // Spreads in SciQlop that the variable will be deleted, so that potential receivers can
231 231 // make some treatments before the deletion
232 232 emit variableAboutToBeDeleted(variable);
233 233
234 234 // Deletes identifier
235 235 impl->m_VariableToIdentifierMap.erase(variable);
236 236
237 237 // Deletes provider
238 238 auto nbProvidersDeleted = impl->m_VariableToProviderMap.erase(variable);
239 239 qCDebug(LOG_VariableController())
240 240 << tr("Number of providers deleted for variable %1: %2")
241 241 .arg(variable->name(), QString::number(nbProvidersDeleted));
242 242
243 243
244 244 // Deletes from model
245 245 impl->m_VariableModel->deleteVariable(variable);
246 246 }
247 247
248 248 void VariableController::deleteVariables(
249 249 const QVector<std::shared_ptr<Variable> > &variables) noexcept
250 250 {
251 251 for (auto variable : qAsConst(variables)) {
252 252 deleteVariable(variable);
253 253 }
254 254 }
255 255
256 256 void VariableController::abortProgress(std::shared_ptr<Variable> variable)
257 257 {
258 258 }
259 259
260 260 std::shared_ptr<Variable>
261 261 VariableController::createVariable(const QString &name, const QVariantHash &metadata,
262 262 std::shared_ptr<IDataProvider> provider) noexcept
263 263 {
264 264 if (!impl->m_TimeController) {
265 265 qCCritical(LOG_VariableController())
266 266 << tr("Impossible to create variable: The time controller is null");
267 267 return nullptr;
268 268 }
269 269
270 270 auto range = impl->m_TimeController->dateTime();
271 271
272 272 if (auto newVariable = impl->m_VariableModel->createVariable(name, range, metadata)) {
273 273 auto identifier = QUuid::createUuid();
274 274
275 275 // store the provider
276 276 impl->registerProvider(provider);
277 277
278 278 // Associate the provider
279 279 impl->m_VariableToProviderMap[newVariable] = provider;
280 280 impl->m_VariableToIdentifierMap[newVariable] = identifier;
281 281
282 282
283 283 auto varRequestId = QUuid::createUuid();
284 284 qCInfo(LOG_VariableController()) << "processRequest for" << name << varRequestId;
285 285 impl->processRequest(newVariable, range, varRequestId);
286 286 impl->updateVariableRequest(varRequestId);
287 287
288 288 return newVariable;
289 289 }
290 290 }
291 291
292 292 void VariableController::onDateTimeOnSelection(const SqpRange &dateTime)
293 293 {
294 294 // TODO check synchronisation and Rescale
295 295 qCDebug(LOG_VariableController()) << "VariableController::onDateTimeOnSelection"
296 296 << QThread::currentThread()->objectName();
297 297 auto selectedRows = impl->m_VariableSelectionModel->selectedRows();
298 298 auto varRequestId = QUuid::createUuid();
299 299
300 300 for (const auto &selectedRow : qAsConst(selectedRows)) {
301 301 if (auto selectedVariable = impl->m_VariableModel->variable(selectedRow.row())) {
302 302 selectedVariable->setRange(dateTime);
303 303 impl->processRequest(selectedVariable, dateTime, varRequestId);
304 304
305 305 // notify that rescale operation has to be done
306 306 emit rangeChanged(selectedVariable, dateTime);
307 307 }
308 308 }
309 309 impl->updateVariableRequest(varRequestId);
310 310 }
311 311
312 312 void VariableController::onDataProvided(QUuid vIdentifier, const SqpRange &rangeRequested,
313 313 const SqpRange &cacheRangeRequested,
314 314 QVector<AcquisitionDataPacket> dataAcquired)
315 315 {
316 316 auto retrievedDataSeries = impl->retrieveDataSeries(dataAcquired);
317 317 auto varRequestId = impl->acceptVariableRequest(vIdentifier, retrievedDataSeries);
318 318 if (!varRequestId.isNull()) {
319 319 impl->updateVariableRequest(varRequestId);
320 320 }
321 321 }
322 322
323 323 void VariableController::onVariableRetrieveDataInProgress(QUuid identifier, double progress)
324 324 {
325 325 if (auto var = impl->findVariable(identifier)) {
326 326 impl->m_VariableModel->setDataProgress(var, progress);
327 327 }
328 328 else {
329 329 qCCritical(LOG_VariableController())
330 330 << tr("Impossible to notify progression of a null variable");
331 331 }
332 332 }
333 333
334 334 void VariableController::onAbortProgressRequested(std::shared_ptr<Variable> variable)
335 335 {
336 336 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAbortProgressRequested"
337 337 << QThread::currentThread()->objectName();
338 338
339 339 auto it = impl->m_VariableToIdentifierMap.find(variable);
340 340 if (it != impl->m_VariableToIdentifierMap.cend()) {
341 341 impl->m_VariableToProviderMap.at(variable)->requestDataAborting(it->second);
342 342 }
343 343 else {
344 344 qCWarning(LOG_VariableController())
345 345 << tr("Aborting progression of inexistant variable detected !!!")
346 346 << QThread::currentThread()->objectName();
347 347 }
348 348 }
349 349
350 350 void VariableController::onAddSynchronizationGroupId(QUuid synchronizationGroupId)
351 351 {
352 352 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronizationGroupId"
353 353 << QThread::currentThread()->objectName()
354 354 << synchronizationGroupId;
355 355 auto vSynchroGroup = std::make_shared<VariableSynchronizationGroup>();
356 356 impl->m_GroupIdToVariableSynchronizationGroupMap.insert(
357 357 std::make_pair(synchronizationGroupId, vSynchroGroup));
358 358 }
359 359
360 360 void VariableController::onRemoveSynchronizationGroupId(QUuid synchronizationGroupId)
361 361 {
362 362 impl->m_GroupIdToVariableSynchronizationGroupMap.erase(synchronizationGroupId);
363 363 }
364 364
365 365 void VariableController::onAddSynchronized(std::shared_ptr<Variable> variable,
366 366 QUuid synchronizationGroupId)
367 367
368 368 {
369 369 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronized"
370 370 << synchronizationGroupId;
371 371 auto varToVarIdIt = impl->m_VariableToIdentifierMap.find(variable);
372 372 if (varToVarIdIt != impl->m_VariableToIdentifierMap.cend()) {
373 373 auto groupIdToVSGIt
374 374 = impl->m_GroupIdToVariableSynchronizationGroupMap.find(synchronizationGroupId);
375 375 if (groupIdToVSGIt != impl->m_GroupIdToVariableSynchronizationGroupMap.cend()) {
376 376 impl->m_VariableIdGroupIdMap.insert(
377 377 std::make_pair(varToVarIdIt->second, synchronizationGroupId));
378 378 groupIdToVSGIt->second->addVariableId(varToVarIdIt->second);
379 379 }
380 380 else {
381 381 qCCritical(LOG_VariableController())
382 382 << tr("Impossible to synchronize a variable with an unknown sycnhronization group")
383 383 << variable->name();
384 384 }
385 385 }
386 386 else {
387 387 qCCritical(LOG_VariableController())
388 388 << tr("Impossible to synchronize a variable with no identifier") << variable->name();
389 389 }
390 390 }
391 391
392 void VariableController::desynchronize(std::shared_ptr<Variable> variable,
393 QUuid synchronizationGroupId)
394 {
395 // Gets variable id
396 auto variableIt = impl->m_VariableToIdentifierMap.find(variable);
397 if (variableIt == impl->m_VariableToIdentifierMap.cend()) {
398 qCCritical(LOG_VariableController())
399 << tr("Can't desynchronize variable %1: variable identifier not found")
400 .arg(variable->name());
401 return;
402 }
403
404 // Gets synchronization group
405 auto groupIt = impl->m_GroupIdToVariableSynchronizationGroupMap.find(synchronizationGroupId);
406 if (groupIt == impl->m_GroupIdToVariableSynchronizationGroupMap.cend()) {
407 qCCritical(LOG_VariableController())
408 << tr("Can't desynchronize variable %1: unknown synchronization group")
409 .arg(variable->name());
410 return;
411 }
412
413 auto variableId = variableIt->second;
414
415 // Removes variable from synchronization group
416 auto synchronizationGroup = groupIt->second;
417 synchronizationGroup->removeVariableId(variableId);
418
419 // Removes link between variable and synchronization group
420 impl->m_VariableIdGroupIdMap.erase(variableId);
421 }
392 422
393 423 void VariableController::onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables,
394 424 const SqpRange &range, const SqpRange &oldRange,
395 425 bool synchronise)
396 426 {
397 427 // NOTE: oldRange isn't really necessary since oldRange == variable->range().
398 428
399 429 // we want to load data of the variable for the dateTime.
400 430 // First we check if the cache contains some of them.
401 431 // For the other, we ask the provider to give them.
402 432
403 433 auto varRequestId = QUuid::createUuid();
404 434 qCInfo(LOG_VariableController()) << "VariableController::onRequestDataLoading"
405 435 << QThread::currentThread()->objectName() << varRequestId;
406 436
407 437 for (const auto &var : variables) {
408 438 qCDebug(LOG_VariableController()) << "processRequest for" << var->name() << varRequestId;
409 439 impl->processRequest(var, range, varRequestId);
410 440 }
411 441
412 442 if (synchronise) {
413 443 // Get the group ids
414 444 qCDebug(LOG_VariableController())
415 445 << "TORM VariableController::onRequestDataLoading for synchro var ENABLE";
416 446 auto groupIds = std::set<QUuid>{};
417 447 auto groupIdToOldRangeMap = std::map<QUuid, SqpRange>{};
418 448 for (const auto &var : variables) {
419 449 auto varToVarIdIt = impl->m_VariableToIdentifierMap.find(var);
420 450 if (varToVarIdIt != impl->m_VariableToIdentifierMap.cend()) {
421 451 auto vId = varToVarIdIt->second;
422 452 auto varIdToGroupIdIt = impl->m_VariableIdGroupIdMap.find(vId);
423 453 if (varIdToGroupIdIt != impl->m_VariableIdGroupIdMap.cend()) {
424 454 auto gId = varIdToGroupIdIt->second;
425 455 groupIdToOldRangeMap.insert(std::make_pair(gId, var->range()));
426 456 if (groupIds.find(gId) == groupIds.cend()) {
427 457 qCDebug(LOG_VariableController()) << "Synchro detect group " << gId;
428 458 groupIds.insert(gId);
429 459 }
430 460 }
431 461 }
432 462 }
433 463
434 464 // We assume here all group ids exist
435 465 for (const auto &gId : groupIds) {
436 466 auto vSynchronizationGroup = impl->m_GroupIdToVariableSynchronizationGroupMap.at(gId);
437 467 auto vSyncIds = vSynchronizationGroup->getIds();
438 468 qCDebug(LOG_VariableController()) << "Var in synchro group ";
439 469 for (auto vId : vSyncIds) {
440 470 auto var = impl->findVariable(vId);
441 471
442 472 // Don't process already processed var
443 473 if (!variables.contains(var)) {
444 474 if (var != nullptr) {
445 475 qCDebug(LOG_VariableController()) << "processRequest synchro for"
446 476 << var->name();
447 477 auto vSyncRangeRequested = computeSynchroRangeRequested(
448 478 var->range(), range, groupIdToOldRangeMap.at(gId));
449 479 qCDebug(LOG_VariableController()) << "synchro RR" << vSyncRangeRequested;
450 480 impl->processRequest(var, vSyncRangeRequested, varRequestId);
451 481 }
452 482 else {
453 483 qCCritical(LOG_VariableController())
454 484
455 485 << tr("Impossible to synchronize a null variable");
456 486 }
457 487 }
458 488 }
459 489 }
460 490 }
461 491
462 492 impl->updateVariableRequest(varRequestId);
463 493 }
464 494
465 495
466 496 void VariableController::initialize()
467 497 {
468 498 qCDebug(LOG_VariableController()) << tr("VariableController init") << QThread::currentThread();
469 499 impl->m_WorkingMutex.lock();
470 500 qCDebug(LOG_VariableController()) << tr("VariableController init END");
471 501 }
472 502
473 503 void VariableController::finalize()
474 504 {
475 505 impl->m_WorkingMutex.unlock();
476 506 }
477 507
478 508 void VariableController::waitForFinish()
479 509 {
480 510 QMutexLocker locker{&impl->m_WorkingMutex};
481 511 }
482 512
483 513 AcquisitionZoomType VariableController::getZoomType(const SqpRange &range, const SqpRange &oldRange)
484 514 {
485 515 // t1.m_TStart <= t2.m_TStart && t2.m_TEnd <= t1.m_TEnd
486 516 auto zoomType = AcquisitionZoomType::Unknown;
487 517 if (range.m_TStart <= oldRange.m_TStart && oldRange.m_TEnd <= range.m_TEnd) {
488 518 zoomType = AcquisitionZoomType::ZoomOut;
489 519 }
490 520 else if (range.m_TStart > oldRange.m_TStart && range.m_TEnd > oldRange.m_TEnd) {
491 521 zoomType = AcquisitionZoomType::PanRight;
492 522 }
493 523 else if (range.m_TStart < oldRange.m_TStart && range.m_TEnd < oldRange.m_TEnd) {
494 524 zoomType = AcquisitionZoomType::PanLeft;
495 525 }
496 526 else if (range.m_TStart > oldRange.m_TStart && oldRange.m_TEnd > range.m_TEnd) {
497 527 zoomType = AcquisitionZoomType::ZoomIn;
498 528 }
499 529 else {
500 530 qCCritical(LOG_VariableController()) << "getZoomType: Unknown type detected";
501 531 }
502 532 return zoomType;
503 533 }
504 534
505 535 void VariableController::VariableControllerPrivate::processRequest(std::shared_ptr<Variable> var,
506 536 const SqpRange &rangeRequested,
507 537 QUuid varRequestId)
508 538 {
509 539
510 540 // TODO: protect at
511 541 auto varRequest = VariableRequest{};
512 542 auto varId = m_VariableToIdentifierMap.at(var);
513 543
514 544 auto varStrategyRangesRequested
515 545 = m_VariableCacheStrategy->computeStrategyRanges(var->range(), rangeRequested);
516 546 auto notInCacheRangeList = var->provideNotInCacheRangeList(varStrategyRangesRequested.second);
517 547 auto inCacheRangeList = var->provideInCacheRangeList(varStrategyRangesRequested.second);
518 548
519 549 if (!notInCacheRangeList.empty()) {
520 550 varRequest.m_RangeRequested = varStrategyRangesRequested.first;
521 551 varRequest.m_CacheRangeRequested = varStrategyRangesRequested.second;
522 552 qCDebug(LOG_VariableAcquisitionWorker()) << tr("TORM processRequest RR ") << rangeRequested;
523 553 qCDebug(LOG_VariableAcquisitionWorker()) << tr("TORM processRequest R ")
524 554 << varStrategyRangesRequested.first;
525 555 qCDebug(LOG_VariableAcquisitionWorker()) << tr("TORM processRequest CR ")
526 556 << varStrategyRangesRequested.second;
527 557 // store VarRequest
528 558 storeVariableRequest(varId, varRequestId, varRequest);
529 559
530 560 auto varProvider = m_VariableToProviderMap.at(var);
531 561 if (varProvider != nullptr) {
532 562 auto varRequestIdCanceled = m_VariableAcquisitionWorker->pushVariableRequest(
533 563 varRequestId, varId, varStrategyRangesRequested.first,
534 564 varStrategyRangesRequested.second,
535 565 DataProviderParameters{std::move(notInCacheRangeList), var->metadata()},
536 566 varProvider);
537 567
538 568 if (!varRequestIdCanceled.isNull()) {
539 569 qCInfo(LOG_VariableAcquisitionWorker()) << tr("varRequestIdCanceled: ")
540 570 << varRequestIdCanceled;
541 571 cancelVariableRequest(varRequestIdCanceled);
542 572 }
543 573 }
544 574 else {
545 575 qCCritical(LOG_VariableController())
546 576 << "Impossible to provide data with a null provider";
547 577 }
548 578
549 579 if (!inCacheRangeList.empty()) {
550 580 emit q->updateVarDisplaying(var, inCacheRangeList.first());
551 581 }
552 582 }
553 583 else {
554 584
555 585 varRequest.m_RangeRequested = varStrategyRangesRequested.first;
556 586 varRequest.m_CacheRangeRequested = varStrategyRangesRequested.second;
557 587 // store VarRequest
558 588 storeVariableRequest(varId, varRequestId, varRequest);
559 589 acceptVariableRequest(varId,
560 590 var->dataSeries()->subDataSeries(varStrategyRangesRequested.second));
561 591 }
562 592 }
563 593
564 594 std::shared_ptr<Variable>
565 595 VariableController::VariableControllerPrivate::findVariable(QUuid vIdentifier)
566 596 {
567 597 std::shared_ptr<Variable> var;
568 598 auto findReply = [vIdentifier](const auto &entry) { return vIdentifier == entry.second; };
569 599
570 600 auto end = m_VariableToIdentifierMap.cend();
571 601 auto it = std::find_if(m_VariableToIdentifierMap.cbegin(), end, findReply);
572 602 if (it != end) {
573 603 var = it->first;
574 604 }
575 605 else {
576 606 qCCritical(LOG_VariableController())
577 607 << tr("Impossible to find the variable with the identifier: ") << vIdentifier;
578 608 }
579 609
580 610 return var;
581 611 }
582 612
583 613 std::shared_ptr<IDataSeries> VariableController::VariableControllerPrivate::retrieveDataSeries(
584 614 const QVector<AcquisitionDataPacket> acqDataPacketVector)
585 615 {
586 616 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size")
587 617 << acqDataPacketVector.size();
588 618 std::shared_ptr<IDataSeries> dataSeries;
589 619 if (!acqDataPacketVector.isEmpty()) {
590 620 dataSeries = acqDataPacketVector[0].m_DateSeries;
591 621 for (int i = 1; i < acqDataPacketVector.size(); ++i) {
592 622 dataSeries->merge(acqDataPacketVector[i].m_DateSeries.get());
593 623 }
594 624 }
595 625 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size END")
596 626 << acqDataPacketVector.size();
597 627 return dataSeries;
598 628 }
599 629
600 630 void VariableController::VariableControllerPrivate::registerProvider(
601 631 std::shared_ptr<IDataProvider> provider)
602 632 {
603 633 if (m_ProviderSet.find(provider) == m_ProviderSet.end()) {
604 634 qCDebug(LOG_VariableController()) << tr("Registering of a new provider")
605 635 << provider->objectName();
606 636 m_ProviderSet.insert(provider);
607 637 connect(provider.get(), &IDataProvider::dataProvided, m_VariableAcquisitionWorker.get(),
608 638 &VariableAcquisitionWorker::onVariableDataAcquired);
609 639 connect(provider.get(), &IDataProvider::dataProvidedProgress,
610 640 m_VariableAcquisitionWorker.get(),
611 641 &VariableAcquisitionWorker::onVariableRetrieveDataInProgress);
612 642 }
613 643 else {
614 644 qCDebug(LOG_VariableController()) << tr("Cannot register provider, it already exists ");
615 645 }
616 646 }
617 647
618 648 void VariableController::VariableControllerPrivate::storeVariableRequest(
619 649 QUuid varId, QUuid varRequestId, const VariableRequest &varRequest)
620 650 {
621 651 // First request for the variable. we can create an entry for it
622 652 auto varIdToVarRequestIdQueueMapIt = m_VarIdToVarRequestIdQueueMap.find(varId);
623 653 if (varIdToVarRequestIdQueueMapIt == m_VarIdToVarRequestIdQueueMap.cend()) {
624 654 auto varRequestIdQueue = std::deque<QUuid>{};
625 655 qCDebug(LOG_VariableController()) << tr("Store REQUEST in QUEUE");
626 656 varRequestIdQueue.push_back(varRequestId);
627 657 m_VarIdToVarRequestIdQueueMap.insert(std::make_pair(varId, std::move(varRequestIdQueue)));
628 658 }
629 659 else {
630 660 qCDebug(LOG_VariableController()) << tr("Store REQUEST in EXISTING QUEUE");
631 661 auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second;
632 662 varRequestIdQueue.push_back(varRequestId);
633 663 }
634 664
635 665 auto varRequestIdToVarIdVarRequestMapIt = m_VarRequestIdToVarIdVarRequestMap.find(varRequestId);
636 666 if (varRequestIdToVarIdVarRequestMapIt == m_VarRequestIdToVarIdVarRequestMap.cend()) {
637 667 auto varIdToVarRequestMap = std::map<QUuid, VariableRequest>{};
638 668 varIdToVarRequestMap.insert(std::make_pair(varId, varRequest));
639 669 qCDebug(LOG_VariableController()) << tr("Store REQUESTID in MAP");
640 670 m_VarRequestIdToVarIdVarRequestMap.insert(
641 671 std::make_pair(varRequestId, std::move(varIdToVarRequestMap)));
642 672 }
643 673 else {
644 674 auto &varIdToVarRequestMap = varRequestIdToVarIdVarRequestMapIt->second;
645 675 qCDebug(LOG_VariableController()) << tr("Store REQUESTID in EXISTING MAP");
646 676 varIdToVarRequestMap.insert(std::make_pair(varId, varRequest));
647 677 }
648 678 }
649 679
650 680 QUuid VariableController::VariableControllerPrivate::acceptVariableRequest(
651 681 QUuid varId, std::shared_ptr<IDataSeries> dataSeries)
652 682 {
653 683 QUuid varRequestId;
654 684 auto varIdToVarRequestIdQueueMapIt = m_VarIdToVarRequestIdQueueMap.find(varId);
655 685 if (varIdToVarRequestIdQueueMapIt != m_VarIdToVarRequestIdQueueMap.cend()) {
656 686 auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second;
657 687 varRequestId = varRequestIdQueue.front();
658 688 auto varRequestIdToVarIdVarRequestMapIt
659 689 = m_VarRequestIdToVarIdVarRequestMap.find(varRequestId);
660 690 if (varRequestIdToVarIdVarRequestMapIt != m_VarRequestIdToVarIdVarRequestMap.cend()) {
661 691 auto &varIdToVarRequestMap = varRequestIdToVarIdVarRequestMapIt->second;
662 692 auto varIdToVarRequestMapIt = varIdToVarRequestMap.find(varId);
663 693 if (varIdToVarRequestMapIt != varIdToVarRequestMap.cend()) {
664 694 qCDebug(LOG_VariableController()) << tr("acceptVariableRequest");
665 695 auto &varRequest = varIdToVarRequestMapIt->second;
666 696 varRequest.m_DataSeries = dataSeries;
667 697 varRequest.m_CanUpdate = true;
668 698 }
669 699 else {
670 700 qCDebug(LOG_VariableController())
671 701 << tr("Impossible to acceptVariableRequest of a unknown variable id attached "
672 702 "to a variableRequestId")
673 703 << varRequestId << varId;
674 704 }
675 705 }
676 706 else {
677 707 qCCritical(LOG_VariableController())
678 708 << tr("Impossible to acceptVariableRequest of a unknown variableRequestId")
679 709 << varRequestId;
680 710 }
681 711
682 712 qCDebug(LOG_VariableController()) << tr("1: erase REQUEST in QUEUE ?")
683 713 << varRequestIdQueue.size();
684 714 varRequestIdQueue.pop_front();
685 715 qCDebug(LOG_VariableController()) << tr("2: erase REQUEST in QUEUE ?")
686 716 << varRequestIdQueue.size();
687 717 if (varRequestIdQueue.empty()) {
688 718 m_VarIdToVarRequestIdQueueMap.erase(varId);
689 719 }
690 720 }
691 721 else {
692 722 qCCritical(LOG_VariableController())
693 723 << tr("Impossible to acceptVariableRequest of a unknown variable id") << varId;
694 724 }
695 725
696 726 return varRequestId;
697 727 }
698 728
699 729 void VariableController::VariableControllerPrivate::updateVariableRequest(QUuid varRequestId)
700 730 {
701 731
702 732 auto varRequestIdToVarIdVarRequestMapIt = m_VarRequestIdToVarIdVarRequestMap.find(varRequestId);
703 733 if (varRequestIdToVarIdVarRequestMapIt != m_VarRequestIdToVarIdVarRequestMap.cend()) {
704 734 bool processVariableUpdate = true;
705 735 auto &varIdToVarRequestMap = varRequestIdToVarIdVarRequestMapIt->second;
706 736 for (auto varIdToVarRequestMapIt = varIdToVarRequestMap.cbegin();
707 737 (varIdToVarRequestMapIt != varIdToVarRequestMap.cend()) && processVariableUpdate;
708 738 ++varIdToVarRequestMapIt) {
709 739 processVariableUpdate &= varIdToVarRequestMapIt->second.m_CanUpdate;
710 740 qCDebug(LOG_VariableController()) << tr("updateVariableRequest")
711 741 << processVariableUpdate;
712 742 }
713 743
714 744 if (processVariableUpdate) {
715 745 for (auto varIdToVarRequestMapIt = varIdToVarRequestMap.cbegin();
716 746 varIdToVarRequestMapIt != varIdToVarRequestMap.cend(); ++varIdToVarRequestMapIt) {
717 747 if (auto var = findVariable(varIdToVarRequestMapIt->first)) {
718 748 auto &varRequest = varIdToVarRequestMapIt->second;
719 749 var->setRange(varRequest.m_RangeRequested);
720 750 var->setCacheRange(varRequest.m_CacheRangeRequested);
721 751 qCDebug(LOG_VariableController()) << tr("1: onDataProvided")
722 752 << varRequest.m_RangeRequested;
723 753 qCDebug(LOG_VariableController()) << tr("2: onDataProvided")
724 754 << varRequest.m_CacheRangeRequested;
725 755 var->mergeDataSeries(varRequest.m_DataSeries);
726 756 qCDebug(LOG_VariableController()) << tr("3: onDataProvided")
727 757 << varRequest.m_DataSeries->range();
728 758 qCDebug(LOG_VariableController()) << tr("4: onDataProvided");
729 759
730 760 /// @todo MPL: confirm
731 761 // Variable update is notified only if there is no pending request for it
732 762 if (m_VarIdToVarRequestIdQueueMap.count(varIdToVarRequestMapIt->first) == 0) {
733 763 emit var->updated();
734 764 }
735 765 }
736 766 else {
737 767 qCCritical(LOG_VariableController())
738 768 << tr("Impossible to update data to a null variable");
739 769 }
740 770 }
741 771
742 772 // cleaning varRequestId
743 773 qCDebug(LOG_VariableController()) << tr("0: erase REQUEST in MAP ?")
744 774 << m_VarRequestIdToVarIdVarRequestMap.size();
745 775 m_VarRequestIdToVarIdVarRequestMap.erase(varRequestId);
746 776 qCDebug(LOG_VariableController()) << tr("1: erase REQUEST in MAP ?")
747 777 << m_VarRequestIdToVarIdVarRequestMap.size();
748 778 }
749 779 }
750 780 else {
751 781 qCCritical(LOG_VariableController())
752 782 << tr("Cannot updateVariableRequest for a unknow varRequestId") << varRequestId;
753 783 }
754 784 }
755 785
756 786 void VariableController::VariableControllerPrivate::cancelVariableRequest(QUuid varRequestId)
757 787 {
758 788 // cleaning varRequestId
759 789 m_VarRequestIdToVarIdVarRequestMap.erase(varRequestId);
760 790
761 791 for (auto varIdToVarRequestIdQueueMapIt = m_VarIdToVarRequestIdQueueMap.begin();
762 792 varIdToVarRequestIdQueueMapIt != m_VarIdToVarRequestIdQueueMap.end();) {
763 793 auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second;
764 794 varRequestIdQueue.erase(
765 795 std::remove(varRequestIdQueue.begin(), varRequestIdQueue.end(), varRequestId),
766 796 varRequestIdQueue.end());
767 797 if (varRequestIdQueue.empty()) {
768 798 varIdToVarRequestIdQueueMapIt
769 799 = m_VarIdToVarRequestIdQueueMap.erase(varIdToVarRequestIdQueueMapIt);
770 800 }
771 801 else {
772 802 ++varIdToVarRequestIdQueueMapIt;
773 803 }
774 804 }
775 805 }
@@ -1,94 +1,98
1 1 #ifndef SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
2 2 #define SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
3 3
4 4 #include "Visualization/IVisualizationWidget.h"
5 5
6 6 #include <QLoggingCategory>
7 7 #include <QWidget>
8 8
9 9 #include <memory>
10 10
11 11 #include <Common/spimpl.h>
12 12
13 13 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationGraphWidget)
14 14
15 15 class QCPRange;
16 16 class QCustomPlot;
17 17 class SqpRange;
18 18 class Variable;
19 19
20 20 namespace Ui {
21 21 class VisualizationGraphWidget;
22 22 } // namespace Ui
23 23
24 24 class VisualizationGraphWidget : public QWidget, public IVisualizationWidget {
25 25 Q_OBJECT
26 26
27 27 friend class QCustomPlotSynchronizer;
28 28 friend class VisualizationGraphRenderingDelegate;
29 29
30 30 public:
31 31 explicit VisualizationGraphWidget(const QString &name = {}, QWidget *parent = 0);
32 32 virtual ~VisualizationGraphWidget();
33 33
34 34 /// If acquisition isn't enable, requestDataLoading signal cannot be emit
35 35 void enableAcquisition(bool enable);
36 36
37 37 void addVariable(std::shared_ptr<Variable> variable, SqpRange range);
38 38
39 39 /// Removes a variable from the graph
40 40 void removeVariable(std::shared_ptr<Variable> variable) noexcept;
41 41
42 42 void setRange(std::shared_ptr<Variable> variable, const SqpRange &range);
43 43 void setYRange(const SqpRange &range);
44 44 SqpRange graphRange() const noexcept;
45 45 void setGraphRange(const SqpRange &range);
46 46
47 47 // IVisualizationWidget interface
48 48 void accept(IVisualizationWidgetVisitor *visitor) override;
49 49 bool canDrop(const Variable &variable) const override;
50 50 bool contains(const Variable &variable) const override;
51 51 QString name() const override;
52 52
53 53
54 54 signals:
55 55 void synchronize(const SqpRange &range, const SqpRange &oldRange);
56 56 void requestDataLoading(QVector<std::shared_ptr<Variable> > variable, const SqpRange &range,
57 57 const SqpRange &oldRange, bool synchronise);
58 58
59 /// Signal emitted when the variable is about to be removed from the graph
60 void variableAboutToBeRemoved(std::shared_ptr<Variable> var);
61 /// Signal emitted when the variable has been added to the graph
59 62 void variableAdded(std::shared_ptr<Variable> var);
60 63
61 64 protected:
65 void closeEvent(QCloseEvent *event) override;
62 66 void enterEvent(QEvent *event) override;
63 67 void leaveEvent(QEvent *event) override;
64 68
65 69 QCustomPlot &plot() noexcept;
66 70
67 71 private:
68 72 Ui::VisualizationGraphWidget *ui;
69 73
70 74 class VisualizationGraphWidgetPrivate;
71 75 spimpl::unique_impl_ptr<VisualizationGraphWidgetPrivate> impl;
72 76
73 77 private slots:
74 78 /// Slot called when right clicking on the graph (displays a menu)
75 79 void onGraphMenuRequested(const QPoint &pos) noexcept;
76 80
77 81 /// Rescale the X axe to range parameter
78 82 void onRangeChanged(const QCPRange &t1, const QCPRange &t2);
79 83
80 84 /// Slot called when a mouse move was made
81 85 void onMouseMove(QMouseEvent *event) noexcept;
82 86 /// Slot called when a mouse wheel was made, to perform some processing before the zoom is done
83 87 void onMouseWheel(QWheelEvent *event) noexcept;
84 88 /// Slot called when a mouse press was made, to activate the calibration of a graph
85 89 void onMousePress(QMouseEvent *event) noexcept;
86 90 /// Slot called when a mouse release was made, to deactivate the calibration of a graph
87 91 void onMouseRelease(QMouseEvent *event) noexcept;
88 92
89 93 void onDataCacheVariableUpdated();
90 94
91 95 void onUpdateVarDisplaying(std::shared_ptr<Variable> variable, const SqpRange &range);
92 96 };
93 97
94 98 #endif // SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
@@ -1,54 +1,57
1 1 #ifndef SCIQLOP_VISUALIZATIONTABWIDGET_H
2 2 #define SCIQLOP_VISUALIZATIONTABWIDGET_H
3 3
4 4 #include "Visualization/IVisualizationWidget.h"
5 5
6 6 #include <Common/spimpl.h>
7 7
8 8 #include <QLoggingCategory>
9 9 #include <QWidget>
10 10
11 11 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationTabWidget)
12 12
13 13 class Variable;
14 14 class VisualizationZoneWidget;
15 15
16 16 namespace Ui {
17 17 class VisualizationTabWidget;
18 18 } // namespace Ui
19 19
20 20 class VisualizationTabWidget : public QWidget, public IVisualizationWidget {
21 21 Q_OBJECT
22 22
23 23 public:
24 24 explicit VisualizationTabWidget(const QString &name = {}, QWidget *parent = 0);
25 25 virtual ~VisualizationTabWidget();
26 26
27 27 /// Add a zone widget
28 28 void addZone(VisualizationZoneWidget *zoneWidget);
29 29
30 30 /**
31 31 * Creates a zone using a variable. The variable will be displayed in a new graph of the new
32 32 * zone.
33 33 * @param variable the variable for which to create the zone
34 34 * @return the pointer to the created zone
35 35 */
36 36 VisualizationZoneWidget *createZone(std::shared_ptr<Variable> variable);
37 37
38 38 // IVisualizationWidget interface
39 39 void accept(IVisualizationWidgetVisitor *visitor) override;
40 40 bool canDrop(const Variable &variable) const override;
41 41 bool contains(const Variable &variable) const override;
42 42 QString name() const override;
43 43
44 protected:
45 void closeEvent(QCloseEvent *event) override;
46
44 47 private:
45 48 /// @return the layout of tab in which zones are added
46 49 QLayout &tabLayout() const noexcept;
47 50
48 51 Ui::VisualizationTabWidget *ui;
49 52
50 53 class VisualizationTabWidgetPrivate;
51 54 spimpl::unique_impl_ptr<VisualizationTabWidgetPrivate> impl;
52 55 };
53 56
54 57 #endif // SCIQLOP_VISUALIZATIONTABWIDGET_H
@@ -1,51 +1,54
1 1 #ifndef SCIQLOP_VISUALIZATIONWIDGET_H
2 2 #define SCIQLOP_VISUALIZATIONWIDGET_H
3 3
4 4 #include "Visualization/IVisualizationWidget.h"
5 5 #include <Data/SqpRange.h>
6 6
7 7 #include <QLoggingCategory>
8 8 #include <QWidget>
9 9
10 10 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationWidget)
11 11
12 12 class QMenu;
13 13 class Variable;
14 14 class VisualizationTabWidget;
15 15
16 16 namespace Ui {
17 17 class VisualizationWidget;
18 18 } // namespace Ui
19 19
20 20 class VisualizationWidget : public QWidget, public IVisualizationWidget {
21 21 Q_OBJECT
22 22
23 23 public:
24 24 explicit VisualizationWidget(QWidget *parent = 0);
25 25 virtual ~VisualizationWidget();
26 26
27 27 // IVisualizationWidget interface
28 28 void accept(IVisualizationWidgetVisitor *visitor) override;
29 29 bool canDrop(const Variable &variable) const override;
30 30 bool contains(const Variable &variable) const override;
31 31 QString name() const override;
32 32
33 33 public slots:
34 34 /**
35 35 * Attaches to a menu the menu relative to the visualization of variables
36 36 * @param menu the parent menu of the generated menu
37 37 * @param variables the variables for which to generate the menu
38 38 */
39 39 void attachVariableMenu(QMenu *menu,
40 40 const QVector<std::shared_ptr<Variable> > &variables) noexcept;
41 41
42 42 /// Slot called when a variable is about to be deleted from SciQlop
43 43 void onVariableAboutToBeDeleted(std::shared_ptr<Variable> variable) noexcept;
44 44
45 45 void onRangeChanged(std::shared_ptr<Variable> variable, const SqpRange &range) noexcept;
46 46
47 protected:
48 void closeEvent(QCloseEvent *event) override;
49
47 50 private:
48 51 Ui::VisualizationWidget *ui;
49 52 };
50 53
51 54 #endif // VISUALIZATIONWIDGET_H
@@ -1,55 +1,60
1 1 #ifndef SCIQLOP_VISUALIZATIONZONEWIDGET_H
2 2 #define SCIQLOP_VISUALIZATIONZONEWIDGET_H
3 3
4 4 #include "Visualization/IVisualizationWidget.h"
5 5
6 6 #include <QLoggingCategory>
7 7 #include <QWidget>
8 8
9 9 #include <memory>
10 10
11 11 #include <Common/spimpl.h>
12 12
13 13 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationZoneWidget)
14 14
15 15 namespace Ui {
16 16 class VisualizationZoneWidget;
17 17 } // Ui
18 18
19 19 class Variable;
20 20 class VisualizationGraphWidget;
21 21
22 22 class VisualizationZoneWidget : public QWidget, public IVisualizationWidget {
23 23 Q_OBJECT
24 24
25 25 public:
26 26 explicit VisualizationZoneWidget(const QString &name = {}, QWidget *parent = 0);
27 27 virtual ~VisualizationZoneWidget();
28 28
29 29 /// Add a graph widget
30 30 void addGraph(VisualizationGraphWidget *graphWidget);
31 31
32 32 /**
33 33 * Creates a graph using a variable. The variable will be displayed in the new graph.
34 34 * @param variable the variable for which to create the graph
35 35 * @return the pointer to the created graph
36 36 */
37 37 VisualizationGraphWidget *createGraph(std::shared_ptr<Variable> variable);
38 38
39 39 // IVisualizationWidget interface
40 40 void accept(IVisualizationWidgetVisitor *visitor) override;
41 41 bool canDrop(const Variable &variable) const override;
42 42 bool contains(const Variable &variable) const override;
43 43 QString name() const override;
44 44
45 protected:
46 void closeEvent(QCloseEvent *event) override;
47
45 48 private:
46 49 Ui::VisualizationZoneWidget *ui;
47 50
48 51 class VisualizationZoneWidgetPrivate;
49 52 spimpl::unique_impl_ptr<VisualizationZoneWidgetPrivate> impl;
50 53
51 54 private slots:
52 55 void onVariableAdded(std::shared_ptr<Variable> variable);
56 /// Slot called when a variable is about to be removed from a graph contained in the zone
57 void onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable);
53 58 };
54 59
55 60 #endif // SCIQLOP_VISUALIZATIONZONEWIDGET_H
@@ -1,42 +1,48
1 1 #ifndef SCIQLOP_GENERATEVARIABLEMENUOPERATION_H
2 2 #define SCIQLOP_GENERATEVARIABLEMENUOPERATION_H
3 3
4 4 #include "Visualization/IVisualizationWidgetVisitor.h"
5 5
6 6 #include <Common/spimpl.h>
7 7
8 8 #include <QLoggingCategory>
9 9
10 #include <set>
11
10 12 class QMenu;
13 class IVisualizationWidget;
11 14 class Variable;
12 15
13 16 Q_DECLARE_LOGGING_CATEGORY(LOG_GenerateVariableMenuOperation)
14 17
15 18 /**
16 19 * @brief The GenerateVariableMenuOperation class defines an operation that traverses all of
17 20 * visualization widgets to determine which can accommodate a variable. The result of the operation
18 21 * is a menu that contains actions to add the variable into the containers.
19 22 */
20 23 class GenerateVariableMenuOperation : public IVisualizationWidgetVisitor {
21 24 public:
22 25 /**
23 26 * Ctor
24 27 * @param menu the menu to which to attach the generated menu
25 28 * @param variable the variable for which to generate the menu
29 * @param variableContainers the containers that already contain the variable for which to
30 * generate the menu
26 31 */
27 explicit GenerateVariableMenuOperation(QMenu *menu, std::shared_ptr<Variable> variable);
32 explicit GenerateVariableMenuOperation(QMenu *menu, std::shared_ptr<Variable> variable,
33 std::set<IVisualizationWidget *> variableContainers);
28 34
29 35 void visitEnter(VisualizationWidget *widget) override final;
30 36 void visitLeave(VisualizationWidget *widget) override final;
31 37 void visitEnter(VisualizationTabWidget *tabWidget) override final;
32 38 void visitLeave(VisualizationTabWidget *tabWidget) override final;
33 39 void visitEnter(VisualizationZoneWidget *zoneWidget) override final;
34 40 void visitLeave(VisualizationZoneWidget *zoneWidget) override final;
35 41 void visit(VisualizationGraphWidget *graphWidget) override final;
36 42
37 43 private:
38 44 class GenerateVariableMenuOperationPrivate;
39 45 spimpl::unique_impl_ptr<GenerateVariableMenuOperationPrivate> impl;
40 46 };
41 47
42 48 #endif // SCIQLOP_GENERATEVARIABLEMENUOPERATION_H
@@ -1,76 +1,77
1 1
2 2 gui_moc_headers = [
3 3 'include/DataSource/DataSourceWidget.h',
4 4 'include/Settings/SqpSettingsDialog.h',
5 5 'include/Settings/SqpSettingsGeneralWidget.h',
6 6 'include/SidePane/SqpSidePane.h',
7 7 'include/SqpApplication.h',
8 8 'include/TimeWidget/TimeWidget.h',
9 9 'include/Variable/VariableInspectorWidget.h',
10 10 'include/Visualization/qcustomplot.h',
11 11 'include/Visualization/VisualizationGraphWidget.h',
12 12 'include/Visualization/VisualizationTabWidget.h',
13 13 'include/Visualization/VisualizationWidget.h',
14 14 'include/Visualization/VisualizationZoneWidget.h'
15 15 ]
16 16
17 17 gui_ui_files = [
18 18 'ui/DataSource/DataSourceWidget.ui',
19 19 'ui/Settings/SqpSettingsDialog.ui',
20 20 'ui/Settings/SqpSettingsGeneralWidget.ui',
21 21 'ui/SidePane/SqpSidePane.ui',
22 22 'ui/TimeWidget/TimeWidget.ui',
23 23 'ui/Variable/VariableInspectorWidget.ui',
24 24 'ui/Variable/VariableMenuHeaderWidget.ui',
25 25 'ui/Visualization/VisualizationGraphWidget.ui',
26 26 'ui/Visualization/VisualizationTabWidget.ui',
27 27 'ui/Visualization/VisualizationWidget.ui',
28 28 'ui/Visualization/VisualizationZoneWidget.ui'
29 29 ]
30 30
31 31 gui_qresources = ['resources/sqpguiresources.qrc']
32 32
33 33 gui_moc_files = qt5.preprocess(moc_headers : gui_moc_headers,
34 34 ui_files : gui_ui_files,
35 35 qresources : gui_qresources)
36 36
37 37 gui_sources = [
38 38 'src/SqpApplication.cpp',
39 39 'src/Common/ColorUtils.cpp',
40 40 'src/DataSource/DataSourceTreeWidgetItem.cpp',
41 41 'src/DataSource/DataSourceTreeWidgetHelper.cpp',
42 42 'src/DataSource/DataSourceWidget.cpp',
43 43 'src/Settings/SqpSettingsDialog.cpp',
44 44 'src/Settings/SqpSettingsGeneralWidget.cpp',
45 45 'src/SidePane/SqpSidePane.cpp',
46 46 'src/TimeWidget/TimeWidget.cpp',
47 47 'src/Variable/VariableInspectorWidget.cpp',
48 48 'src/Variable/VariableMenuHeaderWidget.cpp',
49 49 'src/Visualization/VisualizationGraphHelper.cpp',
50 50 'src/Visualization/VisualizationGraphRenderingDelegate.cpp',
51 51 'src/Visualization/VisualizationGraphWidget.cpp',
52 52 'src/Visualization/VisualizationTabWidget.cpp',
53 53 'src/Visualization/VisualizationWidget.cpp',
54 54 'src/Visualization/VisualizationZoneWidget.cpp',
55 55 'src/Visualization/qcustomplot.cpp',
56 56 'src/Visualization/QCustomPlotSynchronizer.cpp',
57 'src/Visualization/operations/FindVariableOperation.cpp',
57 58 'src/Visualization/operations/GenerateVariableMenuOperation.cpp',
58 59 'src/Visualization/operations/MenuBuilder.cpp',
59 60 'src/Visualization/operations/RemoveVariableOperation.cpp',
60 61 'src/Visualization/operations/RescaleAxeOperation.cpp'
61 62 ]
62 63
63 64 gui_inc = include_directories(['include'])
64 65
65 66 sciqlop_gui_lib = library('sciqlopgui',
66 67 gui_sources,
67 68 gui_moc_files,
68 69 include_directories : [gui_inc],
69 70 dependencies : [ qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core],
70 71 install : true
71 72 )
72 73
73 74 sciqlop_gui = declare_dependency(link_with : sciqlop_gui_lib,
74 75 include_directories : gui_inc,
75 76 dependencies : [qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core])
76 77
@@ -1,344 +1,356
1 1 #include "Visualization/VisualizationGraphWidget.h"
2 2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 3 #include "Visualization/VisualizationDefs.h"
4 4 #include "Visualization/VisualizationGraphHelper.h"
5 5 #include "Visualization/VisualizationGraphRenderingDelegate.h"
6 6 #include "ui_VisualizationGraphWidget.h"
7 7
8 8 #include <Data/ArrayData.h>
9 9 #include <Data/IDataSeries.h>
10 10 #include <Settings/SqpSettingsDefs.h>
11 11 #include <SqpApplication.h>
12 12 #include <Variable/Variable.h>
13 13 #include <Variable/VariableController.h>
14 14
15 15 #include <unordered_map>
16 16
17 17 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
18 18
19 19 namespace {
20 20
21 21 /// Key pressed to enable zoom on horizontal axis
22 22 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::NoModifier;
23 23
24 24 /// Key pressed to enable zoom on vertical axis
25 25 const auto VERTICAL_ZOOM_MODIFIER = Qt::ControlModifier;
26 26
27 27 } // namespace
28 28
29 29 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
30 30
31 31 explicit VisualizationGraphWidgetPrivate(const QString &name)
32 32 : m_Name{name},
33 33 m_DoAcquisition{true},
34 34 m_IsCalibration{false},
35 35 m_RenderingDelegate{nullptr}
36 36 {
37 37 }
38 38
39 39 QString m_Name;
40 40 // 1 variable -> n qcpplot
41 41 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
42 42 bool m_DoAcquisition;
43 43 bool m_IsCalibration;
44 44 QCPItemTracer *m_TextTracer;
45 45 /// Delegate used to attach rendering features to the plot
46 46 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
47 47 };
48 48
49 49 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
50 50 : QWidget{parent},
51 51 ui{new Ui::VisualizationGraphWidget},
52 52 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
53 53 {
54 54 ui->setupUi(this);
55 55
56 56 // 'Close' options : widget is deleted when closed
57 57 setAttribute(Qt::WA_DeleteOnClose);
58 58
59 59 // Set qcpplot properties :
60 60 // - Drag (on x-axis) and zoom are enabled
61 61 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
62 62 ui->widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectItems);
63 63 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal);
64 64
65 65 // The delegate must be initialized after the ui as it uses the plot
66 66 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
67 67
68 68 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
69 69 connect(ui->widget, &QCustomPlot::mouseRelease, this,
70 70 &VisualizationGraphWidget::onMouseRelease);
71 71 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
72 72 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
73 73 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
74 74 &QCPAxis::rangeChanged),
75 75 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
76 76
77 77 // Activates menu when right clicking on the graph
78 78 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
79 79 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
80 80 &VisualizationGraphWidget::onGraphMenuRequested);
81 81
82 82 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
83 83 &VariableController::onRequestDataLoading);
84 84
85 85 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
86 86 &VisualizationGraphWidget::onUpdateVarDisplaying);
87 87 }
88 88
89 89
90 90 VisualizationGraphWidget::~VisualizationGraphWidget()
91 91 {
92 92 delete ui;
93 93 }
94 94
95 95 void VisualizationGraphWidget::enableAcquisition(bool enable)
96 96 {
97 97 impl->m_DoAcquisition = enable;
98 98 }
99 99
100 100 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
101 101 {
102 102 // Uses delegate to create the qcpplot components according to the variable
103 103 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
104 104 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
105 105
106 106 // Set axes properties according to the units of the data series
107 107 /// @todo : for the moment, no control is performed on the axes: the units and the tickers
108 108 /// are fixed for the default x-axis and y-axis of the plot, and according to the new graph
109 109 auto xAxisUnit = Unit{};
110 110 auto valuesUnit = Unit{};
111 111
112 112 if (auto dataSeries = variable->dataSeries()) {
113 113 dataSeries->lockRead();
114 114 xAxisUnit = dataSeries->xAxisUnit();
115 115 valuesUnit = dataSeries->valuesUnit();
116 116 dataSeries->unlock();
117 117 }
118 118 impl->m_RenderingDelegate->setAxesProperties(xAxisUnit, valuesUnit);
119 119
120 120 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
121 121
122 122 auto varRange = variable->range();
123 123
124 124 this->enableAcquisition(false);
125 125 this->setGraphRange(range);
126 126 this->enableAcquisition(true);
127 127
128 128 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable, range, varRange,
129 129 false);
130 130
131 131 emit variableAdded(variable);
132 132 }
133 133
134 134 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
135 135 {
136 136 // Each component associated to the variable :
137 137 // - is removed from qcpplot (which deletes it)
138 138 // - is no longer referenced in the map
139 139 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
140 140 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
141 emit variableAboutToBeRemoved(variable);
142
141 143 auto &plottablesMap = variableIt->second;
142 144
143 145 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
144 146 plottableIt != plottableEnd;) {
145 147 ui->widget->removePlottable(plottableIt->second);
146 148 plottableIt = plottablesMap.erase(plottableIt);
147 149 }
148 150
149 151 impl->m_VariableToPlotMultiMap.erase(variableIt);
150 152 }
151 153
152 154 // Updates graph
153 155 ui->widget->replot();
154 156 }
155 157
156 158 void VisualizationGraphWidget::setRange(std::shared_ptr<Variable> variable, const SqpRange &range)
157 159 {
158 160 // Note: in case of different axes that depends on variable, we could start with a code like
159 161 // that:
160 162 // auto componentsIt = impl->m_VariableToPlotMultiMap.equal_range(variable);
161 163 // for (auto it = componentsIt.first; it != componentsIt.second;) {
162 164 // }
163 165 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
164 166 ui->widget->replot();
165 167 }
166 168
167 169 void VisualizationGraphWidget::setYRange(const SqpRange &range)
168 170 {
169 171 ui->widget->yAxis->setRange(range.m_TStart, range.m_TEnd);
170 172 }
171 173
172 174 SqpRange VisualizationGraphWidget::graphRange() const noexcept
173 175 {
174 176 auto graphRange = ui->widget->xAxis->range();
175 177 return SqpRange{graphRange.lower, graphRange.upper};
176 178 }
177 179
178 180 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
179 181 {
180 182 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
181 183 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
182 184 ui->widget->replot();
183 185 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
184 186 }
185 187
186 188 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
187 189 {
188 190 if (visitor) {
189 191 visitor->visit(this);
190 192 }
191 193 else {
192 194 qCCritical(LOG_VisualizationGraphWidget())
193 195 << tr("Can't visit widget : the visitor is null");
194 196 }
195 197 }
196 198
197 199 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
198 200 {
199 201 /// @todo : for the moment, a graph can always accomodate a variable
200 202 Q_UNUSED(variable);
201 203 return true;
202 204 }
203 205
204 206 bool VisualizationGraphWidget::contains(const Variable &variable) const
205 207 {
206 208 // Finds the variable among the keys of the map
207 209 auto variablePtr = &variable;
208 210 auto findVariable
209 211 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
210 212
211 213 auto end = impl->m_VariableToPlotMultiMap.cend();
212 214 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
213 215 return it != end;
214 216 }
215 217
216 218 QString VisualizationGraphWidget::name() const
217 219 {
218 220 return impl->m_Name;
219 221 }
220 222
223 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
224 {
225 Q_UNUSED(event);
226
227 // Prevents that all variables will be removed from graph when it will be closed
228 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
229 emit variableAboutToBeRemoved(variableEntry.first);
230 }
231 }
232
221 233 void VisualizationGraphWidget::enterEvent(QEvent *event)
222 234 {
223 235 Q_UNUSED(event);
224 236 impl->m_RenderingDelegate->showGraphOverlay(true);
225 237 }
226 238
227 239 void VisualizationGraphWidget::leaveEvent(QEvent *event)
228 240 {
229 241 Q_UNUSED(event);
230 242 impl->m_RenderingDelegate->showGraphOverlay(false);
231 243 }
232 244
233 245 QCustomPlot &VisualizationGraphWidget::plot() noexcept
234 246 {
235 247 return *ui->widget;
236 248 }
237 249
238 250 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
239 251 {
240 252 QMenu graphMenu{};
241 253
242 254 // Iterates on variables (unique keys)
243 255 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
244 256 end = impl->m_VariableToPlotMultiMap.cend();
245 257 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
246 258 // 'Remove variable' action
247 259 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
248 260 [ this, var = it->first ]() { removeVariable(var); });
249 261 }
250 262
251 263 if (!graphMenu.isEmpty()) {
252 264 graphMenu.exec(QCursor::pos());
253 265 }
254 266 }
255 267
256 268 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
257 269 {
258 270 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
259 271 << QThread::currentThread()->objectName() << "DoAcqui"
260 272 << impl->m_DoAcquisition;
261 273
262 274 auto graphRange = SqpRange{t1.lower, t1.upper};
263 275 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
264 276
265 277 if (impl->m_DoAcquisition) {
266 278 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
267 279
268 280 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
269 281 end = impl->m_VariableToPlotMultiMap.end();
270 282 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
271 283 variableUnderGraphVector.push_back(it->first);
272 284 }
273 285 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange, oldGraphRange,
274 286 !impl->m_IsCalibration);
275 287
276 288 if (!impl->m_IsCalibration) {
277 289 qCDebug(LOG_VisualizationGraphWidget())
278 290 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
279 291 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
280 292 emit synchronize(graphRange, oldGraphRange);
281 293 }
282 294 }
283 295 }
284 296
285 297 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
286 298 {
287 299 // Handles plot rendering when mouse is moving
288 300 impl->m_RenderingDelegate->onMouseMove(event);
289 301 }
290 302
291 303 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
292 304 {
293 305 auto zoomOrientations = QFlags<Qt::Orientation>{};
294 306
295 307 // Lambda that enables a zoom orientation if the key modifier related to this orientation
296 308 // has
297 309 // been pressed
298 310 auto enableOrientation
299 311 = [&zoomOrientations, event](const auto &orientation, const auto &modifier) {
300 312 auto orientationEnabled = event->modifiers().testFlag(modifier);
301 313 zoomOrientations.setFlag(orientation, orientationEnabled);
302 314 };
303 315 enableOrientation(Qt::Vertical, VERTICAL_ZOOM_MODIFIER);
304 316 enableOrientation(Qt::Horizontal, HORIZONTAL_ZOOM_MODIFIER);
305 317
306 318 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
307 319 }
308 320
309 321 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
310 322 {
311 323 impl->m_IsCalibration = event->modifiers().testFlag(Qt::ControlModifier);
312 324 }
313 325
314 326 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
315 327 {
316 328 impl->m_IsCalibration = false;
317 329 }
318 330
319 331 void VisualizationGraphWidget::onDataCacheVariableUpdated()
320 332 {
321 333 auto graphRange = ui->widget->xAxis->range();
322 334 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
323 335
324 336 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
325 337 auto variable = variableEntry.first;
326 338 qCDebug(LOG_VisualizationGraphWidget())
327 339 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
328 340 qCDebug(LOG_VisualizationGraphWidget())
329 341 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
330 342 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
331 343 VisualizationGraphHelper::updateData(variableEntry.second, variable->dataSeries(),
332 344 variable->range());
333 345 }
334 346 }
335 347 }
336 348
337 349 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
338 350 const SqpRange &range)
339 351 {
340 352 auto it = impl->m_VariableToPlotMultiMap.find(variable);
341 353 if (it != impl->m_VariableToPlotMultiMap.end()) {
342 354 VisualizationGraphHelper::updateData(it->second, variable->dataSeries(), range);
343 355 }
344 356 }
@@ -1,110 +1,129
1 1 #include "Visualization/VisualizationTabWidget.h"
2 2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 3 #include "ui_VisualizationTabWidget.h"
4 4
5 5 #include "Visualization/VisualizationZoneWidget.h"
6 6
7 7 Q_LOGGING_CATEGORY(LOG_VisualizationTabWidget, "VisualizationTabWidget")
8 8
9 9 namespace {
10 10
11 11 /// Generates a default name for a new zone, according to the number of zones already displayed in
12 12 /// the tab
13 13 QString defaultZoneName(const QLayout &layout)
14 14 {
15 15 auto count = 0;
16 16 for (auto i = 0; i < layout.count(); ++i) {
17 17 if (dynamic_cast<VisualizationZoneWidget *>(layout.itemAt(i)->widget())) {
18 18 count++;
19 19 }
20 20 }
21 21
22 22 return QObject::tr("Zone %1").arg(count + 1);
23 23 }
24 24
25 /**
26 * Applies a function to all zones of the tab represented by its layout
27 * @param layout the layout that contains zones
28 * @param fun the function to apply to each zone
29 */
30 template <typename Fun>
31 void processZones(QLayout &layout, Fun fun)
32 {
33 for (auto i = 0; i < layout.count(); ++i) {
34 if (auto item = layout.itemAt(i)) {
35 if (auto visualizationZoneWidget
36 = dynamic_cast<VisualizationZoneWidget *>(item->widget())) {
37 fun(*visualizationZoneWidget);
38 }
39 }
40 }
41 }
42
25 43 } // namespace
26 44
27 45 struct VisualizationTabWidget::VisualizationTabWidgetPrivate {
28 46 explicit VisualizationTabWidgetPrivate(const QString &name) : m_Name{name} {}
29 47
30 48 QString m_Name;
31 49 };
32 50
33 51 VisualizationTabWidget::VisualizationTabWidget(const QString &name, QWidget *parent)
34 52 : QWidget{parent},
35 53 ui{new Ui::VisualizationTabWidget},
36 54 impl{spimpl::make_unique_impl<VisualizationTabWidgetPrivate>(name)}
37 55 {
38 56 ui->setupUi(this);
39 57
40 58 // Widget is deleted when closed
41 59 setAttribute(Qt::WA_DeleteOnClose);
42 60 }
43 61
44 62 VisualizationTabWidget::~VisualizationTabWidget()
45 63 {
46 64 delete ui;
47 65 }
48 66
49 67 void VisualizationTabWidget::addZone(VisualizationZoneWidget *zoneWidget)
50 68 {
51 69 tabLayout().addWidget(zoneWidget);
52 70 }
53 71
54 72 VisualizationZoneWidget *VisualizationTabWidget::createZone(std::shared_ptr<Variable> variable)
55 73 {
56 74 auto zoneWidget = new VisualizationZoneWidget{defaultZoneName(tabLayout()), this};
57 75 this->addZone(zoneWidget);
58 76
59 77 // Creates a new graph into the zone
60 78 zoneWidget->createGraph(variable);
61 79
62 80 return zoneWidget;
63 81 }
64 82
65 83 void VisualizationTabWidget::accept(IVisualizationWidgetVisitor *visitor)
66 84 {
67 85 if (visitor) {
68 86 visitor->visitEnter(this);
69 87
70 // Apply visitor to zone children
71 auto &layout = tabLayout();
72 for (auto i = 0; i < layout.count(); ++i) {
73 if (auto item = layout.itemAt(i)) {
74 // Widgets different from zones are not visited (no action)
75 if (auto visualizationZoneWidget
76 = dynamic_cast<VisualizationZoneWidget *>(item->widget())) {
77 visualizationZoneWidget->accept(visitor);
78 }
79 }
80 }
88 // Apply visitor to zone children: widgets different from zones are not visited (no action)
89 processZones(tabLayout(), [visitor](VisualizationZoneWidget &zoneWidget) {
90 zoneWidget.accept(visitor);
91 });
81 92
82 93 visitor->visitLeave(this);
83 94 }
84 95 else {
85 96 qCCritical(LOG_VisualizationTabWidget()) << tr("Can't visit widget : the visitor is null");
86 97 }
87 98 }
88 99
89 100 bool VisualizationTabWidget::canDrop(const Variable &variable) const
90 101 {
91 102 // A tab can always accomodate a variable
92 103 Q_UNUSED(variable);
93 104 return true;
94 105 }
95 106
96 107 bool VisualizationTabWidget::contains(const Variable &variable) const
97 108 {
98 109 Q_UNUSED(variable);
99 110 return false;
100 111 }
101 112
102 113 QString VisualizationTabWidget::name() const
103 114 {
104 115 return impl->m_Name;
105 116 }
106 117
118 void VisualizationTabWidget::closeEvent(QCloseEvent *event)
119 {
120 // Closes zones in the tab
121 processZones(tabLayout(), [](VisualizationZoneWidget &zoneWidget) { zoneWidget.close(); });
122
123 QWidget::closeEvent(event);
124 }
125
107 126 QLayout &VisualizationTabWidget::tabLayout() const noexcept
108 127 {
109 128 return *ui->scrollAreaWidgetContents->layout();
110 129 }
@@ -1,152 +1,172
1 1 #include "Visualization/VisualizationWidget.h"
2 2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 3 #include "Visualization/VisualizationGraphWidget.h"
4 4 #include "Visualization/VisualizationTabWidget.h"
5 5 #include "Visualization/VisualizationZoneWidget.h"
6 #include "Visualization/operations/FindVariableOperation.h"
6 7 #include "Visualization/operations/GenerateVariableMenuOperation.h"
7 8 #include "Visualization/operations/RemoveVariableOperation.h"
8 9 #include "Visualization/operations/RescaleAxeOperation.h"
9 10 #include "Visualization/qcustomplot.h"
10 11
11 12 #include "ui_VisualizationWidget.h"
12 13
13 14 #include <QToolButton>
14 15
15 16 Q_LOGGING_CATEGORY(LOG_VisualizationWidget, "VisualizationWidget")
16 17
17 18 VisualizationWidget::VisualizationWidget(QWidget *parent)
18 19 : QWidget{parent}, ui{new Ui::VisualizationWidget}
19 20 {
20 21 ui->setupUi(this);
21 22
22 23 auto addTabViewButton = new QToolButton{ui->tabWidget};
23 24 addTabViewButton->setText(tr("Add View"));
24 25 addTabViewButton->setCursor(Qt::ArrowCursor);
25 26 ui->tabWidget->setCornerWidget(addTabViewButton, Qt::TopRightCorner);
26 27
27 28 auto enableMinimumCornerWidgetSize = [this](bool enable) {
28 29
29 30 auto tabViewCornerWidget = ui->tabWidget->cornerWidget();
30 31 auto width = enable ? tabViewCornerWidget->width() : 0;
31 32 auto height = enable ? tabViewCornerWidget->height() : 0;
32 33 tabViewCornerWidget->setMinimumHeight(height);
33 34 tabViewCornerWidget->setMinimumWidth(width);
34 35 ui->tabWidget->setMinimumHeight(height);
35 36 ui->tabWidget->setMinimumWidth(width);
36 37 };
37 38
38 39 auto addTabView = [this, enableMinimumCornerWidgetSize]() {
39 40 auto widget = new VisualizationTabWidget{QString{"View %1"}.arg(ui->tabWidget->count() + 1),
40 41 ui->tabWidget};
41 42 auto index = ui->tabWidget->addTab(widget, widget->name());
42 43 if (ui->tabWidget->count() > 0) {
43 44 enableMinimumCornerWidgetSize(false);
44 45 }
45 46 qCInfo(LOG_VisualizationWidget()) << tr("add the tab of index %1").arg(index);
46 47 };
47 48
48 49 auto removeTabView = [this, enableMinimumCornerWidgetSize](int index) {
49 50 if (ui->tabWidget->count() == 1) {
50 51 enableMinimumCornerWidgetSize(true);
51 52 }
52 53
53 54 // Removes widget from tab and closes it
54 55 auto widget = ui->tabWidget->widget(index);
55 56 ui->tabWidget->removeTab(index);
56 57 if (widget) {
57 58 widget->close();
58 59 }
59 60
60 61 qCInfo(LOG_VisualizationWidget()) << tr("remove the tab of index %1").arg(index);
61 62
62 63 };
63 64
64 65 ui->tabWidget->setTabsClosable(true);
65 66
66 67 connect(addTabViewButton, &QToolButton::clicked, addTabView);
67 68 connect(ui->tabWidget, &QTabWidget::tabCloseRequested, removeTabView);
68 69
69 70 // Adds default tab
70 71 addTabView();
71 72 }
72 73
73 74 VisualizationWidget::~VisualizationWidget()
74 75 {
75 76 delete ui;
76 77 }
77 78
78 79 void VisualizationWidget::accept(IVisualizationWidgetVisitor *visitor)
79 80 {
80 81 if (visitor) {
81 82 visitor->visitEnter(this);
82 83
83 84 // Apply visitor for tab children
84 85 for (auto i = 0; i < ui->tabWidget->count(); ++i) {
85 86 // Widgets different from tabs are not visited (no action)
86 87 if (auto visualizationTabWidget
87 88 = dynamic_cast<VisualizationTabWidget *>(ui->tabWidget->widget(i))) {
88 89 visualizationTabWidget->accept(visitor);
89 90 }
90 91 }
91 92
92 93 visitor->visitLeave(this);
93 94 }
94 95 else {
95 96 qCCritical(LOG_VisualizationWidget()) << tr("Can't visit widget : the visitor is null");
96 97 }
97 98 }
98 99
99 100 bool VisualizationWidget::canDrop(const Variable &variable) const
100 101 {
101 102 // The main widget can never accomodate a variable
102 103 Q_UNUSED(variable);
103 104 return false;
104 105 }
105 106
106 107 bool VisualizationWidget::contains(const Variable &variable) const
107 108 {
108 109 Q_UNUSED(variable);
109 110 return false;
110 111 }
111 112
112 113 QString VisualizationWidget::name() const
113 114 {
114 115 return QStringLiteral("MainView");
115 116 }
116 117
117 118 void VisualizationWidget::attachVariableMenu(
118 119 QMenu *menu, const QVector<std::shared_ptr<Variable> > &variables) noexcept
119 120 {
120 121 // Menu is generated only if there is a single variable
121 122 if (variables.size() == 1) {
122 123 if (auto variable = variables.first()) {
124 // Gets the containers of the variable
125 FindVariableOperation findVariableOperation{variable};
126 accept(&findVariableOperation);
127 auto variableContainers = findVariableOperation.result();
128
123 129 // Generates the actions that make it possible to visualize the variable
124 auto generateVariableMenuOperation = GenerateVariableMenuOperation{menu, variable};
130 GenerateVariableMenuOperation generateVariableMenuOperation{
131 menu, variable, std::move(variableContainers)};
125 132 accept(&generateVariableMenuOperation);
126 133 }
127 134 else {
128 135 qCCritical(LOG_VisualizationWidget()) << tr(
129 136 "Can't generate the menu relative to the visualization: the variable is null");
130 137 }
131 138 }
132 139 else {
133 140 qCDebug(LOG_VisualizationWidget())
134 141 << tr("No generation of the menu related to the visualization: several variables are "
135 142 "selected");
136 143 }
137 144 }
138 145
139 146 void VisualizationWidget::onVariableAboutToBeDeleted(std::shared_ptr<Variable> variable) noexcept
140 147 {
141 148 // Calls the operation of removing all references to the variable in the visualization
142 149 auto removeVariableOperation = RemoveVariableOperation{variable};
143 150 accept(&removeVariableOperation);
144 151 }
145 152
146 153 void VisualizationWidget::onRangeChanged(std::shared_ptr<Variable> variable,
147 154 const SqpRange &range) noexcept
148 155 {
149 156 // Calls the operation of rescaling all graph that contrains variable in the visualization
150 157 auto rescaleVariableOperation = RescaleAxeOperation{variable, range};
151 158 accept(&rescaleVariableOperation);
152 159 }
160
161 void VisualizationWidget::closeEvent(QCloseEvent *event)
162 {
163 // Closes tabs in the widget
164 for (auto i = 0; i < ui->tabWidget->count(); ++i) {
165 if (auto visualizationTabWidget
166 = dynamic_cast<VisualizationTabWidget *>(ui->tabWidget->widget(i))) {
167 visualizationTabWidget->close();
168 }
169 }
170
171 QWidget::closeEvent(event);
172 }
@@ -1,268 +1,302
1 1 #include "Visualization/VisualizationZoneWidget.h"
2 2
3 3 #include "Visualization/IVisualizationWidgetVisitor.h"
4 4 #include "Visualization/QCustomPlotSynchronizer.h"
5 5 #include "Visualization/VisualizationGraphWidget.h"
6 6 #include "ui_VisualizationZoneWidget.h"
7 7
8 8 #include <Data/SqpRange.h>
9 9 #include <Variable/Variable.h>
10 10 #include <Variable/VariableController.h>
11 11
12 12 #include <QUuid>
13 13 #include <SqpApplication.h>
14 14 #include <cmath>
15 15
16 16 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
17 17
18 18 namespace {
19 19
20 20 /// Minimum height for graph added in zones (in pixels)
21 21 const auto GRAPH_MINIMUM_HEIGHT = 300;
22 22
23 23 /// Generates a default name for a new graph, according to the number of graphs already displayed in
24 24 /// the zone
25 25 QString defaultGraphName(const QLayout &layout)
26 26 {
27 27 auto count = 0;
28 28 for (auto i = 0; i < layout.count(); ++i) {
29 29 if (dynamic_cast<VisualizationGraphWidget *>(layout.itemAt(i)->widget())) {
30 30 count++;
31 31 }
32 32 }
33 33
34 34 return QObject::tr("Graph %1").arg(count + 1);
35 35 }
36 36
37 /**
38 * Applies a function to all graphs of the zone represented by its layout
39 * @param layout the layout that contains graphs
40 * @param fun the function to apply to each graph
41 */
42 template <typename Fun>
43 void processGraphs(QLayout &layout, Fun fun)
44 {
45 for (auto i = 0; i < layout.count(); ++i) {
46 if (auto item = layout.itemAt(i)) {
47 if (auto visualizationGraphWidget
48 = dynamic_cast<VisualizationGraphWidget *>(item->widget())) {
49 fun(*visualizationGraphWidget);
50 }
51 }
52 }
53 }
54
37 55 } // namespace
38 56
39 57 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate {
40 58
41 59 explicit VisualizationZoneWidgetPrivate()
42 60 : m_SynchronisationGroupId{QUuid::createUuid()},
43 61 m_Synchronizer{std::make_unique<QCustomPlotSynchronizer>()}
44 62 {
45 63 }
46 64 QUuid m_SynchronisationGroupId;
47 65 std::unique_ptr<IGraphSynchronizer> m_Synchronizer;
48 66 };
49 67
50 68 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
51 69 : QWidget{parent},
52 70 ui{new Ui::VisualizationZoneWidget},
53 71 impl{spimpl::make_unique_impl<VisualizationZoneWidgetPrivate>()}
54 72 {
55 73 ui->setupUi(this);
56 74
57 75 ui->zoneNameLabel->setText(name);
58 76
59 77 // 'Close' options : widget is deleted when closed
60 78 setAttribute(Qt::WA_DeleteOnClose);
61 79 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
62 80 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
63 81
64 82 // Synchronisation id
65 83 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronizationGroupId",
66 84 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
67 85 }
68 86
69 87 VisualizationZoneWidget::~VisualizationZoneWidget()
70 88 {
71 89 delete ui;
72 90 }
73 91
74 92 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
75 93 {
76 94 // Synchronize new graph with others in the zone
77 95 impl->m_Synchronizer->addGraph(*graphWidget);
78 96
79 97 ui->visualizationZoneFrame->layout()->addWidget(graphWidget);
80 98 }
81 99
82 100 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
83 101 {
84 102 auto graphWidget = new VisualizationGraphWidget{
85 103 defaultGraphName(*ui->visualizationZoneFrame->layout()), this};
86 104
87 105
88 106 // Set graph properties
89 107 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
90 108 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
91 109
92 110
93 111 // Lambda to synchronize zone widget
94 112 auto synchronizeZoneWidget = [this, graphWidget](const SqpRange &graphRange,
95 113 const SqpRange &oldGraphRange) {
96 114
97 115 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
98 116 auto frameLayout = ui->visualizationZoneFrame->layout();
99 117 for (auto i = 0; i < frameLayout->count(); ++i) {
100 118 auto graphChild
101 119 = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
102 120 if (graphChild && (graphChild != graphWidget)) {
103 121
104 122 auto graphChildRange = graphChild->graphRange();
105 123 switch (zoomType) {
106 124 case AcquisitionZoomType::ZoomIn: {
107 125 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
108 126 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
109 127 graphChildRange.m_TStart += deltaLeft;
110 128 graphChildRange.m_TEnd -= deltaRight;
111 129 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomIn");
112 130 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
113 131 << deltaLeft;
114 132 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
115 133 << deltaRight;
116 134 qCDebug(LOG_VisualizationZoneWidget())
117 135 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
118 136
119 137 break;
120 138 }
121 139
122 140 case AcquisitionZoomType::ZoomOut: {
123 141 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomOut");
124 142 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
125 143 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
126 144 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
127 145 << deltaLeft;
128 146 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
129 147 << deltaRight;
130 148 qCDebug(LOG_VisualizationZoneWidget())
131 149 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
132 150 graphChildRange.m_TStart -= deltaLeft;
133 151 graphChildRange.m_TEnd += deltaRight;
134 152 break;
135 153 }
136 154 case AcquisitionZoomType::PanRight: {
137 155 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanRight");
138 156 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
139 157 graphChildRange.m_TStart += deltaRight;
140 158 graphChildRange.m_TEnd += deltaRight;
141 159 qCDebug(LOG_VisualizationZoneWidget())
142 160 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
143 161 break;
144 162 }
145 163 case AcquisitionZoomType::PanLeft: {
146 164 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanLeft");
147 165 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
148 166 graphChildRange.m_TStart -= deltaLeft;
149 167 graphChildRange.m_TEnd -= deltaLeft;
150 168 break;
151 169 }
152 170 case AcquisitionZoomType::Unknown: {
153 171 qCDebug(LOG_VisualizationZoneWidget())
154 172 << tr("Impossible to synchronize: zoom type unknown");
155 173 break;
156 174 }
157 175 default:
158 176 qCCritical(LOG_VisualizationZoneWidget())
159 177 << tr("Impossible to synchronize: zoom type not take into account");
160 178 // No action
161 179 break;
162 180 }
163 181 graphChild->enableAcquisition(false);
164 182 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range before: ")
165 183 << graphChild->graphRange();
166 184 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range after : ")
167 185 << graphChildRange;
168 186 qCDebug(LOG_VisualizationZoneWidget())
169 187 << tr("TORM: child dt") << graphChildRange.m_TEnd - graphChildRange.m_TStart;
170 188 graphChild->setGraphRange(graphChildRange);
171 189 graphChild->enableAcquisition(true);
172 190 }
173 191 }
174 192 };
175 193
176 194 // connection for synchronization
177 195 connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
178 196 connect(graphWidget, &VisualizationGraphWidget::variableAdded, this,
179 197 &VisualizationZoneWidget::onVariableAdded);
198 connect(graphWidget, &VisualizationGraphWidget::variableAboutToBeRemoved, this,
199 &VisualizationZoneWidget::onVariableAboutToBeRemoved);
180 200
181 201 auto range = SqpRange{};
182 202
183 203 // Apply visitor to graph children
184 204 auto layout = ui->visualizationZoneFrame->layout();
185 205 if (layout->count() > 0) {
186 206 // Case of a new graph in a existant zone
187 207 if (auto visualizationGraphWidget
188 208 = dynamic_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
189 209 range = visualizationGraphWidget->graphRange();
190 210 }
191 211 }
192 212 else {
193 213 // Case of a new graph as the first of the zone
194 214 range = variable->range();
195 215 }
196 216
197 217 this->addGraph(graphWidget);
198 218
199 219 graphWidget->addVariable(variable, range);
200 220
201 221 // get y using variable range
202 222 if (auto dataSeries = variable->dataSeries()) {
203 223 dataSeries->lockRead();
204 224 auto valuesBounds
205 225 = dataSeries->valuesBounds(variable->range().m_TStart, variable->range().m_TEnd);
206 226 auto end = dataSeries->cend();
207 227 if (valuesBounds.first != end && valuesBounds.second != end) {
208 228 auto rangeValue = [](const auto &value) { return std::isnan(value) ? 0. : value; };
209 229
210 230 auto minValue = rangeValue(valuesBounds.first->minValue());
211 231 auto maxValue = rangeValue(valuesBounds.second->maxValue());
212 232
213 233 graphWidget->setYRange(SqpRange{minValue, maxValue});
214 234 }
215 235 dataSeries->unlock();
216 236 }
217 237
218 238 return graphWidget;
219 239 }
220 240
221 241 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
222 242 {
223 243 if (visitor) {
224 244 visitor->visitEnter(this);
225 245
226 // Apply visitor to graph children
227 auto layout = ui->visualizationZoneFrame->layout();
228 for (auto i = 0; i < layout->count(); ++i) {
229 if (auto item = layout->itemAt(i)) {
230 // Widgets different from graphs are not visited (no action)
231 if (auto visualizationGraphWidget
232 = dynamic_cast<VisualizationGraphWidget *>(item->widget())) {
233 visualizationGraphWidget->accept(visitor);
234 }
235 }
236 }
246 // Apply visitor to graph children: widgets different from graphs are not visited (no
247 // action)
248 processGraphs(
249 *ui->visualizationZoneFrame->layout(),
250 [visitor](VisualizationGraphWidget &graphWidget) { graphWidget.accept(visitor); });
237 251
238 252 visitor->visitLeave(this);
239 253 }
240 254 else {
241 255 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
242 256 }
243 257 }
244 258
245 259 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
246 260 {
247 261 // A tab can always accomodate a variable
248 262 Q_UNUSED(variable);
249 263 return true;
250 264 }
251 265
252 266 bool VisualizationZoneWidget::contains(const Variable &variable) const
253 267 {
254 268 Q_UNUSED(variable);
255 269 return false;
256 270 }
257 271
258 272 QString VisualizationZoneWidget::name() const
259 273 {
260 274 return ui->zoneNameLabel->text();
261 275 }
262 276
277 void VisualizationZoneWidget::closeEvent(QCloseEvent *event)
278 {
279 // Closes graphs in the zone
280 processGraphs(*ui->visualizationZoneFrame->layout(),
281 [](VisualizationGraphWidget &graphWidget) { graphWidget.close(); });
282
283 // Delete synchronization group from variable controller
284 QMetaObject::invokeMethod(&sqpApp->variableController(), "onRemoveSynchronizationGroupId",
285 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
286
287 QWidget::closeEvent(event);
288 }
289
263 290 void VisualizationZoneWidget::onVariableAdded(std::shared_ptr<Variable> variable)
264 291 {
265 292 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronized",
266 293 Qt::QueuedConnection, Q_ARG(std::shared_ptr<Variable>, variable),
267 294 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
268 295 }
296
297 void VisualizationZoneWidget::onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable)
298 {
299 QMetaObject::invokeMethod(&sqpApp->variableController(), "desynchronize", Qt::QueuedConnection,
300 Q_ARG(std::shared_ptr<Variable>, variable),
301 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
302 }
@@ -1,201 +1,216
1 1 #include "Visualization/operations/GenerateVariableMenuOperation.h"
2 2 #include "Visualization/operations/MenuBuilder.h"
3 3
4 4 #include "Visualization/VisualizationGraphWidget.h"
5 5 #include "Visualization/VisualizationTabWidget.h"
6 6 #include "Visualization/VisualizationZoneWidget.h"
7 7
8 8 #include <Variable/Variable.h>
9 9
10 10 #include <QMenu>
11 11 #include <QStack>
12 12
13 13 Q_LOGGING_CATEGORY(LOG_GenerateVariableMenuOperation, "GenerateVariableMenuOperation")
14 14
15 15 struct GenerateVariableMenuOperation::GenerateVariableMenuOperationPrivate {
16 explicit GenerateVariableMenuOperationPrivate(QMenu *menu, std::shared_ptr<Variable> variable)
17 : m_Variable{variable}, m_PlotMenuBuilder{menu}, m_UnplotMenuBuilder{menu}
16 explicit GenerateVariableMenuOperationPrivate(
17 QMenu *menu, std::shared_ptr<Variable> variable,
18 std::set<IVisualizationWidget *> variableContainers)
19 : m_Variable{variable},
20 m_PlotMenuBuilder{menu},
21 m_UnplotMenuBuilder{menu},
22 m_VariableContainers{std::move(variableContainers)}
18 23 {
19 24 }
20 25
21 26 void visitRootEnter()
22 27 {
23 28 // Creates the root menu
24 29 if (auto plotMenu
25 30 = m_PlotMenuBuilder.addMenu(QObject::tr("Plot"), QIcon{":/icones/plot.png"})) {
26 31 plotMenu->setEnabled(m_Variable && m_Variable->dataSeries() != nullptr);
27 32 }
28 33
29 34 m_UnplotMenuBuilder.addMenu(QObject::tr("Unplot"), QIcon{":/icones/unplot.png"});
30 35 }
31 36
32 37 void visitRootLeave()
33 38 {
34 39 // Closes the root menu
35 40 m_PlotMenuBuilder.closeMenu();
36 41 m_UnplotMenuBuilder.closeMenu();
37 42 }
38 43
39 44 void visitNodeEnter(const IVisualizationWidget &container)
40 45 {
41 46 // Opens a new menu associated to the node
42 47 m_PlotMenuBuilder.addMenu(container.name());
43 48 m_UnplotMenuBuilder.addMenu(container.name());
44 49 }
45 50
46 51 template <typename ActionFun>
47 52 void visitNodeLeavePlot(const IVisualizationWidget &container, const QString &actionName,
48 53 ActionFun actionFunction)
49 54 {
50 if (m_Variable && container.canDrop(*m_Variable)) {
55 if (isValidContainer(container)) {
51 56 m_PlotMenuBuilder.addSeparator();
52 57 m_PlotMenuBuilder.addAction(actionName, actionFunction);
53 58 }
54 59
55 60 // Closes the menu associated to the node
56 61 m_PlotMenuBuilder.closeMenu();
57 62 }
58 63
59 64 void visitNodeLeaveUnplot()
60 65 {
61 66 // Closes the menu associated to the node
62 67 m_UnplotMenuBuilder.closeMenu();
63 68 }
64 69
65 70 template <typename ActionFun>
66 71 void visitLeafPlot(const IVisualizationWidget &container, const QString &actionName,
67 72 ActionFun actionFunction)
68 73 {
69 if (m_Variable && container.canDrop(*m_Variable)) {
74 if (isValidContainer(container)) {
70 75 m_PlotMenuBuilder.addAction(actionName, actionFunction);
71 76 }
72 77 }
73 78
74 79 template <typename ActionFun>
75 void visitLeafUnplot(const IVisualizationWidget &container, const QString &actionName,
80 void visitLeafUnplot(IVisualizationWidget *container, const QString &actionName,
76 81 ActionFun actionFunction)
77 82 {
78 if (m_Variable && container.contains(*m_Variable)) {
83 // If the container contains the variable, we generate 'unplot' action
84 if (m_VariableContainers.count(container) == 1) {
79 85 m_UnplotMenuBuilder.addAction(actionName, actionFunction);
80 86 }
81 87 }
82 88
89 bool isValidContainer(const IVisualizationWidget &container) const noexcept
90 {
91 // A container is valid if it can contain the variable and if the variable is not already
92 // contained in another container
93 return m_Variable && m_VariableContainers.size() == 0 && container.canDrop(*m_Variable);
94 }
95
83 96 std::shared_ptr<Variable> m_Variable;
97 std::set<IVisualizationWidget *> m_VariableContainers;
84 98 MenuBuilder m_PlotMenuBuilder; ///< Builder for the 'Plot' menu
85 99 MenuBuilder m_UnplotMenuBuilder; ///< Builder for the 'Unplot' menu
86 100 };
87 101
88 GenerateVariableMenuOperation::GenerateVariableMenuOperation(QMenu *menu,
89 std::shared_ptr<Variable> variable)
90 : impl{spimpl::make_unique_impl<GenerateVariableMenuOperationPrivate>(menu, variable)}
102 GenerateVariableMenuOperation::GenerateVariableMenuOperation(
103 QMenu *menu, std::shared_ptr<Variable> variable,
104 std::set<IVisualizationWidget *> variableContainers)
105 : impl{spimpl::make_unique_impl<GenerateVariableMenuOperationPrivate>(
106 menu, variable, std::move(variableContainers))}
91 107 {
92 108 }
93 109
94 110 void GenerateVariableMenuOperation::visitEnter(VisualizationWidget *widget)
95 111 {
96 112 // VisualizationWidget is not intended to accommodate a variable
97 113 Q_UNUSED(widget)
98 114
99 115 // 'Plot' and 'Unplot' menus
100 116 impl->visitRootEnter();
101 117 }
102 118
103 119 void GenerateVariableMenuOperation::visitLeave(VisualizationWidget *widget)
104 120 {
105 121 // VisualizationWidget is not intended to accommodate a variable
106 122 Q_UNUSED(widget)
107 123
108 124 // 'Plot' and 'Unplot' menus
109 125 impl->visitRootLeave();
110 126 }
111 127
112 128 void GenerateVariableMenuOperation::visitEnter(VisualizationTabWidget *tabWidget)
113 129 {
114 130 if (tabWidget) {
115 131 // 'Plot' and 'Unplot' menus
116 132 impl->visitNodeEnter(*tabWidget);
117 133 }
118 134 else {
119 135 qCCritical(LOG_GenerateVariableMenuOperation(),
120 136 "Can't visit enter VisualizationTabWidget : the widget is null");
121 137 }
122 138 }
123 139
124 140 void GenerateVariableMenuOperation::visitLeave(VisualizationTabWidget *tabWidget)
125 141 {
126 142 if (tabWidget) {
127 143 // 'Plot' menu
128 144 impl->visitNodeLeavePlot(*tabWidget, QObject::tr("Open in a new zone"),
129 145 [ varW = std::weak_ptr<Variable>{impl->m_Variable}, tabWidget ]() {
130 146 if (auto var = varW.lock()) {
131 147 tabWidget->createZone(var);
132 148 }
133 149 });
134 150
135 151 // 'Unplot' menu
136 152 impl->visitNodeLeaveUnplot();
137 153 }
138 154 else {
139 155 qCCritical(LOG_GenerateVariableMenuOperation(),
140 156 "Can't visit leave VisualizationTabWidget : the widget is null");
141 157 }
142 158 }
143 159
144 160 void GenerateVariableMenuOperation::visitEnter(VisualizationZoneWidget *zoneWidget)
145 161 {
146 162 if (zoneWidget) {
147 163 // 'Plot' and 'Unplot' menus
148 164 impl->visitNodeEnter(*zoneWidget);
149 165 }
150 166 else {
151 167 qCCritical(LOG_GenerateVariableMenuOperation(),
152 168 "Can't visit enter VisualizationZoneWidget : the widget is null");
153 169 }
154 170 }
155 171
156 172 void GenerateVariableMenuOperation::visitLeave(VisualizationZoneWidget *zoneWidget)
157 173 {
158 qCCritical(LOG_GenerateVariableMenuOperation(), "Open in a new graph DETECTED !!");
159 174 if (zoneWidget) {
160 175 // 'Plot' menu
161 176 impl->visitNodeLeavePlot(
162 177 *zoneWidget, QObject::tr("Open in a new graph"),
163 178 [ varW = std::weak_ptr<Variable>{impl->m_Variable}, zoneWidget ]() {
164 179 if (auto var = varW.lock()) {
165 180 zoneWidget->createGraph(var);
166 181 }
167 182 });
168 183
169 184 // 'Unplot' menu
170 185 impl->visitNodeLeaveUnplot();
171 186 }
172 187 else {
173 188 qCCritical(LOG_GenerateVariableMenuOperation(),
174 189 "Can't visit leave VisualizationZoneWidget : the widget is null");
175 190 }
176 191 }
177 192
178 193 void GenerateVariableMenuOperation::visit(VisualizationGraphWidget *graphWidget)
179 194 {
180 195 if (graphWidget) {
181 196 // 'Plot' menu
182 197 impl->visitLeafPlot(*graphWidget, QObject::tr("Open in %1").arg(graphWidget->name()),
183 198 [ varW = std::weak_ptr<Variable>{impl->m_Variable}, graphWidget ]() {
184 199 if (auto var = varW.lock()) {
185 200 graphWidget->addVariable(var, graphWidget->graphRange());
186 201 }
187 202 });
188 203
189 204 // 'Unplot' menu
190 impl->visitLeafUnplot(*graphWidget, QObject::tr("Remove from %1").arg(graphWidget->name()),
205 impl->visitLeafUnplot(graphWidget, QObject::tr("Remove from %1").arg(graphWidget->name()),
191 206 [ varW = std::weak_ptr<Variable>{impl->m_Variable}, graphWidget ]() {
192 207 if (auto var = varW.lock()) {
193 208 graphWidget->removeVariable(var);
194 209 }
195 210 });
196 211 }
197 212 else {
198 213 qCCritical(LOG_GenerateVariableMenuOperation(),
199 214 "Can't visit VisualizationGraphWidget : the widget is null");
200 215 }
201 216 }
General Comments 0
You need to be logged in to leave comments. Login now