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