##// END OF EJS Templates
Correction for MR
perrinel -
r447:00ae2619d35f
parent child
Show More
@@ -1,82 +1,82
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 /**
19 /**
20 * Possible types of zoom operation
20 * Possible types of zoom operation
21 */
21 */
22 enum class VisualizationGraphWidgetZoomType { ZoomOut, ZoomIn, PanRight, PanLeft, Unknown };
22 enum class VisualizationGraphWidgetZoomType { ZoomOut, ZoomIn, PanRight, PanLeft, Unknown };
23
23
24 namespace Ui {
24 namespace Ui {
25 class VisualizationGraphWidget;
25 class VisualizationGraphWidget;
26 } // namespace Ui
26 } // namespace Ui
27
27
28 class VisualizationGraphWidget : public QWidget, public IVisualizationWidget {
28 class VisualizationGraphWidget : public QWidget, public IVisualizationWidget {
29 Q_OBJECT
29 Q_OBJECT
30
30
31 public:
31 public:
32 explicit VisualizationGraphWidget(const QString &name = {}, QWidget *parent = 0);
32 explicit VisualizationGraphWidget(const QString &name = {}, QWidget *parent = 0);
33 virtual ~VisualizationGraphWidget();
33 virtual ~VisualizationGraphWidget();
34
34
35 void enableSynchronize(bool enable);
35 void enableSynchronize(bool enable);
36
36
37 void addVariable(std::shared_ptr<Variable> variable);
37 void addVariable(std::shared_ptr<Variable> variable);
38 void addVariableUsingGraph(std::shared_ptr<Variable> variable);
38 void addVariableUsingGraph(std::shared_ptr<Variable> variable);
39 /// Removes a variable from the graph
39 /// Removes a variable from the graph
40 void removeVariable(std::shared_ptr<Variable> variable) noexcept;
40 void removeVariable(std::shared_ptr<Variable> variable) noexcept;
41
41
42 void setRange(std::shared_ptr<Variable> variable, const SqpDateTime &range);
42 void setRange(std::shared_ptr<Variable> variable, const SqpDateTime &range);
43 SqpDateTime graphRange();
43 SqpDateTime graphRange() const noexcept;
44 void setGraphRange(const SqpDateTime &range);
44 void setGraphRange(const SqpDateTime &range);
45
45
46 // IVisualizationWidget interface
46 // IVisualizationWidget interface
47 void accept(IVisualizationWidgetVisitor *visitor) override;
47 void accept(IVisualizationWidgetVisitor *visitor) override;
48 bool canDrop(const Variable &variable) const override;
48 bool canDrop(const Variable &variable) const override;
49 bool contains(const Variable &variable) const override;
49 bool contains(const Variable &variable) const override;
50 QString name() const override;
50 QString name() const override;
51
51
52
52
53 signals:
53 signals:
54 void requestDataLoading(std::shared_ptr<Variable> variable, const SqpDateTime &dateTime);
54 void requestDataLoading(std::shared_ptr<Variable> variable, const SqpDateTime &dateTime);
55 void synchronize(const SqpDateTime &dateTime, const SqpDateTime &oldDateTime,
55 void synchronize(const SqpDateTime &dateTime, const SqpDateTime &oldDateTime,
56 VisualizationGraphWidgetZoomType zoomType);
56 VisualizationGraphWidgetZoomType zoomType);
57
57
58
58
59 private:
59 private:
60 Ui::VisualizationGraphWidget *ui;
60 Ui::VisualizationGraphWidget *ui;
61
61
62 class VisualizationGraphWidgetPrivate;
62 class VisualizationGraphWidgetPrivate;
63 spimpl::unique_impl_ptr<VisualizationGraphWidgetPrivate> impl;
63 spimpl::unique_impl_ptr<VisualizationGraphWidgetPrivate> impl;
64
64
65 private slots:
65 private slots:
66 /// Slot called when right clicking on the graph (displays a menu)
66 /// Slot called when right clicking on the graph (displays a menu)
67 void onGraphMenuRequested(const QPoint &pos) noexcept;
67 void onGraphMenuRequested(const QPoint &pos) noexcept;
68
68
69 /// Rescale the X axe to range parameter
69 /// Rescale the X axe to range parameter
70 void onRangeChanged(const QCPRange &t1, const QCPRange &t2);
70 void onRangeChanged(const QCPRange &t1, const QCPRange &t2);
71
71
72 /// Slot called when a mouse wheel was made, to perform some processing before the zoom is done
72 /// Slot called when a mouse wheel was made, to perform some processing before the zoom is done
73 void onMouseWheel(QWheelEvent *event) noexcept;
73 void onMouseWheel(QWheelEvent *event) noexcept;
74 /// Slot called when a mouse press was made, to activate the calibration of a graph
74 /// Slot called when a mouse press was made, to activate the calibration of a graph
75 void onMousePress(QMouseEvent *event) noexcept;
75 void onMousePress(QMouseEvent *event) noexcept;
76 /// Slot called when a mouse release was made, to deactivate the calibration of a graph
76 /// Slot called when a mouse release was made, to deactivate the calibration of a graph
77 void onMouseRelease(QMouseEvent *event) noexcept;
77 void onMouseRelease(QMouseEvent *event) noexcept;
78
78
79 void onDataCacheVariableUpdated();
79 void onDataCacheVariableUpdated();
80 };
80 };
81
81
82 #endif // SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
82 #endif // SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
@@ -1,200 +1,199
1 #include <Variable/VariableController.h>
1 #include <Variable/VariableController.h>
2 #include <Variable/VariableInspectorWidget.h>
2 #include <Variable/VariableInspectorWidget.h>
3 #include <Variable/VariableMenuHeaderWidget.h>
3 #include <Variable/VariableMenuHeaderWidget.h>
4 #include <Variable/VariableModel.h>
4 #include <Variable/VariableModel.h>
5
5
6 #include <ui_VariableInspectorWidget.h>
6 #include <ui_VariableInspectorWidget.h>
7
7
8 #include <QMouseEvent>
8 #include <QMouseEvent>
9 #include <QSortFilterProxyModel>
9 #include <QSortFilterProxyModel>
10 #include <QStyledItemDelegate>
10 #include <QStyledItemDelegate>
11 #include <QWidgetAction>
11 #include <QWidgetAction>
12
12
13 #include <SqpApplication.h>
13 #include <SqpApplication.h>
14
14
15 Q_LOGGING_CATEGORY(LOG_VariableInspectorWidget, "VariableInspectorWidget")
15 Q_LOGGING_CATEGORY(LOG_VariableInspectorWidget, "VariableInspectorWidget")
16
16
17
17
18 class QProgressBarItemDelegate : public QStyledItemDelegate {
18 class QProgressBarItemDelegate : public QStyledItemDelegate {
19
19
20 public:
20 public:
21 QProgressBarItemDelegate(QObject *parent) : QStyledItemDelegate{parent} {}
21 QProgressBarItemDelegate(QObject *parent) : QStyledItemDelegate{parent} {}
22
22
23 void paint(QPainter *painter, const QStyleOptionViewItem &option,
23 void paint(QPainter *painter, const QStyleOptionViewItem &option,
24 const QModelIndex &index) const
24 const QModelIndex &index) const
25 {
25 {
26 auto data = index.data(Qt::DisplayRole);
26 auto data = index.data(Qt::DisplayRole);
27 auto progressData = index.data(VariableRoles::ProgressRole);
27 auto progressData = index.data(VariableRoles::ProgressRole);
28 if (data.isValid() && progressData.isValid()) {
28 if (data.isValid() && progressData.isValid()) {
29 auto name = data.value<QString>();
29 auto name = data.value<QString>();
30 auto progress = progressData.value<double>();
30 auto progress = progressData.value<double>();
31 if (progress > 0) {
31 if (progress > 0) {
32 auto cancelButtonWidth = 20;
32 auto cancelButtonWidth = 20;
33 auto progressBarOption = QStyleOptionProgressBar{};
33 auto progressBarOption = QStyleOptionProgressBar{};
34 auto progressRect = option.rect;
34 auto progressRect = option.rect;
35 progressRect.setWidth(progressRect.width() - cancelButtonWidth);
35 progressRect.setWidth(progressRect.width() - cancelButtonWidth);
36 progressBarOption.rect = progressRect;
36 progressBarOption.rect = progressRect;
37 progressBarOption.minimum = 0;
37 progressBarOption.minimum = 0;
38 progressBarOption.maximum = 100;
38 progressBarOption.maximum = 100;
39 progressBarOption.progress = progress;
39 progressBarOption.progress = progress;
40 progressBarOption.text
40 progressBarOption.text
41 = QString("%1 %2").arg(name).arg(QString::number(progress, 'f', 2) + "%");
41 = QString("%1 %2").arg(name).arg(QString::number(progress, 'f', 2) + "%");
42 progressBarOption.textVisible = true;
42 progressBarOption.textVisible = true;
43 progressBarOption.textAlignment = Qt::AlignCenter;
43 progressBarOption.textAlignment = Qt::AlignCenter;
44
44
45
45
46 QApplication::style()->drawControl(QStyle::CE_ProgressBar, &progressBarOption,
46 QApplication::style()->drawControl(QStyle::CE_ProgressBar, &progressBarOption,
47 painter);
47 painter);
48
48
49 // Cancel button
49 // Cancel button
50 auto buttonRect = QRect(progressRect.right(), option.rect.top(), cancelButtonWidth,
50 auto buttonRect = QRect(progressRect.right(), option.rect.top(), cancelButtonWidth,
51 option.rect.height());
51 option.rect.height());
52 auto buttonOption = QStyleOptionButton{};
52 auto buttonOption = QStyleOptionButton{};
53 buttonOption.rect = buttonRect;
53 buttonOption.rect = buttonRect;
54 buttonOption.text = "X";
54 buttonOption.text = "X";
55
55
56 QApplication::style()->drawControl(QStyle::CE_PushButton, &buttonOption, painter);
56 QApplication::style()->drawControl(QStyle::CE_PushButton, &buttonOption, painter);
57 }
57 }
58 else {
58 else {
59 QStyledItemDelegate::paint(painter, option, index);
59 QStyledItemDelegate::paint(painter, option, index);
60 }
60 }
61 }
61 }
62 else {
62 else {
63 QStyledItemDelegate::paint(painter, option, index);
63 QStyledItemDelegate::paint(painter, option, index);
64 }
64 }
65 }
65 }
66
66
67 bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option,
67 bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option,
68 const QModelIndex &index)
68 const QModelIndex &index)
69 {
69 {
70 if (event->type() == QEvent::MouseButtonRelease) {
70 if (event->type() == QEvent::MouseButtonRelease) {
71 auto data = index.data(Qt::DisplayRole);
71 auto data = index.data(Qt::DisplayRole);
72 auto progressData = index.data(VariableRoles::ProgressRole);
72 auto progressData = index.data(VariableRoles::ProgressRole);
73 if (data.isValid() && progressData.isValid()) {
73 if (data.isValid() && progressData.isValid()) {
74 auto cancelButtonWidth = 20;
74 auto cancelButtonWidth = 20;
75 auto progressRect = option.rect;
75 auto progressRect = option.rect;
76 progressRect.setWidth(progressRect.width() - cancelButtonWidth);
76 progressRect.setWidth(progressRect.width() - cancelButtonWidth);
77 // Cancel button
77 // Cancel button
78 auto buttonRect = QRect(progressRect.right(), option.rect.top(), cancelButtonWidth,
78 auto buttonRect = QRect(progressRect.right(), option.rect.top(), cancelButtonWidth,
79 option.rect.height());
79 option.rect.height());
80
80
81 QMouseEvent *e = (QMouseEvent *)event;
81 auto e = (QMouseEvent *)event;
82 int clickX = e->x();
82 auto clickX = e->x();
83 int clickY = e->y();
83 auto clickY = e->y();
84
84
85 auto x = buttonRect.left(); // the X coordinate
85 auto x = buttonRect.left(); // the X coordinate
86 auto y = buttonRect.top(); // the Y coordinate
86 auto y = buttonRect.top(); // the Y coordinate
87 auto w = buttonRect.width(); // button width
87 auto w = buttonRect.width(); // button width
88 auto h = buttonRect.height(); // button height
88 auto h = buttonRect.height(); // button height
89
89
90 if (clickX > x && clickX < x + w) {
90 if (clickX > x && clickX < x + w) {
91 if (clickY > y && clickY < y + h) {
91 if (clickY > y && clickY < y + h) {
92 qCritical(LOG_VariableInspectorWidget()) << tr("editorEvent CLIC");
93 auto variableModel = sqpApp->variableController().variableModel();
92 auto variableModel = sqpApp->variableController().variableModel();
94 variableModel->abortProgress(index);
93 variableModel->abortProgress(index);
95 }
94 }
96 }
95 }
97 else {
96 else {
98 QStyledItemDelegate::editorEvent(event, model, option, index);
97 QStyledItemDelegate::editorEvent(event, model, option, index);
99 }
98 }
100 }
99 }
101 else {
100 else {
102 QStyledItemDelegate::editorEvent(event, model, option, index);
101 QStyledItemDelegate::editorEvent(event, model, option, index);
103 }
102 }
104 }
103 }
105 else {
104 else {
106 QStyledItemDelegate::editorEvent(event, model, option, index);
105 QStyledItemDelegate::editorEvent(event, model, option, index);
107 }
106 }
108 }
107 }
109 };
108 };
110
109
111 VariableInspectorWidget::VariableInspectorWidget(QWidget *parent)
110 VariableInspectorWidget::VariableInspectorWidget(QWidget *parent)
112 : QWidget{parent},
111 : QWidget{parent},
113 ui{new Ui::VariableInspectorWidget},
112 ui{new Ui::VariableInspectorWidget},
114 m_ProgressBarItemDelegate{new QProgressBarItemDelegate{this}}
113 m_ProgressBarItemDelegate{new QProgressBarItemDelegate{this}}
115 {
114 {
116 ui->setupUi(this);
115 ui->setupUi(this);
117
116
118 // Sets model for table
117 // Sets model for table
119 // auto sortFilterModel = new QSortFilterProxyModel{this};
118 // auto sortFilterModel = new QSortFilterProxyModel{this};
120 // sortFilterModel->setSourceModel(sqpApp->variableController().variableModel());
119 // sortFilterModel->setSourceModel(sqpApp->variableController().variableModel());
121
120
122 auto variableModel = sqpApp->variableController().variableModel();
121 auto variableModel = sqpApp->variableController().variableModel();
123 ui->tableView->setModel(variableModel);
122 ui->tableView->setModel(variableModel);
124
123
125 // Adds extra signal/slot between view and model, so the view can be updated instantly when
124 // Adds extra signal/slot between view and model, so the view can be updated instantly when
126 // there is a change of data in the model
125 // there is a change of data in the model
127 connect(variableModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), this,
126 connect(variableModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), this,
128 SLOT(refresh()));
127 SLOT(refresh()));
129
128
130 ui->tableView->setSelectionModel(sqpApp->variableController().variableSelectionModel());
129 ui->tableView->setSelectionModel(sqpApp->variableController().variableSelectionModel());
131 ui->tableView->setItemDelegateForColumn(0, m_ProgressBarItemDelegate);
130 ui->tableView->setItemDelegateForColumn(0, m_ProgressBarItemDelegate);
132
131
133 // Fixes column sizes
132 // Fixes column sizes
134 auto model = ui->tableView->model();
133 auto model = ui->tableView->model();
135 const auto count = model->columnCount();
134 const auto count = model->columnCount();
136 for (auto i = 0; i < count; ++i) {
135 for (auto i = 0; i < count; ++i) {
137 ui->tableView->setColumnWidth(
136 ui->tableView->setColumnWidth(
138 i, model->headerData(i, Qt::Horizontal, Qt::SizeHintRole).toSize().width());
137 i, model->headerData(i, Qt::Horizontal, Qt::SizeHintRole).toSize().width());
139 }
138 }
140
139
141 // Sets selection options
140 // Sets selection options
142 ui->tableView->setSelectionBehavior(QTableView::SelectRows);
141 ui->tableView->setSelectionBehavior(QTableView::SelectRows);
143 ui->tableView->setSelectionMode(QTableView::ExtendedSelection);
142 ui->tableView->setSelectionMode(QTableView::ExtendedSelection);
144
143
145 // Connection to show a menu when right clicking on the tree
144 // Connection to show a menu when right clicking on the tree
146 ui->tableView->setContextMenuPolicy(Qt::CustomContextMenu);
145 ui->tableView->setContextMenuPolicy(Qt::CustomContextMenu);
147 connect(ui->tableView, &QTableView::customContextMenuRequested, this,
146 connect(ui->tableView, &QTableView::customContextMenuRequested, this,
148 &VariableInspectorWidget::onTableMenuRequested);
147 &VariableInspectorWidget::onTableMenuRequested);
149 }
148 }
150
149
151 VariableInspectorWidget::~VariableInspectorWidget()
150 VariableInspectorWidget::~VariableInspectorWidget()
152 {
151 {
153 delete ui;
152 delete ui;
154 }
153 }
155
154
156 void VariableInspectorWidget::onTableMenuRequested(const QPoint &pos) noexcept
155 void VariableInspectorWidget::onTableMenuRequested(const QPoint &pos) noexcept
157 {
156 {
158 auto selectedRows = ui->tableView->selectionModel()->selectedRows();
157 auto selectedRows = ui->tableView->selectionModel()->selectedRows();
159
158
160 // Gets the model to retrieve the underlying selected variables
159 // Gets the model to retrieve the underlying selected variables
161 auto model = sqpApp->variableController().variableModel();
160 auto model = sqpApp->variableController().variableModel();
162 auto selectedVariables = QVector<std::shared_ptr<Variable> >{};
161 auto selectedVariables = QVector<std::shared_ptr<Variable> >{};
163 for (const auto &selectedRow : qAsConst(selectedRows)) {
162 for (const auto &selectedRow : qAsConst(selectedRows)) {
164 if (auto selectedVariable = model->variable(selectedRow.row())) {
163 if (auto selectedVariable = model->variable(selectedRow.row())) {
165 selectedVariables.push_back(selectedVariable);
164 selectedVariables.push_back(selectedVariable);
166 }
165 }
167 }
166 }
168
167
169 QMenu tableMenu{};
168 QMenu tableMenu{};
170
169
171 // Emits a signal so that potential receivers can populate the menu before displaying it
170 // Emits a signal so that potential receivers can populate the menu before displaying it
172 emit tableMenuAboutToBeDisplayed(&tableMenu, selectedVariables);
171 emit tableMenuAboutToBeDisplayed(&tableMenu, selectedVariables);
173
172
174 // Adds menu-specific actions
173 // Adds menu-specific actions
175 if (!selectedVariables.isEmpty()) {
174 if (!selectedVariables.isEmpty()) {
176 // 'Delete' action
175 // 'Delete' action
177 auto deleteFun = [&selectedVariables]() {
176 auto deleteFun = [&selectedVariables]() {
178 sqpApp->variableController().deleteVariables(selectedVariables);
177 sqpApp->variableController().deleteVariables(selectedVariables);
179 };
178 };
180
179
181 tableMenu.addSeparator();
180 tableMenu.addSeparator();
182 tableMenu.addAction(QIcon{":/icones/delete.png"}, tr("Delete"), deleteFun);
181 tableMenu.addAction(QIcon{":/icones/delete.png"}, tr("Delete"), deleteFun);
183 }
182 }
184
183
185 if (!tableMenu.isEmpty()) {
184 if (!tableMenu.isEmpty()) {
186 // Generates menu header (inserted before first action)
185 // Generates menu header (inserted before first action)
187 auto firstAction = tableMenu.actions().first();
186 auto firstAction = tableMenu.actions().first();
188 auto headerAction = new QWidgetAction{&tableMenu};
187 auto headerAction = new QWidgetAction{&tableMenu};
189 headerAction->setDefaultWidget(new VariableMenuHeaderWidget{selectedVariables, &tableMenu});
188 headerAction->setDefaultWidget(new VariableMenuHeaderWidget{selectedVariables, &tableMenu});
190 tableMenu.insertAction(firstAction, headerAction);
189 tableMenu.insertAction(firstAction, headerAction);
191
190
192 // Displays menu
191 // Displays menu
193 tableMenu.exec(mapToGlobal(pos));
192 tableMenu.exec(mapToGlobal(pos));
194 }
193 }
195 }
194 }
196
195
197 void VariableInspectorWidget::refresh() noexcept
196 void VariableInspectorWidget::refresh() noexcept
198 {
197 {
199 ui->tableView->viewport()->update();
198 ui->tableView->viewport()->update();
200 }
199 }
@@ -1,399 +1,401
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 explicit VisualizationGraphWidgetPrivate() : m_DoSynchronize(true), m_IsCalibration(false) {}
28 explicit VisualizationGraphWidgetPrivate() : m_DoSynchronize{true}, m_IsCalibration{false} {}
29
29
30
30
31 // Return the operation when range changed
31 // Return the operation when range changed
32 VisualizationGraphWidgetZoomType getZoomType(const QCPRange &t1, const QCPRange &t2);
32 VisualizationGraphWidgetZoomType getZoomType(const QCPRange &t1, const QCPRange &t2);
33
33
34 // 1 variable -> n qcpplot
34 // 1 variable -> n qcpplot
35 std::multimap<std::shared_ptr<Variable>, QCPAbstractPlottable *> m_VariableToPlotMultiMap;
35 std::multimap<std::shared_ptr<Variable>, QCPAbstractPlottable *> m_VariableToPlotMultiMap;
36
36
37 bool m_DoSynchronize;
37 bool m_DoSynchronize;
38 bool m_IsCalibration;
38 bool m_IsCalibration;
39 };
39 };
40
40
41 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
41 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
42 : QWidget{parent},
42 : QWidget{parent},
43 ui{new Ui::VisualizationGraphWidget},
43 ui{new Ui::VisualizationGraphWidget},
44 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>()}
44 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>()}
45 {
45 {
46 ui->setupUi(this);
46 ui->setupUi(this);
47
47
48 ui->graphNameLabel->setText(name);
48 ui->graphNameLabel->setText(name);
49
49
50 // 'Close' options : widget is deleted when closed
50 // 'Close' options : widget is deleted when closed
51 setAttribute(Qt::WA_DeleteOnClose);
51 setAttribute(Qt::WA_DeleteOnClose);
52 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationGraphWidget::close);
52 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationGraphWidget::close);
53 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
53 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
54
54
55 // Set qcpplot properties :
55 // Set qcpplot properties :
56 // - Drag (on x-axis) and zoom are enabled
56 // - Drag (on x-axis) and zoom are enabled
57 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
57 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
58 ui->widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);
58 ui->widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);
59 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal);
59 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal);
60 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
60 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
61 connect(ui->widget, &QCustomPlot::mouseRelease, this,
61 connect(ui->widget, &QCustomPlot::mouseRelease, this,
62 &VisualizationGraphWidget::onMouseRelease);
62 &VisualizationGraphWidget::onMouseRelease);
63 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
63 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
64 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
64 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
65 &QCPAxis::rangeChanged),
65 &QCPAxis::rangeChanged),
66 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
66 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
67
67
68 // Activates menu when right clicking on the graph
68 // Activates menu when right clicking on the graph
69 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
69 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
70 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
70 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
71 &VisualizationGraphWidget::onGraphMenuRequested);
71 &VisualizationGraphWidget::onGraphMenuRequested);
72
72
73 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
73 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
74 &VariableController::onRequestDataLoading);
74 &VariableController::onRequestDataLoading);
75 }
75 }
76
76
77
77
78 VisualizationGraphWidget::~VisualizationGraphWidget()
78 VisualizationGraphWidget::~VisualizationGraphWidget()
79 {
79 {
80 delete ui;
80 delete ui;
81 }
81 }
82
82
83 void VisualizationGraphWidget::enableSynchronize(bool enable)
83 void VisualizationGraphWidget::enableSynchronize(bool enable)
84 {
84 {
85 impl->m_DoSynchronize = enable;
85 impl->m_DoSynchronize = enable;
86 }
86 }
87
87
88 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable)
88 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable)
89 {
89 {
90 // Uses delegate to create the qcpplot components according to the variable
90 // Uses delegate to create the qcpplot components according to the variable
91 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
91 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
92
92
93 for (auto createdPlottable : qAsConst(createdPlottables)) {
93 for (auto createdPlottable : qAsConst(createdPlottables)) {
94 impl->m_VariableToPlotMultiMap.insert({variable, createdPlottable});
94 impl->m_VariableToPlotMultiMap.insert({variable, createdPlottable});
95 }
95 }
96
96
97 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
97 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
98 }
98 }
99 void VisualizationGraphWidget::addVariableUsingGraph(std::shared_ptr<Variable> variable)
99 void VisualizationGraphWidget::addVariableUsingGraph(std::shared_ptr<Variable> variable)
100 {
100 {
101
101
102 // when adding a variable, we need to set its time range to the current graph range
102 // when adding a variable, we need to set its time range to the current graph range
103 auto grapheRange = ui->widget->xAxis->range();
103 auto grapheRange = ui->widget->xAxis->range();
104 auto dateTime = SqpDateTime{grapheRange.lower, grapheRange.upper};
104 auto dateTime = SqpDateTime{grapheRange.lower, grapheRange.upper};
105 variable->setDateTime(dateTime);
105 variable->setDateTime(dateTime);
106
106
107 auto variableDateTimeWithTolerance = dateTime;
107 auto variableDateTimeWithTolerance = dateTime;
108
108
109 // add 10% tolerance for each side
109 // add 20% tolerance for each side
110 auto tolerance = 0.1 * (dateTime.m_TEnd - dateTime.m_TStart);
110 auto tolerance = 0.2 * (dateTime.m_TEnd - dateTime.m_TStart);
111 variableDateTimeWithTolerance.m_TStart -= tolerance;
111 variableDateTimeWithTolerance.m_TStart -= tolerance;
112 variableDateTimeWithTolerance.m_TEnd += tolerance;
112 variableDateTimeWithTolerance.m_TEnd += tolerance;
113
113
114 // Uses delegate to create the qcpplot components according to the variable
114 // Uses delegate to create the qcpplot components according to the variable
115 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
115 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
116
116
117 for (auto createdPlottable : qAsConst(createdPlottables)) {
117 for (auto createdPlottable : qAsConst(createdPlottables)) {
118 impl->m_VariableToPlotMultiMap.insert({variable, createdPlottable});
118 impl->m_VariableToPlotMultiMap.insert({variable, createdPlottable});
119 }
119 }
120
120
121 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
121 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
122
122
123 // CHangement detected, we need to ask controller to request data loading
123 // CHangement detected, we need to ask controller to request data loading
124 emit requestDataLoading(variable, variableDateTimeWithTolerance);
124 emit requestDataLoading(variable, variableDateTimeWithTolerance);
125 }
125 }
126
126
127 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
127 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
128 {
128 {
129 // Each component associated to the variable :
129 // Each component associated to the variable :
130 // - is removed from qcpplot (which deletes it)
130 // - is removed from qcpplot (which deletes it)
131 // - is no longer referenced in the map
131 // - is no longer referenced in the map
132 auto componentsIt = impl->m_VariableToPlotMultiMap.equal_range(variable);
132 auto componentsIt = impl->m_VariableToPlotMultiMap.equal_range(variable);
133 for (auto it = componentsIt.first; it != componentsIt.second;) {
133 for (auto it = componentsIt.first; it != componentsIt.second;) {
134 ui->widget->removePlottable(it->second);
134 ui->widget->removePlottable(it->second);
135 it = impl->m_VariableToPlotMultiMap.erase(it);
135 it = impl->m_VariableToPlotMultiMap.erase(it);
136 }
136 }
137
137
138 // Updates graph
138 // Updates graph
139 ui->widget->replot();
139 ui->widget->replot();
140 }
140 }
141
141
142 void VisualizationGraphWidget::setRange(std::shared_ptr<Variable> variable,
142 void VisualizationGraphWidget::setRange(std::shared_ptr<Variable> variable,
143 const SqpDateTime &range)
143 const SqpDateTime &range)
144 {
144 {
145 // Note: in case of different axes that depends on variable, we could start with a code like
146 // that:
145 // auto componentsIt = impl->m_VariableToPlotMultiMap.equal_range(variable);
147 // auto componentsIt = impl->m_VariableToPlotMultiMap.equal_range(variable);
146 // for (auto it = componentsIt.first; it != componentsIt.second;) {
148 // for (auto it = componentsIt.first; it != componentsIt.second;) {
147 // }
149 // }
148 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
150 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
149 ui->widget->replot();
151 ui->widget->replot();
150 }
152 }
151
153
152 SqpDateTime VisualizationGraphWidget::graphRange()
154 SqpDateTime VisualizationGraphWidget::graphRange() const noexcept
153 {
155 {
154 auto grapheRange = ui->widget->xAxis->range();
156 auto grapheRange = ui->widget->xAxis->range();
155 return SqpDateTime{grapheRange.lower, grapheRange.upper};
157 return SqpDateTime{grapheRange.lower, grapheRange.upper};
156 }
158 }
157
159
158 void VisualizationGraphWidget::setGraphRange(const SqpDateTime &range)
160 void VisualizationGraphWidget::setGraphRange(const SqpDateTime &range)
159 {
161 {
160 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
162 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
161 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
163 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
162 ui->widget->replot();
164 ui->widget->replot();
163 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
165 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
164 }
166 }
165
167
166 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
168 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
167 {
169 {
168 if (visitor) {
170 if (visitor) {
169 visitor->visit(this);
171 visitor->visit(this);
170 }
172 }
171 else {
173 else {
172 qCCritical(LOG_VisualizationGraphWidget())
174 qCCritical(LOG_VisualizationGraphWidget())
173 << tr("Can't visit widget : the visitor is null");
175 << tr("Can't visit widget : the visitor is null");
174 }
176 }
175 }
177 }
176
178
177 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
179 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
178 {
180 {
179 /// @todo : for the moment, a graph can always accomodate a variable
181 /// @todo : for the moment, a graph can always accomodate a variable
180 Q_UNUSED(variable);
182 Q_UNUSED(variable);
181 return true;
183 return true;
182 }
184 }
183
185
184 bool VisualizationGraphWidget::contains(const Variable &variable) const
186 bool VisualizationGraphWidget::contains(const Variable &variable) const
185 {
187 {
186 // Finds the variable among the keys of the map
188 // Finds the variable among the keys of the map
187 auto variablePtr = &variable;
189 auto variablePtr = &variable;
188 auto findVariable
190 auto findVariable
189 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
191 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
190
192
191 auto end = impl->m_VariableToPlotMultiMap.cend();
193 auto end = impl->m_VariableToPlotMultiMap.cend();
192 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
194 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
193 return it != end;
195 return it != end;
194 }
196 }
195
197
196 QString VisualizationGraphWidget::name() const
198 QString VisualizationGraphWidget::name() const
197 {
199 {
198 return ui->graphNameLabel->text();
200 return ui->graphNameLabel->text();
199 }
201 }
200
202
201 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
203 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
202 {
204 {
203 QMenu graphMenu{};
205 QMenu graphMenu{};
204
206
205 // Iterates on variables (unique keys)
207 // Iterates on variables (unique keys)
206 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
208 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
207 end = impl->m_VariableToPlotMultiMap.cend();
209 end = impl->m_VariableToPlotMultiMap.cend();
208 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
210 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
209 // 'Remove variable' action
211 // 'Remove variable' action
210 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
212 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
211 [ this, var = it->first ]() { removeVariable(var); });
213 [ this, var = it->first ]() { removeVariable(var); });
212 }
214 }
213
215
214 if (!graphMenu.isEmpty()) {
216 if (!graphMenu.isEmpty()) {
215 graphMenu.exec(mapToGlobal(pos));
217 graphMenu.exec(mapToGlobal(pos));
216 }
218 }
217 }
219 }
218
220
219 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
221 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
220 {
222 {
221 qCInfo(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::onRangeChanged")
223 qCInfo(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::onRangeChanged")
222 << QThread::currentThread()->objectName();
224 << QThread::currentThread()->objectName();
223
225
224 auto dateTimeRange = SqpDateTime{t1.lower, t1.upper};
226 auto dateTimeRange = SqpDateTime{t1.lower, t1.upper};
225
227
226 auto zoomType = impl->getZoomType(t1, t2);
228 auto zoomType = impl->getZoomType(t1, t2);
227 for (auto it = impl->m_VariableToPlotMultiMap.cbegin();
229 for (auto it = impl->m_VariableToPlotMultiMap.cbegin();
228 it != impl->m_VariableToPlotMultiMap.cend(); ++it) {
230 it != impl->m_VariableToPlotMultiMap.cend(); ++it) {
229
231
230 auto variable = it->first;
232 auto variable = it->first;
231 auto currentDateTime = dateTimeRange;
233 auto currentDateTime = dateTimeRange;
232
234
233 auto toleranceFactor = 0.2;
235 auto toleranceFactor = 0.2;
234 auto tolerance = toleranceFactor * (currentDateTime.m_TEnd - currentDateTime.m_TStart);
236 auto tolerance = toleranceFactor * (currentDateTime.m_TEnd - currentDateTime.m_TStart);
235 auto variableDateTimeWithTolerance = currentDateTime;
237 auto variableDateTimeWithTolerance = currentDateTime;
236 variableDateTimeWithTolerance.m_TStart -= tolerance;
238 variableDateTimeWithTolerance.m_TStart -= tolerance;
237 variableDateTimeWithTolerance.m_TEnd += tolerance;
239 variableDateTimeWithTolerance.m_TEnd += tolerance;
238
240
239 qCDebug(LOG_VisualizationGraphWidget()) << "r" << currentDateTime;
241 qCDebug(LOG_VisualizationGraphWidget()) << "r" << currentDateTime;
240 qCDebug(LOG_VisualizationGraphWidget()) << "t" << variableDateTimeWithTolerance;
242 qCDebug(LOG_VisualizationGraphWidget()) << "t" << variableDateTimeWithTolerance;
241 qCDebug(LOG_VisualizationGraphWidget()) << "v" << variable->dateTime();
243 qCDebug(LOG_VisualizationGraphWidget()) << "v" << variable->dateTime();
242 // If new range with tol is upper than variable datetime parameters. we need to request new
244 // If new range with tol is upper than variable datetime parameters. we need to request new
243 // data
245 // data
244 if (!variable->contains(variableDateTimeWithTolerance)) {
246 if (!variable->contains(variableDateTimeWithTolerance)) {
245
247
246 auto variableDateTimeWithTolerance = currentDateTime;
248 auto variableDateTimeWithTolerance = currentDateTime;
247 if (!variable->isInside(currentDateTime)) {
249 if (!variable->isInside(currentDateTime)) {
248 auto variableDateTime = variable->dateTime();
250 auto variableDateTime = variable->dateTime();
249 if (variable->contains(variableDateTimeWithTolerance)) {
251 if (variable->contains(variableDateTimeWithTolerance)) {
250 qCDebug(LOG_VisualizationGraphWidget())
252 qCDebug(LOG_VisualizationGraphWidget())
251 << tr("TORM: Detection zoom in that need request:");
253 << tr("TORM: Detection zoom in that need request:");
252 // add 10% tolerance for each side
254 // add 10% tolerance for each side
253 tolerance
255 tolerance
254 = toleranceFactor * (currentDateTime.m_TEnd - currentDateTime.m_TStart);
256 = toleranceFactor * (currentDateTime.m_TEnd - currentDateTime.m_TStart);
255 variableDateTimeWithTolerance.m_TStart -= tolerance;
257 variableDateTimeWithTolerance.m_TStart -= tolerance;
256 variableDateTimeWithTolerance.m_TEnd += tolerance;
258 variableDateTimeWithTolerance.m_TEnd += tolerance;
257 }
259 }
258 else if (variableDateTime.m_TStart < currentDateTime.m_TStart) {
260 else if (variableDateTime.m_TStart < currentDateTime.m_TStart) {
259 qCInfo(LOG_VisualizationGraphWidget()) << tr("TORM: Detection pan to right:");
261 qCInfo(LOG_VisualizationGraphWidget()) << tr("TORM: Detection pan to right:");
260
262
261 auto diffEndToKeepDelta = currentDateTime.m_TEnd - variableDateTime.m_TEnd;
263 auto diffEndToKeepDelta = currentDateTime.m_TEnd - variableDateTime.m_TEnd;
262 currentDateTime.m_TStart = variableDateTime.m_TStart + diffEndToKeepDelta;
264 currentDateTime.m_TStart = variableDateTime.m_TStart + diffEndToKeepDelta;
263 // Tolerance have to be added to the right
265 // Tolerance have to be added to the right
264 // add tolerance for right (end) side
266 // add tolerance for right (end) side
265 tolerance
267 tolerance
266 = toleranceFactor * (currentDateTime.m_TEnd - currentDateTime.m_TStart);
268 = toleranceFactor * (currentDateTime.m_TEnd - currentDateTime.m_TStart);
267 variableDateTimeWithTolerance.m_TEnd += tolerance;
269 variableDateTimeWithTolerance.m_TEnd += tolerance;
268 }
270 }
269 else if (variableDateTime.m_TEnd > currentDateTime.m_TEnd) {
271 else if (variableDateTime.m_TEnd > currentDateTime.m_TEnd) {
270 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: Detection pan to left: ");
272 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: Detection pan to left: ");
271 auto diffStartToKeepDelta
273 auto diffStartToKeepDelta
272 = variableDateTime.m_TStart - currentDateTime.m_TStart;
274 = variableDateTime.m_TStart - currentDateTime.m_TStart;
273 currentDateTime.m_TEnd = variableDateTime.m_TEnd - diffStartToKeepDelta;
275 currentDateTime.m_TEnd = variableDateTime.m_TEnd - diffStartToKeepDelta;
274 // Tolerance have to be added to the left
276 // Tolerance have to be added to the left
275 // add tolerance for left (start) side
277 // add tolerance for left (start) side
276 tolerance
278 tolerance
277 = toleranceFactor * (currentDateTime.m_TEnd - currentDateTime.m_TStart);
279 = toleranceFactor * (currentDateTime.m_TEnd - currentDateTime.m_TStart);
278 variableDateTimeWithTolerance.m_TStart -= tolerance;
280 variableDateTimeWithTolerance.m_TStart -= tolerance;
279 }
281 }
280 else {
282 else {
281 qCCritical(LOG_VisualizationGraphWidget())
283 qCCritical(LOG_VisualizationGraphWidget())
282 << tr("Detection anormal zoom detection: ");
284 << tr("Detection anormal zoom detection: ");
283 }
285 }
284 }
286 }
285 else {
287 else {
286 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: Detection zoom out: ");
288 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: Detection zoom out: ");
287 // add 10% tolerance for each side
289 // add 10% tolerance for each side
288 tolerance = toleranceFactor * (currentDateTime.m_TEnd - currentDateTime.m_TStart);
290 tolerance = toleranceFactor * (currentDateTime.m_TEnd - currentDateTime.m_TStart);
289 variableDateTimeWithTolerance.m_TStart -= tolerance;
291 variableDateTimeWithTolerance.m_TStart -= tolerance;
290 variableDateTimeWithTolerance.m_TEnd += tolerance;
292 variableDateTimeWithTolerance.m_TEnd += tolerance;
291 zoomType = VisualizationGraphWidgetZoomType::ZoomOut;
293 zoomType = VisualizationGraphWidgetZoomType::ZoomOut;
292 }
294 }
293 if (!variable->contains(dateTimeRange)) {
295 if (!variable->contains(dateTimeRange)) {
294 qCDebug(LOG_VisualizationGraphWidget())
296 qCDebug(LOG_VisualizationGraphWidget())
295 << "TORM: Modif on variable datetime detected" << currentDateTime;
297 << "TORM: Modif on variable datetime detected" << currentDateTime;
296 variable->setDateTime(currentDateTime);
298 variable->setDateTime(currentDateTime);
297 }
299 }
298
300
299 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: Request data detection: ");
301 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: Request data detection: ");
300 // CHangement detected, we need to ask controller to request data loading
302 // CHangement detected, we need to ask controller to request data loading
301 emit requestDataLoading(variable, variableDateTimeWithTolerance);
303 emit requestDataLoading(variable, variableDateTimeWithTolerance);
302 }
304 }
303 else {
305 else {
304 qCInfo(LOG_VisualizationGraphWidget())
306 qCInfo(LOG_VisualizationGraphWidget())
305 << tr("TORM: Detection zoom in that doesn't need request: ");
307 << tr("TORM: Detection zoom in that doesn't need request: ");
306 zoomType = VisualizationGraphWidgetZoomType::ZoomIn;
308 zoomType = VisualizationGraphWidgetZoomType::ZoomIn;
307 }
309 }
308 }
310 }
309
311
310 if (impl->m_DoSynchronize && !impl->m_IsCalibration) {
312 if (impl->m_DoSynchronize && !impl->m_IsCalibration) {
311 auto oldDateTime = SqpDateTime{t2.lower, t2.upper};
313 auto oldDateTime = SqpDateTime{t2.lower, t2.upper};
312 qCDebug(LOG_VisualizationGraphWidget())
314 qCDebug(LOG_VisualizationGraphWidget())
313 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
315 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
314 << QThread::currentThread()->objectName();
316 << QThread::currentThread()->objectName();
315 emit synchronize(dateTimeRange, oldDateTime, zoomType);
317 emit synchronize(dateTimeRange, oldDateTime, zoomType);
316 }
318 }
317 }
319 }
318
320
319 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
321 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
320 {
322 {
321 auto zoomOrientations = QFlags<Qt::Orientation>{};
323 auto zoomOrientations = QFlags<Qt::Orientation>{};
322
324
323 // Lambda that enables a zoom orientation if the key modifier related to this orientation
325 // Lambda that enables a zoom orientation if the key modifier related to this orientation
324 // has
326 // has
325 // been pressed
327 // been pressed
326 auto enableOrientation
328 auto enableOrientation
327 = [&zoomOrientations, event](const auto &orientation, const auto &modifier) {
329 = [&zoomOrientations, event](const auto &orientation, const auto &modifier) {
328 auto orientationEnabled = event->modifiers().testFlag(modifier);
330 auto orientationEnabled = event->modifiers().testFlag(modifier);
329 zoomOrientations.setFlag(orientation, orientationEnabled);
331 zoomOrientations.setFlag(orientation, orientationEnabled);
330 };
332 };
331 enableOrientation(Qt::Vertical, VERTICAL_ZOOM_MODIFIER);
333 enableOrientation(Qt::Vertical, VERTICAL_ZOOM_MODIFIER);
332 enableOrientation(Qt::Horizontal, HORIZONTAL_ZOOM_MODIFIER);
334 enableOrientation(Qt::Horizontal, HORIZONTAL_ZOOM_MODIFIER);
333
335
334 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
336 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
335 }
337 }
336
338
337 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
339 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
338 {
340 {
339 impl->m_IsCalibration = event->modifiers().testFlag(Qt::ControlModifier);
341 impl->m_IsCalibration = event->modifiers().testFlag(Qt::ControlModifier);
340 }
342 }
341
343
342 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
344 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
343 {
345 {
344 impl->m_IsCalibration = false;
346 impl->m_IsCalibration = false;
345 }
347 }
346
348
347 void VisualizationGraphWidget::onDataCacheVariableUpdated()
349 void VisualizationGraphWidget::onDataCacheVariableUpdated()
348 {
350 {
349 // NOTE:
351 // NOTE:
350 // We don't want to call the method for each component of a variable unitarily, but for
352 // We don't want to call the method for each component of a variable unitarily, but for
351 // all
353 // all
352 // its components at once (eg its three components in the case of a vector).
354 // its components at once (eg its three components in the case of a vector).
353
355
354 // The unordered_multimap does not do this easily, so the question is whether to:
356 // The unordered_multimap does not do this easily, so the question is whether to:
355 // - use an ordered_multimap and the algos of std to group the values by key
357 // - use an ordered_multimap and the algos of std to group the values by key
356 // - use a map (unique keys) and store as values directly the list of components
358 // - use a map (unique keys) and store as values directly the list of components
357
359
358 auto grapheRange = ui->widget->xAxis->range();
360 auto grapheRange = ui->widget->xAxis->range();
359 auto dateTime = SqpDateTime{grapheRange.lower, grapheRange.upper};
361 auto dateTime = SqpDateTime{grapheRange.lower, grapheRange.upper};
360
362
361 for (auto it = impl->m_VariableToPlotMultiMap.cbegin();
363 for (auto it = impl->m_VariableToPlotMultiMap.cbegin();
362 it != impl->m_VariableToPlotMultiMap.cend(); ++it) {
364 it != impl->m_VariableToPlotMultiMap.cend(); ++it) {
363 auto variable = it->first;
365 auto variable = it->first;
364 qCDebug(LOG_VisualizationGraphWidget())
366 qCDebug(LOG_VisualizationGraphWidget())
365 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S"
367 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S"
366 << variable->dateTime();
368 << variable->dateTime();
367 qCDebug(LOG_VisualizationGraphWidget())
369 qCDebug(LOG_VisualizationGraphWidget())
368 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
370 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
369 if (dateTime.contains(variable->dateTime()) || dateTime.intersect(variable->dateTime())) {
371 if (dateTime.contains(variable->dateTime()) || dateTime.intersect(variable->dateTime())) {
370
372
371 VisualizationGraphHelper::updateData(QVector<QCPAbstractPlottable *>{} << it->second,
373 VisualizationGraphHelper::updateData(QVector<QCPAbstractPlottable *>{} << it->second,
372 variable->dataSeries(), variable->dateTime());
374 variable->dataSeries(), variable->dateTime());
373 }
375 }
374 }
376 }
375 }
377 }
376
378
377 VisualizationGraphWidgetZoomType
379 VisualizationGraphWidgetZoomType
378 VisualizationGraphWidget::VisualizationGraphWidgetPrivate::getZoomType(const QCPRange &t1,
380 VisualizationGraphWidget::VisualizationGraphWidgetPrivate::getZoomType(const QCPRange &t1,
379 const QCPRange &t2)
381 const QCPRange &t2)
380 {
382 {
381 // t1.lower <= t2.lower && t2.upper <= t1.upper
383 // t1.lower <= t2.lower && t2.upper <= t1.upper
382 auto zoomType = VisualizationGraphWidgetZoomType::Unknown;
384 auto zoomType = VisualizationGraphWidgetZoomType::Unknown;
383 if (t1.lower <= t2.lower && t2.upper <= t1.upper) {
385 if (t1.lower <= t2.lower && t2.upper <= t1.upper) {
384 zoomType = VisualizationGraphWidgetZoomType::ZoomOut;
386 zoomType = VisualizationGraphWidgetZoomType::ZoomOut;
385 }
387 }
386 else if (t1.lower > t2.lower && t1.upper > t2.upper) {
388 else if (t1.lower > t2.lower && t1.upper > t2.upper) {
387 zoomType = VisualizationGraphWidgetZoomType::PanRight;
389 zoomType = VisualizationGraphWidgetZoomType::PanRight;
388 }
390 }
389 else if (t1.lower < t2.lower && t1.upper < t2.upper) {
391 else if (t1.lower < t2.lower && t1.upper < t2.upper) {
390 zoomType = VisualizationGraphWidgetZoomType::PanLeft;
392 zoomType = VisualizationGraphWidgetZoomType::PanLeft;
391 }
393 }
392 else if (t1.lower > t2.lower && t2.upper > t1.upper) {
394 else if (t1.lower > t2.lower && t2.upper > t1.upper) {
393 zoomType = VisualizationGraphWidgetZoomType::ZoomIn;
395 zoomType = VisualizationGraphWidgetZoomType::ZoomIn;
394 }
396 }
395 else {
397 else {
396 qCCritical(LOG_VisualizationGraphWidget()) << "getZoomType: Unknown type detected";
398 qCCritical(LOG_VisualizationGraphWidget()) << "getZoomType: Unknown type detected";
397 }
399 }
398 return zoomType;
400 return zoomType;
399 }
401 }
@@ -1,152 +1,152
1 #include "Visualization/VisualizationWidget.h"
1 #include "Visualization/VisualizationWidget.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 #include "Visualization/VisualizationGraphWidget.h"
3 #include "Visualization/VisualizationGraphWidget.h"
4 #include "Visualization/VisualizationTabWidget.h"
4 #include "Visualization/VisualizationTabWidget.h"
5 #include "Visualization/VisualizationZoneWidget.h"
5 #include "Visualization/VisualizationZoneWidget.h"
6 #include "Visualization/operations/GenerateVariableMenuOperation.h"
6 #include "Visualization/operations/GenerateVariableMenuOperation.h"
7 #include "Visualization/operations/RemoveVariableOperation.h"
7 #include "Visualization/operations/RemoveVariableOperation.h"
8 #include "Visualization/operations/RescaleAxeOperation.h"
8 #include "Visualization/operations/RescaleAxeOperation.h"
9 #include "Visualization/qcustomplot.h"
9 #include "Visualization/qcustomplot.h"
10
10
11 #include "ui_VisualizationWidget.h"
11 #include "ui_VisualizationWidget.h"
12
12
13 #include <QToolButton>
13 #include <QToolButton>
14
14
15 Q_LOGGING_CATEGORY(LOG_VisualizationWidget, "VisualizationWidget")
15 Q_LOGGING_CATEGORY(LOG_VisualizationWidget, "VisualizationWidget")
16
16
17 VisualizationWidget::VisualizationWidget(QWidget *parent)
17 VisualizationWidget::VisualizationWidget(QWidget *parent)
18 : QWidget{parent}, ui{new Ui::VisualizationWidget}
18 : QWidget{parent}, ui{new Ui::VisualizationWidget}
19 {
19 {
20 ui->setupUi(this);
20 ui->setupUi(this);
21
21
22 auto addTabViewButton = new QToolButton{ui->tabWidget};
22 auto addTabViewButton = new QToolButton{ui->tabWidget};
23 addTabViewButton->setText(tr("Add View"));
23 addTabViewButton->setText(tr("Add View"));
24 addTabViewButton->setCursor(Qt::ArrowCursor);
24 addTabViewButton->setCursor(Qt::ArrowCursor);
25 ui->tabWidget->setCornerWidget(addTabViewButton, Qt::TopRightCorner);
25 ui->tabWidget->setCornerWidget(addTabViewButton, Qt::TopRightCorner);
26
26
27 auto enableMinimumCornerWidgetSize = [this](bool enable) {
27 auto enableMinimumCornerWidgetSize = [this](bool enable) {
28
28
29 auto tabViewCornerWidget = ui->tabWidget->cornerWidget();
29 auto tabViewCornerWidget = ui->tabWidget->cornerWidget();
30 auto width = enable ? tabViewCornerWidget->width() : 0;
30 auto width = enable ? tabViewCornerWidget->width() : 0;
31 auto height = enable ? tabViewCornerWidget->height() : 0;
31 auto height = enable ? tabViewCornerWidget->height() : 0;
32 tabViewCornerWidget->setMinimumHeight(height);
32 tabViewCornerWidget->setMinimumHeight(height);
33 tabViewCornerWidget->setMinimumWidth(width);
33 tabViewCornerWidget->setMinimumWidth(width);
34 ui->tabWidget->setMinimumHeight(height);
34 ui->tabWidget->setMinimumHeight(height);
35 ui->tabWidget->setMinimumWidth(width);
35 ui->tabWidget->setMinimumWidth(width);
36 };
36 };
37
37
38 auto addTabView = [this, enableMinimumCornerWidgetSize]() {
38 auto addTabView = [this, enableMinimumCornerWidgetSize]() {
39 auto widget = new VisualizationTabWidget{QString{"View %1"}.arg(ui->tabWidget->count() + 1),
39 auto widget = new VisualizationTabWidget{QString{"View %1"}.arg(ui->tabWidget->count() + 1),
40 ui->tabWidget};
40 ui->tabWidget};
41 auto index = ui->tabWidget->addTab(widget, widget->name());
41 auto index = ui->tabWidget->addTab(widget, widget->name());
42 if (ui->tabWidget->count() > 0) {
42 if (ui->tabWidget->count() > 0) {
43 enableMinimumCornerWidgetSize(false);
43 enableMinimumCornerWidgetSize(false);
44 }
44 }
45 qCInfo(LOG_VisualizationWidget()) << tr("add the tab of index %1").arg(index);
45 qCInfo(LOG_VisualizationWidget()) << tr("add the tab of index %1").arg(index);
46 };
46 };
47
47
48 auto removeTabView = [this, enableMinimumCornerWidgetSize](int index) {
48 auto removeTabView = [this, enableMinimumCornerWidgetSize](int index) {
49 if (ui->tabWidget->count() == 1) {
49 if (ui->tabWidget->count() == 1) {
50 enableMinimumCornerWidgetSize(true);
50 enableMinimumCornerWidgetSize(true);
51 }
51 }
52
52
53 // Removes widget from tab and closes it
53 // Removes widget from tab and closes it
54 auto widget = ui->tabWidget->widget(index);
54 auto widget = ui->tabWidget->widget(index);
55 ui->tabWidget->removeTab(index);
55 ui->tabWidget->removeTab(index);
56 if (widget) {
56 if (widget) {
57 widget->close();
57 widget->close();
58 }
58 }
59
59
60 qCInfo(LOG_VisualizationWidget()) << tr("remove the tab of index %1").arg(index);
60 qCInfo(LOG_VisualizationWidget()) << tr("remove the tab of index %1").arg(index);
61
61
62 };
62 };
63
63
64 ui->tabWidget->setTabsClosable(true);
64 ui->tabWidget->setTabsClosable(true);
65
65
66 connect(addTabViewButton, &QToolButton::clicked, addTabView);
66 connect(addTabViewButton, &QToolButton::clicked, addTabView);
67 connect(ui->tabWidget, &QTabWidget::tabCloseRequested, removeTabView);
67 connect(ui->tabWidget, &QTabWidget::tabCloseRequested, removeTabView);
68
68
69 // Adds default tab
69 // Adds default tab
70 addTabView();
70 addTabView();
71 }
71 }
72
72
73 VisualizationWidget::~VisualizationWidget()
73 VisualizationWidget::~VisualizationWidget()
74 {
74 {
75 delete ui;
75 delete ui;
76 }
76 }
77
77
78 void VisualizationWidget::accept(IVisualizationWidgetVisitor *visitor)
78 void VisualizationWidget::accept(IVisualizationWidgetVisitor *visitor)
79 {
79 {
80 if (visitor) {
80 if (visitor) {
81 visitor->visitEnter(this);
81 visitor->visitEnter(this);
82
82
83 // Apply visitor for tab children
83 // Apply visitor for tab children
84 for (auto i = 0; i < ui->tabWidget->count(); ++i) {
84 for (auto i = 0; i < ui->tabWidget->count(); ++i) {
85 // Widgets different from tabs are not visited (no action)
85 // Widgets different from tabs are not visited (no action)
86 if (auto visualizationTabWidget
86 if (auto visualizationTabWidget
87 = dynamic_cast<VisualizationTabWidget *>(ui->tabWidget->widget(i))) {
87 = dynamic_cast<VisualizationTabWidget *>(ui->tabWidget->widget(i))) {
88 visualizationTabWidget->accept(visitor);
88 visualizationTabWidget->accept(visitor);
89 }
89 }
90 }
90 }
91
91
92 visitor->visitLeave(this);
92 visitor->visitLeave(this);
93 }
93 }
94 else {
94 else {
95 qCCritical(LOG_VisualizationWidget()) << tr("Can't visit widget : the visitor is null");
95 qCCritical(LOG_VisualizationWidget()) << tr("Can't visit widget : the visitor is null");
96 }
96 }
97 }
97 }
98
98
99 bool VisualizationWidget::canDrop(const Variable &variable) const
99 bool VisualizationWidget::canDrop(const Variable &variable) const
100 {
100 {
101 // The main widget can never accomodate a variable
101 // The main widget can never accomodate a variable
102 Q_UNUSED(variable);
102 Q_UNUSED(variable);
103 return false;
103 return false;
104 }
104 }
105
105
106 bool VisualizationWidget::contains(const Variable &variable) const
106 bool VisualizationWidget::contains(const Variable &variable) const
107 {
107 {
108 Q_UNUSED(variable);
108 Q_UNUSED(variable);
109 return false;
109 return false;
110 }
110 }
111
111
112 QString VisualizationWidget::name() const
112 QString VisualizationWidget::name() const
113 {
113 {
114 return QStringLiteral("MainView");
114 return QStringLiteral("MainView");
115 }
115 }
116
116
117 void VisualizationWidget::attachVariableMenu(
117 void VisualizationWidget::attachVariableMenu(
118 QMenu *menu, const QVector<std::shared_ptr<Variable> > &variables) noexcept
118 QMenu *menu, const QVector<std::shared_ptr<Variable> > &variables) noexcept
119 {
119 {
120 // Menu is generated only if there is a single variable
120 // Menu is generated only if there is a single variable
121 if (variables.size() == 1) {
121 if (variables.size() == 1) {
122 if (auto variable = variables.first()) {
122 if (auto variable = variables.first()) {
123 // Generates the actions that make it possible to visualize the variable
123 // Generates the actions that make it possible to visualize the variable
124 auto generateVariableMenuOperation = GenerateVariableMenuOperation{menu, variable};
124 auto generateVariableMenuOperation = GenerateVariableMenuOperation{menu, variable};
125 accept(&generateVariableMenuOperation);
125 accept(&generateVariableMenuOperation);
126 }
126 }
127 else {
127 else {
128 qCCritical(LOG_VisualizationWidget()) << tr(
128 qCCritical(LOG_VisualizationWidget()) << tr(
129 "Can't generate the menu relative to the visualization: the variable is null");
129 "Can't generate the menu relative to the visualization: the variable is null");
130 }
130 }
131 }
131 }
132 else {
132 else {
133 qCDebug(LOG_VisualizationWidget())
133 qCDebug(LOG_VisualizationWidget())
134 << tr("No generation of the menu related to the visualization: several variables are "
134 << tr("No generation of the menu related to the visualization: several variables are "
135 "selected");
135 "selected");
136 }
136 }
137 }
137 }
138
138
139 void VisualizationWidget::onVariableAboutToBeDeleted(std::shared_ptr<Variable> variable) noexcept
139 void VisualizationWidget::onVariableAboutToBeDeleted(std::shared_ptr<Variable> variable) noexcept
140 {
140 {
141 // Calls the operation of removing all references to the variable in the visualization
141 // Calls the operation of removing all references to the variable in the visualization
142 auto removeVariableOperation = RemoveVariableOperation{variable};
142 auto removeVariableOperation = RemoveVariableOperation{variable};
143 accept(&removeVariableOperation);
143 accept(&removeVariableOperation);
144 }
144 }
145
145
146 void VisualizationWidget::onRangeChanged(std::shared_ptr<Variable> variable,
146 void VisualizationWidget::onRangeChanged(std::shared_ptr<Variable> variable,
147 const SqpDateTime &range) noexcept
147 const SqpDateTime &range) noexcept
148 {
148 {
149 // Calls the operation of removing all references to the variable in the visualization
149 // Calls the operation of rescaling all graph that contrains variable in the visualization
150 auto rescaleVariableOperation = RescaleAxeOperation{variable, range};
150 auto rescaleVariableOperation = RescaleAxeOperation{variable, range};
151 accept(&rescaleVariableOperation);
151 accept(&rescaleVariableOperation);
152 }
152 }
@@ -1,71 +1,71
1 #include "Visualization/operations/RescaleAxeOperation.h"
1 #include "Visualization/operations/RescaleAxeOperation.h"
2 #include "Visualization/VisualizationGraphWidget.h"
2 #include "Visualization/VisualizationGraphWidget.h"
3
3
4 Q_LOGGING_CATEGORY(LOG_RescaleAxeOperation, "RescaleAxeOperation")
4 Q_LOGGING_CATEGORY(LOG_RescaleAxeOperation, "RescaleAxeOperation")
5
5
6 struct RescaleAxeOperation::RescaleAxeOperationPrivate {
6 struct RescaleAxeOperation::RescaleAxeOperationPrivate {
7 explicit RescaleAxeOperationPrivate(std::shared_ptr<Variable> variable,
7 explicit RescaleAxeOperationPrivate(std::shared_ptr<Variable> variable,
8 const SqpDateTime &range)
8 const SqpDateTime &range)
9 : m_Variable(variable), m_Range(range)
9 : m_Variable{variable}, m_Range{range}
10 {
10 {
11 }
11 }
12
12
13 std::shared_ptr<Variable> m_Variable;
13 std::shared_ptr<Variable> m_Variable;
14 SqpDateTime m_Range;
14 SqpDateTime m_Range;
15 };
15 };
16
16
17 RescaleAxeOperation::RescaleAxeOperation(std::shared_ptr<Variable> variable,
17 RescaleAxeOperation::RescaleAxeOperation(std::shared_ptr<Variable> variable,
18 const SqpDateTime &range)
18 const SqpDateTime &range)
19 : impl{spimpl::make_unique_impl<RescaleAxeOperationPrivate>(variable, range)}
19 : impl{spimpl::make_unique_impl<RescaleAxeOperationPrivate>(variable, range)}
20 {
20 {
21 }
21 }
22
22
23 void RescaleAxeOperation::visitEnter(VisualizationWidget *widget)
23 void RescaleAxeOperation::visitEnter(VisualizationWidget *widget)
24 {
24 {
25 // VisualizationWidget is not intended to contain a variable
25 // VisualizationWidget is not intended to contain a variable
26 Q_UNUSED(widget)
26 Q_UNUSED(widget)
27 }
27 }
28
28
29 void RescaleAxeOperation::visitLeave(VisualizationWidget *widget)
29 void RescaleAxeOperation::visitLeave(VisualizationWidget *widget)
30 {
30 {
31 // VisualizationWidget is not intended to contain a variable
31 // VisualizationWidget is not intended to contain a variable
32 Q_UNUSED(widget)
32 Q_UNUSED(widget)
33 }
33 }
34
34
35 void RescaleAxeOperation::visitEnter(VisualizationTabWidget *tabWidget)
35 void RescaleAxeOperation::visitEnter(VisualizationTabWidget *tabWidget)
36 {
36 {
37 // VisualizationTabWidget is not intended to contain a variable
37 // VisualizationTabWidget is not intended to contain a variable
38 Q_UNUSED(tabWidget)
38 Q_UNUSED(tabWidget)
39 }
39 }
40
40
41 void RescaleAxeOperation::visitLeave(VisualizationTabWidget *tabWidget)
41 void RescaleAxeOperation::visitLeave(VisualizationTabWidget *tabWidget)
42 {
42 {
43 // VisualizationTabWidget is not intended to contain a variable
43 // VisualizationTabWidget is not intended to contain a variable
44 Q_UNUSED(tabWidget)
44 Q_UNUSED(tabWidget)
45 }
45 }
46
46
47 void RescaleAxeOperation::visitEnter(VisualizationZoneWidget *zoneWidget)
47 void RescaleAxeOperation::visitEnter(VisualizationZoneWidget *zoneWidget)
48 {
48 {
49 // VisualizationZoneWidget is not intended to contain a variable
49 // VisualizationZoneWidget is not intended to contain a variable
50 Q_UNUSED(zoneWidget)
50 Q_UNUSED(zoneWidget)
51 }
51 }
52
52
53 void RescaleAxeOperation::visitLeave(VisualizationZoneWidget *zoneWidget)
53 void RescaleAxeOperation::visitLeave(VisualizationZoneWidget *zoneWidget)
54 {
54 {
55 // VisualizationZoneWidget is not intended to contain a variable
55 // VisualizationZoneWidget is not intended to contain a variable
56 Q_UNUSED(zoneWidget)
56 Q_UNUSED(zoneWidget)
57 }
57 }
58
58
59 void RescaleAxeOperation::visit(VisualizationGraphWidget *graphWidget)
59 void RescaleAxeOperation::visit(VisualizationGraphWidget *graphWidget)
60 {
60 {
61 if (graphWidget) {
61 if (graphWidget) {
62 // If the widget contains the variable, removes it
62 // If the widget contains the variable, rescale it
63 if (impl->m_Variable && graphWidget->contains(*impl->m_Variable)) {
63 if (impl->m_Variable && graphWidget->contains(*impl->m_Variable)) {
64 graphWidget->setRange(impl->m_Variable, impl->m_Range);
64 graphWidget->setRange(impl->m_Variable, impl->m_Range);
65 }
65 }
66 }
66 }
67 else {
67 else {
68 qCCritical(LOG_RescaleAxeOperation(),
68 qCCritical(LOG_RescaleAxeOperation(),
69 "Can't visit VisualizationGraphWidget : the widget is null");
69 "Can't visit VisualizationGraphWidget : the widget is null");
70 }
70 }
71 }
71 }
@@ -1,182 +1,182
1 #include "AmdaResultParser.h"
1 #include "AmdaResultParser.h"
2
2
3 #include <Data/ScalarSeries.h>
3 #include <Data/ScalarSeries.h>
4
4
5 #include <QObject>
5 #include <QObject>
6 #include <QtTest>
6 #include <QtTest>
7
7
8 namespace {
8 namespace {
9
9
10 /// Path for the tests
10 /// Path for the tests
11 const auto TESTS_RESOURCES_PATH
11 const auto TESTS_RESOURCES_PATH
12 = QFileInfo{QString{AMDA_TESTS_RESOURCES_DIR}, "TestAmdaResultParser"}.absoluteFilePath();
12 = QFileInfo{QString{AMDA_TESTS_RESOURCES_DIR}, "TestAmdaResultParser"}.absoluteFilePath();
13
13
14 QString inputFilePath(const QString &inputFileName)
14 QString inputFilePath(const QString &inputFileName)
15 {
15 {
16 return QFileInfo{TESTS_RESOURCES_PATH, inputFileName}.absoluteFilePath();
16 return QFileInfo{TESTS_RESOURCES_PATH, inputFileName}.absoluteFilePath();
17 }
17 }
18
18
19 struct ExpectedResults {
19 struct ExpectedResults {
20 explicit ExpectedResults() = default;
20 explicit ExpectedResults() = default;
21
21
22 /// Ctor with QVector<QDateTime> as x-axis data. Datetimes are converted to doubles
22 /// Ctor with QVector<QDateTime> as x-axis data. Datetimes are converted to doubles
23 explicit ExpectedResults(Unit xAxisUnit, Unit valuesUnit, const QVector<QDateTime> &xAxisData,
23 explicit ExpectedResults(Unit xAxisUnit, Unit valuesUnit, const QVector<QDateTime> &xAxisData,
24 QVector<double> valuesData)
24 QVector<double> valuesData)
25 : m_ParsingOK{true},
25 : m_ParsingOK{true},
26 m_XAxisUnit{xAxisUnit},
26 m_XAxisUnit{xAxisUnit},
27 m_ValuesUnit{valuesUnit},
27 m_ValuesUnit{valuesUnit},
28 m_XAxisData{},
28 m_XAxisData{},
29 m_ValuesData{std::move(valuesData)}
29 m_ValuesData{std::move(valuesData)}
30 {
30 {
31 // Converts QVector<QDateTime> to QVector<double>
31 // Converts QVector<QDateTime> to QVector<double>
32 std::transform(xAxisData.cbegin(), xAxisData.cend(), std::back_inserter(m_XAxisData),
32 std::transform(xAxisData.cbegin(), xAxisData.cend(), std::back_inserter(m_XAxisData),
33 [](const auto &dateTime) { return dateTime.toMSecsSinceEpoch() / 1000.; });
33 [](const auto &dateTime) { return dateTime.toMSecsSinceEpoch() / 1000.; });
34 }
34 }
35
35
36 /**
36 /**
37 * Validates a DataSeries compared to the expected results
37 * Validates a DataSeries compared to the expected results
38 * @param results the DataSeries to validate
38 * @param results the DataSeries to validate
39 */
39 */
40 void validate(std::shared_ptr<IDataSeries> results)
40 void validate(std::shared_ptr<IDataSeries> results)
41 {
41 {
42 if (m_ParsingOK) {
42 if (m_ParsingOK) {
43 auto scalarSeries = dynamic_cast<ScalarSeries *>(results.get());
43 auto scalarSeries = dynamic_cast<ScalarSeries *>(results.get());
44 QVERIFY(scalarSeries != nullptr);
44 QVERIFY(scalarSeries != nullptr);
45
45
46 // Checks units
46 // Checks units
47 QVERIFY(scalarSeries->xAxisUnit() == m_XAxisUnit);
47 QVERIFY(scalarSeries->xAxisUnit() == m_XAxisUnit);
48 QVERIFY(scalarSeries->valuesUnit() == m_ValuesUnit);
48 QVERIFY(scalarSeries->valuesUnit() == m_ValuesUnit);
49
49
50 // Checks values
50 // Checks values
51 QVERIFY(scalarSeries->xAxisData()->data() == m_XAxisData);
51 QVERIFY(scalarSeries->xAxisData()->data() == m_XAxisData);
52 QVERIFY(scalarSeries->valuesData()->data() == m_ValuesData);
52 QVERIFY(scalarSeries->valuesData()->data() == m_ValuesData);
53 }
53 }
54 else {
54 else {
55 QVERIFY(results == nullptr);
55 QVERIFY(results == nullptr);
56 }
56 }
57 }
57 }
58
58
59 // Parsing was successfully completed
59 // Parsing was successfully completed
60 bool m_ParsingOK{false};
60 bool m_ParsingOK{false};
61 // Expected x-axis unit
61 // Expected x-axis unit
62 Unit m_XAxisUnit{};
62 Unit m_XAxisUnit{};
63 // Expected values unit
63 // Expected values unit
64 Unit m_ValuesUnit{};
64 Unit m_ValuesUnit{};
65 // Expected x-axis data
65 // Expected x-axis data
66 QVector<double> m_XAxisData{};
66 QVector<double> m_XAxisData{};
67 // Expected values data
67 // Expected values data
68 QVector<double> m_ValuesData{};
68 QVector<double> m_ValuesData{};
69 };
69 };
70
70
71 } // namespace
71 } // namespace
72
72
73 Q_DECLARE_METATYPE(ExpectedResults)
73 Q_DECLARE_METATYPE(ExpectedResults)
74
74
75 class TestAmdaResultParser : public QObject {
75 class TestAmdaResultParser : public QObject {
76 Q_OBJECT
76 Q_OBJECT
77 private slots:
77 private slots:
78 /// Input test data
78 /// Input test data
79 /// @sa testTxtJson()
79 /// @sa testTxtJson()
80 void testReadTxt_data();
80 void testReadTxt_data();
81
81
82 /// Tests parsing of a TXT file
82 /// Tests parsing of a TXT file
83 void testReadTxt();
83 void testReadTxt();
84 };
84 };
85
85
86 void TestAmdaResultParser::testReadTxt_data()
86 void TestAmdaResultParser::testReadTxt_data()
87 {
87 {
88 // ////////////// //
88 // ////////////// //
89 // Test structure //
89 // Test structure //
90 // ////////////// //
90 // ////////////// //
91
91
92 // Name of TXT file to read
92 // Name of TXT file to read
93 QTest::addColumn<QString>("inputFileName");
93 QTest::addColumn<QString>("inputFileName");
94 // Expected results
94 // Expected results
95 QTest::addColumn<ExpectedResults>("expectedResults");
95 QTest::addColumn<ExpectedResults>("expectedResults");
96
96
97 // ////////// //
97 // ////////// //
98 // Test cases //
98 // Test cases //
99 // ////////// //
99 // ////////// //
100
100
101 auto dateTime = [](int year, int month, int day, int hours, int minutes, int seconds) {
101 auto dateTime = [](int year, int month, int day, int hours, int minutes, int seconds) {
102 return QDateTime{{year, month, day}, {hours, minutes, seconds}};
102 return QDateTime{{year, month, day}, {hours, minutes, seconds}};
103 };
103 };
104
104
105 // Valid file
105 // Valid file
106 QTest::newRow("Valid file")
106 QTest::newRow("Valid file")
107 << QStringLiteral("ValidScalar1.txt")
107 << QStringLiteral("ValidScalar1.txt")
108 << ExpectedResults{
108 << ExpectedResults{
109 Unit{QStringLiteral("nT"), true}, Unit{},
109 Unit{QStringLiteral("nT"), true}, Unit{},
110 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 0, 30), dateTime(2013, 9, 23, 9, 1, 30),
110 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 0, 30), dateTime(2013, 9, 23, 9, 1, 30),
111 dateTime(2013, 9, 23, 9, 2, 30), dateTime(2013, 9, 23, 9, 3, 30),
111 dateTime(2013, 9, 23, 9, 2, 30), dateTime(2013, 9, 23, 9, 3, 30),
112 dateTime(2013, 9, 23, 9, 4, 30), dateTime(2013, 9, 23, 9, 5, 30),
112 dateTime(2013, 9, 23, 9, 4, 30), dateTime(2013, 9, 23, 9, 5, 30),
113 dateTime(2013, 9, 23, 9, 6, 30), dateTime(2013, 9, 23, 9, 7, 30),
113 dateTime(2013, 9, 23, 9, 6, 30), dateTime(2013, 9, 23, 9, 7, 30),
114 dateTime(2013, 9, 23, 9, 8, 30), dateTime(2013, 9, 23, 9, 9, 30)},
114 dateTime(2013, 9, 23, 9, 8, 30), dateTime(2013, 9, 23, 9, 9, 30)},
115 QVector<double>{-2.83950, -2.71850, -2.52150, -2.57633, -2.58050, -2.48325, -2.63025,
115 QVector<double>{-2.83950, -2.71850, -2.52150, -2.57633, -2.58050, -2.48325, -2.63025,
116 -2.55800, -2.43250, -2.42200}};
116 -2.55800, -2.43250, -2.42200}};
117
117
118 // Valid files but with some invalid lines (wrong unit, wrong values, etc.)
118 // Valid files but with some invalid lines (wrong unit, wrong values, etc.)
119 QTest::newRow("No unit file") << QStringLiteral("NoUnit.txt")
119 QTest::newRow("No unit file") << QStringLiteral("NoUnit.txt")
120 << ExpectedResults{Unit{QStringLiteral(""), true}, Unit{},
120 << ExpectedResults{Unit{QStringLiteral(""), true}, Unit{},
121 QVector<QDateTime>{}, QVector<double>{}};
121 QVector<QDateTime>{}, QVector<double>{}};
122 QTest::newRow("Wrong unit file")
122 QTest::newRow("Wrong unit file")
123 << QStringLiteral("WrongUnit.txt")
123 << QStringLiteral("WrongUnit.txt")
124 << ExpectedResults{Unit{QStringLiteral(""), true}, Unit{},
124 << ExpectedResults{Unit{QStringLiteral(""), true}, Unit{},
125 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 0, 30),
125 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 0, 30),
126 dateTime(2013, 9, 23, 9, 1, 30),
126 dateTime(2013, 9, 23, 9, 1, 30),
127 dateTime(2013, 9, 23, 9, 2, 30)},
127 dateTime(2013, 9, 23, 9, 2, 30)},
128 QVector<double>{-2.83950, -2.71850, -2.52150}};
128 QVector<double>{-2.83950, -2.71850, -2.52150}};
129
129
130 QTest::newRow("Wrong results file (date of first line is invalid")
130 QTest::newRow("Wrong results file (date of first line is invalid")
131 << QStringLiteral("WrongDate.txt")
131 << QStringLiteral("WrongDate.txt")
132 << ExpectedResults{
132 << ExpectedResults{
133 Unit{QStringLiteral("nT"), true}, Unit{},
133 Unit{QStringLiteral("nT"), true}, Unit{},
134 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)},
134 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)},
135 QVector<double>{-2.71850, -2.52150}};
135 QVector<double>{-2.71850, -2.52150}};
136
136
137 QTest::newRow("Wrong results file (too many values for first line")
137 QTest::newRow("Wrong results file (too many values for first line")
138 << QStringLiteral("TooManyValues.txt")
138 << QStringLiteral("TooManyValues.txt")
139 << ExpectedResults{
139 << ExpectedResults{
140 Unit{QStringLiteral("nT"), true}, Unit{},
140 Unit{QStringLiteral("nT"), true}, Unit{},
141 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)},
141 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)},
142 QVector<double>{-2.71850, -2.52150}};
142 QVector<double>{-2.71850, -2.52150}};
143
143
144 QTest::newRow("Wrong results file (value of first line is invalid")
144 QTest::newRow("Wrong results file (value of first line is invalid")
145 << QStringLiteral("WrongValue.txt")
145 << QStringLiteral("WrongValue.txt")
146 << ExpectedResults{
146 << ExpectedResults{
147 Unit{QStringLiteral("nT"), true}, Unit{},
147 Unit{QStringLiteral("nT"), true}, Unit{},
148 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)},
148 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)},
149 QVector<double>{-2.71850, -2.52150}};
149 QVector<double>{-2.71850, -2.52150}};
150
150
151 QTest::newRow("Wrong results file (value of first line is NaN")
151 QTest::newRow("Wrong results file (value of first line is NaN")
152 << QStringLiteral("NaNValue.txt")
152 << QStringLiteral("NaNValue.txt")
153 << ExpectedResults{
153 << ExpectedResults{
154 Unit{QStringLiteral("nT"), true}, Unit{},
154 Unit{QStringLiteral("nT"), true}, Unit{},
155 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)},
155 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)},
156 QVector<double>{-2.71850, -2.52150}};
156 QVector<double>{-2.71850, -2.52150}};
157
157
158 // Invalid files
158 // Invalid files
159 QTest::newRow("Invalid file (unexisting file)")
159 QTest::newRow("Invalid file (unexisting file)") << QStringLiteral("UnexistingFile.txt")
160 << QStringLiteral("UnexistingFile.txt") << ExpectedResults{};
160 << ExpectedResults{};
161
161
162 QTest::newRow("Invalid file (file not found on server)")
162 QTest::newRow("Invalid file (file not found on server)") << QStringLiteral("FileNotFound.txt")
163 << QStringLiteral("FileNotFound.txt") << ExpectedResults{};
163 << ExpectedResults{};
164 }
164 }
165
165
166 void TestAmdaResultParser::testReadTxt()
166 void TestAmdaResultParser::testReadTxt()
167 {
167 {
168 QFETCH(QString, inputFileName);
168 QFETCH(QString, inputFileName);
169 QFETCH(ExpectedResults, expectedResults);
169 QFETCH(ExpectedResults, expectedResults);
170
170
171 // Parses file
171 // Parses file
172 auto filePath = inputFilePath(inputFileName);
172 auto filePath = inputFilePath(inputFileName);
173 auto results = AmdaResultParser::readTxt(filePath);
173 auto results = AmdaResultParser::readTxt(filePath);
174
174
175 // ///////////////// //
175 // ///////////////// //
176 // Validates results //
176 // Validates results //
177 // ///////////////// //
177 // ///////////////// //
178 expectedResults.validate(results);
178 expectedResults.validate(results);
179 }
179 }
180
180
181 QTEST_MAIN(TestAmdaResultParser)
181 QTEST_MAIN(TestAmdaResultParser)
182 #include "TestAmdaResultParser.moc"
182 #include "TestAmdaResultParser.moc"
General Comments 0
You need to be logged in to leave comments. Login now