##// END OF EJS Templates
Merge branch 'feature/TimeVariableAtDisplay' into develop
perrinel -
r317:e774472e365b merge
parent child
Show More
@@ -1,63 +1,64
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 namespace Ui {
19 namespace Ui {
20 class VisualizationGraphWidget;
20 class VisualizationGraphWidget;
21 } // namespace Ui
21 } // namespace Ui
22
22
23 class VisualizationGraphWidget : public QWidget, public IVisualizationWidget {
23 class VisualizationGraphWidget : public QWidget, public IVisualizationWidget {
24 Q_OBJECT
24 Q_OBJECT
25
25
26 public:
26 public:
27 explicit VisualizationGraphWidget(const QString &name = {}, QWidget *parent = 0);
27 explicit VisualizationGraphWidget(const QString &name = {}, QWidget *parent = 0);
28 virtual ~VisualizationGraphWidget();
28 virtual ~VisualizationGraphWidget();
29
29
30 void addVariable(std::shared_ptr<Variable> variable);
30 void addVariable(std::shared_ptr<Variable> variable);
31 void addVariableUsingGraph(std::shared_ptr<Variable> variable);
31 /// Removes a variable from the graph
32 /// Removes a variable from the graph
32 void removeVariable(std::shared_ptr<Variable> variable) noexcept;
33 void removeVariable(std::shared_ptr<Variable> variable) noexcept;
33
34
34 // IVisualizationWidget interface
35 // IVisualizationWidget interface
35 void accept(IVisualizationWidgetVisitor *visitor) override;
36 void accept(IVisualizationWidgetVisitor *visitor) override;
36 bool canDrop(const Variable &variable) const override;
37 bool canDrop(const Variable &variable) const override;
37 QString name() const override;
38 QString name() const override;
38
39
39 void updateDisplay(std::shared_ptr<Variable> variable);
40 void updateDisplay(std::shared_ptr<Variable> variable);
40
41
41 signals:
42 signals:
42 void requestDataLoading(std::shared_ptr<Variable> variable, const SqpDateTime &dateTime);
43 void requestDataLoading(std::shared_ptr<Variable> variable, const SqpDateTime &dateTime);
43
44
44
45
45 private:
46 private:
46 Ui::VisualizationGraphWidget *ui;
47 Ui::VisualizationGraphWidget *ui;
47
48
48 class VisualizationGraphWidgetPrivate;
49 class VisualizationGraphWidgetPrivate;
49 spimpl::unique_impl_ptr<VisualizationGraphWidgetPrivate> impl;
50 spimpl::unique_impl_ptr<VisualizationGraphWidgetPrivate> impl;
50
51
51 private slots:
52 private slots:
52 /// Slot called when right clicking on the graph (displays a menu)
53 /// Slot called when right clicking on the graph (displays a menu)
53 void onGraphMenuRequested(const QPoint &pos) noexcept;
54 void onGraphMenuRequested(const QPoint &pos) noexcept;
54
55
55 void onRangeChanged(const QCPRange &t1, const QCPRange &t2);
56 void onRangeChanged(const QCPRange &t1);
56
57
57 /// Slot called when a mouse wheel was made, to perform some processing before the zoom is done
58 /// Slot called when a mouse wheel was made, to perform some processing before the zoom is done
58 void onMouseWheel(QWheelEvent *event) noexcept;
59 void onMouseWheel(QWheelEvent *event) noexcept;
59
60
60 void onDataCacheVariableUpdated();
61 void onDataCacheVariableUpdated();
61 };
62 };
62
63
63 #endif // SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
64 #endif // SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
@@ -1,153 +1,157
1 #include "Visualization/VisualizationGraphHelper.h"
1 #include "Visualization/VisualizationGraphHelper.h"
2 #include "Visualization/qcustomplot.h"
2 #include "Visualization/qcustomplot.h"
3
3
4 #include <Data/ScalarSeries.h>
4 #include <Data/ScalarSeries.h>
5
5
6 #include <Variable/Variable.h>
6 #include <Variable/Variable.h>
7
7
8 #include <QElapsedTimer>
8 #include <QElapsedTimer>
9
9
10 Q_LOGGING_CATEGORY(LOG_VisualizationGraphHelper, "VisualizationGraphHelper")
10 Q_LOGGING_CATEGORY(LOG_VisualizationGraphHelper, "VisualizationGraphHelper")
11
11
12 namespace {
12 namespace {
13
13
14 /// Format for datetimes on a axis
14 /// Format for datetimes on a axis
15 const auto DATETIME_TICKER_FORMAT = QStringLiteral("yyyy/MM/dd \nhh:mm:ss");
15 const auto DATETIME_TICKER_FORMAT = QStringLiteral("yyyy/MM/dd \nhh:mm:ss");
16
16
17 /// Generates the appropriate ticker for an axis, depending on whether the axis displays time or
17 /// Generates the appropriate ticker for an axis, depending on whether the axis displays time or
18 /// non-time data
18 /// non-time data
19 QSharedPointer<QCPAxisTicker> axisTicker(bool isTimeAxis)
19 QSharedPointer<QCPAxisTicker> axisTicker(bool isTimeAxis)
20 {
20 {
21 if (isTimeAxis) {
21 if (isTimeAxis) {
22 auto dateTicker = QSharedPointer<QCPAxisTickerDateTime>::create();
22 auto dateTicker = QSharedPointer<QCPAxisTickerDateTime>::create();
23 dateTicker->setDateTimeFormat(DATETIME_TICKER_FORMAT);
23 dateTicker->setDateTimeFormat(DATETIME_TICKER_FORMAT);
24
24
25 return dateTicker;
25 return dateTicker;
26 }
26 }
27 else {
27 else {
28 // default ticker
28 // default ticker
29 return QSharedPointer<QCPAxisTicker>::create();
29 return QSharedPointer<QCPAxisTicker>::create();
30 }
30 }
31 }
31 }
32
32
33 void updateScalarData(QCPAbstractPlottable *component, ScalarSeries &scalarSeries,
33 void updateScalarData(QCPAbstractPlottable *component, ScalarSeries &scalarSeries,
34 const SqpDateTime &dateTime)
34 const SqpDateTime &dateTime)
35 {
35 {
36 QElapsedTimer timer;
36 QElapsedTimer timer;
37 timer.start();
37 timer.start();
38 if (auto qcpGraph = dynamic_cast<QCPGraph *>(component)) {
38 if (auto qcpGraph = dynamic_cast<QCPGraph *>(component)) {
39 // Clean the graph
39 // Clean the graph
40 // NAIVE approch
40 // NAIVE approch
41 const auto &xData = scalarSeries.xAxisData()->data();
41 const auto &xData = scalarSeries.xAxisData()->data();
42 const auto &valuesData = scalarSeries.valuesData()->data();
42 const auto &valuesData = scalarSeries.valuesData()->data();
43 const auto count = xData.count();
43 const auto count = xData.count();
44 qCInfo(LOG_VisualizationGraphHelper()) << "TORM: Current points in cache" << xData.count();
44 qCInfo(LOG_VisualizationGraphHelper()) << "TORM: Current points in cache" << xData.count();
45
45
46 auto xValue = QVector<double>(count);
46 auto xValue = QVector<double>(count);
47 auto vValue = QVector<double>(count);
47 auto vValue = QVector<double>(count);
48
48
49 int n = 0;
49 int n = 0;
50 for (auto i = 0; i < count; ++i) {
50 for (auto i = 0; i < count; ++i) {
51 const auto x = xData[i];
51 const auto x = xData[i];
52 if (x >= dateTime.m_TStart && x <= dateTime.m_TEnd) {
52 if (x >= dateTime.m_TStart && x <= dateTime.m_TEnd) {
53 xValue[n] = x;
53 xValue[n] = x;
54 vValue[n] = valuesData[i];
54 vValue[n] = valuesData[i];
55 ++n;
55 ++n;
56 }
56 }
57 }
57 }
58
58
59 xValue.resize(n);
59 xValue.resize(n);
60 vValue.resize(n);
60 vValue.resize(n);
61
61
62 qCInfo(LOG_VisualizationGraphHelper()) << "TORM: Current points displayed"
62 qCInfo(LOG_VisualizationGraphHelper()) << "TORM: Current points displayed"
63 << xValue.count();
63 << xValue.count();
64
64
65 qcpGraph->setData(xValue, vValue);
65 qcpGraph->setData(xValue, vValue);
66
67 // Display all data
68 // component->parentPlot()->xAxis->setRange(dateTime.m_TStart, dateTime.m_TEnd);
69 component->rescaleAxes();
70 component->parentPlot()->replot();
66 }
71 }
67 else {
72 else {
68 /// @todo DEBUG
73 /// @todo DEBUG
69 }
74 }
70 }
75 }
71
76
72 QCPAbstractPlottable *createScalarSeriesComponent(ScalarSeries &scalarSeries, QCustomPlot &plot,
77 QCPAbstractPlottable *createScalarSeriesComponent(ScalarSeries &scalarSeries, QCustomPlot &plot,
73 const SqpDateTime &dateTime)
78 const SqpDateTime &dateTime)
74 {
79 {
75 auto component = plot.addGraph();
80 auto component = plot.addGraph();
76
81
77 if (component) {
82 if (component) {
78 // // Graph data
83 // // Graph data
79 component->setData(scalarSeries.xAxisData()->data(), scalarSeries.valuesData()->data(),
84 component->setData(scalarSeries.xAxisData()->data(), scalarSeries.valuesData()->data(),
80 true);
85 true);
81
86
82 updateScalarData(component, scalarSeries, dateTime);
87 updateScalarData(component, scalarSeries, dateTime);
83
88
84 // Axes properties
89 // Axes properties
85 /// @todo : for the moment, no control is performed on the axes: the units and the tickers
90 /// @todo : for the moment, no control is performed on the axes: the units and the tickers
86 /// are fixed for the default x-axis and y-axis of the plot, and according to the new graph
91 /// are fixed for the default x-axis and y-axis of the plot, and according to the new graph
87
92
88 auto setAxisProperties = [](auto axis, const auto &unit) {
93 auto setAxisProperties = [](auto axis, const auto &unit) {
89 // label (unit name)
94 // label (unit name)
90 axis->setLabel(unit.m_Name);
95 axis->setLabel(unit.m_Name);
91
96
92 // ticker (depending on the type of unit)
97 // ticker (depending on the type of unit)
93 axis->setTicker(axisTicker(unit.m_TimeUnit));
98 axis->setTicker(axisTicker(unit.m_TimeUnit));
94 };
99 };
95 setAxisProperties(plot.xAxis, scalarSeries.xAxisUnit());
100 setAxisProperties(plot.xAxis, scalarSeries.xAxisUnit());
96 setAxisProperties(plot.yAxis, scalarSeries.valuesUnit());
101 setAxisProperties(plot.yAxis, scalarSeries.valuesUnit());
97
102
98 // Display all data
103 // Display all data
99 component->rescaleAxes();
104 component->rescaleAxes();
100
101 plot.replot();
105 plot.replot();
102 }
106 }
103 else {
107 else {
104 qCDebug(LOG_VisualizationGraphHelper())
108 qCDebug(LOG_VisualizationGraphHelper())
105 << QObject::tr("Can't create graph for the scalar series");
109 << QObject::tr("Can't create graph for the scalar series");
106 }
110 }
107
111
108 return component;
112 return component;
109 }
113 }
110
114
111 } // namespace
115 } // namespace
112
116
113 QVector<QCPAbstractPlottable *> VisualizationGraphHelper::create(std::shared_ptr<Variable> variable,
117 QVector<QCPAbstractPlottable *> VisualizationGraphHelper::create(std::shared_ptr<Variable> variable,
114 QCustomPlot &plot) noexcept
118 QCustomPlot &plot) noexcept
115 {
119 {
116 auto result = QVector<QCPAbstractPlottable *>{};
120 auto result = QVector<QCPAbstractPlottable *>{};
117
121
118 if (variable) {
122 if (variable) {
119 // Gets the data series of the variable to call the creation of the right components
123 // Gets the data series of the variable to call the creation of the right components
120 // according to its type
124 // according to its type
121 if (auto scalarSeries = dynamic_cast<ScalarSeries *>(variable->dataSeries())) {
125 if (auto scalarSeries = dynamic_cast<ScalarSeries *>(variable->dataSeries())) {
122 result.append(createScalarSeriesComponent(*scalarSeries, plot, variable->dateTime()));
126 result.append(createScalarSeriesComponent(*scalarSeries, plot, variable->dateTime()));
123 }
127 }
124 else {
128 else {
125 qCDebug(LOG_VisualizationGraphHelper())
129 qCDebug(LOG_VisualizationGraphHelper())
126 << QObject::tr("Can't create graph plottables : unmanaged data series type");
130 << QObject::tr("Can't create graph plottables : unmanaged data series type");
127 }
131 }
128 }
132 }
129 else {
133 else {
130 qCDebug(LOG_VisualizationGraphHelper())
134 qCDebug(LOG_VisualizationGraphHelper())
131 << QObject::tr("Can't create graph plottables : the variable is null");
135 << QObject::tr("Can't create graph plottables : the variable is null");
132 }
136 }
133
137
134 return result;
138 return result;
135 }
139 }
136
140
137 void VisualizationGraphHelper::updateData(QVector<QCPAbstractPlottable *> plotableVect,
141 void VisualizationGraphHelper::updateData(QVector<QCPAbstractPlottable *> plotableVect,
138 IDataSeries *dataSeries, const SqpDateTime &dateTime)
142 IDataSeries *dataSeries, const SqpDateTime &dateTime)
139 {
143 {
140 if (auto scalarSeries = dynamic_cast<ScalarSeries *>(dataSeries)) {
144 if (auto scalarSeries = dynamic_cast<ScalarSeries *>(dataSeries)) {
141 if (plotableVect.size() == 1) {
145 if (plotableVect.size() == 1) {
142 updateScalarData(plotableVect.at(0), *scalarSeries, dateTime);
146 updateScalarData(plotableVect.at(0), *scalarSeries, dateTime);
143 }
147 }
144 else {
148 else {
145 qCCritical(LOG_VisualizationGraphHelper()) << QObject::tr(
149 qCCritical(LOG_VisualizationGraphHelper()) << QObject::tr(
146 "Can't update Data of a scalarSeries because there is not only one component "
150 "Can't update Data of a scalarSeries because there is not only one component "
147 "associated");
151 "associated");
148 }
152 }
149 }
153 }
150 else {
154 else {
151 /// @todo DEBUG
155 /// @todo DEBUG
152 }
156 }
153 }
157 }
@@ -1,236 +1,263
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,
53 &QCPAxis::rangeChanged),
53 static_cast<void (QCPAxis::*)(const QCPRange &)>(&QCPAxis::rangeChanged), this,
54 this, &VisualizationGraphWidget::onRangeChanged);
54 &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 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
61 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
62 &VariableController::onRequestDataLoading);
62 &VariableController::onRequestDataLoading);
63 }
63 }
64
64
65
65
66 VisualizationGraphWidget::~VisualizationGraphWidget()
66 VisualizationGraphWidget::~VisualizationGraphWidget()
67 {
67 {
68 delete ui;
68 delete ui;
69 }
69 }
70
70
71 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable)
71 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable)
72 {
72 {
73 // Uses delegate to create the qcpplot components according to the variable
73 // Uses delegate to create the qcpplot components according to the variable
74 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
74 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
75
75
76 for (auto createdPlottable : qAsConst(createdPlottables)) {
76 for (auto createdPlottable : qAsConst(createdPlottables)) {
77 impl->m_VariableToPlotMultiMap.insert({variable, createdPlottable});
77 impl->m_VariableToPlotMultiMap.insert({variable, createdPlottable});
78 }
78 }
79
79
80 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
80 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
81 }
81 }
82
82
83 void VisualizationGraphWidget::addVariableUsingGraph(std::shared_ptr<Variable> variable)
84 {
85
86 // when adding a variable, we need to set its time range to the current graph range
87 auto grapheRange = ui->widget->xAxis->range();
88 auto dateTime = SqpDateTime{grapheRange.lower, grapheRange.upper};
89 variable->setDateTime(dateTime);
90
91 auto variableDateTimeWithTolerance = dateTime;
92
93 // add 10% tolerance for each side
94 auto tolerance = 0.1 * (dateTime.m_TEnd - dateTime.m_TStart);
95 variableDateTimeWithTolerance.m_TStart -= tolerance;
96 variableDateTimeWithTolerance.m_TEnd += tolerance;
97
98 // Uses delegate to create the qcpplot components according to the variable
99 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
100
101 for (auto createdPlottable : qAsConst(createdPlottables)) {
102 impl->m_VariableToPlotMultiMap.insert({variable, createdPlottable});
103 }
104
105 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
106
107 // CHangement detected, we need to ask controller to request data loading
108 emit requestDataLoading(variable, variableDateTimeWithTolerance);
109 }
110
83 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
111 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
84 {
112 {
85 // Each component associated to the variable :
113 // Each component associated to the variable :
86 // - is removed from qcpplot (which deletes it)
114 // - is removed from qcpplot (which deletes it)
87 // - is no longer referenced in the map
115 // - is no longer referenced in the map
88 auto componentsIt = impl->m_VariableToPlotMultiMap.equal_range(variable);
116 auto componentsIt = impl->m_VariableToPlotMultiMap.equal_range(variable);
89 for (auto it = componentsIt.first; it != componentsIt.second;) {
117 for (auto it = componentsIt.first; it != componentsIt.second;) {
90 ui->widget->removePlottable(it->second);
118 ui->widget->removePlottable(it->second);
91 it = impl->m_VariableToPlotMultiMap.erase(it);
119 it = impl->m_VariableToPlotMultiMap.erase(it);
92 }
120 }
93
121
94 // Updates graph
122 // Updates graph
95 ui->widget->replot();
123 ui->widget->replot();
96 }
124 }
97
125
98 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
126 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
99 {
127 {
100 if (visitor) {
128 if (visitor) {
101 visitor->visit(this);
129 visitor->visit(this);
102 }
130 }
103 else {
131 else {
104 qCCritical(LOG_VisualizationGraphWidget())
132 qCCritical(LOG_VisualizationGraphWidget())
105 << tr("Can't visit widget : the visitor is null");
133 << tr("Can't visit widget : the visitor is null");
106 }
134 }
107 }
135 }
108
136
109 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
137 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
110 {
138 {
111 /// @todo : for the moment, a graph can always accomodate a variable
139 /// @todo : for the moment, a graph can always accomodate a variable
112 Q_UNUSED(variable);
140 Q_UNUSED(variable);
113 return true;
141 return true;
114 }
142 }
115
143
116 QString VisualizationGraphWidget::name() const
144 QString VisualizationGraphWidget::name() const
117 {
145 {
118 return ui->graphNameLabel->text();
146 return ui->graphNameLabel->text();
119 }
147 }
120
148
121 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
149 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
122 {
150 {
123 QMenu graphMenu{};
151 QMenu graphMenu{};
124
152
125 // Iterates on variables (unique keys)
153 // Iterates on variables (unique keys)
126 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
154 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
127 end = impl->m_VariableToPlotMultiMap.cend();
155 end = impl->m_VariableToPlotMultiMap.cend();
128 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
156 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
129 // 'Remove variable' action
157 // 'Remove variable' action
130 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
158 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
131 [ this, var = it->first ]() { removeVariable(var); });
159 [ this, var = it->first ]() { removeVariable(var); });
132 }
160 }
133
161
134 if (!graphMenu.isEmpty()) {
162 if (!graphMenu.isEmpty()) {
135 graphMenu.exec(mapToGlobal(pos));
163 graphMenu.exec(mapToGlobal(pos));
136 }
164 }
137 }
165 }
138
166
139 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
167 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1)
140 {
168 {
141
142 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::onRangeChanged");
169 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::onRangeChanged");
143
170
144 for (auto it = impl->m_VariableToPlotMultiMap.cbegin();
171 for (auto it = impl->m_VariableToPlotMultiMap.cbegin();
145 it != impl->m_VariableToPlotMultiMap.cend(); ++it) {
172 it != impl->m_VariableToPlotMultiMap.cend(); ++it) {
146
173
147 auto variable = it->first;
174 auto variable = it->first;
148 auto dateTime = SqpDateTime{t2.lower, t2.upper};
175 auto dateTime = SqpDateTime{t1.lower, t1.upper};
149
176
150 if (!variable->contains(dateTime)) {
177 if (!variable->contains(dateTime)) {
151
178
152 auto variableDateTimeWithTolerance = dateTime;
179 auto variableDateTimeWithTolerance = dateTime;
153 if (variable->intersect(dateTime)) {
180 if (variable->intersect(dateTime)) {
154 auto variableDateTime = variable->dateTime();
181 auto variableDateTime = variable->dateTime();
155 if (variableDateTime.m_TStart < dateTime.m_TStart) {
182 if (variableDateTime.m_TStart < dateTime.m_TStart) {
156
183
157 auto diffEndToKeepDelta = dateTime.m_TEnd - variableDateTime.m_TEnd;
184 auto diffEndToKeepDelta = dateTime.m_TEnd - variableDateTime.m_TEnd;
158 dateTime.m_TStart = variableDateTime.m_TStart + diffEndToKeepDelta;
185 dateTime.m_TStart = variableDateTime.m_TStart + diffEndToKeepDelta;
159 // Tolerance have to be added to the right
186 // Tolerance have to be added to the right
160 // add 10% tolerance for right (end) side
187 // add 10% tolerance for right (end) side
161 auto tolerance = 0.1 * (dateTime.m_TEnd - dateTime.m_TStart);
188 auto tolerance = 0.1 * (dateTime.m_TEnd - dateTime.m_TStart);
162 variableDateTimeWithTolerance.m_TEnd += tolerance;
189 variableDateTimeWithTolerance.m_TEnd += tolerance;
163 }
190 }
164 if (variableDateTime.m_TEnd > dateTime.m_TEnd) {
191 if (variableDateTime.m_TEnd > dateTime.m_TEnd) {
165 auto diffStartToKeepDelta = variableDateTime.m_TStart - dateTime.m_TStart;
192 auto diffStartToKeepDelta = variableDateTime.m_TStart - dateTime.m_TStart;
166 dateTime.m_TEnd = variableDateTime.m_TEnd - diffStartToKeepDelta;
193 dateTime.m_TEnd = variableDateTime.m_TEnd - diffStartToKeepDelta;
167 // Tolerance have to be added to the left
194 // Tolerance have to be added to the left
168 // add 10% tolerance for left (start) side
195 // add 10% tolerance for left (start) side
169 auto tolerance = 0.1 * (dateTime.m_TEnd - dateTime.m_TStart);
196 auto tolerance = 0.1 * (dateTime.m_TEnd - dateTime.m_TStart);
170 variableDateTimeWithTolerance.m_TStart -= tolerance;
197 variableDateTimeWithTolerance.m_TStart -= tolerance;
171 }
198 }
172 }
199 }
173 else {
200 else {
174 // add 10% tolerance for each side
201 // add 10% tolerance for each side
175 auto tolerance = 0.1 * (dateTime.m_TEnd - dateTime.m_TStart);
202 auto tolerance = 0.1 * (dateTime.m_TEnd - dateTime.m_TStart);
176 variableDateTimeWithTolerance.m_TStart -= tolerance;
203 variableDateTimeWithTolerance.m_TStart -= tolerance;
177 variableDateTimeWithTolerance.m_TEnd += tolerance;
204 variableDateTimeWithTolerance.m_TEnd += tolerance;
178 }
205 }
179 variable->setDateTime(dateTime);
206 variable->setDateTime(dateTime);
180
207
181 // CHangement detected, we need to ask controller to request data loading
208 // CHangement detected, we need to ask controller to request data loading
182 emit requestDataLoading(variable, variableDateTimeWithTolerance);
209 emit requestDataLoading(variable, variableDateTimeWithTolerance);
183 }
210 }
184 }
211 }
185 }
212 }
186
213
187 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
214 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
188 {
215 {
189 auto zoomOrientations = QFlags<Qt::Orientation>{};
216 auto zoomOrientations = QFlags<Qt::Orientation>{};
190
217
191 // Lambda that enables a zoom orientation if the key modifier related to this orientation
218 // Lambda that enables a zoom orientation if the key modifier related to this orientation
192 // has
219 // has
193 // been pressed
220 // been pressed
194 auto enableOrientation
221 auto enableOrientation
195 = [&zoomOrientations, event](const auto &orientation, const auto &modifier) {
222 = [&zoomOrientations, event](const auto &orientation, const auto &modifier) {
196 auto orientationEnabled = event->modifiers().testFlag(modifier);
223 auto orientationEnabled = event->modifiers().testFlag(modifier);
197 zoomOrientations.setFlag(orientation, orientationEnabled);
224 zoomOrientations.setFlag(orientation, orientationEnabled);
198 };
225 };
199 enableOrientation(Qt::Vertical, VERTICAL_ZOOM_MODIFIER);
226 enableOrientation(Qt::Vertical, VERTICAL_ZOOM_MODIFIER);
200 enableOrientation(Qt::Horizontal, HORIZONTAL_ZOOM_MODIFIER);
227 enableOrientation(Qt::Horizontal, HORIZONTAL_ZOOM_MODIFIER);
201
228
202 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
229 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
203 }
230 }
204
231
205 void VisualizationGraphWidget::onDataCacheVariableUpdated()
232 void VisualizationGraphWidget::onDataCacheVariableUpdated()
206 {
233 {
207 // NOTE:
234 // NOTE:
208 // We don't want to call the method for each component of a variable unitarily, but for
235 // We don't want to call the method for each component of a variable unitarily, but for
209 // all
236 // all
210 // its components at once (eg its three components in the case of a vector).
237 // its components at once (eg its three components in the case of a vector).
211
238
212 // The unordered_multimap does not do this easily, so the question is whether to:
239 // The unordered_multimap does not do this easily, so the question is whether to:
213 // - use an ordered_multimap and the algos of std to group the values by key
240 // - use an ordered_multimap and the algos of std to group the values by key
214 // - use a map (unique keys) and store as values directly the list of components
241 // - use a map (unique keys) and store as values directly the list of components
215
242
216 for (auto it = impl->m_VariableToPlotMultiMap.cbegin();
243 for (auto it = impl->m_VariableToPlotMultiMap.cbegin();
217 it != impl->m_VariableToPlotMultiMap.cend(); ++it) {
244 it != impl->m_VariableToPlotMultiMap.cend(); ++it) {
218 auto variable = it->first;
245 auto variable = it->first;
219 VisualizationGraphHelper::updateData(QVector<QCPAbstractPlottable *>{} << it->second,
246 VisualizationGraphHelper::updateData(QVector<QCPAbstractPlottable *>{} << it->second,
220 variable->dataSeries(), variable->dateTime());
247 variable->dataSeries(), variable->dateTime());
221 }
248 }
222 }
249 }
223
250
224 void VisualizationGraphWidget::updateDisplay(std::shared_ptr<Variable> variable)
251 void VisualizationGraphWidget::updateDisplay(std::shared_ptr<Variable> variable)
225 {
252 {
226 auto abstractPlotableItPair = impl->m_VariableToPlotMultiMap.equal_range(variable);
253 auto abstractPlotableItPair = impl->m_VariableToPlotMultiMap.equal_range(variable);
227
254
228 auto abstractPlotableVect = QVector<QCPAbstractPlottable *>{};
255 auto abstractPlotableVect = QVector<QCPAbstractPlottable *>{};
229
256
230 for (auto it = abstractPlotableItPair.first; it != abstractPlotableItPair.second; ++it) {
257 for (auto it = abstractPlotableItPair.first; it != abstractPlotableItPair.second; ++it) {
231 abstractPlotableVect.push_back(it->second);
258 abstractPlotableVect.push_back(it->second);
232 }
259 }
233
260
234 VisualizationGraphHelper::updateData(abstractPlotableVect, variable->dataSeries(),
261 VisualizationGraphHelper::updateData(abstractPlotableVect, variable->dataSeries(),
235 variable->dateTime());
262 variable->dateTime());
236 }
263 }
@@ -1,146 +1,146
1 #include "Visualization/operations/GenerateVariableMenuOperation.h"
1 #include "Visualization/operations/GenerateVariableMenuOperation.h"
2 #include "Visualization/operations/MenuBuilder.h"
2 #include "Visualization/operations/MenuBuilder.h"
3
3
4 #include "Visualization/VisualizationGraphWidget.h"
4 #include "Visualization/VisualizationGraphWidget.h"
5 #include "Visualization/VisualizationTabWidget.h"
5 #include "Visualization/VisualizationTabWidget.h"
6 #include "Visualization/VisualizationZoneWidget.h"
6 #include "Visualization/VisualizationZoneWidget.h"
7
7
8 #include <Variable/Variable.h>
8 #include <Variable/Variable.h>
9
9
10 #include <QMenu>
10 #include <QMenu>
11 #include <QStack>
11 #include <QStack>
12
12
13 Q_LOGGING_CATEGORY(LOG_GenerateVariableMenuOperation, "GenerateVariableMenuOperation")
13 Q_LOGGING_CATEGORY(LOG_GenerateVariableMenuOperation, "GenerateVariableMenuOperation")
14
14
15 struct GenerateVariableMenuOperation::GenerateVariableMenuOperationPrivate {
15 struct GenerateVariableMenuOperation::GenerateVariableMenuOperationPrivate {
16 explicit GenerateVariableMenuOperationPrivate(QMenu *menu, std::shared_ptr<Variable> variable)
16 explicit GenerateVariableMenuOperationPrivate(QMenu *menu, std::shared_ptr<Variable> variable)
17 : m_Variable{variable}, m_MenuBuilder{menu}
17 : m_Variable{variable}, m_MenuBuilder{menu}
18 {
18 {
19 }
19 }
20
20
21 void visitRootEnter()
21 void visitRootEnter()
22 {
22 {
23 // Creates the root menu
23 // Creates the root menu
24 m_MenuBuilder.addMenu(QObject::tr("Plot"));
24 m_MenuBuilder.addMenu(QObject::tr("Plot"));
25 }
25 }
26
26
27 void visitRootLeave()
27 void visitRootLeave()
28 {
28 {
29 // Closes the root menu
29 // Closes the root menu
30 m_MenuBuilder.closeMenu();
30 m_MenuBuilder.closeMenu();
31 }
31 }
32
32
33 void visitNodeEnter(const IVisualizationWidget &container)
33 void visitNodeEnter(const IVisualizationWidget &container)
34 {
34 {
35 // Opens a new menu associated to the node
35 // Opens a new menu associated to the node
36 m_MenuBuilder.addMenu(container.name());
36 m_MenuBuilder.addMenu(container.name());
37 }
37 }
38
38
39 template <typename ActionFun>
39 template <typename ActionFun>
40 void visitNodeLeave(const IVisualizationWidget &container, const QString &actionName,
40 void visitNodeLeave(const IVisualizationWidget &container, const QString &actionName,
41 ActionFun actionFunction)
41 ActionFun actionFunction)
42 {
42 {
43 if (m_Variable && container.canDrop(*m_Variable)) {
43 if (m_Variable && container.canDrop(*m_Variable)) {
44 m_MenuBuilder.addSeparator();
44 m_MenuBuilder.addSeparator();
45 m_MenuBuilder.addAction(actionName, actionFunction);
45 m_MenuBuilder.addAction(actionName, actionFunction);
46 }
46 }
47
47
48 // Closes the menu associated to the node
48 // Closes the menu associated to the node
49 m_MenuBuilder.closeMenu();
49 m_MenuBuilder.closeMenu();
50 }
50 }
51
51
52 template <typename ActionFun>
52 template <typename ActionFun>
53 void visitLeaf(const IVisualizationWidget &container, const QString &actionName,
53 void visitLeaf(const IVisualizationWidget &container, const QString &actionName,
54 ActionFun actionFunction)
54 ActionFun actionFunction)
55 {
55 {
56 if (m_Variable && container.canDrop(*m_Variable)) {
56 if (m_Variable && container.canDrop(*m_Variable)) {
57 m_MenuBuilder.addAction(actionName, actionFunction);
57 m_MenuBuilder.addAction(actionName, actionFunction);
58 }
58 }
59 }
59 }
60
60
61 std::shared_ptr<Variable> m_Variable;
61 std::shared_ptr<Variable> m_Variable;
62 MenuBuilder m_MenuBuilder;
62 MenuBuilder m_MenuBuilder;
63 };
63 };
64
64
65 GenerateVariableMenuOperation::GenerateVariableMenuOperation(QMenu *menu,
65 GenerateVariableMenuOperation::GenerateVariableMenuOperation(QMenu *menu,
66 std::shared_ptr<Variable> variable)
66 std::shared_ptr<Variable> variable)
67 : impl{spimpl::make_unique_impl<GenerateVariableMenuOperationPrivate>(menu, variable)}
67 : impl{spimpl::make_unique_impl<GenerateVariableMenuOperationPrivate>(menu, variable)}
68 {
68 {
69 }
69 }
70
70
71 void GenerateVariableMenuOperation::visitEnter(VisualizationWidget *widget)
71 void GenerateVariableMenuOperation::visitEnter(VisualizationWidget *widget)
72 {
72 {
73 // VisualizationWidget is not intended to accommodate a variable
73 // VisualizationWidget is not intended to accommodate a variable
74 Q_UNUSED(widget)
74 Q_UNUSED(widget)
75
75
76 impl->visitRootEnter();
76 impl->visitRootEnter();
77 }
77 }
78
78
79 void GenerateVariableMenuOperation::visitLeave(VisualizationWidget *widget)
79 void GenerateVariableMenuOperation::visitLeave(VisualizationWidget *widget)
80 {
80 {
81 // VisualizationWidget is not intended to accommodate a variable
81 // VisualizationWidget is not intended to accommodate a variable
82 Q_UNUSED(widget)
82 Q_UNUSED(widget)
83
83
84 impl->visitRootLeave();
84 impl->visitRootLeave();
85 }
85 }
86
86
87 void GenerateVariableMenuOperation::visitEnter(VisualizationTabWidget *tabWidget)
87 void GenerateVariableMenuOperation::visitEnter(VisualizationTabWidget *tabWidget)
88 {
88 {
89 if (tabWidget) {
89 if (tabWidget) {
90 impl->visitNodeEnter(*tabWidget);
90 impl->visitNodeEnter(*tabWidget);
91 }
91 }
92 else {
92 else {
93 qCCritical(LOG_GenerateVariableMenuOperation(),
93 qCCritical(LOG_GenerateVariableMenuOperation(),
94 "Can't visit enter VisualizationTabWidget : the widget is null");
94 "Can't visit enter VisualizationTabWidget : the widget is null");
95 }
95 }
96 }
96 }
97
97
98 void GenerateVariableMenuOperation::visitLeave(VisualizationTabWidget *tabWidget)
98 void GenerateVariableMenuOperation::visitLeave(VisualizationTabWidget *tabWidget)
99 {
99 {
100 if (tabWidget) {
100 if (tabWidget) {
101 impl->visitNodeLeave(
101 impl->visitNodeLeave(
102 *tabWidget, QObject::tr("Open in a new zone"),
102 *tabWidget, QObject::tr("Open in a new zone"),
103 [ var = impl->m_Variable, tabWidget ]() { tabWidget->createZone(var); });
103 [ var = impl->m_Variable, tabWidget ]() { tabWidget->createZone(var); });
104 }
104 }
105 else {
105 else {
106 qCCritical(LOG_GenerateVariableMenuOperation(),
106 qCCritical(LOG_GenerateVariableMenuOperation(),
107 "Can't visit leave VisualizationTabWidget : the widget is null");
107 "Can't visit leave VisualizationTabWidget : the widget is null");
108 }
108 }
109 }
109 }
110
110
111 void GenerateVariableMenuOperation::visitEnter(VisualizationZoneWidget *zoneWidget)
111 void GenerateVariableMenuOperation::visitEnter(VisualizationZoneWidget *zoneWidget)
112 {
112 {
113 if (zoneWidget) {
113 if (zoneWidget) {
114 impl->visitNodeEnter(*zoneWidget);
114 impl->visitNodeEnter(*zoneWidget);
115 }
115 }
116 else {
116 else {
117 qCCritical(LOG_GenerateVariableMenuOperation(),
117 qCCritical(LOG_GenerateVariableMenuOperation(),
118 "Can't visit enter VisualizationZoneWidget : the widget is null");
118 "Can't visit enter VisualizationZoneWidget : the widget is null");
119 }
119 }
120 }
120 }
121
121
122 void GenerateVariableMenuOperation::visitLeave(VisualizationZoneWidget *zoneWidget)
122 void GenerateVariableMenuOperation::visitLeave(VisualizationZoneWidget *zoneWidget)
123 {
123 {
124 if (zoneWidget) {
124 if (zoneWidget) {
125 impl->visitNodeLeave(
125 impl->visitNodeLeave(
126 *zoneWidget, QObject::tr("Open in a new graph"),
126 *zoneWidget, QObject::tr("Open in a new graph"),
127 [ var = impl->m_Variable, zoneWidget ]() { zoneWidget->createGraph(var); });
127 [ var = impl->m_Variable, zoneWidget ]() { zoneWidget->createGraph(var); });
128 }
128 }
129 else {
129 else {
130 qCCritical(LOG_GenerateVariableMenuOperation(),
130 qCCritical(LOG_GenerateVariableMenuOperation(),
131 "Can't visit leave VisualizationZoneWidget : the widget is null");
131 "Can't visit leave VisualizationZoneWidget : the widget is null");
132 }
132 }
133 }
133 }
134
134
135 void GenerateVariableMenuOperation::visit(VisualizationGraphWidget *graphWidget)
135 void GenerateVariableMenuOperation::visit(VisualizationGraphWidget *graphWidget)
136 {
136 {
137 if (graphWidget) {
137 if (graphWidget) {
138 impl->visitLeaf(
138 impl->visitLeaf(
139 *graphWidget, QObject::tr("Open in %1").arg(graphWidget->name()),
139 *graphWidget, QObject::tr("Open in %1").arg(graphWidget->name()),
140 [ var = impl->m_Variable, graphWidget ]() { graphWidget->addVariable(var); });
140 [ var = impl->m_Variable, graphWidget ]() { graphWidget->addVariableUsingGraph(var); });
141 }
141 }
142 else {
142 else {
143 qCCritical(LOG_GenerateVariableMenuOperation(),
143 qCCritical(LOG_GenerateVariableMenuOperation(),
144 "Can't visit VisualizationGraphWidget : the widget is null");
144 "Can't visit VisualizationGraphWidget : the widget is null");
145 }
145 }
146 }
146 }
General Comments 0
You need to be logged in to leave comments. Login now