##// END OF EJS Templates
Handles desynchronisation when removing variable from a graph (2)...
Alexandre Leroux -
r677:48ebbf123b7f
parent child
Show More
@@ -1,97 +1,98
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 QCustomPlot;
17 17 class SqpRange;
18 18 class Variable;
19 19
20 20 namespace Ui {
21 21 class VisualizationGraphWidget;
22 22 } // namespace Ui
23 23
24 24 class VisualizationGraphWidget : public QWidget, public IVisualizationWidget {
25 25 Q_OBJECT
26 26
27 27 friend class QCustomPlotSynchronizer;
28 28 friend class VisualizationGraphRenderingDelegate;
29 29
30 30 public:
31 31 explicit VisualizationGraphWidget(const QString &name = {}, QWidget *parent = 0);
32 32 virtual ~VisualizationGraphWidget();
33 33
34 34 /// If acquisition isn't enable, requestDataLoading signal cannot be emit
35 35 void enableAcquisition(bool enable);
36 36
37 37 void addVariable(std::shared_ptr<Variable> variable, SqpRange range);
38 38
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 SqpRange &range);
43 43 void setYRange(const SqpRange &range);
44 44 SqpRange graphRange() const noexcept;
45 45 void setGraphRange(const SqpRange &range);
46 46
47 47 // IVisualizationWidget interface
48 48 void accept(IVisualizationWidgetVisitor *visitor) override;
49 49 bool canDrop(const Variable &variable) const override;
50 50 bool contains(const Variable &variable) const override;
51 51 QString name() const override;
52 52
53 53
54 54 signals:
55 55 void synchronize(const SqpRange &range, const SqpRange &oldRange);
56 56 void requestDataLoading(QVector<std::shared_ptr<Variable> > variable, const SqpRange &range,
57 57 const SqpRange &oldRange, bool synchronise);
58 58
59 59 /// Signal emitted when the variable is about to be removed from the graph
60 60 void variableAboutToBeRemoved(std::shared_ptr<Variable> var);
61 61 /// Signal emitted when the variable has been added to the graph
62 62 void variableAdded(std::shared_ptr<Variable> var);
63 63
64 64 protected:
65 void closeEvent(QCloseEvent *event) override;
65 66 void enterEvent(QEvent *event) override;
66 67 void leaveEvent(QEvent *event) override;
67 68
68 69 QCustomPlot &plot() noexcept;
69 70
70 71 private:
71 72 Ui::VisualizationGraphWidget *ui;
72 73
73 74 class VisualizationGraphWidgetPrivate;
74 75 spimpl::unique_impl_ptr<VisualizationGraphWidgetPrivate> impl;
75 76
76 77 private slots:
77 78 /// Slot called when right clicking on the graph (displays a menu)
78 79 void onGraphMenuRequested(const QPoint &pos) noexcept;
79 80
80 81 /// Rescale the X axe to range parameter
81 82 void onRangeChanged(const QCPRange &t1, const QCPRange &t2);
82 83
83 84 /// Slot called when a mouse move was made
84 85 void onMouseMove(QMouseEvent *event) noexcept;
85 86 /// Slot called when a mouse wheel was made, to perform some processing before the zoom is done
86 87 void onMouseWheel(QWheelEvent *event) noexcept;
87 88 /// Slot called when a mouse press was made, to activate the calibration of a graph
88 89 void onMousePress(QMouseEvent *event) noexcept;
89 90 /// Slot called when a mouse release was made, to deactivate the calibration of a graph
90 91 void onMouseRelease(QMouseEvent *event) noexcept;
91 92
92 93 void onDataCacheVariableUpdated();
93 94
94 95 void onUpdateVarDisplaying(std::shared_ptr<Variable> variable, const SqpRange &range);
95 96 };
96 97
97 98 #endif // SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
@@ -1,54 +1,57
1 1 #ifndef SCIQLOP_VISUALIZATIONTABWIDGET_H
2 2 #define SCIQLOP_VISUALIZATIONTABWIDGET_H
3 3
4 4 #include "Visualization/IVisualizationWidget.h"
5 5
6 6 #include <Common/spimpl.h>
7 7
8 8 #include <QLoggingCategory>
9 9 #include <QWidget>
10 10
11 11 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationTabWidget)
12 12
13 13 class Variable;
14 14 class VisualizationZoneWidget;
15 15
16 16 namespace Ui {
17 17 class VisualizationTabWidget;
18 18 } // namespace Ui
19 19
20 20 class VisualizationTabWidget : public QWidget, public IVisualizationWidget {
21 21 Q_OBJECT
22 22
23 23 public:
24 24 explicit VisualizationTabWidget(const QString &name = {}, QWidget *parent = 0);
25 25 virtual ~VisualizationTabWidget();
26 26
27 27 /// Add a zone widget
28 28 void addZone(VisualizationZoneWidget *zoneWidget);
29 29
30 30 /**
31 31 * Creates a zone using a variable. The variable will be displayed in a new graph of the new
32 32 * zone.
33 33 * @param variable the variable for which to create the zone
34 34 * @return the pointer to the created zone
35 35 */
36 36 VisualizationZoneWidget *createZone(std::shared_ptr<Variable> variable);
37 37
38 38 // IVisualizationWidget interface
39 39 void accept(IVisualizationWidgetVisitor *visitor) override;
40 40 bool canDrop(const Variable &variable) const override;
41 41 bool contains(const Variable &variable) const override;
42 42 QString name() const override;
43 43
44 protected:
45 void closeEvent(QCloseEvent *event) override;
46
44 47 private:
45 48 /// @return the layout of tab in which zones are added
46 49 QLayout &tabLayout() const noexcept;
47 50
48 51 Ui::VisualizationTabWidget *ui;
49 52
50 53 class VisualizationTabWidgetPrivate;
51 54 spimpl::unique_impl_ptr<VisualizationTabWidgetPrivate> impl;
52 55 };
53 56
54 57 #endif // SCIQLOP_VISUALIZATIONTABWIDGET_H
@@ -1,51 +1,54
1 1 #ifndef SCIQLOP_VISUALIZATIONWIDGET_H
2 2 #define SCIQLOP_VISUALIZATIONWIDGET_H
3 3
4 4 #include "Visualization/IVisualizationWidget.h"
5 5 #include <Data/SqpRange.h>
6 6
7 7 #include <QLoggingCategory>
8 8 #include <QWidget>
9 9
10 10 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationWidget)
11 11
12 12 class QMenu;
13 13 class Variable;
14 14 class VisualizationTabWidget;
15 15
16 16 namespace Ui {
17 17 class VisualizationWidget;
18 18 } // namespace Ui
19 19
20 20 class VisualizationWidget : public QWidget, public IVisualizationWidget {
21 21 Q_OBJECT
22 22
23 23 public:
24 24 explicit VisualizationWidget(QWidget *parent = 0);
25 25 virtual ~VisualizationWidget();
26 26
27 27 // IVisualizationWidget interface
28 28 void accept(IVisualizationWidgetVisitor *visitor) override;
29 29 bool canDrop(const Variable &variable) const override;
30 30 bool contains(const Variable &variable) const override;
31 31 QString name() const override;
32 32
33 33 public slots:
34 34 /**
35 35 * Attaches to a menu the menu relative to the visualization of variables
36 36 * @param menu the parent menu of the generated menu
37 37 * @param variables the variables for which to generate the menu
38 38 */
39 39 void attachVariableMenu(QMenu *menu,
40 40 const QVector<std::shared_ptr<Variable> > &variables) noexcept;
41 41
42 42 /// Slot called when a variable is about to be deleted from SciQlop
43 43 void onVariableAboutToBeDeleted(std::shared_ptr<Variable> variable) noexcept;
44 44
45 45 void onRangeChanged(std::shared_ptr<Variable> variable, const SqpRange &range) noexcept;
46 46
47 protected:
48 void closeEvent(QCloseEvent *event) override;
49
47 50 private:
48 51 Ui::VisualizationWidget *ui;
49 52 };
50 53
51 54 #endif // VISUALIZATIONWIDGET_H
@@ -1,57 +1,60
1 1 #ifndef SCIQLOP_VISUALIZATIONZONEWIDGET_H
2 2 #define SCIQLOP_VISUALIZATIONZONEWIDGET_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_VisualizationZoneWidget)
14 14
15 15 namespace Ui {
16 16 class VisualizationZoneWidget;
17 17 } // Ui
18 18
19 19 class Variable;
20 20 class VisualizationGraphWidget;
21 21
22 22 class VisualizationZoneWidget : public QWidget, public IVisualizationWidget {
23 23 Q_OBJECT
24 24
25 25 public:
26 26 explicit VisualizationZoneWidget(const QString &name = {}, QWidget *parent = 0);
27 27 virtual ~VisualizationZoneWidget();
28 28
29 29 /// Add a graph widget
30 30 void addGraph(VisualizationGraphWidget *graphWidget);
31 31
32 32 /**
33 33 * Creates a graph using a variable. The variable will be displayed in the new graph.
34 34 * @param variable the variable for which to create the graph
35 35 * @return the pointer to the created graph
36 36 */
37 37 VisualizationGraphWidget *createGraph(std::shared_ptr<Variable> variable);
38 38
39 39 // IVisualizationWidget interface
40 40 void accept(IVisualizationWidgetVisitor *visitor) override;
41 41 bool canDrop(const Variable &variable) const override;
42 42 bool contains(const Variable &variable) const override;
43 43 QString name() const override;
44 44
45 protected:
46 void closeEvent(QCloseEvent *event) override;
47
45 48 private:
46 49 Ui::VisualizationZoneWidget *ui;
47 50
48 51 class VisualizationZoneWidgetPrivate;
49 52 spimpl::unique_impl_ptr<VisualizationZoneWidgetPrivate> impl;
50 53
51 54 private slots:
52 55 void onVariableAdded(std::shared_ptr<Variable> variable);
53 56 /// Slot called when a variable is about to be removed from a graph contained in the zone
54 57 void onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable);
55 58 };
56 59
57 60 #endif // SCIQLOP_VISUALIZATIONZONEWIDGET_H
@@ -1,346 +1,356
1 1 #include "Visualization/VisualizationGraphWidget.h"
2 2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 3 #include "Visualization/VisualizationDefs.h"
4 4 #include "Visualization/VisualizationGraphHelper.h"
5 5 #include "Visualization/VisualizationGraphRenderingDelegate.h"
6 6 #include "ui_VisualizationGraphWidget.h"
7 7
8 8 #include <Data/ArrayData.h>
9 9 #include <Data/IDataSeries.h>
10 10 #include <Settings/SqpSettingsDefs.h>
11 11 #include <SqpApplication.h>
12 12 #include <Variable/Variable.h>
13 13 #include <Variable/VariableController.h>
14 14
15 15 #include <unordered_map>
16 16
17 17 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
18 18
19 19 namespace {
20 20
21 21 /// Key pressed to enable zoom on horizontal axis
22 22 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::NoModifier;
23 23
24 24 /// Key pressed to enable zoom on vertical axis
25 25 const auto VERTICAL_ZOOM_MODIFIER = Qt::ControlModifier;
26 26
27 27 } // namespace
28 28
29 29 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
30 30
31 31 explicit VisualizationGraphWidgetPrivate(const QString &name)
32 32 : m_Name{name},
33 33 m_DoAcquisition{true},
34 34 m_IsCalibration{false},
35 35 m_RenderingDelegate{nullptr}
36 36 {
37 37 }
38 38
39 39 QString m_Name;
40 40 // 1 variable -> n qcpplot
41 41 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
42 42 bool m_DoAcquisition;
43 43 bool m_IsCalibration;
44 44 QCPItemTracer *m_TextTracer;
45 45 /// Delegate used to attach rendering features to the plot
46 46 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
47 47 };
48 48
49 49 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
50 50 : QWidget{parent},
51 51 ui{new Ui::VisualizationGraphWidget},
52 52 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
53 53 {
54 54 ui->setupUi(this);
55 55
56 56 // 'Close' options : widget is deleted when closed
57 57 setAttribute(Qt::WA_DeleteOnClose);
58 58
59 59 // Set qcpplot properties :
60 60 // - Drag (on x-axis) and zoom are enabled
61 61 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
62 62 ui->widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectItems);
63 63 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal);
64 64
65 65 // The delegate must be initialized after the ui as it uses the plot
66 66 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
67 67
68 68 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
69 69 connect(ui->widget, &QCustomPlot::mouseRelease, this,
70 70 &VisualizationGraphWidget::onMouseRelease);
71 71 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
72 72 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
73 73 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
74 74 &QCPAxis::rangeChanged),
75 75 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
76 76
77 77 // Activates menu when right clicking on the graph
78 78 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
79 79 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
80 80 &VisualizationGraphWidget::onGraphMenuRequested);
81 81
82 82 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
83 83 &VariableController::onRequestDataLoading);
84 84
85 85 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
86 86 &VisualizationGraphWidget::onUpdateVarDisplaying);
87 87 }
88 88
89 89
90 90 VisualizationGraphWidget::~VisualizationGraphWidget()
91 91 {
92 92 delete ui;
93 93 }
94 94
95 95 void VisualizationGraphWidget::enableAcquisition(bool enable)
96 96 {
97 97 impl->m_DoAcquisition = enable;
98 98 }
99 99
100 100 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
101 101 {
102 102 // Uses delegate to create the qcpplot components according to the variable
103 103 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
104 104 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
105 105
106 106 // Set axes properties according to the units of the data series
107 107 /// @todo : for the moment, no control is performed on the axes: the units and the tickers
108 108 /// are fixed for the default x-axis and y-axis of the plot, and according to the new graph
109 109 auto xAxisUnit = Unit{};
110 110 auto valuesUnit = Unit{};
111 111
112 112 if (auto dataSeries = variable->dataSeries()) {
113 113 dataSeries->lockRead();
114 114 xAxisUnit = dataSeries->xAxisUnit();
115 115 valuesUnit = dataSeries->valuesUnit();
116 116 dataSeries->unlock();
117 117 }
118 118 impl->m_RenderingDelegate->setAxesProperties(xAxisUnit, valuesUnit);
119 119
120 120 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
121 121
122 122 auto varRange = variable->range();
123 123
124 124 this->enableAcquisition(false);
125 125 this->setGraphRange(range);
126 126 this->enableAcquisition(true);
127 127
128 128 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable, range, varRange,
129 129 false);
130 130
131 131 emit variableAdded(variable);
132 132 }
133 133
134 134 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
135 135 {
136 136 // Each component associated to the variable :
137 137 // - is removed from qcpplot (which deletes it)
138 138 // - is no longer referenced in the map
139 139 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
140 140 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
141 141 emit variableAboutToBeRemoved(variable);
142 142
143 143 auto &plottablesMap = variableIt->second;
144 144
145 145 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
146 146 plottableIt != plottableEnd;) {
147 147 ui->widget->removePlottable(plottableIt->second);
148 148 plottableIt = plottablesMap.erase(plottableIt);
149 149 }
150 150
151 151 impl->m_VariableToPlotMultiMap.erase(variableIt);
152 152 }
153 153
154 154 // Updates graph
155 155 ui->widget->replot();
156 156 }
157 157
158 158 void VisualizationGraphWidget::setRange(std::shared_ptr<Variable> variable, const SqpRange &range)
159 159 {
160 160 // Note: in case of different axes that depends on variable, we could start with a code like
161 161 // that:
162 162 // auto componentsIt = impl->m_VariableToPlotMultiMap.equal_range(variable);
163 163 // for (auto it = componentsIt.first; it != componentsIt.second;) {
164 164 // }
165 165 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
166 166 ui->widget->replot();
167 167 }
168 168
169 169 void VisualizationGraphWidget::setYRange(const SqpRange &range)
170 170 {
171 171 ui->widget->yAxis->setRange(range.m_TStart, range.m_TEnd);
172 172 }
173 173
174 174 SqpRange VisualizationGraphWidget::graphRange() const noexcept
175 175 {
176 176 auto graphRange = ui->widget->xAxis->range();
177 177 return SqpRange{graphRange.lower, graphRange.upper};
178 178 }
179 179
180 180 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
181 181 {
182 182 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
183 183 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
184 184 ui->widget->replot();
185 185 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
186 186 }
187 187
188 188 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
189 189 {
190 190 if (visitor) {
191 191 visitor->visit(this);
192 192 }
193 193 else {
194 194 qCCritical(LOG_VisualizationGraphWidget())
195 195 << tr("Can't visit widget : the visitor is null");
196 196 }
197 197 }
198 198
199 199 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
200 200 {
201 201 /// @todo : for the moment, a graph can always accomodate a variable
202 202 Q_UNUSED(variable);
203 203 return true;
204 204 }
205 205
206 206 bool VisualizationGraphWidget::contains(const Variable &variable) const
207 207 {
208 208 // Finds the variable among the keys of the map
209 209 auto variablePtr = &variable;
210 210 auto findVariable
211 211 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
212 212
213 213 auto end = impl->m_VariableToPlotMultiMap.cend();
214 214 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
215 215 return it != end;
216 216 }
217 217
218 218 QString VisualizationGraphWidget::name() const
219 219 {
220 220 return impl->m_Name;
221 221 }
222 222
223 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
224 {
225 Q_UNUSED(event);
226
227 // Prevents that all variables will be removed from graph when it will be closed
228 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
229 emit variableAboutToBeRemoved(variableEntry.first);
230 }
231 }
232
223 233 void VisualizationGraphWidget::enterEvent(QEvent *event)
224 234 {
225 235 Q_UNUSED(event);
226 236 impl->m_RenderingDelegate->showGraphOverlay(true);
227 237 }
228 238
229 239 void VisualizationGraphWidget::leaveEvent(QEvent *event)
230 240 {
231 241 Q_UNUSED(event);
232 242 impl->m_RenderingDelegate->showGraphOverlay(false);
233 243 }
234 244
235 245 QCustomPlot &VisualizationGraphWidget::plot() noexcept
236 246 {
237 247 return *ui->widget;
238 248 }
239 249
240 250 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
241 251 {
242 252 QMenu graphMenu{};
243 253
244 254 // Iterates on variables (unique keys)
245 255 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
246 256 end = impl->m_VariableToPlotMultiMap.cend();
247 257 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
248 258 // 'Remove variable' action
249 259 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
250 260 [ this, var = it->first ]() { removeVariable(var); });
251 261 }
252 262
253 263 if (!graphMenu.isEmpty()) {
254 264 graphMenu.exec(QCursor::pos());
255 265 }
256 266 }
257 267
258 268 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
259 269 {
260 270 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
261 271 << QThread::currentThread()->objectName() << "DoAcqui"
262 272 << impl->m_DoAcquisition;
263 273
264 274 auto graphRange = SqpRange{t1.lower, t1.upper};
265 275 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
266 276
267 277 if (impl->m_DoAcquisition) {
268 278 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
269 279
270 280 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
271 281 end = impl->m_VariableToPlotMultiMap.end();
272 282 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
273 283 variableUnderGraphVector.push_back(it->first);
274 284 }
275 285 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange, oldGraphRange,
276 286 !impl->m_IsCalibration);
277 287
278 288 if (!impl->m_IsCalibration) {
279 289 qCDebug(LOG_VisualizationGraphWidget())
280 290 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
281 291 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
282 292 emit synchronize(graphRange, oldGraphRange);
283 293 }
284 294 }
285 295 }
286 296
287 297 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
288 298 {
289 299 // Handles plot rendering when mouse is moving
290 300 impl->m_RenderingDelegate->onMouseMove(event);
291 301 }
292 302
293 303 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
294 304 {
295 305 auto zoomOrientations = QFlags<Qt::Orientation>{};
296 306
297 307 // Lambda that enables a zoom orientation if the key modifier related to this orientation
298 308 // has
299 309 // been pressed
300 310 auto enableOrientation
301 311 = [&zoomOrientations, event](const auto &orientation, const auto &modifier) {
302 312 auto orientationEnabled = event->modifiers().testFlag(modifier);
303 313 zoomOrientations.setFlag(orientation, orientationEnabled);
304 314 };
305 315 enableOrientation(Qt::Vertical, VERTICAL_ZOOM_MODIFIER);
306 316 enableOrientation(Qt::Horizontal, HORIZONTAL_ZOOM_MODIFIER);
307 317
308 318 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
309 319 }
310 320
311 321 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
312 322 {
313 323 impl->m_IsCalibration = event->modifiers().testFlag(Qt::ControlModifier);
314 324 }
315 325
316 326 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
317 327 {
318 328 impl->m_IsCalibration = false;
319 329 }
320 330
321 331 void VisualizationGraphWidget::onDataCacheVariableUpdated()
322 332 {
323 333 auto graphRange = ui->widget->xAxis->range();
324 334 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
325 335
326 336 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
327 337 auto variable = variableEntry.first;
328 338 qCDebug(LOG_VisualizationGraphWidget())
329 339 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
330 340 qCDebug(LOG_VisualizationGraphWidget())
331 341 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
332 342 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
333 343 VisualizationGraphHelper::updateData(variableEntry.second, variable->dataSeries(),
334 344 variable->range());
335 345 }
336 346 }
337 347 }
338 348
339 349 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
340 350 const SqpRange &range)
341 351 {
342 352 auto it = impl->m_VariableToPlotMultiMap.find(variable);
343 353 if (it != impl->m_VariableToPlotMultiMap.end()) {
344 354 VisualizationGraphHelper::updateData(it->second, variable->dataSeries(), range);
345 355 }
346 356 }
@@ -1,110 +1,129
1 1 #include "Visualization/VisualizationTabWidget.h"
2 2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 3 #include "ui_VisualizationTabWidget.h"
4 4
5 5 #include "Visualization/VisualizationZoneWidget.h"
6 6
7 7 Q_LOGGING_CATEGORY(LOG_VisualizationTabWidget, "VisualizationTabWidget")
8 8
9 9 namespace {
10 10
11 11 /// Generates a default name for a new zone, according to the number of zones already displayed in
12 12 /// the tab
13 13 QString defaultZoneName(const QLayout &layout)
14 14 {
15 15 auto count = 0;
16 16 for (auto i = 0; i < layout.count(); ++i) {
17 17 if (dynamic_cast<VisualizationZoneWidget *>(layout.itemAt(i)->widget())) {
18 18 count++;
19 19 }
20 20 }
21 21
22 22 return QObject::tr("Zone %1").arg(count + 1);
23 23 }
24 24
25 /**
26 * Applies a function to all zones of the tab represented by its layout
27 * @param layout the layout that contains zones
28 * @param fun the function to apply to each zone
29 */
30 template <typename Fun>
31 void processZones(QLayout &layout, Fun fun)
32 {
33 for (auto i = 0; i < layout.count(); ++i) {
34 if (auto item = layout.itemAt(i)) {
35 if (auto visualizationZoneWidget
36 = dynamic_cast<VisualizationZoneWidget *>(item->widget())) {
37 fun(*visualizationZoneWidget);
38 }
39 }
40 }
41 }
42
25 43 } // namespace
26 44
27 45 struct VisualizationTabWidget::VisualizationTabWidgetPrivate {
28 46 explicit VisualizationTabWidgetPrivate(const QString &name) : m_Name{name} {}
29 47
30 48 QString m_Name;
31 49 };
32 50
33 51 VisualizationTabWidget::VisualizationTabWidget(const QString &name, QWidget *parent)
34 52 : QWidget{parent},
35 53 ui{new Ui::VisualizationTabWidget},
36 54 impl{spimpl::make_unique_impl<VisualizationTabWidgetPrivate>(name)}
37 55 {
38 56 ui->setupUi(this);
39 57
40 58 // Widget is deleted when closed
41 59 setAttribute(Qt::WA_DeleteOnClose);
42 60 }
43 61
44 62 VisualizationTabWidget::~VisualizationTabWidget()
45 63 {
46 64 delete ui;
47 65 }
48 66
49 67 void VisualizationTabWidget::addZone(VisualizationZoneWidget *zoneWidget)
50 68 {
51 69 tabLayout().addWidget(zoneWidget);
52 70 }
53 71
54 72 VisualizationZoneWidget *VisualizationTabWidget::createZone(std::shared_ptr<Variable> variable)
55 73 {
56 74 auto zoneWidget = new VisualizationZoneWidget{defaultZoneName(tabLayout()), this};
57 75 this->addZone(zoneWidget);
58 76
59 77 // Creates a new graph into the zone
60 78 zoneWidget->createGraph(variable);
61 79
62 80 return zoneWidget;
63 81 }
64 82
65 83 void VisualizationTabWidget::accept(IVisualizationWidgetVisitor *visitor)
66 84 {
67 85 if (visitor) {
68 86 visitor->visitEnter(this);
69 87
70 // Apply visitor to zone children
71 auto &layout = tabLayout();
72 for (auto i = 0; i < layout.count(); ++i) {
73 if (auto item = layout.itemAt(i)) {
74 // Widgets different from zones are not visited (no action)
75 if (auto visualizationZoneWidget
76 = dynamic_cast<VisualizationZoneWidget *>(item->widget())) {
77 visualizationZoneWidget->accept(visitor);
78 }
79 }
80 }
88 // Apply visitor to zone children: widgets different from zones are not visited (no action)
89 processZones(tabLayout(), [visitor](VisualizationZoneWidget &zoneWidget) {
90 zoneWidget.accept(visitor);
91 });
81 92
82 93 visitor->visitLeave(this);
83 94 }
84 95 else {
85 96 qCCritical(LOG_VisualizationTabWidget()) << tr("Can't visit widget : the visitor is null");
86 97 }
87 98 }
88 99
89 100 bool VisualizationTabWidget::canDrop(const Variable &variable) const
90 101 {
91 102 // A tab can always accomodate a variable
92 103 Q_UNUSED(variable);
93 104 return true;
94 105 }
95 106
96 107 bool VisualizationTabWidget::contains(const Variable &variable) const
97 108 {
98 109 Q_UNUSED(variable);
99 110 return false;
100 111 }
101 112
102 113 QString VisualizationTabWidget::name() const
103 114 {
104 115 return impl->m_Name;
105 116 }
106 117
118 void VisualizationTabWidget::closeEvent(QCloseEvent *event)
119 {
120 // Closes zones in the tab
121 processZones(tabLayout(), [](VisualizationZoneWidget &zoneWidget) { zoneWidget.close(); });
122
123 QWidget::closeEvent(event);
124 }
125
107 126 QLayout &VisualizationTabWidget::tabLayout() const noexcept
108 127 {
109 128 return *ui->scrollAreaWidgetContents->layout();
110 129 }
@@ -1,159 +1,172
1 1 #include "Visualization/VisualizationWidget.h"
2 2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 3 #include "Visualization/VisualizationGraphWidget.h"
4 4 #include "Visualization/VisualizationTabWidget.h"
5 5 #include "Visualization/VisualizationZoneWidget.h"
6 6 #include "Visualization/operations/FindVariableOperation.h"
7 7 #include "Visualization/operations/GenerateVariableMenuOperation.h"
8 8 #include "Visualization/operations/RemoveVariableOperation.h"
9 9 #include "Visualization/operations/RescaleAxeOperation.h"
10 10 #include "Visualization/qcustomplot.h"
11 11
12 12 #include "ui_VisualizationWidget.h"
13 13
14 14 #include <QToolButton>
15 15
16 16 Q_LOGGING_CATEGORY(LOG_VisualizationWidget, "VisualizationWidget")
17 17
18 18 VisualizationWidget::VisualizationWidget(QWidget *parent)
19 19 : QWidget{parent}, ui{new Ui::VisualizationWidget}
20 20 {
21 21 ui->setupUi(this);
22 22
23 23 auto addTabViewButton = new QToolButton{ui->tabWidget};
24 24 addTabViewButton->setText(tr("Add View"));
25 25 addTabViewButton->setCursor(Qt::ArrowCursor);
26 26 ui->tabWidget->setCornerWidget(addTabViewButton, Qt::TopRightCorner);
27 27
28 28 auto enableMinimumCornerWidgetSize = [this](bool enable) {
29 29
30 30 auto tabViewCornerWidget = ui->tabWidget->cornerWidget();
31 31 auto width = enable ? tabViewCornerWidget->width() : 0;
32 32 auto height = enable ? tabViewCornerWidget->height() : 0;
33 33 tabViewCornerWidget->setMinimumHeight(height);
34 34 tabViewCornerWidget->setMinimumWidth(width);
35 35 ui->tabWidget->setMinimumHeight(height);
36 36 ui->tabWidget->setMinimumWidth(width);
37 37 };
38 38
39 39 auto addTabView = [this, enableMinimumCornerWidgetSize]() {
40 40 auto widget = new VisualizationTabWidget{QString{"View %1"}.arg(ui->tabWidget->count() + 1),
41 41 ui->tabWidget};
42 42 auto index = ui->tabWidget->addTab(widget, widget->name());
43 43 if (ui->tabWidget->count() > 0) {
44 44 enableMinimumCornerWidgetSize(false);
45 45 }
46 46 qCInfo(LOG_VisualizationWidget()) << tr("add the tab of index %1").arg(index);
47 47 };
48 48
49 49 auto removeTabView = [this, enableMinimumCornerWidgetSize](int index) {
50 50 if (ui->tabWidget->count() == 1) {
51 51 enableMinimumCornerWidgetSize(true);
52 52 }
53 53
54 54 // Removes widget from tab and closes it
55 55 auto widget = ui->tabWidget->widget(index);
56 56 ui->tabWidget->removeTab(index);
57 57 if (widget) {
58 58 widget->close();
59 59 }
60 60
61 61 qCInfo(LOG_VisualizationWidget()) << tr("remove the tab of index %1").arg(index);
62 62
63 63 };
64 64
65 65 ui->tabWidget->setTabsClosable(true);
66 66
67 67 connect(addTabViewButton, &QToolButton::clicked, addTabView);
68 68 connect(ui->tabWidget, &QTabWidget::tabCloseRequested, removeTabView);
69 69
70 70 // Adds default tab
71 71 addTabView();
72 72 }
73 73
74 74 VisualizationWidget::~VisualizationWidget()
75 75 {
76 76 delete ui;
77 77 }
78 78
79 79 void VisualizationWidget::accept(IVisualizationWidgetVisitor *visitor)
80 80 {
81 81 if (visitor) {
82 82 visitor->visitEnter(this);
83 83
84 84 // Apply visitor for tab children
85 85 for (auto i = 0; i < ui->tabWidget->count(); ++i) {
86 86 // Widgets different from tabs are not visited (no action)
87 87 if (auto visualizationTabWidget
88 88 = dynamic_cast<VisualizationTabWidget *>(ui->tabWidget->widget(i))) {
89 89 visualizationTabWidget->accept(visitor);
90 90 }
91 91 }
92 92
93 93 visitor->visitLeave(this);
94 94 }
95 95 else {
96 96 qCCritical(LOG_VisualizationWidget()) << tr("Can't visit widget : the visitor is null");
97 97 }
98 98 }
99 99
100 100 bool VisualizationWidget::canDrop(const Variable &variable) const
101 101 {
102 102 // The main widget can never accomodate a variable
103 103 Q_UNUSED(variable);
104 104 return false;
105 105 }
106 106
107 107 bool VisualizationWidget::contains(const Variable &variable) const
108 108 {
109 109 Q_UNUSED(variable);
110 110 return false;
111 111 }
112 112
113 113 QString VisualizationWidget::name() const
114 114 {
115 115 return QStringLiteral("MainView");
116 116 }
117 117
118 118 void VisualizationWidget::attachVariableMenu(
119 119 QMenu *menu, const QVector<std::shared_ptr<Variable> > &variables) noexcept
120 120 {
121 121 // Menu is generated only if there is a single variable
122 122 if (variables.size() == 1) {
123 123 if (auto variable = variables.first()) {
124 124 // Gets the containers of the variable
125 125 FindVariableOperation findVariableOperation{variable};
126 126 accept(&findVariableOperation);
127 127 auto variableContainers = findVariableOperation.result();
128 128
129 129 // Generates the actions that make it possible to visualize the variable
130 130 GenerateVariableMenuOperation generateVariableMenuOperation{
131 131 menu, variable, std::move(variableContainers)};
132 132 accept(&generateVariableMenuOperation);
133 133 }
134 134 else {
135 135 qCCritical(LOG_VisualizationWidget()) << tr(
136 136 "Can't generate the menu relative to the visualization: the variable is null");
137 137 }
138 138 }
139 139 else {
140 140 qCDebug(LOG_VisualizationWidget())
141 141 << tr("No generation of the menu related to the visualization: several variables are "
142 142 "selected");
143 143 }
144 144 }
145 145
146 146 void VisualizationWidget::onVariableAboutToBeDeleted(std::shared_ptr<Variable> variable) noexcept
147 147 {
148 148 // Calls the operation of removing all references to the variable in the visualization
149 149 auto removeVariableOperation = RemoveVariableOperation{variable};
150 150 accept(&removeVariableOperation);
151 151 }
152 152
153 153 void VisualizationWidget::onRangeChanged(std::shared_ptr<Variable> variable,
154 154 const SqpRange &range) noexcept
155 155 {
156 156 // Calls the operation of rescaling all graph that contrains variable in the visualization
157 157 auto rescaleVariableOperation = RescaleAxeOperation{variable, range};
158 158 accept(&rescaleVariableOperation);
159 159 }
160
161 void VisualizationWidget::closeEvent(QCloseEvent *event)
162 {
163 // Closes tabs in the widget
164 for (auto i = 0; i < ui->tabWidget->count(); ++i) {
165 if (auto visualizationTabWidget
166 = dynamic_cast<VisualizationTabWidget *>(ui->tabWidget->widget(i))) {
167 visualizationTabWidget->close();
168 }
169 }
170
171 QWidget::closeEvent(event);
172 }
@@ -1,277 +1,298
1 1 #include "Visualization/VisualizationZoneWidget.h"
2 2
3 3 #include "Visualization/IVisualizationWidgetVisitor.h"
4 4 #include "Visualization/QCustomPlotSynchronizer.h"
5 5 #include "Visualization/VisualizationGraphWidget.h"
6 6 #include "ui_VisualizationZoneWidget.h"
7 7
8 8 #include <Data/SqpRange.h>
9 9 #include <Variable/Variable.h>
10 10 #include <Variable/VariableController.h>
11 11
12 12 #include <QUuid>
13 13 #include <SqpApplication.h>
14 14 #include <cmath>
15 15
16 16 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
17 17
18 18 namespace {
19 19
20 20 /// Minimum height for graph added in zones (in pixels)
21 21 const auto GRAPH_MINIMUM_HEIGHT = 300;
22 22
23 23 /// Generates a default name for a new graph, according to the number of graphs already displayed in
24 24 /// the zone
25 25 QString defaultGraphName(const QLayout &layout)
26 26 {
27 27 auto count = 0;
28 28 for (auto i = 0; i < layout.count(); ++i) {
29 29 if (dynamic_cast<VisualizationGraphWidget *>(layout.itemAt(i)->widget())) {
30 30 count++;
31 31 }
32 32 }
33 33
34 34 return QObject::tr("Graph %1").arg(count + 1);
35 35 }
36 36
37 /**
38 * Applies a function to all graphs of the zone represented by its layout
39 * @param layout the layout that contains graphs
40 * @param fun the function to apply to each graph
41 */
42 template <typename Fun>
43 void processGraphs(QLayout &layout, Fun fun)
44 {
45 for (auto i = 0; i < layout.count(); ++i) {
46 if (auto item = layout.itemAt(i)) {
47 if (auto visualizationGraphWidget
48 = dynamic_cast<VisualizationGraphWidget *>(item->widget())) {
49 fun(*visualizationGraphWidget);
50 }
51 }
52 }
53 }
54
37 55 } // namespace
38 56
39 57 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate {
40 58
41 59 explicit VisualizationZoneWidgetPrivate()
42 60 : m_SynchronisationGroupId{QUuid::createUuid()},
43 61 m_Synchronizer{std::make_unique<QCustomPlotSynchronizer>()}
44 62 {
45 63 }
46 64 QUuid m_SynchronisationGroupId;
47 65 std::unique_ptr<IGraphSynchronizer> m_Synchronizer;
48 66 };
49 67
50 68 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
51 69 : QWidget{parent},
52 70 ui{new Ui::VisualizationZoneWidget},
53 71 impl{spimpl::make_unique_impl<VisualizationZoneWidgetPrivate>()}
54 72 {
55 73 ui->setupUi(this);
56 74
57 75 ui->zoneNameLabel->setText(name);
58 76
59 77 // 'Close' options : widget is deleted when closed
60 78 setAttribute(Qt::WA_DeleteOnClose);
61 79 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
62 80 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
63 81
64 82 // Synchronisation id
65 83 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronizationGroupId",
66 84 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
67 85 }
68 86
69 87 VisualizationZoneWidget::~VisualizationZoneWidget()
70 88 {
71 89 delete ui;
72 90 }
73 91
74 92 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
75 93 {
76 94 // Synchronize new graph with others in the zone
77 95 impl->m_Synchronizer->addGraph(*graphWidget);
78 96
79 97 ui->visualizationZoneFrame->layout()->addWidget(graphWidget);
80 98 }
81 99
82 100 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
83 101 {
84 102 auto graphWidget = new VisualizationGraphWidget{
85 103 defaultGraphName(*ui->visualizationZoneFrame->layout()), this};
86 104
87 105
88 106 // Set graph properties
89 107 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
90 108 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
91 109
92 110
93 111 // Lambda to synchronize zone widget
94 112 auto synchronizeZoneWidget = [this, graphWidget](const SqpRange &graphRange,
95 113 const SqpRange &oldGraphRange) {
96 114
97 115 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
98 116 auto frameLayout = ui->visualizationZoneFrame->layout();
99 117 for (auto i = 0; i < frameLayout->count(); ++i) {
100 118 auto graphChild
101 119 = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
102 120 if (graphChild && (graphChild != graphWidget)) {
103 121
104 122 auto graphChildRange = graphChild->graphRange();
105 123 switch (zoomType) {
106 124 case AcquisitionZoomType::ZoomIn: {
107 125 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
108 126 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
109 127 graphChildRange.m_TStart += deltaLeft;
110 128 graphChildRange.m_TEnd -= deltaRight;
111 129 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomIn");
112 130 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
113 131 << deltaLeft;
114 132 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
115 133 << deltaRight;
116 134 qCDebug(LOG_VisualizationZoneWidget())
117 135 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
118 136
119 137 break;
120 138 }
121 139
122 140 case AcquisitionZoomType::ZoomOut: {
123 141 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomOut");
124 142 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
125 143 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
126 144 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
127 145 << deltaLeft;
128 146 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
129 147 << deltaRight;
130 148 qCDebug(LOG_VisualizationZoneWidget())
131 149 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
132 150 graphChildRange.m_TStart -= deltaLeft;
133 151 graphChildRange.m_TEnd += deltaRight;
134 152 break;
135 153 }
136 154 case AcquisitionZoomType::PanRight: {
137 155 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanRight");
138 156 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
139 157 graphChildRange.m_TStart += deltaRight;
140 158 graphChildRange.m_TEnd += deltaRight;
141 159 qCDebug(LOG_VisualizationZoneWidget())
142 160 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
143 161 break;
144 162 }
145 163 case AcquisitionZoomType::PanLeft: {
146 164 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanLeft");
147 165 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
148 166 graphChildRange.m_TStart -= deltaLeft;
149 167 graphChildRange.m_TEnd -= deltaLeft;
150 168 break;
151 169 }
152 170 case AcquisitionZoomType::Unknown: {
153 171 qCDebug(LOG_VisualizationZoneWidget())
154 172 << tr("Impossible to synchronize: zoom type unknown");
155 173 break;
156 174 }
157 175 default:
158 176 qCCritical(LOG_VisualizationZoneWidget())
159 177 << tr("Impossible to synchronize: zoom type not take into account");
160 178 // No action
161 179 break;
162 180 }
163 181 graphChild->enableAcquisition(false);
164 182 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range before: ")
165 183 << graphChild->graphRange();
166 184 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range after : ")
167 185 << graphChildRange;
168 186 qCDebug(LOG_VisualizationZoneWidget())
169 187 << tr("TORM: child dt") << graphChildRange.m_TEnd - graphChildRange.m_TStart;
170 188 graphChild->setGraphRange(graphChildRange);
171 189 graphChild->enableAcquisition(true);
172 190 }
173 191 }
174 192 };
175 193
176 194 // connection for synchronization
177 195 connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
178 196 connect(graphWidget, &VisualizationGraphWidget::variableAdded, this,
179 197 &VisualizationZoneWidget::onVariableAdded);
180 198 connect(graphWidget, &VisualizationGraphWidget::variableAboutToBeRemoved, this,
181 199 &VisualizationZoneWidget::onVariableAboutToBeRemoved);
182 200
183 201 auto range = SqpRange{};
184 202
185 203 // Apply visitor to graph children
186 204 auto layout = ui->visualizationZoneFrame->layout();
187 205 if (layout->count() > 0) {
188 206 // Case of a new graph in a existant zone
189 207 if (auto visualizationGraphWidget
190 208 = dynamic_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
191 209 range = visualizationGraphWidget->graphRange();
192 210 }
193 211 }
194 212 else {
195 213 // Case of a new graph as the first of the zone
196 214 range = variable->range();
197 215 }
198 216
199 217 this->addGraph(graphWidget);
200 218
201 219 graphWidget->addVariable(variable, range);
202 220
203 221 // get y using variable range
204 222 if (auto dataSeries = variable->dataSeries()) {
205 223 dataSeries->lockRead();
206 224 auto valuesBounds
207 225 = dataSeries->valuesBounds(variable->range().m_TStart, variable->range().m_TEnd);
208 226 auto end = dataSeries->cend();
209 227 if (valuesBounds.first != end && valuesBounds.second != end) {
210 228 auto rangeValue = [](const auto &value) { return std::isnan(value) ? 0. : value; };
211 229
212 230 auto minValue = rangeValue(valuesBounds.first->minValue());
213 231 auto maxValue = rangeValue(valuesBounds.second->maxValue());
214 232
215 233 graphWidget->setYRange(SqpRange{minValue, maxValue});
216 234 }
217 235 dataSeries->unlock();
218 236 }
219 237
220 238 return graphWidget;
221 239 }
222 240
223 241 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
224 242 {
225 243 if (visitor) {
226 244 visitor->visitEnter(this);
227 245
228 // Apply visitor to graph children
229 auto layout = ui->visualizationZoneFrame->layout();
230 for (auto i = 0; i < layout->count(); ++i) {
231 if (auto item = layout->itemAt(i)) {
232 // Widgets different from graphs are not visited (no action)
233 if (auto visualizationGraphWidget
234 = dynamic_cast<VisualizationGraphWidget *>(item->widget())) {
235 visualizationGraphWidget->accept(visitor);
236 }
237 }
238 }
246 // Apply visitor to graph children: widgets different from graphs are not visited (no
247 // action)
248 processGraphs(
249 *ui->visualizationZoneFrame->layout(),
250 [visitor](VisualizationGraphWidget &graphWidget) { graphWidget.accept(visitor); });
239 251
240 252 visitor->visitLeave(this);
241 253 }
242 254 else {
243 255 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
244 256 }
245 257 }
246 258
247 259 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
248 260 {
249 261 // A tab can always accomodate a variable
250 262 Q_UNUSED(variable);
251 263 return true;
252 264 }
253 265
254 266 bool VisualizationZoneWidget::contains(const Variable &variable) const
255 267 {
256 268 Q_UNUSED(variable);
257 269 return false;
258 270 }
259 271
260 272 QString VisualizationZoneWidget::name() const
261 273 {
262 274 return ui->zoneNameLabel->text();
263 275 }
264 276
277 void VisualizationZoneWidget::closeEvent(QCloseEvent *event)
278 {
279 // Closes graphs in the zone
280 processGraphs(*ui->visualizationZoneFrame->layout(),
281 [](VisualizationGraphWidget &graphWidget) { graphWidget.close(); });
282
283 QWidget::closeEvent(event);
284 }
285
265 286 void VisualizationZoneWidget::onVariableAdded(std::shared_ptr<Variable> variable)
266 287 {
267 288 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronized",
268 289 Qt::QueuedConnection, Q_ARG(std::shared_ptr<Variable>, variable),
269 290 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
270 291 }
271 292
272 293 void VisualizationZoneWidget::onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable)
273 294 {
274 295 QMetaObject::invokeMethod(&sqpApp->variableController(), "desynchronize", Qt::QueuedConnection,
275 296 Q_ARG(std::shared_ptr<Variable>, variable),
276 297 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
277 298 }
General Comments 0
You need to be logged in to leave comments. Login now