##// END OF EJS Templates
Implementation of the calibration for the synchronization...
perrinel -
r411:a75bae0e8d4d
parent child
Show More
@@ -1,78 +1,82
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 SqpDateTime;
17 17 class Variable;
18 18
19 19 /**
20 20 * Possible types of zoom operation
21 21 */
22 22 enum class VisualizationGraphWidgetZoomType { ZoomOut, ZoomIn, PanRight, PanLeft, Unknown };
23 23
24 24 namespace Ui {
25 25 class VisualizationGraphWidget;
26 26 } // namespace Ui
27 27
28 28 class VisualizationGraphWidget : public QWidget, public IVisualizationWidget {
29 29 Q_OBJECT
30 30
31 31 public:
32 32 explicit VisualizationGraphWidget(const QString &name = {}, QWidget *parent = 0);
33 33 virtual ~VisualizationGraphWidget();
34 34
35 35 void enableSynchronize(bool enable);
36 36
37 37 void addVariable(std::shared_ptr<Variable> variable);
38 38 void addVariableUsingGraph(std::shared_ptr<Variable> variable);
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 SqpDateTime &range);
43 43 SqpDateTime graphRange();
44 44 void setGraphRange(const SqpDateTime &range);
45 45
46 46 // IVisualizationWidget interface
47 47 void accept(IVisualizationWidgetVisitor *visitor) override;
48 48 bool canDrop(const Variable &variable) const override;
49 49 bool contains(const Variable &variable) const override;
50 50 QString name() const override;
51 51
52 52
53 53 signals:
54 54 void requestDataLoading(std::shared_ptr<Variable> variable, const SqpDateTime &dateTime);
55 55 void synchronize(const SqpDateTime &dateTime, const SqpDateTime &oldDateTime,
56 56 VisualizationGraphWidgetZoomType zoomType);
57 57
58 58
59 59 private:
60 60 Ui::VisualizationGraphWidget *ui;
61 61
62 62 class VisualizationGraphWidgetPrivate;
63 63 spimpl::unique_impl_ptr<VisualizationGraphWidgetPrivate> impl;
64 64
65 65 private slots:
66 66 /// Slot called when right clicking on the graph (displays a menu)
67 67 void onGraphMenuRequested(const QPoint &pos) noexcept;
68 68
69 69 /// Rescale the X axe to range parameter
70 70 void onRangeChanged(const QCPRange &t1, const QCPRange &t2);
71 71
72 72 /// Slot called when a mouse wheel was made, to perform some processing before the zoom is done
73 73 void onMouseWheel(QWheelEvent *event) noexcept;
74 /// Slot called when a mouse press was made, to activate the calibration of a graph
75 void onMousePress(QMouseEvent *event) noexcept;
76 /// Slot called when a mouse release was made, to deactivate the calibration of a graph
77 void onMouseRelease(QMouseEvent *event) noexcept;
74 78
75 79 void onDataCacheVariableUpdated();
76 80 };
77 81
78 82 #endif // SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
@@ -1,362 +1,399
1 1 #include "Visualization/VisualizationGraphWidget.h"
2 2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 3 #include "Visualization/VisualizationGraphHelper.h"
4 4 #include "ui_VisualizationGraphWidget.h"
5 5
6 6 #include <Data/ArrayData.h>
7 7 #include <Data/IDataSeries.h>
8 8 #include <SqpApplication.h>
9 9 #include <Variable/Variable.h>
10 10 #include <Variable/VariableController.h>
11 11
12 12 #include <unordered_map>
13 13
14 14 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
15 15
16 16 namespace {
17 17
18 18 /// Key pressed to enable zoom on horizontal axis
19 19 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::NoModifier;
20 20
21 21 /// Key pressed to enable zoom on vertical axis
22 22 const auto VERTICAL_ZOOM_MODIFIER = Qt::ControlModifier;
23 23
24 24 } // namespace
25 25
26 26 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
27 27
28 explicit VisualizationGraphWidgetPrivate() : m_DoSynchronize(true) {}
28 explicit VisualizationGraphWidgetPrivate() : m_DoSynchronize(true), m_IsCalibration(false) {}
29
30
31 // Return the operation when range changed
32 VisualizationGraphWidgetZoomType getZoomType(const QCPRange &t1, const QCPRange &t2);
29 33
30 34 // 1 variable -> n qcpplot
31 35 std::multimap<std::shared_ptr<Variable>, QCPAbstractPlottable *> m_VariableToPlotMultiMap;
32 36
33 37 bool m_DoSynchronize;
38 bool m_IsCalibration;
34 39 };
35 40
36 41 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
37 42 : QWidget{parent},
38 43 ui{new Ui::VisualizationGraphWidget},
39 44 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>()}
40 45 {
41 46 ui->setupUi(this);
42 47
43 48 ui->graphNameLabel->setText(name);
44 49
45 50 // 'Close' options : widget is deleted when closed
46 51 setAttribute(Qt::WA_DeleteOnClose);
47 52 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationGraphWidget::close);
48 53 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
49 54
50 55 // Set qcpplot properties :
51 56 // - Drag (on x-axis) and zoom are enabled
52 57 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
53 58 ui->widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);
54 59 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal);
60 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
61 connect(ui->widget, &QCustomPlot::mouseRelease, this,
62 &VisualizationGraphWidget::onMouseRelease);
55 63 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
56 64 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
57 65 &QCPAxis::rangeChanged),
58 this, &VisualizationGraphWidget::onRangeChanged);
66 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
59 67
60 68 // Activates menu when right clicking on the graph
61 69 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
62 70 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
63 71 &VisualizationGraphWidget::onGraphMenuRequested);
64 72
65 73 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
66 74 &VariableController::onRequestDataLoading);
67 75 }
68 76
69 77
70 78 VisualizationGraphWidget::~VisualizationGraphWidget()
71 79 {
72 80 delete ui;
73 81 }
74 82
75 83 void VisualizationGraphWidget::enableSynchronize(bool enable)
76 84 {
77 85 impl->m_DoSynchronize = enable;
78 86 }
79 87
80 88 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable)
81 89 {
82 90 // Uses delegate to create the qcpplot components according to the variable
83 91 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
84 92
85 93 for (auto createdPlottable : qAsConst(createdPlottables)) {
86 94 impl->m_VariableToPlotMultiMap.insert({variable, createdPlottable});
87 95 }
88 96
89 97 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
90 98 }
91 99 void VisualizationGraphWidget::addVariableUsingGraph(std::shared_ptr<Variable> variable)
92 100 {
93 101
94 102 // when adding a variable, we need to set its time range to the current graph range
95 103 auto grapheRange = ui->widget->xAxis->range();
96 104 auto dateTime = SqpDateTime{grapheRange.lower, grapheRange.upper};
97 105 variable->setDateTime(dateTime);
98 106
99 107 auto variableDateTimeWithTolerance = dateTime;
100 108
101 109 // add 10% tolerance for each side
102 110 auto tolerance = 0.1 * (dateTime.m_TEnd - dateTime.m_TStart);
103 111 variableDateTimeWithTolerance.m_TStart -= tolerance;
104 112 variableDateTimeWithTolerance.m_TEnd += tolerance;
105 113
106 114 // Uses delegate to create the qcpplot components according to the variable
107 115 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
108 116
109 117 for (auto createdPlottable : qAsConst(createdPlottables)) {
110 118 impl->m_VariableToPlotMultiMap.insert({variable, createdPlottable});
111 119 }
112 120
113 121 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
114 122
115 123 // CHangement detected, we need to ask controller to request data loading
116 124 emit requestDataLoading(variable, variableDateTimeWithTolerance);
117 125 }
118 126
119 127 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
120 128 {
121 129 // Each component associated to the variable :
122 130 // - is removed from qcpplot (which deletes it)
123 131 // - is no longer referenced in the map
124 132 auto componentsIt = impl->m_VariableToPlotMultiMap.equal_range(variable);
125 133 for (auto it = componentsIt.first; it != componentsIt.second;) {
126 134 ui->widget->removePlottable(it->second);
127 135 it = impl->m_VariableToPlotMultiMap.erase(it);
128 136 }
129 137
130 138 // Updates graph
131 139 ui->widget->replot();
132 140 }
133 141
134 142 void VisualizationGraphWidget::setRange(std::shared_ptr<Variable> variable,
135 143 const SqpDateTime &range)
136 144 {
137 145 // auto componentsIt = impl->m_VariableToPlotMultiMap.equal_range(variable);
138 146 // for (auto it = componentsIt.first; it != componentsIt.second;) {
139 147 // }
140 148 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
141 149 ui->widget->replot();
142 150 }
143 151
144 152 SqpDateTime VisualizationGraphWidget::graphRange()
145 153 {
146 154 auto grapheRange = ui->widget->xAxis->range();
147 155 return SqpDateTime{grapheRange.lower, grapheRange.upper};
148 156 }
149 157
150 158 void VisualizationGraphWidget::setGraphRange(const SqpDateTime &range)
151 159 {
152 qCDebug(LOG_VisualizationGraphWidget())
153 << tr("VisualizationGraphWidget::setGraphRange START");
160 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
154 161 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
155 162 ui->widget->replot();
156 163 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
157 164 }
158 165
159 166 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
160 167 {
161 168 if (visitor) {
162 169 visitor->visit(this);
163 170 }
164 171 else {
165 172 qCCritical(LOG_VisualizationGraphWidget())
166 173 << tr("Can't visit widget : the visitor is null");
167 174 }
168 175 }
169 176
170 177 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
171 178 {
172 179 /// @todo : for the moment, a graph can always accomodate a variable
173 180 Q_UNUSED(variable);
174 181 return true;
175 182 }
176 183
177 184 bool VisualizationGraphWidget::contains(const Variable &variable) const
178 185 {
179 186 // Finds the variable among the keys of the map
180 187 auto variablePtr = &variable;
181 188 auto findVariable
182 189 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
183 190
184 191 auto end = impl->m_VariableToPlotMultiMap.cend();
185 192 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
186 193 return it != end;
187 194 }
188 195
189 196 QString VisualizationGraphWidget::name() const
190 197 {
191 198 return ui->graphNameLabel->text();
192 199 }
193 200
194 201 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
195 202 {
196 203 QMenu graphMenu{};
197 204
198 205 // Iterates on variables (unique keys)
199 206 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
200 207 end = impl->m_VariableToPlotMultiMap.cend();
201 208 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
202 209 // 'Remove variable' action
203 210 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
204 211 [ this, var = it->first ]() { removeVariable(var); });
205 212 }
206 213
207 214 if (!graphMenu.isEmpty()) {
208 215 graphMenu.exec(mapToGlobal(pos));
209 216 }
210 217 }
211 218
212 219 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
213 220 {
214 221 qCInfo(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::onRangeChanged")
215 222 << QThread::currentThread()->objectName();
216 223
217 224 auto dateTimeRange = SqpDateTime{t1.lower, t1.upper};
218 225
219 auto zoomType = VisualizationGraphWidgetZoomType::ZoomOut;
226 auto zoomType = impl->getZoomType(t1, t2);
220 227 for (auto it = impl->m_VariableToPlotMultiMap.cbegin();
221 228 it != impl->m_VariableToPlotMultiMap.cend(); ++it) {
222 229
223 230 auto variable = it->first;
224 231 auto currentDateTime = dateTimeRange;
225 232
226 233 auto toleranceFactor = 0.2;
227 234 auto tolerance = toleranceFactor * (currentDateTime.m_TEnd - currentDateTime.m_TStart);
228 235 auto variableDateTimeWithTolerance = currentDateTime;
229 236 variableDateTimeWithTolerance.m_TStart -= tolerance;
230 237 variableDateTimeWithTolerance.m_TEnd += tolerance;
231 238
232 239 qCDebug(LOG_VisualizationGraphWidget()) << "r" << currentDateTime;
233 240 qCDebug(LOG_VisualizationGraphWidget()) << "t" << variableDateTimeWithTolerance;
234 241 qCDebug(LOG_VisualizationGraphWidget()) << "v" << variable->dateTime();
235 242 // If new range with tol is upper than variable datetime parameters. we need to request new
236 243 // data
237 244 if (!variable->contains(variableDateTimeWithTolerance)) {
238 245
239 246 auto variableDateTimeWithTolerance = currentDateTime;
240 247 if (!variable->isInside(currentDateTime)) {
241 248 auto variableDateTime = variable->dateTime();
242 249 if (variable->contains(variableDateTimeWithTolerance)) {
243 qCInfo(LOG_VisualizationGraphWidget())
250 qCDebug(LOG_VisualizationGraphWidget())
244 251 << tr("TORM: Detection zoom in that need request:");
245 252 // add 10% tolerance for each side
246 253 tolerance
247 254 = toleranceFactor * (currentDateTime.m_TEnd - currentDateTime.m_TStart);
248 255 variableDateTimeWithTolerance.m_TStart -= tolerance;
249 256 variableDateTimeWithTolerance.m_TEnd += tolerance;
250 zoomType = VisualizationGraphWidgetZoomType::ZoomIn;
251 257 }
252 258 else if (variableDateTime.m_TStart < currentDateTime.m_TStart) {
253 259 qCInfo(LOG_VisualizationGraphWidget()) << tr("TORM: Detection pan to right:");
254 260
255 261 auto diffEndToKeepDelta = currentDateTime.m_TEnd - variableDateTime.m_TEnd;
256 262 currentDateTime.m_TStart = variableDateTime.m_TStart + diffEndToKeepDelta;
257 263 // Tolerance have to be added to the right
258 264 // add tolerance for right (end) side
259 265 tolerance
260 266 = toleranceFactor * (currentDateTime.m_TEnd - currentDateTime.m_TStart);
261 267 variableDateTimeWithTolerance.m_TEnd += tolerance;
262 zoomType = VisualizationGraphWidgetZoomType::PanRight;
263 268 }
264 269 else if (variableDateTime.m_TEnd > currentDateTime.m_TEnd) {
265 qCInfo(LOG_VisualizationGraphWidget()) << tr("TORM: Detection pan to left: ");
270 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: Detection pan to left: ");
266 271 auto diffStartToKeepDelta
267 272 = variableDateTime.m_TStart - currentDateTime.m_TStart;
268 273 currentDateTime.m_TEnd = variableDateTime.m_TEnd - diffStartToKeepDelta;
269 274 // Tolerance have to be added to the left
270 275 // add tolerance for left (start) side
271 276 tolerance
272 277 = toleranceFactor * (currentDateTime.m_TEnd - currentDateTime.m_TStart);
273 278 variableDateTimeWithTolerance.m_TStart -= tolerance;
274 zoomType = VisualizationGraphWidgetZoomType::PanLeft;
275 279 }
276 280 else {
277 qCInfo(LOG_VisualizationGraphWidget())
281 qCCritical(LOG_VisualizationGraphWidget())
278 282 << tr("Detection anormal zoom detection: ");
279 zoomType = VisualizationGraphWidgetZoomType::Unknown;
280 283 }
281 284 }
282 285 else {
283 qCInfo(LOG_VisualizationGraphWidget()) << tr("TORM: Detection zoom out: ");
286 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: Detection zoom out: ");
284 287 // add 10% tolerance for each side
285 288 tolerance = toleranceFactor * (currentDateTime.m_TEnd - currentDateTime.m_TStart);
286 289 variableDateTimeWithTolerance.m_TStart -= tolerance;
287 290 variableDateTimeWithTolerance.m_TEnd += tolerance;
288 291 zoomType = VisualizationGraphWidgetZoomType::ZoomOut;
289 292 }
290 293 if (!variable->contains(dateTimeRange)) {
291 qCInfo(LOG_VisualizationGraphWidget())
294 qCDebug(LOG_VisualizationGraphWidget())
292 295 << "TORM: Modif on variable datetime detected" << currentDateTime;
293 296 variable->setDateTime(currentDateTime);
294 297 }
295 298
296 qCInfo(LOG_VisualizationGraphWidget()) << tr("TORM: Request data detection: ");
299 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: Request data detection: ");
297 300 // CHangement detected, we need to ask controller to request data loading
298 301 emit requestDataLoading(variable, variableDateTimeWithTolerance);
299 302 }
300 303 else {
301 304 qCInfo(LOG_VisualizationGraphWidget())
302 305 << tr("TORM: Detection zoom in that doesn't need request: ");
303 306 zoomType = VisualizationGraphWidgetZoomType::ZoomIn;
304 307 }
305 308 }
306 309
307 if (impl->m_DoSynchronize) {
310 if (impl->m_DoSynchronize && !impl->m_IsCalibration) {
308 311 auto oldDateTime = SqpDateTime{t2.lower, t2.upper};
309 312 qCDebug(LOG_VisualizationGraphWidget())
310 313 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
311 314 << QThread::currentThread()->objectName();
312 315 emit synchronize(dateTimeRange, oldDateTime, zoomType);
313 316 }
314 317 }
315 318
316 319 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
317 320 {
318 321 auto zoomOrientations = QFlags<Qt::Orientation>{};
319 322
320 323 // Lambda that enables a zoom orientation if the key modifier related to this orientation
321 324 // has
322 325 // been pressed
323 326 auto enableOrientation
324 327 = [&zoomOrientations, event](const auto &orientation, const auto &modifier) {
325 328 auto orientationEnabled = event->modifiers().testFlag(modifier);
326 329 zoomOrientations.setFlag(orientation, orientationEnabled);
327 330 };
328 331 enableOrientation(Qt::Vertical, VERTICAL_ZOOM_MODIFIER);
329 332 enableOrientation(Qt::Horizontal, HORIZONTAL_ZOOM_MODIFIER);
330 333
331 334 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
332 335 }
333 336
337 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
338 {
339 impl->m_IsCalibration = event->modifiers().testFlag(Qt::ControlModifier);
340 }
341
342 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
343 {
344 impl->m_IsCalibration = false;
345 }
346
334 347 void VisualizationGraphWidget::onDataCacheVariableUpdated()
335 348 {
336 349 // NOTE:
337 350 // We don't want to call the method for each component of a variable unitarily, but for
338 351 // all
339 352 // its components at once (eg its three components in the case of a vector).
340 353
341 354 // The unordered_multimap does not do this easily, so the question is whether to:
342 355 // - use an ordered_multimap and the algos of std to group the values by key
343 356 // - use a map (unique keys) and store as values directly the list of components
344 357
345 358 auto grapheRange = ui->widget->xAxis->range();
346 359 auto dateTime = SqpDateTime{grapheRange.lower, grapheRange.upper};
347 360
348 361 for (auto it = impl->m_VariableToPlotMultiMap.cbegin();
349 362 it != impl->m_VariableToPlotMultiMap.cend(); ++it) {
350 363 auto variable = it->first;
351 364 qCDebug(LOG_VisualizationGraphWidget())
352 365 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S"
353 366 << variable->dateTime();
354 367 qCDebug(LOG_VisualizationGraphWidget())
355 368 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
356 369 if (dateTime.contains(variable->dateTime()) || dateTime.intersect(variable->dateTime())) {
357 370
358 371 VisualizationGraphHelper::updateData(QVector<QCPAbstractPlottable *>{} << it->second,
359 372 variable->dataSeries(), variable->dateTime());
360 373 }
361 374 }
362 375 }
376
377 VisualizationGraphWidgetZoomType
378 VisualizationGraphWidget::VisualizationGraphWidgetPrivate::getZoomType(const QCPRange &t1,
379 const QCPRange &t2)
380 {
381 // t1.lower <= t2.lower && t2.upper <= t1.upper
382 auto zoomType = VisualizationGraphWidgetZoomType::Unknown;
383 if (t1.lower <= t2.lower && t2.upper <= t1.upper) {
384 zoomType = VisualizationGraphWidgetZoomType::ZoomOut;
385 }
386 else if (t1.lower > t2.lower && t1.upper > t2.upper) {
387 zoomType = VisualizationGraphWidgetZoomType::PanRight;
388 }
389 else if (t1.lower < t2.lower && t1.upper < t2.upper) {
390 zoomType = VisualizationGraphWidgetZoomType::PanLeft;
391 }
392 else if (t1.lower > t2.lower && t2.upper > t1.upper) {
393 zoomType = VisualizationGraphWidgetZoomType::ZoomIn;
394 }
395 else {
396 qCCritical(LOG_VisualizationGraphWidget()) << "getZoomType: Unknown type detected";
397 }
398 return zoomType;
399 }
@@ -1,180 +1,200
1 1 #include "Visualization/VisualizationZoneWidget.h"
2 2
3 3 #include "Data/SqpDateTime.h"
4 4
5 5 #include "Visualization/IVisualizationWidgetVisitor.h"
6 6 #include "Visualization/VisualizationGraphWidget.h"
7 7 #include "ui_VisualizationZoneWidget.h"
8 8
9 9
10 10 #include <SqpApplication.h>
11 11
12 12 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
13 13
14 14 namespace {
15 15
16 16 /// Minimum height for graph added in zones (in pixels)
17 17 const auto GRAPH_MINIMUM_HEIGHT = 300;
18 18
19 19 /// Generates a default name for a new graph, according to the number of graphs already displayed in
20 20 /// the zone
21 21 QString defaultGraphName(const QLayout &layout)
22 22 {
23 23 auto count = 0;
24 24 for (auto i = 0; i < layout.count(); ++i) {
25 25 if (dynamic_cast<VisualizationGraphWidget *>(layout.itemAt(i)->widget())) {
26 26 count++;
27 27 }
28 28 }
29 29
30 30 return QObject::tr("Graph %1").arg(count + 1);
31 31 }
32 32
33 33 } // namespace
34 34
35 35 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
36 36 : QWidget{parent}, ui{new Ui::VisualizationZoneWidget}
37 37 {
38 38 ui->setupUi(this);
39 39
40 40 ui->zoneNameLabel->setText(name);
41 41
42 42 // 'Close' options : widget is deleted when closed
43 43 setAttribute(Qt::WA_DeleteOnClose);
44 44 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
45 45 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
46 46 }
47 47
48 48 VisualizationZoneWidget::~VisualizationZoneWidget()
49 49 {
50 50 delete ui;
51 51 }
52 52
53 53 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
54 54 {
55 55 ui->visualizationZoneFrame->layout()->addWidget(graphWidget);
56 56 }
57 57
58 58 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
59 59 {
60 60 auto graphWidget = new VisualizationGraphWidget{
61 61 defaultGraphName(*ui->visualizationZoneFrame->layout()), this};
62 62
63 63
64 64 // Set graph properties
65 65 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
66 66 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
67 67
68 68 this->addGraph(graphWidget);
69 69
70 70 graphWidget->addVariable(variable);
71 71
72 72 // Lambda to synchronize zone widget
73 73 auto synchronizeZoneWidget = [this, graphWidget](const SqpDateTime &dateTime,
74 74 const SqpDateTime &oldDateTime,
75 75 VisualizationGraphWidgetZoomType zoomType) {
76 76 auto frameLayout = ui->visualizationZoneFrame->layout();
77 77 for (auto i = 0; i < frameLayout->count(); ++i) {
78 78 auto graphChild
79 79 = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
80 80 if (graphChild && (graphChild != graphWidget)) {
81 81
82 auto dateTimeThatKeepDelta = dateTime;
83 82 auto graphChildRange = graphChild->graphRange();
84 83 switch (zoomType) {
85 84 case VisualizationGraphWidgetZoomType::ZoomIn: {
86 85 auto deltaLeft = dateTime.m_TStart - oldDateTime.m_TStart;
87 86 auto deltaRight = oldDateTime.m_TEnd - dateTime.m_TEnd;
88 87 graphChildRange.m_TStart += deltaLeft;
89 88 graphChildRange.m_TEnd -= deltaRight;
90 dateTimeThatKeepDelta = graphChildRange;
89 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomIn");
90 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
91 << deltaLeft;
92 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
93 << deltaRight;
94 qCCritical(LOG_VisualizationZoneWidget())
95 << tr("TORM: dt") << dateTime.m_TEnd - dateTime.m_TStart;
96
91 97 break;
92 98 }
93 99
94 100 case VisualizationGraphWidgetZoomType::ZoomOut: {
101 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomOut");
95 102 auto deltaLeft = oldDateTime.m_TStart - dateTime.m_TStart;
96 103 auto deltaRight = dateTime.m_TEnd - oldDateTime.m_TEnd;
104 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
105 << deltaLeft;
106 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
107 << deltaRight;
108 qCCritical(LOG_VisualizationZoneWidget())
109 << tr("TORM: dt") << dateTime.m_TEnd - dateTime.m_TStart;
97 110 graphChildRange.m_TStart -= deltaLeft;
98 111 graphChildRange.m_TEnd += deltaRight;
99 dateTimeThatKeepDelta = graphChildRange;
100 112 break;
101 113 }
102 114 case VisualizationGraphWidgetZoomType::PanRight: {
115 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: PanRight");
103 116 auto deltaRight = dateTime.m_TEnd - oldDateTime.m_TEnd;
104 117 graphChildRange.m_TStart += deltaRight;
105 118 graphChildRange.m_TEnd += deltaRight;
106 dateTimeThatKeepDelta = graphChildRange;
119 qCCritical(LOG_VisualizationZoneWidget())
120 << tr("TORM: dt") << dateTime.m_TEnd - dateTime.m_TStart;
107 121 break;
108 122 }
109 123 case VisualizationGraphWidgetZoomType::PanLeft: {
124 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: PanLeft");
110 125 auto deltaLeft = oldDateTime.m_TStart - dateTime.m_TStart;
111 126 graphChildRange.m_TStart -= deltaLeft;
112 127 graphChildRange.m_TEnd -= deltaLeft;
113 dateTimeThatKeepDelta = graphChildRange;
114 128 break;
115 129 }
116 130 case VisualizationGraphWidgetZoomType::Unknown: {
117 131 qCCritical(LOG_VisualizationZoneWidget())
118 132 << tr("Impossible to synchronize: zoom type unknown");
119 133 break;
120 134 }
121 135 default:
122 136 qCCritical(LOG_VisualizationZoneWidget())
123 137 << tr("Impossible to synchronize: zoom type not take into account");
124 138 // No action
125 139 break;
126 140 }
127 141 graphChild->enableSynchronize(false);
128 graphChild->setGraphRange(dateTimeThatKeepDelta);
142 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: Range before: ")
143 << graphChild->graphRange();
144 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: Range after : ")
145 << graphChildRange;
146 qCCritical(LOG_VisualizationZoneWidget())
147 << tr("TORM: child dt") << graphChildRange.m_TEnd - graphChildRange.m_TStart;
148 graphChild->setGraphRange(graphChildRange);
129 149 graphChild->enableSynchronize(true);
130 150 }
131 151 }
132 152 };
133 153
134 154 // connection for synchronization
135 155 connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
136 156
137 157 return graphWidget;
138 158 }
139 159
140 160 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
141 161 {
142 162 if (visitor) {
143 163 visitor->visitEnter(this);
144 164
145 165 // Apply visitor to graph children
146 166 auto layout = ui->visualizationZoneFrame->layout();
147 167 for (auto i = 0; i < layout->count(); ++i) {
148 168 if (auto item = layout->itemAt(i)) {
149 169 // Widgets different from graphs are not visited (no action)
150 170 if (auto visualizationGraphWidget
151 171 = dynamic_cast<VisualizationGraphWidget *>(item->widget())) {
152 172 visualizationGraphWidget->accept(visitor);
153 173 }
154 174 }
155 175 }
156 176
157 177 visitor->visitLeave(this);
158 178 }
159 179 else {
160 180 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
161 181 }
162 182 }
163 183
164 184 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
165 185 {
166 186 // A tab can always accomodate a variable
167 187 Q_UNUSED(variable);
168 188 return true;
169 189 }
170 190
171 191 bool VisualizationZoneWidget::contains(const Variable &variable) const
172 192 {
173 193 Q_UNUSED(variable);
174 194 return false;
175 195 }
176 196
177 197 QString VisualizationZoneWidget::name() const
178 198 {
179 199 return ui->zoneNameLabel->text();
180 200 }
General Comments 3
Under Review
author

Pull request updated. Auto status change to "Under Review"

Changed commits:
  * 3 added
  * 0 removed

Changed files:
  * A plugins/amda/tests-resources/TestAmdaResultParser/FileNotFound.txt
  * M gui/src/Visualization/operations/RescaleAxeOperation.cpp
  * M app/src/MainWindow.cpp
  * M core/include/Data/IDataProvider.h
  * M core/include/DataSource/DataSourceItemAction.h
  * M core/include/Variable/VariableController.h
  * M core/include/Variable/VariableModel.h
  * M core/include/Visualization/VisualizationController.h
  * M core/src/Network/NetworkController.cpp
  * M core/src/Variable/Variable.cpp
  * M core/src/Variable/VariableController.cpp
  * M core/src/Variable/VariableModel.cpp
  * M gui/include/Visualization/VisualizationGraphWidget.h
  * M gui/include/Visualization/VisualizationWidget.h
  * M gui/src/SqpApplication.cpp
  * M gui/src/Variable/VariableInspectorWidget.cpp
  * M gui/src/Visualization/VisualizationGraphHelper.cpp
  * M gui/src/Visualization/VisualizationGraphWidget.cpp
  * M gui/src/Visualization/VisualizationWidget.cpp
  * M gui/src/Visualization/VisualizationZoneWidget.cpp
  * M plugins/amda/include/AmdaProvider.h
  * M plugins/amda/src/AmdaProvider.cpp
  * M plugins/amda/src/AmdaResultParser.cpp
  * M plugins/amda/tests/TestAmdaResultParser.cpp
  * M plugins/mockplugin/include/CosinusProvider.h
  * M plugins/mockplugin/src/CosinusProvider.cpp
  * R COPYING
  * R app/ui/MainWindow.ui
  * R cmake/sciqlop_package_qt.cmake
  * R core/include/Common/MetaTypes.h
  * R core/include/Data/ArrayData.h
  * R core/include/Data/DataProviderParameters.h
  * R core/include/Data/DataSeries.h
  * R core/include/Data/IDataSeries.h
  * R core/include/Data/ScalarSeries.h
  * R core/include/Data/SqpDateTime.h
  * R core/include/Network/NetworkController.h
  * R core/include/Plugin/PluginManager.h
  * R core/include/Time/TimeController.h
  * R core/include/Variable/Variable.h
  * R core/include/Variable/VariableCacheController.h
  * R core/src/Data/ScalarSeries.cpp
  * R core/src/DataSource/DataSourceItemAction.cpp
  * R core/src/Plugin/PluginManager.cpp
  * R core/src/Time/TimeController.cpp
  * R core/src/Variable/VariableCacheController.cpp
  * R core/src/Visualization/VisualizationController.cpp
  * R core/tests/Variable/TestVariableCacheController.cpp
  * R gui/include/DataSource/DataSourceTreeWidgetItem.h
  * R gui/include/DataSource/DataSourceWidget.h
  * R gui/include/SidePane/SqpSidePane.h
  * R gui/include/TimeWidget/TimeWidget.h
  * R gui/include/Variable/VariableInspectorWidget.h
  * R gui/include/Variable/VariableMenuHeaderWidget.h
  * R gui/include/Visualization/IVariableContainer.h
  * R gui/include/Visualization/IVisualizationWidget.h
  * R gui/include/Visualization/IVisualizationWidgetVisitor.h
  * R gui/include/Visualization/VisualizationGraphHelper.h
  * R gui/include/Visualization/VisualizationTabWidget.h
  * R gui/include/Visualization/VisualizationZoneWidget.h
  * R gui/include/Visualization/operations/GenerateVariableMenuOperation.h
  * R gui/include/Visualization/operations/MenuBuilder.h
  * R gui/include/Visualization/operations/RemoveVariableOperation.h
  * R gui/include/Visualization/qcustomplot.h
  * R gui/resources/icones/dataSourceComponent.png
  * R gui/resources/icones/dataSourceNode.png
  * R gui/resources/icones/dataSourceProduct.png
  * R gui/resources/icones/dataSourceRoot.png
  * R gui/resources/icones/delete.png
  * R gui/resources/icones/next.png
  * R gui/resources/icones/openInspector.png
  * R gui/resources/icones/plot.png
  * R gui/resources/icones/previous.png
  * R gui/resources/icones/sciqlop2PNG_1024.png
  * R gui/resources/icones/unplot.png
  * R gui/resources/sqpguiresources.qrc
  * R gui/src/DataSource/DataSourceTreeWidgetItem.cpp
  * R gui/src/DataSource/DataSourceWidget.cpp
  * R gui/src/SidePane/SqpSidePane.cpp
  * R gui/src/TimeWidget/TimeWidget.cpp
  * R gui/src/Variable/VariableMenuHeaderWidget.cpp
  * R gui/src/Visualization/VisualizationTabWidget.cpp
  * R gui/src/Visualization/operations/GenerateVariableMenuOperation.cpp
  * R gui/src/Visualization/operations/MenuBuilder.cpp
  * R gui/src/Visualization/operations/RemoveVariableOperation.cpp
  * R gui/src/Visualization/qcustomplot.cpp
  * R gui/ui/DataSource/DataSourceWidget.ui
  * R gui/ui/SidePane/SqpSidePane.ui
  * R gui/ui/TimeWidget/TimeWidget.ui
  * R gui/ui/Variable/VariableInspectorWidget.ui
  * R gui/ui/Variable/VariableMenuHeaderWidget.ui
  * R gui/ui/Visualization/VisualizationGraphWidget.ui
  * R gui/ui/Visualization/VisualizationTabWidget.ui
  * R gui/ui/Visualization/VisualizationWidget.ui
  * R gui/ui/Visualization/VisualizationZoneWidget.ui
  * R gui/vera-exclusions/exclusions.txt
  * R plugin/CMakeLists.txt
  * R plugin/cmake/Findsciqlop-plugin.cmake
  * R plugin/include/Plugin/IPlugin.h
  * R plugins/amda/CMakeLists.txt
  * R plugins/amda/cmake/Findsciqlop-amda.cmake
  * R plugins/amda/include/AmdaDefs.h
  * R plugins/amda/include/AmdaGlobal.h
  * R plugins/amda/include/AmdaParser.h
  * R plugins/amda/include/AmdaPlugin.h
  * R plugins/amda/include/AmdaResultParser.h
  * R plugins/amda/resources/amda.json
  * R plugins/amda/resources/amdaresources.qrc
  * R plugins/amda/resources/samples/AmdaSample.json
  * R plugins/amda/src/AmdaDefs.cpp
  * R plugins/amda/src/AmdaParser.cpp
  * R plugins/amda/src/AmdaPlugin.cpp
  * R plugins/amda/tests-resources/TestAmdaParser/TwoRootsFile.json
  * R plugins/amda/tests-resources/TestAmdaParser/ValidFile1.json
  * R plugins/amda/tests-resources/TestAmdaParser/WrongRootKey.json
  * R plugins/amda/tests-resources/TestAmdaParser/WrongRootType.json
  * R plugins/amda/tests-resources/TestAmdaResultParser/NaNValue.txt
  * R plugins/amda/tests-resources/TestAmdaResultParser/NoUnit.txt
  * R plugins/amda/tests-resources/TestAmdaResultParser/TooManyValues.txt
  * R plugins/amda/tests-resources/TestAmdaResultParser/ValidScalar1.txt
  * R plugins/amda/tests-resources/TestAmdaResultParser/WrongDate.txt
  * R plugins/amda/tests-resources/TestAmdaResultParser/WrongUnit.txt
  * R plugins/amda/tests-resources/TestAmdaResultParser/WrongValue.txt
  * R plugins/amda/tests/TestAmdaParser.cpp
  * R plugins/mockplugin/CMakeLists.txt
  * R plugins/mockplugin/cmake/Findsciqlop-mockplugin.cmake
  * R plugins/mockplugin/include/MockPlugin.h
  * R plugins/mockplugin/include/MockPluginGlobal.h
  * R plugins/mockplugin/resources/mockplugin.json
  * R plugins/mockplugin/src/MockPlugin.cpp
  * R README.md
  * R app/CMakeLists.txt
  * R app/include/MainWindow.h
  * R app/src/Main.cpp
  * R app/vera-exclusions/exclusions.txt
  * R cmake/sciqlop.cmake
  * R cmake/sciqlop_applications.cmake
  * R cmake/sciqlop_package.cmake
  * R cmake/sciqlop_params.cmake
  * R core/CMakeLists.txt
  * R core/include/Common/spimpl.h
  * R core/include/DataSource/DataSourceController.h
  * R core/include/DataSource/DataSourceItem.h
  * R core/src/DataSource/DataSourceController.cpp
  * R core/src/DataSource/DataSourceItem.cpp
  * R core/tests/DataSource/TestDataSourceController.cpp
  * R core/vera-exclusions/exclusions.txt
  * R formatting/cmake/use_clangformat.cmake
  * R formatting/vera-exclusions/exclusions.txt
  * R gui/CMakeLists.txt
  * R gui/include/SqpApplication.h
  * R LICENSE
  * R app/src/mainwindow.cpp
  * R app/src/mainwindow.ui
Approved
author

Status change > Approved

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