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