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