##// END OF EJS Templates
Remove variable from graph (3)...
Alexandre Leroux -
r251:7858a36671f7
parent child
Show More
@@ -1,226 +1,237
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 // 1 variable -> n qcpplot
28 // 1 variable -> n qcpplot
29 std::multimap<std::shared_ptr<Variable>, QCPAbstractPlottable *> m_VariableToPlotMultiMap;
29 std::multimap<std::shared_ptr<Variable>, QCPAbstractPlottable *> m_VariableToPlotMultiMap;
30 };
30 };
31
31
32 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
32 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
33 : QWidget{parent},
33 : QWidget{parent},
34 ui{new Ui::VisualizationGraphWidget},
34 ui{new Ui::VisualizationGraphWidget},
35 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>()}
35 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>()}
36 {
36 {
37 ui->setupUi(this);
37 ui->setupUi(this);
38
38
39 ui->graphNameLabel->setText(name);
39 ui->graphNameLabel->setText(name);
40
40
41 // 'Close' options : widget is deleted when closed
41 // 'Close' options : widget is deleted when closed
42 setAttribute(Qt::WA_DeleteOnClose);
42 setAttribute(Qt::WA_DeleteOnClose);
43 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationGraphWidget::close);
43 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationGraphWidget::close);
44 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
44 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
45
45
46 // Set qcpplot properties :
46 // Set qcpplot properties :
47 // - Drag (on x-axis) and zoom are enabled
47 // - Drag (on x-axis) and zoom are enabled
48 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
48 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
49 ui->widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);
49 ui->widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);
50 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal);
50 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal);
51 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
51 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
52 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
52 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
53 &QCPAxis::rangeChanged),
53 &QCPAxis::rangeChanged),
54 this, &VisualizationGraphWidget::onRangeChanged);
54 this, &VisualizationGraphWidget::onRangeChanged);
55
55
56 // Activates menu when right clicking on the graph
56 // Activates menu when right clicking on the graph
57 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
57 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
58 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
58 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
59 &VisualizationGraphWidget::onGraphMenuRequested);
59 &VisualizationGraphWidget::onGraphMenuRequested);
60 }
60 }
61
61
62
62
63 VisualizationGraphWidget::~VisualizationGraphWidget()
63 VisualizationGraphWidget::~VisualizationGraphWidget()
64 {
64 {
65 delete ui;
65 delete ui;
66 }
66 }
67
67
68 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable)
68 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable)
69 {
69 {
70 // Uses delegate to create the qcpplot components according to the variable
70 // Uses delegate to create the qcpplot components according to the variable
71 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
71 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
72
72
73 for (auto createdPlottable : qAsConst(createdPlottables)) {
73 for (auto createdPlottable : qAsConst(createdPlottables)) {
74 impl->m_VariableToPlotMultiMap.insert({variable, createdPlottable});
74 impl->m_VariableToPlotMultiMap.insert({variable, createdPlottable});
75 }
75 }
76
76
77 connect(variable.get(), SIGNAL(dataCacheUpdated()), this, SLOT(onDataCacheVariableUpdated()));
77 connect(variable.get(), SIGNAL(dataCacheUpdated()), this, SLOT(onDataCacheVariableUpdated()));
78 }
78 }
79
79
80 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
80 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
81 {
81 {
82 // Each component associated to the variable :
83 // - is removed from qcpplot (which deletes it)
84 // - is no longer referenced in the map
85 auto componentsIt = impl->m_VariableToPlotMultiMap.equal_range(variable);
86 for (auto it = componentsIt.first; it != componentsIt.second;) {
87 ui->widget->removePlottable(it->second);
88 it = impl->m_VariableToPlotMultiMap.erase(it);
89 }
90
91 // Updates graph
92 ui->widget->replot();
82 }
93 }
83
94
84 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
95 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
85 {
96 {
86 if (visitor) {
97 if (visitor) {
87 visitor->visit(this);
98 visitor->visit(this);
88 }
99 }
89 else {
100 else {
90 qCCritical(LOG_VisualizationGraphWidget())
101 qCCritical(LOG_VisualizationGraphWidget())
91 << tr("Can't visit widget : the visitor is null");
102 << tr("Can't visit widget : the visitor is null");
92 }
103 }
93 }
104 }
94
105
95 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
106 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
96 {
107 {
97 /// @todo : for the moment, a graph can always accomodate a variable
108 /// @todo : for the moment, a graph can always accomodate a variable
98 Q_UNUSED(variable);
109 Q_UNUSED(variable);
99 return true;
110 return true;
100 }
111 }
101
112
102 QString VisualizationGraphWidget::name() const
113 QString VisualizationGraphWidget::name() const
103 {
114 {
104 return ui->graphNameLabel->text();
115 return ui->graphNameLabel->text();
105 }
116 }
106
117
107 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
118 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
108 {
119 {
109 QMenu graphMenu{};
120 QMenu graphMenu{};
110
121
111 // Iterates on variables (unique keys)
122 // Iterates on variables (unique keys)
112 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
123 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
113 end = impl->m_VariableToPlotMultiMap.cend();
124 end = impl->m_VariableToPlotMultiMap.cend();
114 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
125 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
115 // 'Remove variable' action
126 // 'Remove variable' action
116 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
127 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
117 [ this, var = it->first ]() { removeVariable(var); });
128 [ this, var = it->first ]() { removeVariable(var); });
118 }
129 }
119
130
120 if (!graphMenu.isEmpty()) {
131 if (!graphMenu.isEmpty()) {
121 graphMenu.exec(mapToGlobal(pos));
132 graphMenu.exec(mapToGlobal(pos));
122 }
133 }
123 }
134 }
124
135
125 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
136 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
126 {
137 {
127
138
128 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::onRangeChanged");
139 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::onRangeChanged");
129
140
130 for (auto it = impl->m_VariableToPlotMultiMap.cbegin();
141 for (auto it = impl->m_VariableToPlotMultiMap.cbegin();
131 it != impl->m_VariableToPlotMultiMap.cend(); ++it) {
142 it != impl->m_VariableToPlotMultiMap.cend(); ++it) {
132
143
133 auto variable = it->first;
144 auto variable = it->first;
134 qCInfo(LOG_VisualizationGraphWidget())
145 qCInfo(LOG_VisualizationGraphWidget())
135 << tr("TORM: VisualizationGraphWidget::onRangeChanged")
146 << tr("TORM: VisualizationGraphWidget::onRangeChanged")
136 << variable->dataSeries()->xAxisData()->size();
147 << variable->dataSeries()->xAxisData()->size();
137 auto dateTime = SqpDateTime{t2.lower, t2.upper};
148 auto dateTime = SqpDateTime{t2.lower, t2.upper};
138
149
139 if (!variable->contains(dateTime)) {
150 if (!variable->contains(dateTime)) {
140
151
141 auto variableDateTimeWithTolerance = dateTime;
152 auto variableDateTimeWithTolerance = dateTime;
142 if (variable->intersect(dateTime)) {
153 if (variable->intersect(dateTime)) {
143 auto variableDateTime = variable->dateTime();
154 auto variableDateTime = variable->dateTime();
144 if (variableDateTime.m_TStart < dateTime.m_TStart) {
155 if (variableDateTime.m_TStart < dateTime.m_TStart) {
145
156
146 auto diffEndToKeepDelta = dateTime.m_TEnd - variableDateTime.m_TEnd;
157 auto diffEndToKeepDelta = dateTime.m_TEnd - variableDateTime.m_TEnd;
147 dateTime.m_TStart = variableDateTime.m_TStart + diffEndToKeepDelta;
158 dateTime.m_TStart = variableDateTime.m_TStart + diffEndToKeepDelta;
148 // Tolerance have to be added to the right
159 // Tolerance have to be added to the right
149 // add 10% tolerance for right (end) side
160 // add 10% tolerance for right (end) side
150 auto tolerance = 0.1 * (dateTime.m_TEnd - dateTime.m_TStart);
161 auto tolerance = 0.1 * (dateTime.m_TEnd - dateTime.m_TStart);
151 variableDateTimeWithTolerance.m_TEnd += tolerance;
162 variableDateTimeWithTolerance.m_TEnd += tolerance;
152 }
163 }
153 if (variableDateTime.m_TEnd > dateTime.m_TEnd) {
164 if (variableDateTime.m_TEnd > dateTime.m_TEnd) {
154 auto diffStartToKeepDelta = dateTime.m_TStart - dateTime.m_TStart;
165 auto diffStartToKeepDelta = dateTime.m_TStart - dateTime.m_TStart;
155 dateTime.m_TEnd = variableDateTime.m_TEnd - diffStartToKeepDelta;
166 dateTime.m_TEnd = variableDateTime.m_TEnd - diffStartToKeepDelta;
156 // Tolerance have to be added to the left
167 // Tolerance have to be added to the left
157 // add 10% tolerance for left (start) side
168 // add 10% tolerance for left (start) side
158 auto tolerance = 0.1 * (dateTime.m_TEnd - dateTime.m_TStart);
169 auto tolerance = 0.1 * (dateTime.m_TEnd - dateTime.m_TStart);
159 variableDateTimeWithTolerance.m_TStart -= tolerance;
170 variableDateTimeWithTolerance.m_TStart -= tolerance;
160 }
171 }
161 }
172 }
162 else {
173 else {
163 // add 10% tolerance for each side
174 // add 10% tolerance for each side
164 auto tolerance = 0.1 * (dateTime.m_TEnd - dateTime.m_TStart);
175 auto tolerance = 0.1 * (dateTime.m_TEnd - dateTime.m_TStart);
165 variableDateTimeWithTolerance.m_TStart -= tolerance;
176 variableDateTimeWithTolerance.m_TStart -= tolerance;
166 variableDateTimeWithTolerance.m_TEnd += tolerance;
177 variableDateTimeWithTolerance.m_TEnd += tolerance;
167 }
178 }
168 variable->setDateTime(dateTime);
179 variable->setDateTime(dateTime);
169
180
170 // CHangement detected, we need to ask controller to request data loading
181 // CHangement detected, we need to ask controller to request data loading
171 sqpApp->variableController().requestDataLoading(variable,
182 sqpApp->variableController().requestDataLoading(variable,
172 variableDateTimeWithTolerance);
183 variableDateTimeWithTolerance);
173 }
184 }
174 }
185 }
175 }
186 }
176
187
177 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
188 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
178 {
189 {
179 auto zoomOrientations = QFlags<Qt::Orientation>{};
190 auto zoomOrientations = QFlags<Qt::Orientation>{};
180
191
181 // Lambda that enables a zoom orientation if the key modifier related to this orientation
192 // Lambda that enables a zoom orientation if the key modifier related to this orientation
182 // has
193 // has
183 // been pressed
194 // been pressed
184 auto enableOrientation
195 auto enableOrientation
185 = [&zoomOrientations, event](const auto &orientation, const auto &modifier) {
196 = [&zoomOrientations, event](const auto &orientation, const auto &modifier) {
186 auto orientationEnabled = event->modifiers().testFlag(modifier);
197 auto orientationEnabled = event->modifiers().testFlag(modifier);
187 zoomOrientations.setFlag(orientation, orientationEnabled);
198 zoomOrientations.setFlag(orientation, orientationEnabled);
188 };
199 };
189 enableOrientation(Qt::Vertical, VERTICAL_ZOOM_MODIFIER);
200 enableOrientation(Qt::Vertical, VERTICAL_ZOOM_MODIFIER);
190 enableOrientation(Qt::Horizontal, HORIZONTAL_ZOOM_MODIFIER);
201 enableOrientation(Qt::Horizontal, HORIZONTAL_ZOOM_MODIFIER);
191
202
192 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
203 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
193 }
204 }
194
205
195 void VisualizationGraphWidget::onDataCacheVariableUpdated()
206 void VisualizationGraphWidget::onDataCacheVariableUpdated()
196 {
207 {
197 // NOTE:
208 // NOTE:
198 // We don't want to call the method for each component of a variable unitarily, but for
209 // We don't want to call the method for each component of a variable unitarily, but for
199 // all
210 // all
200 // its components at once (eg its three components in the case of a vector).
211 // its components at once (eg its three components in the case of a vector).
201
212
202 // The unordered_multimap does not do this easily, so the question is whether to:
213 // The unordered_multimap does not do this easily, so the question is whether to:
203 // - use an ordered_multimap and the algos of std to group the values by key
214 // - use an ordered_multimap and the algos of std to group the values by key
204 // - use a map (unique keys) and store as values directly the list of components
215 // - use a map (unique keys) and store as values directly the list of components
205
216
206 for (auto it = impl->m_VariableToPlotMultiMap.cbegin();
217 for (auto it = impl->m_VariableToPlotMultiMap.cbegin();
207 it != impl->m_VariableToPlotMultiMap.cend(); ++it) {
218 it != impl->m_VariableToPlotMultiMap.cend(); ++it) {
208 auto variable = it->first;
219 auto variable = it->first;
209 VisualizationGraphHelper::updateData(QVector<QCPAbstractPlottable *>{} << it->second,
220 VisualizationGraphHelper::updateData(QVector<QCPAbstractPlottable *>{} << it->second,
210 variable->dataSeries(), variable->dateTime());
221 variable->dataSeries(), variable->dateTime());
211 }
222 }
212 }
223 }
213
224
214 void VisualizationGraphWidget::updateDisplay(std::shared_ptr<Variable> variable)
225 void VisualizationGraphWidget::updateDisplay(std::shared_ptr<Variable> variable)
215 {
226 {
216 auto abstractPlotableItPair = impl->m_VariableToPlotMultiMap.equal_range(variable);
227 auto abstractPlotableItPair = impl->m_VariableToPlotMultiMap.equal_range(variable);
217
228
218 auto abstractPlotableVect = QVector<QCPAbstractPlottable *>{};
229 auto abstractPlotableVect = QVector<QCPAbstractPlottable *>{};
219
230
220 for (auto it = abstractPlotableItPair.first; it != abstractPlotableItPair.second; ++it) {
231 for (auto it = abstractPlotableItPair.first; it != abstractPlotableItPair.second; ++it) {
221 abstractPlotableVect.push_back(it->second);
232 abstractPlotableVect.push_back(it->second);
222 }
233 }
223
234
224 VisualizationGraphHelper::updateData(abstractPlotableVect, variable->dataSeries(),
235 VisualizationGraphHelper::updateData(abstractPlotableVect, variable->dataSeries(),
225 variable->dateTime());
236 variable->dateTime());
226 }
237 }
General Comments 0
You need to be logged in to leave comments. Login now