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