##// END OF EJS Templates
Merge branch 'feature/DateTimeUTC' into develop
Alexandre Leroux -
r455:a774a1678512 merge
parent child
Show More
@@ -0,0 +1,19
1 #ifndef SCIQLOP_DATEUTILS_H
2 #define SCIQLOP_DATEUTILS_H
3
4 #include "CoreGlobal.h"
5
6 #include <QDateTime>
7
8 /**
9 * Utility class with methods for dates
10 */
11 struct SCIQLOP_CORE_EXPORT DateUtils {
12 /// Converts seconds (since epoch) to datetime. By default, the datetime is in UTC
13 static QDateTime dateTime(double secs, Qt::TimeSpec timeSpec = Qt::UTC) noexcept;
14
15 /// Converts datetime to seconds since epoch
16 static double secondsSinceEpoch(const QDateTime &dateTime) noexcept;
17 };
18
19 #endif // SCIQLOP_DATEUTILS_H
@@ -0,0 +1,13
1 #include "Common/DateUtils.h"
2
3 QDateTime DateUtils::dateTime(double secs, Qt::TimeSpec timeSpec) noexcept
4 {
5 // Uses msecs to be Qt 4 compatible
6 return QDateTime::fromMSecsSinceEpoch(secs * 1000., timeSpec);
7 }
8
9 double DateUtils::secondsSinceEpoch(const QDateTime &dateTime) noexcept
10 {
11 // Uses msecs to be Qt 4 compatible
12 return dateTime.toMSecsSinceEpoch() / 1000.;
13 }
@@ -1,255 +1,254
1 /*------------------------------------------------------------------------------
1 /*------------------------------------------------------------------------------
2 -- This file is a part of the SciQLop Software
2 -- This file is a part of the SciQLop Software
3 -- Copyright (C) 2017, Plasma Physics Laboratory - CNRS
3 -- Copyright (C) 2017, Plasma Physics Laboratory - CNRS
4 --
4 --
5 -- This program is free software; you can redistribute it and/or modify
5 -- This program is free software; you can redistribute it and/or modify
6 -- it under the terms of the GNU General Public License as published by
6 -- it under the terms of the GNU General Public License as published by
7 -- the Free Software Foundation; either version 2 of the License, or
7 -- the Free Software Foundation; either version 2 of the License, or
8 -- (at your option) any later version.
8 -- (at your option) any later version.
9 --
9 --
10 -- This program is distributed in the hope that it will be useful,
10 -- This program is distributed in the hope that it will be useful,
11 -- but WITHOUT ANY WARRANTY; without even the implied warranty of
11 -- but WITHOUT ANY WARRANTY; without even the implied warranty of
12 -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 -- GNU General Public License for more details.
13 -- GNU General Public License for more details.
14 --
14 --
15 -- You should have received a copy of the GNU General Public License
15 -- You should have received a copy of the GNU General Public License
16 -- along with this program; if not, write to the Free Software
16 -- along with this program; if not, write to the Free Software
17 -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 -------------------------------------------------------------------------------*/
18 -------------------------------------------------------------------------------*/
19 /*-- Author : Alexis Jeandet
19 /*-- Author : Alexis Jeandet
20 -- Mail : alexis.jeandet@member.fsf.org
20 -- Mail : alexis.jeandet@member.fsf.org
21 ----------------------------------------------------------------------------*/
21 ----------------------------------------------------------------------------*/
22 #include "MainWindow.h"
22 #include "MainWindow.h"
23 #include "ui_MainWindow.h"
23 #include "ui_MainWindow.h"
24
24
25 #include <DataSource/DataSourceController.h>
25 #include <DataSource/DataSourceController.h>
26 #include <DataSource/DataSourceWidget.h>
26 #include <DataSource/DataSourceWidget.h>
27 #include <Settings/SqpSettingsDialog.h>
27 #include <Settings/SqpSettingsDialog.h>
28 #include <Settings/SqpSettingsGeneralWidget.h>
28 #include <Settings/SqpSettingsGeneralWidget.h>
29 #include <SidePane/SqpSidePane.h>
29 #include <SidePane/SqpSidePane.h>
30 #include <SqpApplication.h>
30 #include <SqpApplication.h>
31 #include <Time/TimeController.h>
31 #include <Time/TimeController.h>
32 #include <TimeWidget/TimeWidget.h>
32 #include <TimeWidget/TimeWidget.h>
33 #include <Variable/Variable.h>
33 #include <Variable/Variable.h>
34 #include <Variable/VariableController.h>
34 #include <Variable/VariableController.h>
35 #include <Visualization/VisualizationController.h>
35 #include <Visualization/VisualizationController.h>
36
36
37 #include <QAction>
37 #include <QAction>
38 #include <QDate>
38 #include <QDate>
39 #include <QDateTime>
40 #include <QDir>
39 #include <QDir>
41 #include <QFileDialog>
40 #include <QFileDialog>
42 #include <QToolBar>
41 #include <QToolBar>
43 #include <QToolButton>
42 #include <QToolButton>
44 #include <memory.h>
43 #include <memory.h>
45
44
46 #include "iostream"
45 #include "iostream"
47
46
48 Q_LOGGING_CATEGORY(LOG_MainWindow, "MainWindow")
47 Q_LOGGING_CATEGORY(LOG_MainWindow, "MainWindow")
49
48
50 namespace {
49 namespace {
51 const auto LEFTMAININSPECTORWIDGETSPLITTERINDEX = 0;
50 const auto LEFTMAININSPECTORWIDGETSPLITTERINDEX = 0;
52 const auto LEFTINSPECTORSIDEPANESPLITTERINDEX = 1;
51 const auto LEFTINSPECTORSIDEPANESPLITTERINDEX = 1;
53 const auto VIEWPLITTERINDEX = 2;
52 const auto VIEWPLITTERINDEX = 2;
54 const auto RIGHTINSPECTORSIDEPANESPLITTERINDEX = 3;
53 const auto RIGHTINSPECTORSIDEPANESPLITTERINDEX = 3;
55 const auto RIGHTMAININSPECTORWIDGETSPLITTERINDEX = 4;
54 const auto RIGHTMAININSPECTORWIDGETSPLITTERINDEX = 4;
56 }
55 }
57
56
58 class MainWindow::MainWindowPrivate {
57 class MainWindow::MainWindowPrivate {
59 public:
58 public:
60 explicit MainWindowPrivate(MainWindow *mainWindow)
59 explicit MainWindowPrivate(MainWindow *mainWindow)
61 : m_LastOpenLeftInspectorSize{},
60 : m_LastOpenLeftInspectorSize{},
62 m_LastOpenRightInspectorSize{},
61 m_LastOpenRightInspectorSize{},
63 m_GeneralSettingsWidget{new SqpSettingsGeneralWidget{mainWindow}},
62 m_GeneralSettingsWidget{new SqpSettingsGeneralWidget{mainWindow}},
64 m_SettingsDialog{new SqpSettingsDialog{mainWindow}}
63 m_SettingsDialog{new SqpSettingsDialog{mainWindow}}
65 {
64 {
66 }
65 }
67
66
68 QSize m_LastOpenLeftInspectorSize;
67 QSize m_LastOpenLeftInspectorSize;
69 QSize m_LastOpenRightInspectorSize;
68 QSize m_LastOpenRightInspectorSize;
70 /// General settings widget. MainWindow has the ownership
69 /// General settings widget. MainWindow has the ownership
71 SqpSettingsGeneralWidget *m_GeneralSettingsWidget;
70 SqpSettingsGeneralWidget *m_GeneralSettingsWidget;
72 /// Settings dialog. MainWindow has the ownership
71 /// Settings dialog. MainWindow has the ownership
73 SqpSettingsDialog *m_SettingsDialog;
72 SqpSettingsDialog *m_SettingsDialog;
74 };
73 };
75
74
76 MainWindow::MainWindow(QWidget *parent)
75 MainWindow::MainWindow(QWidget *parent)
77 : QMainWindow{parent},
76 : QMainWindow{parent},
78 m_Ui{new Ui::MainWindow},
77 m_Ui{new Ui::MainWindow},
79 impl{spimpl::make_unique_impl<MainWindowPrivate>(this)}
78 impl{spimpl::make_unique_impl<MainWindowPrivate>(this)}
80 {
79 {
81 m_Ui->setupUi(this);
80 m_Ui->setupUi(this);
82
81
83 m_Ui->splitter->setCollapsible(LEFTINSPECTORSIDEPANESPLITTERINDEX, false);
82 m_Ui->splitter->setCollapsible(LEFTINSPECTORSIDEPANESPLITTERINDEX, false);
84 m_Ui->splitter->setCollapsible(RIGHTINSPECTORSIDEPANESPLITTERINDEX, false);
83 m_Ui->splitter->setCollapsible(RIGHTINSPECTORSIDEPANESPLITTERINDEX, false);
85
84
86
85
87 auto leftSidePane = m_Ui->leftInspectorSidePane->sidePane();
86 auto leftSidePane = m_Ui->leftInspectorSidePane->sidePane();
88 auto openLeftInspectorAction = new QAction{QIcon{
87 auto openLeftInspectorAction = new QAction{QIcon{
89 ":/icones/previous.png",
88 ":/icones/previous.png",
90 },
89 },
91 tr("Show/hide the left inspector"), this};
90 tr("Show/hide the left inspector"), this};
92
91
93
92
94 auto spacerLeftTop = new QWidget{};
93 auto spacerLeftTop = new QWidget{};
95 spacerLeftTop->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
94 spacerLeftTop->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
96
95
97 auto spacerLeftBottom = new QWidget{};
96 auto spacerLeftBottom = new QWidget{};
98 spacerLeftBottom->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
97 spacerLeftBottom->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
99
98
100 leftSidePane->addWidget(spacerLeftTop);
99 leftSidePane->addWidget(spacerLeftTop);
101 leftSidePane->addAction(openLeftInspectorAction);
100 leftSidePane->addAction(openLeftInspectorAction);
102 leftSidePane->addWidget(spacerLeftBottom);
101 leftSidePane->addWidget(spacerLeftBottom);
103
102
104
103
105 auto rightSidePane = m_Ui->rightInspectorSidePane->sidePane();
104 auto rightSidePane = m_Ui->rightInspectorSidePane->sidePane();
106 auto openRightInspectorAction = new QAction{QIcon{
105 auto openRightInspectorAction = new QAction{QIcon{
107 ":/icones/next.png",
106 ":/icones/next.png",
108 },
107 },
109 tr("Show/hide the right inspector"), this};
108 tr("Show/hide the right inspector"), this};
110
109
111 auto spacerRightTop = new QWidget{};
110 auto spacerRightTop = new QWidget{};
112 spacerRightTop->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
111 spacerRightTop->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
113
112
114 auto spacerRightBottom = new QWidget{};
113 auto spacerRightBottom = new QWidget{};
115 spacerRightBottom->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
114 spacerRightBottom->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
116
115
117 rightSidePane->addWidget(spacerRightTop);
116 rightSidePane->addWidget(spacerRightTop);
118 rightSidePane->addAction(openRightInspectorAction);
117 rightSidePane->addAction(openRightInspectorAction);
119 rightSidePane->addWidget(spacerRightBottom);
118 rightSidePane->addWidget(spacerRightBottom);
120
119
121 openLeftInspectorAction->setCheckable(true);
120 openLeftInspectorAction->setCheckable(true);
122 openRightInspectorAction->setCheckable(true);
121 openRightInspectorAction->setCheckable(true);
123
122
124 auto openInspector = [this](bool checked, bool right, auto action) {
123 auto openInspector = [this](bool checked, bool right, auto action) {
125
124
126 action->setIcon(QIcon{(checked xor right) ? ":/icones/next.png" : ":/icones/previous.png"});
125 action->setIcon(QIcon{(checked xor right) ? ":/icones/next.png" : ":/icones/previous.png"});
127
126
128 auto &lastInspectorSize
127 auto &lastInspectorSize
129 = right ? impl->m_LastOpenRightInspectorSize : impl->m_LastOpenLeftInspectorSize;
128 = right ? impl->m_LastOpenRightInspectorSize : impl->m_LastOpenLeftInspectorSize;
130
129
131 auto nextInspectorSize = right ? m_Ui->rightMainInspectorWidget->size()
130 auto nextInspectorSize = right ? m_Ui->rightMainInspectorWidget->size()
132 : m_Ui->leftMainInspectorWidget->size();
131 : m_Ui->leftMainInspectorWidget->size();
133
132
134 // Update of the last opened geometry
133 // Update of the last opened geometry
135 if (checked) {
134 if (checked) {
136 lastInspectorSize = nextInspectorSize;
135 lastInspectorSize = nextInspectorSize;
137 }
136 }
138
137
139 auto startSize = lastInspectorSize;
138 auto startSize = lastInspectorSize;
140 auto endSize = startSize;
139 auto endSize = startSize;
141 endSize.setWidth(0);
140 endSize.setWidth(0);
142
141
143 auto splitterInspectorIndex
142 auto splitterInspectorIndex
144 = right ? RIGHTMAININSPECTORWIDGETSPLITTERINDEX : LEFTMAININSPECTORWIDGETSPLITTERINDEX;
143 = right ? RIGHTMAININSPECTORWIDGETSPLITTERINDEX : LEFTMAININSPECTORWIDGETSPLITTERINDEX;
145
144
146 auto currentSizes = m_Ui->splitter->sizes();
145 auto currentSizes = m_Ui->splitter->sizes();
147 if (checked) {
146 if (checked) {
148 // adjust sizes individually here, e.g.
147 // adjust sizes individually here, e.g.
149 currentSizes[splitterInspectorIndex] -= lastInspectorSize.width();
148 currentSizes[splitterInspectorIndex] -= lastInspectorSize.width();
150 currentSizes[VIEWPLITTERINDEX] += lastInspectorSize.width();
149 currentSizes[VIEWPLITTERINDEX] += lastInspectorSize.width();
151 m_Ui->splitter->setSizes(currentSizes);
150 m_Ui->splitter->setSizes(currentSizes);
152 }
151 }
153 else {
152 else {
154 // adjust sizes individually here, e.g.
153 // adjust sizes individually here, e.g.
155 currentSizes[splitterInspectorIndex] += lastInspectorSize.width();
154 currentSizes[splitterInspectorIndex] += lastInspectorSize.width();
156 currentSizes[VIEWPLITTERINDEX] -= lastInspectorSize.width();
155 currentSizes[VIEWPLITTERINDEX] -= lastInspectorSize.width();
157 m_Ui->splitter->setSizes(currentSizes);
156 m_Ui->splitter->setSizes(currentSizes);
158 }
157 }
159
158
160 };
159 };
161
160
162
161
163 connect(openLeftInspectorAction, &QAction::triggered,
162 connect(openLeftInspectorAction, &QAction::triggered,
164 [openInspector, openLeftInspectorAction](bool checked) {
163 [openInspector, openLeftInspectorAction](bool checked) {
165 openInspector(checked, false, openLeftInspectorAction);
164 openInspector(checked, false, openLeftInspectorAction);
166 });
165 });
167 connect(openRightInspectorAction, &QAction::triggered,
166 connect(openRightInspectorAction, &QAction::triggered,
168 [openInspector, openRightInspectorAction](bool checked) {
167 [openInspector, openRightInspectorAction](bool checked) {
169 openInspector(checked, true, openRightInspectorAction);
168 openInspector(checked, true, openRightInspectorAction);
170 });
169 });
171
170
172 // //// //
171 // //// //
173 // Menu //
172 // Menu //
174 // //// //
173 // //// //
175 this->menuBar()->addAction(tr("File"));
174 this->menuBar()->addAction(tr("File"));
176 auto toolsMenu = this->menuBar()->addMenu(tr("Tools"));
175 auto toolsMenu = this->menuBar()->addMenu(tr("Tools"));
177 toolsMenu->addAction(tr("Settings..."), [this]() {
176 toolsMenu->addAction(tr("Settings..."), [this]() {
178 // Loads settings
177 // Loads settings
179 impl->m_SettingsDialog->loadSettings();
178 impl->m_SettingsDialog->loadSettings();
180
179
181 // Open settings dialog and save settings if the dialog is accepted
180 // Open settings dialog and save settings if the dialog is accepted
182 if (impl->m_SettingsDialog->exec() == QDialog::Accepted) {
181 if (impl->m_SettingsDialog->exec() == QDialog::Accepted) {
183 impl->m_SettingsDialog->saveSettings();
182 impl->m_SettingsDialog->saveSettings();
184 }
183 }
185
184
186 });
185 });
187
186
188 auto mainToolBar = this->addToolBar(QStringLiteral("MainToolBar"));
187 auto mainToolBar = this->addToolBar(QStringLiteral("MainToolBar"));
189
188
190 auto timeWidget = new TimeWidget{};
189 auto timeWidget = new TimeWidget{};
191 mainToolBar->addWidget(timeWidget);
190 mainToolBar->addWidget(timeWidget);
192
191
193 // //////// //
192 // //////// //
194 // Settings //
193 // Settings //
195 // //////// //
194 // //////// //
196
195
197 // Registers "general settings" widget to the settings dialog
196 // Registers "general settings" widget to the settings dialog
198 impl->m_SettingsDialog->registerWidget(QStringLiteral("General"),
197 impl->m_SettingsDialog->registerWidget(QStringLiteral("General"),
199 impl->m_GeneralSettingsWidget);
198 impl->m_GeneralSettingsWidget);
200
199
201 // /////////// //
200 // /////////// //
202 // Connections //
201 // Connections //
203 // /////////// //
202 // /////////// //
204
203
205 // Controllers / controllers connections
204 // Controllers / controllers connections
206 connect(&sqpApp->timeController(), SIGNAL(timeUpdated(SqpDateTime)),
205 connect(&sqpApp->timeController(), SIGNAL(timeUpdated(SqpDateTime)),
207 &sqpApp->variableController(), SLOT(onDateTimeOnSelection(SqpDateTime)));
206 &sqpApp->variableController(), SLOT(onDateTimeOnSelection(SqpDateTime)));
208
207
209 // Widgets / controllers connections
208 // Widgets / controllers connections
210
209
211 // DataSource
210 // DataSource
212 connect(&sqpApp->dataSourceController(), SIGNAL(dataSourceItemSet(DataSourceItem *)),
211 connect(&sqpApp->dataSourceController(), SIGNAL(dataSourceItemSet(DataSourceItem *)),
213 m_Ui->dataSourceWidget, SLOT(addDataSource(DataSourceItem *)));
212 m_Ui->dataSourceWidget, SLOT(addDataSource(DataSourceItem *)));
214
213
215 // Time
214 // Time
216 connect(timeWidget, SIGNAL(timeUpdated(SqpDateTime)), &sqpApp->timeController(),
215 connect(timeWidget, SIGNAL(timeUpdated(SqpDateTime)), &sqpApp->timeController(),
217 SLOT(onTimeToUpdate(SqpDateTime)));
216 SLOT(onTimeToUpdate(SqpDateTime)));
218
217
219 // Visualization
218 // Visualization
220 connect(&sqpApp->visualizationController(),
219 connect(&sqpApp->visualizationController(),
221 SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)), m_Ui->view,
220 SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)), m_Ui->view,
222 SLOT(onVariableAboutToBeDeleted(std::shared_ptr<Variable>)));
221 SLOT(onVariableAboutToBeDeleted(std::shared_ptr<Variable>)));
223
222
224 connect(&sqpApp->visualizationController(),
223 connect(&sqpApp->visualizationController(),
225 SIGNAL(rangeChanged(std::shared_ptr<Variable>, const SqpDateTime &)), m_Ui->view,
224 SIGNAL(rangeChanged(std::shared_ptr<Variable>, const SqpDateTime &)), m_Ui->view,
226 SLOT(onRangeChanged(std::shared_ptr<Variable>, const SqpDateTime &)));
225 SLOT(onRangeChanged(std::shared_ptr<Variable>, const SqpDateTime &)));
227
226
228 // Widgets / widgets connections
227 // Widgets / widgets connections
229
228
230 // For the following connections, we use DirectConnection to allow each widget that can
229 // For the following connections, we use DirectConnection to allow each widget that can
231 // potentially attach a menu to the variable's menu to do so before this menu is displayed.
230 // potentially attach a menu to the variable's menu to do so before this menu is displayed.
232 // The order of connections is also important, since it determines the order in which each
231 // The order of connections is also important, since it determines the order in which each
233 // widget will attach its menu
232 // widget will attach its menu
234 connect(
233 connect(
235 m_Ui->variableInspectorWidget,
234 m_Ui->variableInspectorWidget,
236 SIGNAL(tableMenuAboutToBeDisplayed(QMenu *, const QVector<std::shared_ptr<Variable> > &)),
235 SIGNAL(tableMenuAboutToBeDisplayed(QMenu *, const QVector<std::shared_ptr<Variable> > &)),
237 m_Ui->view, SLOT(attachVariableMenu(QMenu *, const QVector<std::shared_ptr<Variable> > &)),
236 m_Ui->view, SLOT(attachVariableMenu(QMenu *, const QVector<std::shared_ptr<Variable> > &)),
238 Qt::DirectConnection);
237 Qt::DirectConnection);
239 }
238 }
240
239
241 MainWindow::~MainWindow()
240 MainWindow::~MainWindow()
242 {
241 {
243 }
242 }
244
243
245 void MainWindow::changeEvent(QEvent *e)
244 void MainWindow::changeEvent(QEvent *e)
246 {
245 {
247 QMainWindow::changeEvent(e);
246 QMainWindow::changeEvent(e);
248 switch (e->type()) {
247 switch (e->type()) {
249 case QEvent::LanguageChange:
248 case QEvent::LanguageChange:
250 m_Ui->retranslateUi(this);
249 m_Ui->retranslateUi(this);
251 break;
250 break;
252 default:
251 default:
253 break;
252 break;
254 }
253 }
255 }
254 }
@@ -1,69 +1,69
1 #ifndef SCIQLOP_IDATASERIES_H
1 #ifndef SCIQLOP_IDATASERIES_H
2 #define SCIQLOP_IDATASERIES_H
2 #define SCIQLOP_IDATASERIES_H
3
3
4 #include <Common/MetaTypes.h>
4 #include <Common/MetaTypes.h>
5
5
6 #include <memory>
6 #include <memory>
7
7
8 #include <QString>
8 #include <QString>
9
9
10 template <int Dim>
10 template <int Dim>
11 class ArrayData;
11 class ArrayData;
12
12
13 struct Unit {
13 struct Unit {
14 explicit Unit(const QString &name = {}, bool timeUnit = false)
14 explicit Unit(const QString &name = {}, bool timeUnit = false)
15 : m_Name{name}, m_TimeUnit{timeUnit}
15 : m_Name{name}, m_TimeUnit{timeUnit}
16 {
16 {
17 }
17 }
18
18
19 inline bool operator==(const Unit &other) const
19 inline bool operator==(const Unit &other) const
20 {
20 {
21 return std::tie(m_Name, m_TimeUnit) == std::tie(other.m_Name, other.m_TimeUnit);
21 return std::tie(m_Name, m_TimeUnit) == std::tie(other.m_Name, other.m_TimeUnit);
22 }
22 }
23 inline bool operator!=(const Unit &other) const { return !(*this == other); }
23 inline bool operator!=(const Unit &other) const { return !(*this == other); }
24
24
25 QString m_Name; ///< Unit name
25 QString m_Name; ///< Unit name
26 bool m_TimeUnit; ///< The unit is a unit of time
26 bool m_TimeUnit; ///< The unit is a unit of time (UTC)
27 };
27 };
28
28
29 /**
29 /**
30 * @brief The IDataSeries aims to declare a data series.
30 * @brief The IDataSeries aims to declare a data series.
31 *
31 *
32 * A data series is an entity that contains at least :
32 * A data series is an entity that contains at least :
33 * - one dataset representing the x-axis
33 * - one dataset representing the x-axis
34 * - one dataset representing the values
34 * - one dataset representing the values
35 *
35 *
36 * Each dataset is represented by an ArrayData, and is associated with a unit.
36 * Each dataset is represented by an ArrayData, and is associated with a unit.
37 *
37 *
38 * An ArrayData can be unidimensional or two-dimensional, depending on the implementation of the
38 * An ArrayData can be unidimensional or two-dimensional, depending on the implementation of the
39 * IDataSeries. The x-axis dataset is always unidimensional.
39 * IDataSeries. The x-axis dataset is always unidimensional.
40 *
40 *
41 * @sa ArrayData
41 * @sa ArrayData
42 */
42 */
43 class IDataSeries {
43 class IDataSeries {
44 public:
44 public:
45 virtual ~IDataSeries() noexcept = default;
45 virtual ~IDataSeries() noexcept = default;
46
46
47 /// Returns the x-axis dataset
47 /// Returns the x-axis dataset
48 virtual std::shared_ptr<ArrayData<1> > xAxisData() = 0;
48 virtual std::shared_ptr<ArrayData<1> > xAxisData() = 0;
49
49
50 /// Returns the x-axis dataset (as const)
50 /// Returns the x-axis dataset (as const)
51 virtual const std::shared_ptr<ArrayData<1> > xAxisData() const = 0;
51 virtual const std::shared_ptr<ArrayData<1> > xAxisData() const = 0;
52
52
53 virtual Unit xAxisUnit() const = 0;
53 virtual Unit xAxisUnit() const = 0;
54
54
55 virtual Unit valuesUnit() const = 0;
55 virtual Unit valuesUnit() const = 0;
56
56
57 virtual void merge(IDataSeries *dataSeries) = 0;
57 virtual void merge(IDataSeries *dataSeries) = 0;
58
58
59 virtual std::unique_ptr<IDataSeries> clone() const = 0;
59 virtual std::unique_ptr<IDataSeries> clone() const = 0;
60
60
61 virtual void lockRead() = 0;
61 virtual void lockRead() = 0;
62 virtual void lockWrite() = 0;
62 virtual void lockWrite() = 0;
63 virtual void unlock() = 0;
63 virtual void unlock() = 0;
64 };
64 };
65
65
66 // Required for using shared_ptr in signals/slots
66 // Required for using shared_ptr in signals/slots
67 SCIQLOP_REGISTER_META_TYPE(IDATASERIES_PTR_REGISTRY, std::shared_ptr<IDataSeries>)
67 SCIQLOP_REGISTER_META_TYPE(IDATASERIES_PTR_REGISTRY, std::shared_ptr<IDataSeries>)
68
68
69 #endif // SCIQLOP_IDATASERIES_H
69 #endif // SCIQLOP_IDATASERIES_H
@@ -1,44 +1,43
1 #ifndef SCIQLOP_SQPDATETIME_H
1 #ifndef SCIQLOP_SQPDATETIME_H
2 #define SCIQLOP_SQPDATETIME_H
2 #define SCIQLOP_SQPDATETIME_H
3
3
4 #include <QObject>
4 #include <QObject>
5
5
6 #include <QDateTime>
7 #include <QDebug>
6 #include <QDebug>
8
7
8 #include <Common/DateUtils.h>
9 #include <Common/MetaTypes.h>
9 #include <Common/MetaTypes.h>
10
10
11 /**
11 /**
12 * @brief The SqpDateTime struct holds the information of time parameters
12 * @brief The SqpDateTime struct holds the information of time parameters
13 */
13 */
14 struct SqpDateTime {
14 struct SqpDateTime {
15 /// Start time
15 /// Start time (UTC)
16 double m_TStart;
16 double m_TStart;
17 /// End time
17 /// End time (UTC)
18 double m_TEnd;
18 double m_TEnd;
19
19
20 bool contains(const SqpDateTime &dateTime) const noexcept
20 bool contains(const SqpDateTime &dateTime) const noexcept
21 {
21 {
22 return (m_TStart <= dateTime.m_TStart && m_TEnd >= dateTime.m_TEnd);
22 return (m_TStart <= dateTime.m_TStart && m_TEnd >= dateTime.m_TEnd);
23 }
23 }
24
24
25 bool intersect(const SqpDateTime &dateTime) const noexcept
25 bool intersect(const SqpDateTime &dateTime) const noexcept
26 {
26 {
27 return (m_TEnd >= dateTime.m_TStart && m_TStart <= dateTime.m_TEnd);
27 return (m_TEnd >= dateTime.m_TStart && m_TStart <= dateTime.m_TEnd);
28 }
28 }
29 };
29 };
30
30
31 inline QDebug operator<<(QDebug d, SqpDateTime obj)
31 inline QDebug operator<<(QDebug d, SqpDateTime obj)
32 {
32 {
33 auto tendDateTimeStart = QDateTime::fromMSecsSinceEpoch(obj.m_TStart * 1000);
33 auto tendDateTimeStart = DateUtils::dateTime(obj.m_TStart);
34 auto tendDateTimeEnd = QDateTime::fromMSecsSinceEpoch(obj.m_TEnd * 1000);
34 auto tendDateTimeEnd = DateUtils::dateTime(obj.m_TEnd);
35
35
36 // QDebug << "ts: " << tendDateTimeStart << " te: " << tendDateTimeEnd;
37 d << "ts: " << tendDateTimeStart << " te: " << tendDateTimeEnd;
36 d << "ts: " << tendDateTimeStart << " te: " << tendDateTimeEnd;
38 return d;
37 return d;
39 }
38 }
40
39
41 // Required for using shared_ptr in signals/slots
40 // Required for using shared_ptr in signals/slots
42 SCIQLOP_REGISTER_META_TYPE(SQPDATETIME_REGISTRY, SqpDateTime)
41 SCIQLOP_REGISTER_META_TYPE(SQPDATETIME_REGISTRY, SqpDateTime)
43
42
44 #endif // SCIQLOP_SQPDATETIME_H
43 #endif // SCIQLOP_SQPDATETIME_H
@@ -1,244 +1,243
1 #include <Variable/Variable.h>
1 #include <Variable/Variable.h>
2 #include <Variable/VariableCacheController.h>
2 #include <Variable/VariableCacheController.h>
3 #include <Variable/VariableController.h>
3 #include <Variable/VariableController.h>
4 #include <Variable/VariableModel.h>
4 #include <Variable/VariableModel.h>
5
5
6 #include <Data/DataProviderParameters.h>
6 #include <Data/DataProviderParameters.h>
7 #include <Data/IDataProvider.h>
7 #include <Data/IDataProvider.h>
8 #include <Data/IDataSeries.h>
8 #include <Data/IDataSeries.h>
9 #include <Time/TimeController.h>
9 #include <Time/TimeController.h>
10
10
11 #include <QDateTime>
12 #include <QMutex>
11 #include <QMutex>
13 #include <QThread>
12 #include <QThread>
14 #include <QUuid>
13 #include <QUuid>
15 #include <QtCore/QItemSelectionModel>
14 #include <QtCore/QItemSelectionModel>
16
15
17 #include <unordered_map>
16 #include <unordered_map>
18
17
19 Q_LOGGING_CATEGORY(LOG_VariableController, "VariableController")
18 Q_LOGGING_CATEGORY(LOG_VariableController, "VariableController")
20
19
21 struct VariableController::VariableControllerPrivate {
20 struct VariableController::VariableControllerPrivate {
22 explicit VariableControllerPrivate(VariableController *parent)
21 explicit VariableControllerPrivate(VariableController *parent)
23 : m_WorkingMutex{},
22 : m_WorkingMutex{},
24 m_VariableModel{new VariableModel{parent}},
23 m_VariableModel{new VariableModel{parent}},
25 m_VariableSelectionModel{new QItemSelectionModel{m_VariableModel, parent}},
24 m_VariableSelectionModel{new QItemSelectionModel{m_VariableModel, parent}},
26 m_VariableCacheController{std::make_unique<VariableCacheController>()}
25 m_VariableCacheController{std::make_unique<VariableCacheController>()}
27 {
26 {
28 }
27 }
29
28
30 QMutex m_WorkingMutex;
29 QMutex m_WorkingMutex;
31 /// Variable model. The VariableController has the ownership
30 /// Variable model. The VariableController has the ownership
32 VariableModel *m_VariableModel;
31 VariableModel *m_VariableModel;
33 QItemSelectionModel *m_VariableSelectionModel;
32 QItemSelectionModel *m_VariableSelectionModel;
34
33
35
34
36 TimeController *m_TimeController{nullptr};
35 TimeController *m_TimeController{nullptr};
37 std::unique_ptr<VariableCacheController> m_VariableCacheController;
36 std::unique_ptr<VariableCacheController> m_VariableCacheController;
38
37
39 std::unordered_map<std::shared_ptr<Variable>, std::shared_ptr<IDataProvider> >
38 std::unordered_map<std::shared_ptr<Variable>, std::shared_ptr<IDataProvider> >
40 m_VariableToProviderMap;
39 m_VariableToProviderMap;
41 std::unordered_map<std::shared_ptr<Variable>, QUuid> m_VariableToIdentifierMap;
40 std::unordered_map<std::shared_ptr<Variable>, QUuid> m_VariableToIdentifierMap;
42 };
41 };
43
42
44 VariableController::VariableController(QObject *parent)
43 VariableController::VariableController(QObject *parent)
45 : QObject{parent}, impl{spimpl::make_unique_impl<VariableControllerPrivate>(this)}
44 : QObject{parent}, impl{spimpl::make_unique_impl<VariableControllerPrivate>(this)}
46 {
45 {
47 qCDebug(LOG_VariableController()) << tr("VariableController construction")
46 qCDebug(LOG_VariableController()) << tr("VariableController construction")
48 << QThread::currentThread();
47 << QThread::currentThread();
49
48
50 connect(impl->m_VariableModel, &VariableModel::abortProgessRequested, this,
49 connect(impl->m_VariableModel, &VariableModel::abortProgessRequested, this,
51 &VariableController::onAbortProgressRequested);
50 &VariableController::onAbortProgressRequested);
52 }
51 }
53
52
54 VariableController::~VariableController()
53 VariableController::~VariableController()
55 {
54 {
56 qCDebug(LOG_VariableController()) << tr("VariableController destruction")
55 qCDebug(LOG_VariableController()) << tr("VariableController destruction")
57 << QThread::currentThread();
56 << QThread::currentThread();
58 this->waitForFinish();
57 this->waitForFinish();
59 }
58 }
60
59
61 VariableModel *VariableController::variableModel() noexcept
60 VariableModel *VariableController::variableModel() noexcept
62 {
61 {
63 return impl->m_VariableModel;
62 return impl->m_VariableModel;
64 }
63 }
65
64
66 QItemSelectionModel *VariableController::variableSelectionModel() noexcept
65 QItemSelectionModel *VariableController::variableSelectionModel() noexcept
67 {
66 {
68 return impl->m_VariableSelectionModel;
67 return impl->m_VariableSelectionModel;
69 }
68 }
70
69
71 void VariableController::setTimeController(TimeController *timeController) noexcept
70 void VariableController::setTimeController(TimeController *timeController) noexcept
72 {
71 {
73 impl->m_TimeController = timeController;
72 impl->m_TimeController = timeController;
74 }
73 }
75
74
76 void VariableController::deleteVariable(std::shared_ptr<Variable> variable) noexcept
75 void VariableController::deleteVariable(std::shared_ptr<Variable> variable) noexcept
77 {
76 {
78 if (!variable) {
77 if (!variable) {
79 qCCritical(LOG_VariableController()) << "Can't delete variable: variable is null";
78 qCCritical(LOG_VariableController()) << "Can't delete variable: variable is null";
80 return;
79 return;
81 }
80 }
82
81
83 // Spreads in SciQlop that the variable will be deleted, so that potential receivers can
82 // Spreads in SciQlop that the variable will be deleted, so that potential receivers can
84 // make some treatments before the deletion
83 // make some treatments before the deletion
85 emit variableAboutToBeDeleted(variable);
84 emit variableAboutToBeDeleted(variable);
86
85
87 // Deletes identifier
86 // Deletes identifier
88 impl->m_VariableToIdentifierMap.erase(variable);
87 impl->m_VariableToIdentifierMap.erase(variable);
89
88
90 // Deletes provider
89 // Deletes provider
91 auto nbProvidersDeleted = impl->m_VariableToProviderMap.erase(variable);
90 auto nbProvidersDeleted = impl->m_VariableToProviderMap.erase(variable);
92 qCDebug(LOG_VariableController())
91 qCDebug(LOG_VariableController())
93 << tr("Number of providers deleted for variable %1: %2")
92 << tr("Number of providers deleted for variable %1: %2")
94 .arg(variable->name(), QString::number(nbProvidersDeleted));
93 .arg(variable->name(), QString::number(nbProvidersDeleted));
95
94
96 // Clears cache
95 // Clears cache
97 impl->m_VariableCacheController->clear(variable);
96 impl->m_VariableCacheController->clear(variable);
98
97
99 // Deletes from model
98 // Deletes from model
100 impl->m_VariableModel->deleteVariable(variable);
99 impl->m_VariableModel->deleteVariable(variable);
101 }
100 }
102
101
103 void VariableController::deleteVariables(
102 void VariableController::deleteVariables(
104 const QVector<std::shared_ptr<Variable> > &variables) noexcept
103 const QVector<std::shared_ptr<Variable> > &variables) noexcept
105 {
104 {
106 for (auto variable : qAsConst(variables)) {
105 for (auto variable : qAsConst(variables)) {
107 deleteVariable(variable);
106 deleteVariable(variable);
108 }
107 }
109 }
108 }
110
109
111 void VariableController::abortProgress(std::shared_ptr<Variable> variable)
110 void VariableController::abortProgress(std::shared_ptr<Variable> variable)
112 {
111 {
113 }
112 }
114
113
115 void VariableController::createVariable(const QString &name, const QVariantHash &metadata,
114 void VariableController::createVariable(const QString &name, const QVariantHash &metadata,
116 std::shared_ptr<IDataProvider> provider) noexcept
115 std::shared_ptr<IDataProvider> provider) noexcept
117 {
116 {
118
117
119 if (!impl->m_TimeController) {
118 if (!impl->m_TimeController) {
120 qCCritical(LOG_VariableController())
119 qCCritical(LOG_VariableController())
121 << tr("Impossible to create variable: The time controller is null");
120 << tr("Impossible to create variable: The time controller is null");
122 return;
121 return;
123 }
122 }
124
123
125 auto dateTime = impl->m_TimeController->dateTime();
124 auto dateTime = impl->m_TimeController->dateTime();
126
125
127 if (auto newVariable = impl->m_VariableModel->createVariable(name, dateTime, metadata)) {
126 if (auto newVariable = impl->m_VariableModel->createVariable(name, dateTime, metadata)) {
128 auto identifier = QUuid::createUuid();
127 auto identifier = QUuid::createUuid();
129
128
130 // store the provider
129 // store the provider
131 impl->m_VariableToProviderMap[newVariable] = provider;
130 impl->m_VariableToProviderMap[newVariable] = provider;
132 impl->m_VariableToIdentifierMap[newVariable] = identifier;
131 impl->m_VariableToIdentifierMap[newVariable] = identifier;
133
132
134 auto addDateTimeAcquired = [ this, varW = std::weak_ptr<Variable>{newVariable} ](
133 auto addDateTimeAcquired = [ this, varW = std::weak_ptr<Variable>{newVariable} ](
135 QUuid identifier, auto dataSeriesAcquired, auto dateTimeToPutInCache)
134 QUuid identifier, auto dataSeriesAcquired, auto dateTimeToPutInCache)
136 {
135 {
137 if (auto variable = varW.lock()) {
136 if (auto variable = varW.lock()) {
138 auto varIdentifier = impl->m_VariableToIdentifierMap.at(variable);
137 auto varIdentifier = impl->m_VariableToIdentifierMap.at(variable);
139 if (varIdentifier == identifier) {
138 if (varIdentifier == identifier) {
140 impl->m_VariableCacheController->addDateTime(variable, dateTimeToPutInCache);
139 impl->m_VariableCacheController->addDateTime(variable, dateTimeToPutInCache);
141 variable->setDataSeries(dataSeriesAcquired);
140 variable->setDataSeries(dataSeriesAcquired);
142 emit variable->updated();
141 emit variable->updated();
143 }
142 }
144 }
143 }
145 };
144 };
146
145
147 connect(provider.get(), &IDataProvider::dataProvided, addDateTimeAcquired);
146 connect(provider.get(), &IDataProvider::dataProvided, addDateTimeAcquired);
148 connect(provider.get(), &IDataProvider::dataProvidedProgress, this,
147 connect(provider.get(), &IDataProvider::dataProvidedProgress, this,
149 &VariableController::onVariableRetrieveDataInProgress);
148 &VariableController::onVariableRetrieveDataInProgress);
150 this->onRequestDataLoading(newVariable, dateTime);
149 this->onRequestDataLoading(newVariable, dateTime);
151 }
150 }
152 }
151 }
153
152
154 void VariableController::onDateTimeOnSelection(const SqpDateTime &dateTime)
153 void VariableController::onDateTimeOnSelection(const SqpDateTime &dateTime)
155 {
154 {
156 qCDebug(LOG_VariableController()) << "VariableController::onDateTimeOnSelection"
155 qCDebug(LOG_VariableController()) << "VariableController::onDateTimeOnSelection"
157 << QThread::currentThread()->objectName();
156 << QThread::currentThread()->objectName();
158 auto selectedRows = impl->m_VariableSelectionModel->selectedRows();
157 auto selectedRows = impl->m_VariableSelectionModel->selectedRows();
159
158
160 for (const auto &selectedRow : qAsConst(selectedRows)) {
159 for (const auto &selectedRow : qAsConst(selectedRows)) {
161 if (auto selectedVariable = impl->m_VariableModel->variable(selectedRow.row())) {
160 if (auto selectedVariable = impl->m_VariableModel->variable(selectedRow.row())) {
162 selectedVariable->setDateTime(dateTime);
161 selectedVariable->setDateTime(dateTime);
163 this->onRequestDataLoading(selectedVariable, dateTime);
162 this->onRequestDataLoading(selectedVariable, dateTime);
164
163
165 // notify that rescale operation has to be done
164 // notify that rescale operation has to be done
166 emit rangeChanged(selectedVariable, dateTime);
165 emit rangeChanged(selectedVariable, dateTime);
167 }
166 }
168 }
167 }
169 }
168 }
170
169
171 void VariableController::onVariableRetrieveDataInProgress(QUuid identifier, double progress)
170 void VariableController::onVariableRetrieveDataInProgress(QUuid identifier, double progress)
172 {
171 {
173 auto findReply = [identifier](const auto &entry) { return identifier == entry.second; };
172 auto findReply = [identifier](const auto &entry) { return identifier == entry.second; };
174
173
175 auto end = impl->m_VariableToIdentifierMap.cend();
174 auto end = impl->m_VariableToIdentifierMap.cend();
176 auto it = std::find_if(impl->m_VariableToIdentifierMap.cbegin(), end, findReply);
175 auto it = std::find_if(impl->m_VariableToIdentifierMap.cbegin(), end, findReply);
177 if (it != end) {
176 if (it != end) {
178 impl->m_VariableModel->setDataProgress(it->first, progress);
177 impl->m_VariableModel->setDataProgress(it->first, progress);
179 }
178 }
180 }
179 }
181
180
182 void VariableController::onAbortProgressRequested(std::shared_ptr<Variable> variable)
181 void VariableController::onAbortProgressRequested(std::shared_ptr<Variable> variable)
183 {
182 {
184 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAbortProgressRequested"
183 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAbortProgressRequested"
185 << QThread::currentThread()->objectName();
184 << QThread::currentThread()->objectName();
186
185
187 auto it = impl->m_VariableToIdentifierMap.find(variable);
186 auto it = impl->m_VariableToIdentifierMap.find(variable);
188 if (it != impl->m_VariableToIdentifierMap.cend()) {
187 if (it != impl->m_VariableToIdentifierMap.cend()) {
189 impl->m_VariableToProviderMap.at(variable)->requestDataAborting(it->second);
188 impl->m_VariableToProviderMap.at(variable)->requestDataAborting(it->second);
190 }
189 }
191 else {
190 else {
192 qCWarning(LOG_VariableController())
191 qCWarning(LOG_VariableController())
193 << tr("Aborting progression of inexistant variable detected !!!")
192 << tr("Aborting progression of inexistant variable detected !!!")
194 << QThread::currentThread()->objectName();
193 << QThread::currentThread()->objectName();
195 }
194 }
196 }
195 }
197
196
198
197
199 void VariableController::onRequestDataLoading(std::shared_ptr<Variable> variable,
198 void VariableController::onRequestDataLoading(std::shared_ptr<Variable> variable,
200 const SqpDateTime &dateTime)
199 const SqpDateTime &dateTime)
201 {
200 {
202 qCDebug(LOG_VariableController()) << "VariableController::onRequestDataLoading"
201 qCDebug(LOG_VariableController()) << "VariableController::onRequestDataLoading"
203 << QThread::currentThread()->objectName();
202 << QThread::currentThread()->objectName();
204 // we want to load data of the variable for the dateTime.
203 // we want to load data of the variable for the dateTime.
205 // First we check if the cache contains some of them.
204 // First we check if the cache contains some of them.
206 // For the other, we ask the provider to give them.
205 // For the other, we ask the provider to give them.
207 if (variable) {
206 if (variable) {
208
207
209 auto dateTimeListNotInCache
208 auto dateTimeListNotInCache
210 = impl->m_VariableCacheController->provideNotInCacheDateTimeList(variable, dateTime);
209 = impl->m_VariableCacheController->provideNotInCacheDateTimeList(variable, dateTime);
211
210
212 if (!dateTimeListNotInCache.empty()) {
211 if (!dateTimeListNotInCache.empty()) {
213 // Ask the provider for each data on the dateTimeListNotInCache
212 // Ask the provider for each data on the dateTimeListNotInCache
214 auto identifier = impl->m_VariableToIdentifierMap.at(variable);
213 auto identifier = impl->m_VariableToIdentifierMap.at(variable);
215 impl->m_VariableToProviderMap.at(variable)->requestDataLoading(
214 impl->m_VariableToProviderMap.at(variable)->requestDataLoading(
216 identifier,
215 identifier,
217 DataProviderParameters{std::move(dateTimeListNotInCache), variable->metadata()});
216 DataProviderParameters{std::move(dateTimeListNotInCache), variable->metadata()});
218 }
217 }
219 else {
218 else {
220 emit variable->updated();
219 emit variable->updated();
221 }
220 }
222 }
221 }
223 else {
222 else {
224 qCCritical(LOG_VariableController()) << tr("Impossible to load data of a variable null");
223 qCCritical(LOG_VariableController()) << tr("Impossible to load data of a variable null");
225 }
224 }
226 }
225 }
227
226
228
227
229 void VariableController::initialize()
228 void VariableController::initialize()
230 {
229 {
231 qCDebug(LOG_VariableController()) << tr("VariableController init") << QThread::currentThread();
230 qCDebug(LOG_VariableController()) << tr("VariableController init") << QThread::currentThread();
232 impl->m_WorkingMutex.lock();
231 impl->m_WorkingMutex.lock();
233 qCDebug(LOG_VariableController()) << tr("VariableController init END");
232 qCDebug(LOG_VariableController()) << tr("VariableController init END");
234 }
233 }
235
234
236 void VariableController::finalize()
235 void VariableController::finalize()
237 {
236 {
238 impl->m_WorkingMutex.unlock();
237 impl->m_WorkingMutex.unlock();
239 }
238 }
240
239
241 void VariableController::waitForFinish()
240 void VariableController::waitForFinish()
242 {
241 {
243 QMutexLocker locker{&impl->m_WorkingMutex};
242 QMutexLocker locker{&impl->m_WorkingMutex};
244 }
243 }
@@ -1,248 +1,249
1 #include <Variable/Variable.h>
1 #include <Variable/Variable.h>
2 #include <Variable/VariableModel.h>
2 #include <Variable/VariableModel.h>
3
3
4 #include <Common/DateUtils.h>
5
4 #include <Data/IDataSeries.h>
6 #include <Data/IDataSeries.h>
5
7
6 #include <QDateTime>
7 #include <QSize>
8 #include <QSize>
8 #include <unordered_map>
9 #include <unordered_map>
9
10
10 Q_LOGGING_CATEGORY(LOG_VariableModel, "VariableModel")
11 Q_LOGGING_CATEGORY(LOG_VariableModel, "VariableModel")
11
12
12 namespace {
13 namespace {
13
14
14 // Column indexes
15 // Column indexes
15 const auto NAME_COLUMN = 0;
16 const auto NAME_COLUMN = 0;
16 const auto TSTART_COLUMN = 1;
17 const auto TSTART_COLUMN = 1;
17 const auto TEND_COLUMN = 2;
18 const auto TEND_COLUMN = 2;
18 const auto NB_COLUMNS = 3;
19 const auto NB_COLUMNS = 3;
19
20
20 // Column properties
21 // Column properties
21 const auto DEFAULT_HEIGHT = 25;
22 const auto DEFAULT_HEIGHT = 25;
22 const auto DEFAULT_WIDTH = 100;
23 const auto DEFAULT_WIDTH = 100;
23
24
24 struct ColumnProperties {
25 struct ColumnProperties {
25 ColumnProperties(const QString &name = {}, int width = DEFAULT_WIDTH,
26 ColumnProperties(const QString &name = {}, int width = DEFAULT_WIDTH,
26 int height = DEFAULT_HEIGHT)
27 int height = DEFAULT_HEIGHT)
27 : m_Name{name}, m_Width{width}, m_Height{height}
28 : m_Name{name}, m_Width{width}, m_Height{height}
28 {
29 {
29 }
30 }
30
31
31 QString m_Name;
32 QString m_Name;
32 int m_Width;
33 int m_Width;
33 int m_Height;
34 int m_Height;
34 };
35 };
35
36
36 const auto COLUMN_PROPERTIES
37 const auto COLUMN_PROPERTIES
37 = QHash<int, ColumnProperties>{{NAME_COLUMN, {QObject::tr("Name")}},
38 = QHash<int, ColumnProperties>{{NAME_COLUMN, {QObject::tr("Name")}},
38 {TSTART_COLUMN, {QObject::tr("tStart"), 180}},
39 {TSTART_COLUMN, {QObject::tr("tStart"), 180}},
39 {TEND_COLUMN, {QObject::tr("tEnd"), 180}}};
40 {TEND_COLUMN, {QObject::tr("tEnd"), 180}}};
40
41
41 /// Format for datetimes
42 /// Format for datetimes
42 const auto DATETIME_FORMAT = QStringLiteral("dd/MM/yyyy \nhh:mm:ss:zzz");
43 const auto DATETIME_FORMAT = QStringLiteral("dd/MM/yyyy \nhh:mm:ss:zzz");
43
44
44
45
45 } // namespace
46 } // namespace
46
47
47 struct VariableModel::VariableModelPrivate {
48 struct VariableModel::VariableModelPrivate {
48 /// Variables created in SciQlop
49 /// Variables created in SciQlop
49 std::vector<std::shared_ptr<Variable> > m_Variables;
50 std::vector<std::shared_ptr<Variable> > m_Variables;
50 std::unordered_map<std::shared_ptr<Variable>, double> m_VariableToProgress;
51 std::unordered_map<std::shared_ptr<Variable>, double> m_VariableToProgress;
51
52
52 /// Return the row index of the variable. -1 if it's not found
53 /// Return the row index of the variable. -1 if it's not found
53 int indexOfVariable(Variable *variable) const noexcept;
54 int indexOfVariable(Variable *variable) const noexcept;
54 };
55 };
55
56
56 VariableModel::VariableModel(QObject *parent)
57 VariableModel::VariableModel(QObject *parent)
57 : QAbstractTableModel{parent}, impl{spimpl::make_unique_impl<VariableModelPrivate>()}
58 : QAbstractTableModel{parent}, impl{spimpl::make_unique_impl<VariableModelPrivate>()}
58 {
59 {
59 }
60 }
60
61
61 std::shared_ptr<Variable> VariableModel::createVariable(const QString &name,
62 std::shared_ptr<Variable> VariableModel::createVariable(const QString &name,
62 const SqpDateTime &dateTime,
63 const SqpDateTime &dateTime,
63 const QVariantHash &metadata) noexcept
64 const QVariantHash &metadata) noexcept
64 {
65 {
65 auto insertIndex = rowCount();
66 auto insertIndex = rowCount();
66 beginInsertRows({}, insertIndex, insertIndex);
67 beginInsertRows({}, insertIndex, insertIndex);
67
68
68 auto variable = std::make_shared<Variable>(name, dateTime, metadata);
69 auto variable = std::make_shared<Variable>(name, dateTime, metadata);
69
70
70 impl->m_Variables.push_back(variable);
71 impl->m_Variables.push_back(variable);
71 connect(variable.get(), &Variable::updated, this, &VariableModel::onVariableUpdated);
72 connect(variable.get(), &Variable::updated, this, &VariableModel::onVariableUpdated);
72
73
73 endInsertRows();
74 endInsertRows();
74
75
75 return variable;
76 return variable;
76 }
77 }
77
78
78 void VariableModel::deleteVariable(std::shared_ptr<Variable> variable) noexcept
79 void VariableModel::deleteVariable(std::shared_ptr<Variable> variable) noexcept
79 {
80 {
80 if (!variable) {
81 if (!variable) {
81 qCCritical(LOG_Variable()) << "Can't delete a null variable from the model";
82 qCCritical(LOG_Variable()) << "Can't delete a null variable from the model";
82 return;
83 return;
83 }
84 }
84
85
85 // Finds variable in the model
86 // Finds variable in the model
86 auto begin = impl->m_Variables.cbegin();
87 auto begin = impl->m_Variables.cbegin();
87 auto end = impl->m_Variables.cend();
88 auto end = impl->m_Variables.cend();
88 auto it = std::find(begin, end, variable);
89 auto it = std::find(begin, end, variable);
89 if (it != end) {
90 if (it != end) {
90 auto removeIndex = std::distance(begin, it);
91 auto removeIndex = std::distance(begin, it);
91
92
92 // Deletes variable
93 // Deletes variable
93 beginRemoveRows({}, removeIndex, removeIndex);
94 beginRemoveRows({}, removeIndex, removeIndex);
94 impl->m_Variables.erase(it);
95 impl->m_Variables.erase(it);
95 endRemoveRows();
96 endRemoveRows();
96 }
97 }
97 else {
98 else {
98 qCritical(LOG_VariableModel())
99 qCritical(LOG_VariableModel())
99 << tr("Can't delete variable %1 from the model: the variable is not in the model")
100 << tr("Can't delete variable %1 from the model: the variable is not in the model")
100 .arg(variable->name());
101 .arg(variable->name());
101 }
102 }
102
103
103 // Removes variable from progress map
104 // Removes variable from progress map
104 impl->m_VariableToProgress.erase(variable);
105 impl->m_VariableToProgress.erase(variable);
105 }
106 }
106
107
107
108
108 std::shared_ptr<Variable> VariableModel::variable(int index) const
109 std::shared_ptr<Variable> VariableModel::variable(int index) const
109 {
110 {
110 return (index >= 0 && index < impl->m_Variables.size()) ? impl->m_Variables[index] : nullptr;
111 return (index >= 0 && index < impl->m_Variables.size()) ? impl->m_Variables[index] : nullptr;
111 }
112 }
112
113
113 void VariableModel::setDataProgress(std::shared_ptr<Variable> variable, double progress)
114 void VariableModel::setDataProgress(std::shared_ptr<Variable> variable, double progress)
114 {
115 {
115 if (progress > 0.0) {
116 if (progress > 0.0) {
116 impl->m_VariableToProgress[variable] = progress;
117 impl->m_VariableToProgress[variable] = progress;
117 }
118 }
118 else {
119 else {
119 impl->m_VariableToProgress.erase(variable);
120 impl->m_VariableToProgress.erase(variable);
120 }
121 }
121 auto modelIndex = createIndex(impl->indexOfVariable(variable.get()), NAME_COLUMN);
122 auto modelIndex = createIndex(impl->indexOfVariable(variable.get()), NAME_COLUMN);
122
123
123 emit dataChanged(modelIndex, modelIndex);
124 emit dataChanged(modelIndex, modelIndex);
124 }
125 }
125
126
126 int VariableModel::columnCount(const QModelIndex &parent) const
127 int VariableModel::columnCount(const QModelIndex &parent) const
127 {
128 {
128 Q_UNUSED(parent);
129 Q_UNUSED(parent);
129
130
130 return NB_COLUMNS;
131 return NB_COLUMNS;
131 }
132 }
132
133
133 int VariableModel::rowCount(const QModelIndex &parent) const
134 int VariableModel::rowCount(const QModelIndex &parent) const
134 {
135 {
135 Q_UNUSED(parent);
136 Q_UNUSED(parent);
136
137
137 return impl->m_Variables.size();
138 return impl->m_Variables.size();
138 }
139 }
139
140
140 QVariant VariableModel::data(const QModelIndex &index, int role) const
141 QVariant VariableModel::data(const QModelIndex &index, int role) const
141 {
142 {
142 if (!index.isValid()) {
143 if (!index.isValid()) {
143 return QVariant{};
144 return QVariant{};
144 }
145 }
145
146
146 if (index.row() < 0 || index.row() >= rowCount()) {
147 if (index.row() < 0 || index.row() >= rowCount()) {
147 return QVariant{};
148 return QVariant{};
148 }
149 }
149
150
150 if (role == Qt::DisplayRole) {
151 if (role == Qt::DisplayRole) {
151 if (auto variable = impl->m_Variables.at(index.row()).get()) {
152 if (auto variable = impl->m_Variables.at(index.row()).get()) {
152 /// Lambda function that builds the variant to return for a time value
153 /// Lambda function that builds the variant to return for a time value
153 auto dateTimeVariant = [](double time) {
154 auto dateTimeVariant = [](double secs) {
154 auto dateTime = QDateTime::fromMSecsSinceEpoch(time * 1000.);
155 auto dateTime = DateUtils::dateTime(secs);
155 return dateTime.toString(DATETIME_FORMAT);
156 return dateTime.toString(DATETIME_FORMAT);
156 };
157 };
157
158
158 switch (index.column()) {
159 switch (index.column()) {
159 case NAME_COLUMN:
160 case NAME_COLUMN:
160 return variable->name();
161 return variable->name();
161 case TSTART_COLUMN:
162 case TSTART_COLUMN:
162 return dateTimeVariant(variable->dateTime().m_TStart);
163 return dateTimeVariant(variable->dateTime().m_TStart);
163 case TEND_COLUMN:
164 case TEND_COLUMN:
164 return dateTimeVariant(variable->dateTime().m_TEnd);
165 return dateTimeVariant(variable->dateTime().m_TEnd);
165 default:
166 default:
166 // No action
167 // No action
167 break;
168 break;
168 }
169 }
169
170
170 qWarning(LOG_VariableModel())
171 qWarning(LOG_VariableModel())
171 << tr("Can't get data (unknown column %1)").arg(index.column());
172 << tr("Can't get data (unknown column %1)").arg(index.column());
172 }
173 }
173 else {
174 else {
174 qWarning(LOG_VariableModel()) << tr("Can't get data (no variable)");
175 qWarning(LOG_VariableModel()) << tr("Can't get data (no variable)");
175 }
176 }
176 }
177 }
177 else if (role == VariableRoles::ProgressRole) {
178 else if (role == VariableRoles::ProgressRole) {
178 if (auto variable = impl->m_Variables.at(index.row())) {
179 if (auto variable = impl->m_Variables.at(index.row())) {
179
180
180 auto it = impl->m_VariableToProgress.find(variable);
181 auto it = impl->m_VariableToProgress.find(variable);
181 if (it != impl->m_VariableToProgress.cend()) {
182 if (it != impl->m_VariableToProgress.cend()) {
182 return it->second;
183 return it->second;
183 }
184 }
184 }
185 }
185 }
186 }
186
187
187 return QVariant{};
188 return QVariant{};
188 }
189 }
189
190
190 QVariant VariableModel::headerData(int section, Qt::Orientation orientation, int role) const
191 QVariant VariableModel::headerData(int section, Qt::Orientation orientation, int role) const
191 {
192 {
192 if (role != Qt::DisplayRole && role != Qt::SizeHintRole) {
193 if (role != Qt::DisplayRole && role != Qt::SizeHintRole) {
193 return QVariant{};
194 return QVariant{};
194 }
195 }
195
196
196 if (orientation == Qt::Horizontal) {
197 if (orientation == Qt::Horizontal) {
197 auto propertiesIt = COLUMN_PROPERTIES.find(section);
198 auto propertiesIt = COLUMN_PROPERTIES.find(section);
198 if (propertiesIt != COLUMN_PROPERTIES.cend()) {
199 if (propertiesIt != COLUMN_PROPERTIES.cend()) {
199 // Role is either DisplayRole or SizeHintRole
200 // Role is either DisplayRole or SizeHintRole
200 return (role == Qt::DisplayRole)
201 return (role == Qt::DisplayRole)
201 ? QVariant{propertiesIt->m_Name}
202 ? QVariant{propertiesIt->m_Name}
202 : QVariant{QSize{propertiesIt->m_Width, propertiesIt->m_Height}};
203 : QVariant{QSize{propertiesIt->m_Width, propertiesIt->m_Height}};
203 }
204 }
204 else {
205 else {
205 qWarning(LOG_VariableModel())
206 qWarning(LOG_VariableModel())
206 << tr("Can't get header data (unknown column %1)").arg(section);
207 << tr("Can't get header data (unknown column %1)").arg(section);
207 }
208 }
208 }
209 }
209
210
210 return QVariant{};
211 return QVariant{};
211 }
212 }
212
213
213 void VariableModel::abortProgress(const QModelIndex &index)
214 void VariableModel::abortProgress(const QModelIndex &index)
214 {
215 {
215 if (auto variable = impl->m_Variables.at(index.row())) {
216 if (auto variable = impl->m_Variables.at(index.row())) {
216 emit abortProgessRequested(variable);
217 emit abortProgessRequested(variable);
217 }
218 }
218 }
219 }
219
220
220 void VariableModel::onVariableUpdated() noexcept
221 void VariableModel::onVariableUpdated() noexcept
221 {
222 {
222 // Finds variable that has been updated in the model
223 // Finds variable that has been updated in the model
223 if (auto updatedVariable = dynamic_cast<Variable *>(sender())) {
224 if (auto updatedVariable = dynamic_cast<Variable *>(sender())) {
224 auto updatedVariableIndex = impl->indexOfVariable(updatedVariable);
225 auto updatedVariableIndex = impl->indexOfVariable(updatedVariable);
225
226
226 if (updatedVariableIndex > -1) {
227 if (updatedVariableIndex > -1) {
227 emit dataChanged(createIndex(updatedVariableIndex, 0),
228 emit dataChanged(createIndex(updatedVariableIndex, 0),
228 createIndex(updatedVariableIndex, columnCount() - 1));
229 createIndex(updatedVariableIndex, columnCount() - 1));
229 }
230 }
230 }
231 }
231 }
232 }
232
233
233 int VariableModel::VariableModelPrivate::indexOfVariable(Variable *variable) const noexcept
234 int VariableModel::VariableModelPrivate::indexOfVariable(Variable *variable) const noexcept
234 {
235 {
235 auto begin = std::cbegin(m_Variables);
236 auto begin = std::cbegin(m_Variables);
236 auto end = std::cend(m_Variables);
237 auto end = std::cend(m_Variables);
237 auto it
238 auto it
238 = std::find_if(begin, end, [variable](const auto &var) { return var.get() == variable; });
239 = std::find_if(begin, end, [variable](const auto &var) { return var.get() == variable; });
239
240
240 if (it != end) {
241 if (it != end) {
241 // Gets the index of the variable in the model: we assume here that views have the same
242 // Gets the index of the variable in the model: we assume here that views have the same
242 // order as the model
243 // order as the model
243 return std::distance(begin, it);
244 return std::distance(begin, it);
244 }
245 }
245 else {
246 else {
246 return -1;
247 return -1;
247 }
248 }
248 }
249 }
@@ -1,48 +1,50
1 #include "TimeWidget/TimeWidget.h"
1 #include "TimeWidget/TimeWidget.h"
2 #include "ui_TimeWidget.h"
2 #include "ui_TimeWidget.h"
3
3
4 #include <Common/DateUtils.h>
4 #include <SqpApplication.h>
5 #include <SqpApplication.h>
5 #include <Time/TimeController.h>
6 #include <Time/TimeController.h>
6
7
7 TimeWidget::TimeWidget(QWidget *parent) : QWidget{parent}, ui{new Ui::TimeWidget}
8 TimeWidget::TimeWidget(QWidget *parent) : QWidget{parent}, ui{new Ui::TimeWidget}
8 {
9 {
9 ui->setupUi(this);
10 ui->setupUi(this);
10
11
11 ui->applyToolButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_DialogApplyButton));
12 ui->applyToolButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_DialogApplyButton));
12
13
13 // Connection
14 // Connection
14 connect(ui->startDateTimeEdit, &QDateTimeEdit::dateTimeChanged, this,
15 connect(ui->startDateTimeEdit, &QDateTimeEdit::dateTimeChanged, this,
15 &TimeWidget::onTimeUpdateRequested);
16 &TimeWidget::onTimeUpdateRequested);
16
17
17 connect(ui->endDateTimeEdit, &QDateTimeEdit::dateTimeChanged, this,
18 connect(ui->endDateTimeEdit, &QDateTimeEdit::dateTimeChanged, this,
18 &TimeWidget::onTimeUpdateRequested);
19 &TimeWidget::onTimeUpdateRequested);
19
20
20
21
21 connect(ui->applyToolButton, &QToolButton::clicked, &sqpApp->timeController(),
22 connect(ui->applyToolButton, &QToolButton::clicked, &sqpApp->timeController(),
22 &TimeController::onTimeNotify);
23 &TimeController::onTimeNotify);
23
24
24 // Initialisation
25 // Initialisation
25 ui->startDateTimeEdit->setDateTime(
26 auto endDateTime = QDateTime::currentDateTimeUtc();
26 QDateTime::currentDateTime().addSecs(-3600)); // one hour berefore
27 auto startDateTime = endDateTime.addSecs(-3600); // one hour before
27 ui->endDateTimeEdit->setDateTime(QDateTime::currentDateTime());
28
29 ui->startDateTimeEdit->setDateTime(startDateTime);
30 ui->endDateTimeEdit->setDateTime(endDateTime);
31
32 auto dateTime = SqpDateTime{DateUtils::secondsSinceEpoch(startDateTime),
33 DateUtils::secondsSinceEpoch(endDateTime)};
28
34
29 auto dateTime
30 = SqpDateTime{QDateTime::currentDateTime().addSecs(-3600).toMSecsSinceEpoch() / 1000.0,
31 QDateTime::currentDateTime().toMSecsSinceEpoch() / 1000.0};
32 sqpApp->timeController().onTimeToUpdate(dateTime);
35 sqpApp->timeController().onTimeToUpdate(dateTime);
33 }
36 }
34
37
35
38
36 TimeWidget::~TimeWidget()
39 TimeWidget::~TimeWidget()
37 {
40 {
38 delete ui;
41 delete ui;
39 }
42 }
40
43
41 void TimeWidget::onTimeUpdateRequested()
44 void TimeWidget::onTimeUpdateRequested()
42 {
45 {
43 auto dateTime = SqpDateTime{
46 auto dateTime = SqpDateTime{DateUtils::secondsSinceEpoch(ui->startDateTimeEdit->dateTime()),
44 static_cast<double>(ui->startDateTimeEdit->dateTime().toMSecsSinceEpoch() / 1000.),
47 DateUtils::secondsSinceEpoch(ui->endDateTimeEdit->dateTime())};
45 static_cast<double>(ui->endDateTimeEdit->dateTime().toMSecsSinceEpoch()) / 1000.};
46
48
47 emit timeUpdated(std::move(dateTime));
49 emit timeUpdated(std::move(dateTime));
48 }
50 }
@@ -1,161 +1,162
1 #include "Visualization/VisualizationGraphHelper.h"
1 #include "Visualization/VisualizationGraphHelper.h"
2 #include "Visualization/qcustomplot.h"
2 #include "Visualization/qcustomplot.h"
3
3
4 #include <Data/ScalarSeries.h>
4 #include <Data/ScalarSeries.h>
5
5
6 #include <Variable/Variable.h>
6 #include <Variable/Variable.h>
7
7
8 Q_LOGGING_CATEGORY(LOG_VisualizationGraphHelper, "VisualizationGraphHelper")
8 Q_LOGGING_CATEGORY(LOG_VisualizationGraphHelper, "VisualizationGraphHelper")
9
9
10 namespace {
10 namespace {
11
11
12 class SqpDataContainer : public QCPGraphDataContainer {
12 class SqpDataContainer : public QCPGraphDataContainer {
13 public:
13 public:
14 void appendGraphData(const QCPGraphData &data) { mData.append(data); }
14 void appendGraphData(const QCPGraphData &data) { mData.append(data); }
15 };
15 };
16
16
17
17
18 /// Format for datetimes on a axis
18 /// Format for datetimes on a axis
19 const auto DATETIME_TICKER_FORMAT = QStringLiteral("yyyy/MM/dd \nhh:mm:ss");
19 const auto DATETIME_TICKER_FORMAT = QStringLiteral("yyyy/MM/dd \nhh:mm:ss");
20
20
21 /// Generates the appropriate ticker for an axis, depending on whether the axis displays time or
21 /// Generates the appropriate ticker for an axis, depending on whether the axis displays time or
22 /// non-time data
22 /// non-time data
23 QSharedPointer<QCPAxisTicker> axisTicker(bool isTimeAxis)
23 QSharedPointer<QCPAxisTicker> axisTicker(bool isTimeAxis)
24 {
24 {
25 if (isTimeAxis) {
25 if (isTimeAxis) {
26 auto dateTicker = QSharedPointer<QCPAxisTickerDateTime>::create();
26 auto dateTicker = QSharedPointer<QCPAxisTickerDateTime>::create();
27 dateTicker->setDateTimeFormat(DATETIME_TICKER_FORMAT);
27 dateTicker->setDateTimeFormat(DATETIME_TICKER_FORMAT);
28 dateTicker->setDateTimeSpec(Qt::UTC);
28
29
29 return dateTicker;
30 return dateTicker;
30 }
31 }
31 else {
32 else {
32 // default ticker
33 // default ticker
33 return QSharedPointer<QCPAxisTicker>::create();
34 return QSharedPointer<QCPAxisTicker>::create();
34 }
35 }
35 }
36 }
36
37
37 void updateScalarData(QCPAbstractPlottable *component, ScalarSeries &scalarSeries,
38 void updateScalarData(QCPAbstractPlottable *component, ScalarSeries &scalarSeries,
38 const SqpDateTime &dateTime)
39 const SqpDateTime &dateTime)
39 {
40 {
40 qCDebug(LOG_VisualizationGraphHelper()) << "TORM: updateScalarData"
41 qCDebug(LOG_VisualizationGraphHelper()) << "TORM: updateScalarData"
41 << QThread::currentThread()->objectName();
42 << QThread::currentThread()->objectName();
42 if (auto qcpGraph = dynamic_cast<QCPGraph *>(component)) {
43 if (auto qcpGraph = dynamic_cast<QCPGraph *>(component)) {
43 scalarSeries.lockRead();
44 scalarSeries.lockRead();
44 {
45 {
45 const auto &xData = scalarSeries.xAxisData()->cdata();
46 const auto &xData = scalarSeries.xAxisData()->cdata();
46 const auto &valuesData = scalarSeries.valuesData()->cdata();
47 const auto &valuesData = scalarSeries.valuesData()->cdata();
47
48
48 auto xDataBegin = xData.cbegin();
49 auto xDataBegin = xData.cbegin();
49 auto xDataEnd = xData.cend();
50 auto xDataEnd = xData.cend();
50
51
51 qCInfo(LOG_VisualizationGraphHelper()) << "TORM: Current points in cache"
52 qCInfo(LOG_VisualizationGraphHelper()) << "TORM: Current points in cache"
52 << xData.count();
53 << xData.count();
53
54
54 auto sqpDataContainer = QSharedPointer<SqpDataContainer>::create();
55 auto sqpDataContainer = QSharedPointer<SqpDataContainer>::create();
55 qcpGraph->setData(sqpDataContainer);
56 qcpGraph->setData(sqpDataContainer);
56
57
57 auto lowerIt = std::lower_bound(xDataBegin, xDataEnd, dateTime.m_TStart);
58 auto lowerIt = std::lower_bound(xDataBegin, xDataEnd, dateTime.m_TStart);
58 auto upperIt = std::upper_bound(xDataBegin, xDataEnd, dateTime.m_TEnd);
59 auto upperIt = std::upper_bound(xDataBegin, xDataEnd, dateTime.m_TEnd);
59 auto distance = std::distance(xDataBegin, lowerIt);
60 auto distance = std::distance(xDataBegin, lowerIt);
60
61
61 auto valuesDataIt = valuesData.cbegin() + distance;
62 auto valuesDataIt = valuesData.cbegin() + distance;
62 for (auto xAxisDataIt = lowerIt; xAxisDataIt != upperIt;
63 for (auto xAxisDataIt = lowerIt; xAxisDataIt != upperIt;
63 ++xAxisDataIt, ++valuesDataIt) {
64 ++xAxisDataIt, ++valuesDataIt) {
64 sqpDataContainer->appendGraphData(QCPGraphData(*xAxisDataIt, *valuesDataIt));
65 sqpDataContainer->appendGraphData(QCPGraphData(*xAxisDataIt, *valuesDataIt));
65 }
66 }
66
67
67 qCInfo(LOG_VisualizationGraphHelper()) << "TORM: Current points displayed"
68 qCInfo(LOG_VisualizationGraphHelper()) << "TORM: Current points displayed"
68 << sqpDataContainer->size();
69 << sqpDataContainer->size();
69 }
70 }
70 scalarSeries.unlock();
71 scalarSeries.unlock();
71
72
72
73
73 // Display all data
74 // Display all data
74 component->parentPlot()->replot();
75 component->parentPlot()->replot();
75 }
76 }
76 else {
77 else {
77 /// @todo DEBUG
78 /// @todo DEBUG
78 }
79 }
79 }
80 }
80
81
81 QCPAbstractPlottable *createScalarSeriesComponent(ScalarSeries &scalarSeries, QCustomPlot &plot,
82 QCPAbstractPlottable *createScalarSeriesComponent(ScalarSeries &scalarSeries, QCustomPlot &plot,
82 const SqpDateTime &dateTime)
83 const SqpDateTime &dateTime)
83 {
84 {
84 auto component = plot.addGraph();
85 auto component = plot.addGraph();
85
86
86 if (component) {
87 if (component) {
87 // // Graph data
88 // // Graph data
88 component->setData(scalarSeries.xAxisData()->data(), scalarSeries.valuesData()->data(),
89 component->setData(scalarSeries.xAxisData()->data(), scalarSeries.valuesData()->data(),
89 true);
90 true);
90
91
91 updateScalarData(component, scalarSeries, dateTime);
92 updateScalarData(component, scalarSeries, dateTime);
92
93
93 // Axes properties
94 // Axes properties
94 /// @todo : for the moment, no control is performed on the axes: the units and the tickers
95 /// @todo : for the moment, no control is performed on the axes: the units and the tickers
95 /// are fixed for the default x-axis and y-axis of the plot, and according to the new graph
96 /// are fixed for the default x-axis and y-axis of the plot, and according to the new graph
96
97
97 auto setAxisProperties = [](auto axis, const auto &unit) {
98 auto setAxisProperties = [](auto axis, const auto &unit) {
98 // label (unit name)
99 // label (unit name)
99 axis->setLabel(unit.m_Name);
100 axis->setLabel(unit.m_Name);
100
101
101 // ticker (depending on the type of unit)
102 // ticker (depending on the type of unit)
102 axis->setTicker(axisTicker(unit.m_TimeUnit));
103 axis->setTicker(axisTicker(unit.m_TimeUnit));
103 };
104 };
104 setAxisProperties(plot.xAxis, scalarSeries.xAxisUnit());
105 setAxisProperties(plot.xAxis, scalarSeries.xAxisUnit());
105 setAxisProperties(plot.yAxis, scalarSeries.valuesUnit());
106 setAxisProperties(plot.yAxis, scalarSeries.valuesUnit());
106
107
107 // Display all data
108 // Display all data
108 component->rescaleAxes();
109 component->rescaleAxes();
109 plot.replot();
110 plot.replot();
110 }
111 }
111 else {
112 else {
112 qCDebug(LOG_VisualizationGraphHelper())
113 qCDebug(LOG_VisualizationGraphHelper())
113 << QObject::tr("Can't create graph for the scalar series");
114 << QObject::tr("Can't create graph for the scalar series");
114 }
115 }
115
116
116 return component;
117 return component;
117 }
118 }
118
119
119 } // namespace
120 } // namespace
120
121
121 QVector<QCPAbstractPlottable *> VisualizationGraphHelper::create(std::shared_ptr<Variable> variable,
122 QVector<QCPAbstractPlottable *> VisualizationGraphHelper::create(std::shared_ptr<Variable> variable,
122 QCustomPlot &plot) noexcept
123 QCustomPlot &plot) noexcept
123 {
124 {
124 auto result = QVector<QCPAbstractPlottable *>{};
125 auto result = QVector<QCPAbstractPlottable *>{};
125
126
126 if (variable) {
127 if (variable) {
127 // Gets the data series of the variable to call the creation of the right components
128 // Gets the data series of the variable to call the creation of the right components
128 // according to its type
129 // according to its type
129 if (auto scalarSeries = dynamic_cast<ScalarSeries *>(variable->dataSeries())) {
130 if (auto scalarSeries = dynamic_cast<ScalarSeries *>(variable->dataSeries())) {
130 result.append(createScalarSeriesComponent(*scalarSeries, plot, variable->dateTime()));
131 result.append(createScalarSeriesComponent(*scalarSeries, plot, variable->dateTime()));
131 }
132 }
132 else {
133 else {
133 qCDebug(LOG_VisualizationGraphHelper())
134 qCDebug(LOG_VisualizationGraphHelper())
134 << QObject::tr("Can't create graph plottables : unmanaged data series type");
135 << QObject::tr("Can't create graph plottables : unmanaged data series type");
135 }
136 }
136 }
137 }
137 else {
138 else {
138 qCDebug(LOG_VisualizationGraphHelper())
139 qCDebug(LOG_VisualizationGraphHelper())
139 << QObject::tr("Can't create graph plottables : the variable is null");
140 << QObject::tr("Can't create graph plottables : the variable is null");
140 }
141 }
141
142
142 return result;
143 return result;
143 }
144 }
144
145
145 void VisualizationGraphHelper::updateData(QVector<QCPAbstractPlottable *> plotableVect,
146 void VisualizationGraphHelper::updateData(QVector<QCPAbstractPlottable *> plotableVect,
146 IDataSeries *dataSeries, const SqpDateTime &dateTime)
147 IDataSeries *dataSeries, const SqpDateTime &dateTime)
147 {
148 {
148 if (auto scalarSeries = dynamic_cast<ScalarSeries *>(dataSeries)) {
149 if (auto scalarSeries = dynamic_cast<ScalarSeries *>(dataSeries)) {
149 if (plotableVect.size() == 1) {
150 if (plotableVect.size() == 1) {
150 updateScalarData(plotableVect.at(0), *scalarSeries, dateTime);
151 updateScalarData(plotableVect.at(0), *scalarSeries, dateTime);
151 }
152 }
152 else {
153 else {
153 qCCritical(LOG_VisualizationGraphHelper()) << QObject::tr(
154 qCCritical(LOG_VisualizationGraphHelper()) << QObject::tr(
154 "Can't update Data of a scalarSeries because there is not only one component "
155 "Can't update Data of a scalarSeries because there is not only one component "
155 "associated");
156 "associated");
156 }
157 }
157 }
158 }
158 else {
159 else {
159 /// @todo DEBUG
160 /// @todo DEBUG
160 }
161 }
161 }
162 }
@@ -1,118 +1,123
1 #include "Visualization/VisualizationGraphRenderingDelegate.h"
1 #include "Visualization/VisualizationGraphRenderingDelegate.h"
2 #include "Visualization/qcustomplot.h"
2 #include "Visualization/qcustomplot.h"
3
3
4 #include <Common/DateUtils.h>
5
4 namespace {
6 namespace {
5
7
6 const auto DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd hh:mm:ss:zzz");
8 const auto DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd hh:mm:ss:zzz");
7
9
8 const auto TEXT_TRACER_FORMAT = QStringLiteral("key: %1\nvalue: %2");
10 const auto TEXT_TRACER_FORMAT = QStringLiteral("key: %1\nvalue: %2");
9
11
10 /// Timeout after which a tracer is displayed
12 /// Timeout after which a tracer is displayed
11 const auto TRACER_TIMEOUT = 500;
13 const auto TRACER_TIMEOUT = 500;
12
14
13 /// Formats a data value according to the axis on which it is present
15 /// Formats a data value according to the axis on which it is present
14 QString formatValue(double value, const QCPAxis &axis)
16 QString formatValue(double value, const QCPAxis &axis)
15 {
17 {
16 // If the axis is a time axis, formats the value as a date
18 // If the axis is a time axis, formats the value as a date
17 return qSharedPointerDynamicCast<QCPAxisTickerDateTime>(axis.ticker())
19 if (auto axisTicker = qSharedPointerDynamicCast<QCPAxisTickerDateTime>(axis.ticker())) {
18 ? QCPAxisTickerDateTime::keyToDateTime(value).toString(DATETIME_FORMAT)
20 return DateUtils::dateTime(value, axisTicker->dateTimeSpec()).toString(DATETIME_FORMAT);
19 : QString::number(value);
21 }
22 else {
23 return QString::number(value);
24 }
20 }
25 }
21
26
22 void initPointTracerStyle(QCPItemTracer &tracer) noexcept
27 void initPointTracerStyle(QCPItemTracer &tracer) noexcept
23 {
28 {
24 tracer.setInterpolating(false);
29 tracer.setInterpolating(false);
25 tracer.setStyle(QCPItemTracer::tsPlus);
30 tracer.setStyle(QCPItemTracer::tsPlus);
26 tracer.setPen(QPen(Qt::black));
31 tracer.setPen(QPen(Qt::black));
27 tracer.setBrush(Qt::black);
32 tracer.setBrush(Qt::black);
28 tracer.setSize(10);
33 tracer.setSize(10);
29 }
34 }
30
35
31 void initTextTracerStyle(QCPItemText &tracer) noexcept
36 void initTextTracerStyle(QCPItemText &tracer) noexcept
32 {
37 {
33 tracer.setPen(QPen{Qt::gray});
38 tracer.setPen(QPen{Qt::gray});
34 tracer.setBrush(Qt::white);
39 tracer.setBrush(Qt::white);
35 tracer.setPadding(QMargins{6, 6, 6, 6});
40 tracer.setPadding(QMargins{6, 6, 6, 6});
36 tracer.setPositionAlignment(Qt::AlignTop | Qt::AlignLeft);
41 tracer.setPositionAlignment(Qt::AlignTop | Qt::AlignLeft);
37 tracer.setTextAlignment(Qt::AlignLeft);
42 tracer.setTextAlignment(Qt::AlignLeft);
38 }
43 }
39
44
40 } // namespace
45 } // namespace
41
46
42 struct VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegatePrivate {
47 struct VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegatePrivate {
43 explicit VisualizationGraphRenderingDelegatePrivate(QCustomPlot &plot)
48 explicit VisualizationGraphRenderingDelegatePrivate(QCustomPlot &plot)
44 : m_Plot{plot},
49 : m_Plot{plot},
45 m_PointTracer{new QCPItemTracer{&plot}},
50 m_PointTracer{new QCPItemTracer{&plot}},
46 m_TextTracer{new QCPItemText{&plot}},
51 m_TextTracer{new QCPItemText{&plot}},
47 m_TracerTimer{}
52 m_TracerTimer{}
48 {
53 {
49 initPointTracerStyle(*m_PointTracer);
54 initPointTracerStyle(*m_PointTracer);
50 initTextTracerStyle(*m_TextTracer);
55 initTextTracerStyle(*m_TextTracer);
51
56
52 m_TracerTimer.setInterval(TRACER_TIMEOUT);
57 m_TracerTimer.setInterval(TRACER_TIMEOUT);
53 m_TracerTimer.setSingleShot(true);
58 m_TracerTimer.setSingleShot(true);
54 }
59 }
55
60
56 QCustomPlot &m_Plot;
61 QCustomPlot &m_Plot;
57 QCPItemTracer *m_PointTracer;
62 QCPItemTracer *m_PointTracer;
58 QCPItemText *m_TextTracer;
63 QCPItemText *m_TextTracer;
59 QTimer m_TracerTimer;
64 QTimer m_TracerTimer;
60 };
65 };
61
66
62 VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegate(QCustomPlot &plot)
67 VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegate(QCustomPlot &plot)
63 : impl{spimpl::make_unique_impl<VisualizationGraphRenderingDelegatePrivate>(plot)}
68 : impl{spimpl::make_unique_impl<VisualizationGraphRenderingDelegatePrivate>(plot)}
64 {
69 {
65 }
70 }
66
71
67 void VisualizationGraphRenderingDelegate::onMouseMove(QMouseEvent *event) noexcept
72 void VisualizationGraphRenderingDelegate::onMouseMove(QMouseEvent *event) noexcept
68 {
73 {
69 // Cancels pending refresh
74 // Cancels pending refresh
70 impl->m_TracerTimer.disconnect();
75 impl->m_TracerTimer.disconnect();
71
76
72 auto showTracers = [ eventPos = event->pos(), this ]()
77 auto showTracers = [ eventPos = event->pos(), this ]()
73 {
78 {
74 // Lambda function to display a tracer
79 // Lambda function to display a tracer
75 auto displayTracer = [this](auto &tracer) {
80 auto displayTracer = [this](auto &tracer) {
76 // Tracer is set on top of the plot's main layer
81 // Tracer is set on top of the plot's main layer
77 tracer.setLayer(impl->m_Plot.layer("main"));
82 tracer.setLayer(impl->m_Plot.layer("main"));
78 tracer.setVisible(true);
83 tracer.setVisible(true);
79 impl->m_Plot.replot();
84 impl->m_Plot.replot();
80 };
85 };
81
86
82 // Reinits tracers
87 // Reinits tracers
83 impl->m_PointTracer->setGraph(nullptr);
88 impl->m_PointTracer->setGraph(nullptr);
84 impl->m_PointTracer->setVisible(false);
89 impl->m_PointTracer->setVisible(false);
85 impl->m_TextTracer->setVisible(false);
90 impl->m_TextTracer->setVisible(false);
86 impl->m_Plot.replot();
91 impl->m_Plot.replot();
87
92
88 // Gets the graph under the mouse position
93 // Gets the graph under the mouse position
89 if (auto graph = qobject_cast<QCPGraph *>(impl->m_Plot.plottableAt(eventPos))) {
94 if (auto graph = qobject_cast<QCPGraph *>(impl->m_Plot.plottableAt(eventPos))) {
90 auto mouseKey = graph->keyAxis()->pixelToCoord(eventPos.x());
95 auto mouseKey = graph->keyAxis()->pixelToCoord(eventPos.x());
91 auto graphData = graph->data();
96 auto graphData = graph->data();
92
97
93 // Gets the closest data point to the mouse
98 // Gets the closest data point to the mouse
94 auto graphDataIt = graphData->findBegin(mouseKey);
99 auto graphDataIt = graphData->findBegin(mouseKey);
95 if (graphDataIt != graphData->constEnd()) {
100 if (graphDataIt != graphData->constEnd()) {
96 auto key = formatValue(graphDataIt->key, *graph->keyAxis());
101 auto key = formatValue(graphDataIt->key, *graph->keyAxis());
97 auto value = formatValue(graphDataIt->value, *graph->valueAxis());
102 auto value = formatValue(graphDataIt->value, *graph->valueAxis());
98 impl->m_TextTracer->setText(TEXT_TRACER_FORMAT.arg(key, value));
103 impl->m_TextTracer->setText(TEXT_TRACER_FORMAT.arg(key, value));
99
104
100 // Displays point tracer
105 // Displays point tracer
101 impl->m_PointTracer->setGraph(graph);
106 impl->m_PointTracer->setGraph(graph);
102 impl->m_PointTracer->setGraphKey(mouseKey);
107 impl->m_PointTracer->setGraphKey(mouseKey);
103 displayTracer(*impl->m_PointTracer);
108 displayTracer(*impl->m_PointTracer);
104
109
105 // Displays text tracer
110 // Displays text tracer
106 auto tracerPosition = impl->m_TextTracer->position;
111 auto tracerPosition = impl->m_TextTracer->position;
107 tracerPosition->setAxes(graph->keyAxis(), graph->valueAxis());
112 tracerPosition->setAxes(graph->keyAxis(), graph->valueAxis());
108 tracerPosition->setCoords(impl->m_PointTracer->position->key(),
113 tracerPosition->setCoords(impl->m_PointTracer->position->key(),
109 impl->m_PointTracer->position->value());
114 impl->m_PointTracer->position->value());
110 displayTracer(*impl->m_TextTracer);
115 displayTracer(*impl->m_TextTracer);
111 }
116 }
112 }
117 }
113 };
118 };
114
119
115 // Starts the timer to display tracers at timeout
120 // Starts the timer to display tracers at timeout
116 QObject::connect(&impl->m_TracerTimer, &QTimer::timeout, showTracers);
121 QObject::connect(&impl->m_TracerTimer, &QTimer::timeout, showTracers);
117 impl->m_TracerTimer.start();
122 impl->m_TracerTimer.start();
118 }
123 }
@@ -1,92 +1,98
1 <?xml version="1.0" encoding="UTF-8"?>
1 <?xml version="1.0" encoding="UTF-8"?>
2 <ui version="4.0">
2 <ui version="4.0">
3 <class>TimeWidget</class>
3 <class>TimeWidget</class>
4 <widget class="QWidget" name="TimeWidget">
4 <widget class="QWidget" name="TimeWidget">
5 <property name="geometry">
5 <property name="geometry">
6 <rect>
6 <rect>
7 <x>0</x>
7 <x>0</x>
8 <y>0</y>
8 <y>0</y>
9 <width>716</width>
9 <width>716</width>
10 <height>48</height>
10 <height>48</height>
11 </rect>
11 </rect>
12 </property>
12 </property>
13 <property name="sizePolicy">
13 <property name="sizePolicy">
14 <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
14 <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
15 <horstretch>0</horstretch>
15 <horstretch>0</horstretch>
16 <verstretch>0</verstretch>
16 <verstretch>0</verstretch>
17 </sizepolicy>
17 </sizepolicy>
18 </property>
18 </property>
19 <property name="windowTitle">
19 <property name="windowTitle">
20 <string>Form</string>
20 <string>Form</string>
21 </property>
21 </property>
22 <layout class="QHBoxLayout" name="horizontalLayout_2">
22 <layout class="QHBoxLayout" name="horizontalLayout_2">
23 <item>
23 <item>
24 <widget class="QLabel" name="label">
24 <widget class="QLabel" name="label">
25 <property name="sizePolicy">
25 <property name="sizePolicy">
26 <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
26 <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
27 <horstretch>0</horstretch>
27 <horstretch>0</horstretch>
28 <verstretch>0</verstretch>
28 <verstretch>0</verstretch>
29 </sizepolicy>
29 </sizepolicy>
30 </property>
30 </property>
31 <property name="text">
31 <property name="text">
32 <string>TStart :</string>
32 <string>TStart :</string>
33 </property>
33 </property>
34 </widget>
34 </widget>
35 </item>
35 </item>
36 <item>
36 <item>
37 <widget class="QDateTimeEdit" name="startDateTimeEdit">
37 <widget class="QDateTimeEdit" name="startDateTimeEdit">
38 <property name="sizePolicy">
38 <property name="sizePolicy">
39 <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
39 <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
40 <horstretch>0</horstretch>
40 <horstretch>0</horstretch>
41 <verstretch>0</verstretch>
41 <verstretch>0</verstretch>
42 </sizepolicy>
42 </sizepolicy>
43 </property>
43 </property>
44 <property name="displayFormat">
44 <property name="displayFormat">
45 <string>dd/MM/yyyy HH:mm:ss:zzz</string>
45 <string>dd/MM/yyyy HH:mm:ss:zzz</string>
46 </property>
46 </property>
47 <property name="calendarPopup">
47 <property name="calendarPopup">
48 <bool>true</bool>
48 <bool>true</bool>
49 </property>
49 </property>
50 <property name="timeSpec">
51 <enum>Qt::UTC</enum>
52 </property>
50 </widget>
53 </widget>
51 </item>
54 </item>
52 <item>
55 <item>
53 <widget class="QLabel" name="label_2">
56 <widget class="QLabel" name="label_2">
54 <property name="sizePolicy">
57 <property name="sizePolicy">
55 <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
58 <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
56 <horstretch>0</horstretch>
59 <horstretch>0</horstretch>
57 <verstretch>0</verstretch>
60 <verstretch>0</verstretch>
58 </sizepolicy>
61 </sizepolicy>
59 </property>
62 </property>
60 <property name="text">
63 <property name="text">
61 <string>TEnd :</string>
64 <string>TEnd :</string>
62 </property>
65 </property>
63 </widget>
66 </widget>
64 </item>
67 </item>
65 <item>
68 <item>
66 <widget class="QDateTimeEdit" name="endDateTimeEdit">
69 <widget class="QDateTimeEdit" name="endDateTimeEdit">
67 <property name="sizePolicy">
70 <property name="sizePolicy">
68 <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
71 <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
69 <horstretch>0</horstretch>
72 <horstretch>0</horstretch>
70 <verstretch>0</verstretch>
73 <verstretch>0</verstretch>
71 </sizepolicy>
74 </sizepolicy>
72 </property>
75 </property>
73 <property name="displayFormat">
76 <property name="displayFormat">
74 <string>dd/MM/yyyy HH:mm:ss:zzz</string>
77 <string>dd/MM/yyyy HH:mm:ss:zzz</string>
75 </property>
78 </property>
76 <property name="calendarPopup">
79 <property name="calendarPopup">
77 <bool>true</bool>
80 <bool>true</bool>
78 </property>
81 </property>
82 <property name="timeSpec">
83 <enum>Qt::UTC</enum>
84 </property>
79 </widget>
85 </widget>
80 </item>
86 </item>
81 <item>
87 <item>
82 <widget class="QToolButton" name="applyToolButton">
88 <widget class="QToolButton" name="applyToolButton">
83 <property name="text">
89 <property name="text">
84 <string>...</string>
90 <string>...</string>
85 </property>
91 </property>
86 </widget>
92 </widget>
87 </item>
93 </item>
88 </layout>
94 </layout>
89 </widget>
95 </widget>
90 <resources/>
96 <resources/>
91 <connections/>
97 <connections/>
92 </ui>
98 </ui>
@@ -1,147 +1,148
1 #include "AmdaProvider.h"
1 #include "AmdaProvider.h"
2 #include "AmdaDefs.h"
2 #include "AmdaDefs.h"
3 #include "AmdaResultParser.h"
3 #include "AmdaResultParser.h"
4
4
5 #include <Common/DateUtils.h>
5 #include <Data/DataProviderParameters.h>
6 #include <Data/DataProviderParameters.h>
6 #include <Network/NetworkController.h>
7 #include <Network/NetworkController.h>
7 #include <SqpApplication.h>
8 #include <SqpApplication.h>
8 #include <Variable/Variable.h>
9 #include <Variable/Variable.h>
9
10
10 #include <QNetworkAccessManager>
11 #include <QNetworkAccessManager>
11 #include <QNetworkReply>
12 #include <QNetworkReply>
12 #include <QTemporaryFile>
13 #include <QTemporaryFile>
13 #include <QThread>
14 #include <QThread>
14
15
15 Q_LOGGING_CATEGORY(LOG_AmdaProvider, "AmdaProvider")
16 Q_LOGGING_CATEGORY(LOG_AmdaProvider, "AmdaProvider")
16
17
17 namespace {
18 namespace {
18
19
19 /// URL format for a request on AMDA server. The parameters are as follows:
20 /// URL format for a request on AMDA server. The parameters are as follows:
20 /// - %1: start date
21 /// - %1: start date
21 /// - %2: end date
22 /// - %2: end date
22 /// - %3: parameter id
23 /// - %3: parameter id
23 const auto AMDA_URL_FORMAT = QStringLiteral(
24 const auto AMDA_URL_FORMAT = QStringLiteral(
24 "http://amda.irap.omp.eu/php/rest/"
25 "http://amda.irap.omp.eu/php/rest/"
25 "getParameter.php?startTime=%1&stopTime=%2&parameterID=%3&outputFormat=ASCII&"
26 "getParameter.php?startTime=%1&stopTime=%2&parameterID=%3&outputFormat=ASCII&"
26 "timeFormat=ISO8601&gzip=0");
27 "timeFormat=ISO8601&gzip=0");
27
28
28 /// Dates format passed in the URL (e.g 2013-09-23T09:00)
29 /// Dates format passed in the URL (e.g 2013-09-23T09:00)
29 const auto AMDA_TIME_FORMAT = QStringLiteral("yyyy-MM-ddThh:mm:ss");
30 const auto AMDA_TIME_FORMAT = QStringLiteral("yyyy-MM-ddThh:mm:ss");
30
31
31 /// Formats a time to a date that can be passed in URL
32 /// Formats a time to a date that can be passed in URL
32 QString dateFormat(double sqpDateTime) noexcept
33 QString dateFormat(double sqpDateTime) noexcept
33 {
34 {
34 auto dateTime = QDateTime::fromMSecsSinceEpoch(sqpDateTime * 1000.);
35 auto dateTime = DateUtils::dateTime(sqpDateTime);
35 return dateTime.toString(AMDA_TIME_FORMAT);
36 return dateTime.toString(AMDA_TIME_FORMAT);
36 }
37 }
37
38
38 } // namespace
39 } // namespace
39
40
40 AmdaProvider::AmdaProvider()
41 AmdaProvider::AmdaProvider()
41 {
42 {
42 qCDebug(LOG_AmdaProvider()) << tr("AmdaProvider::AmdaProvider") << QThread::currentThread();
43 qCDebug(LOG_AmdaProvider()) << tr("AmdaProvider::AmdaProvider") << QThread::currentThread();
43 if (auto app = sqpApp) {
44 if (auto app = sqpApp) {
44 auto &networkController = app->networkController();
45 auto &networkController = app->networkController();
45 connect(this, SIGNAL(requestConstructed(QNetworkRequest, QUuid,
46 connect(this, SIGNAL(requestConstructed(QNetworkRequest, QUuid,
46 std::function<void(QNetworkReply *, QUuid)>)),
47 std::function<void(QNetworkReply *, QUuid)>)),
47 &networkController,
48 &networkController,
48 SLOT(onProcessRequested(QNetworkRequest, QUuid,
49 SLOT(onProcessRequested(QNetworkRequest, QUuid,
49 std::function<void(QNetworkReply *, QUuid)>)));
50 std::function<void(QNetworkReply *, QUuid)>)));
50
51
51
52
52 connect(&sqpApp->networkController(), SIGNAL(replyDownloadProgress(QUuid, double)), this,
53 connect(&sqpApp->networkController(), SIGNAL(replyDownloadProgress(QUuid, double)), this,
53 SIGNAL(dataProvidedProgress(QUuid, double)));
54 SIGNAL(dataProvidedProgress(QUuid, double)));
54 }
55 }
55 }
56 }
56
57
57 void AmdaProvider::requestDataLoading(QUuid token, const DataProviderParameters &parameters)
58 void AmdaProvider::requestDataLoading(QUuid token, const DataProviderParameters &parameters)
58 {
59 {
59 // NOTE: Try to use multithread if possible
60 // NOTE: Try to use multithread if possible
60 const auto times = parameters.m_Times;
61 const auto times = parameters.m_Times;
61 const auto data = parameters.m_Data;
62 const auto data = parameters.m_Data;
62 for (const auto &dateTime : qAsConst(times)) {
63 for (const auto &dateTime : qAsConst(times)) {
63 retrieveData(token, dateTime, data);
64 retrieveData(token, dateTime, data);
64 }
65 }
65 }
66 }
66
67
67 void AmdaProvider::requestDataAborting(QUuid identifier)
68 void AmdaProvider::requestDataAborting(QUuid identifier)
68 {
69 {
69 if (auto app = sqpApp) {
70 if (auto app = sqpApp) {
70 auto &networkController = app->networkController();
71 auto &networkController = app->networkController();
71 networkController.onReplyCanceled(identifier);
72 networkController.onReplyCanceled(identifier);
72 }
73 }
73 }
74 }
74
75
75 void AmdaProvider::retrieveData(QUuid token, const SqpDateTime &dateTime, const QVariantHash &data)
76 void AmdaProvider::retrieveData(QUuid token, const SqpDateTime &dateTime, const QVariantHash &data)
76 {
77 {
77 // Retrieves product ID from data: if the value is invalid, no request is made
78 // Retrieves product ID from data: if the value is invalid, no request is made
78 auto productId = data.value(AMDA_XML_ID_KEY).toString();
79 auto productId = data.value(AMDA_XML_ID_KEY).toString();
79 if (productId.isNull()) {
80 if (productId.isNull()) {
80 qCCritical(LOG_AmdaProvider()) << tr("Can't retrieve data: unknown product id");
81 qCCritical(LOG_AmdaProvider()) << tr("Can't retrieve data: unknown product id");
81 return;
82 return;
82 }
83 }
83 qCInfo(LOG_AmdaProvider()) << tr("AmdaProvider::retrieveData") << dateTime;
84 qCInfo(LOG_AmdaProvider()) << tr("AmdaProvider::retrieveData") << dateTime;
84
85
85 // /////////// //
86 // /////////// //
86 // Creates URL //
87 // Creates URL //
87 // /////////// //
88 // /////////// //
88
89
89 auto startDate = dateFormat(dateTime.m_TStart);
90 auto startDate = dateFormat(dateTime.m_TStart);
90 auto endDate = dateFormat(dateTime.m_TEnd);
91 auto endDate = dateFormat(dateTime.m_TEnd);
91
92
92 auto url = QUrl{QString{AMDA_URL_FORMAT}.arg(startDate, endDate, productId)};
93 auto url = QUrl{QString{AMDA_URL_FORMAT}.arg(startDate, endDate, productId)};
93 qCInfo(LOG_AmdaProvider()) << tr("AmdaProvider::retrieveData url:") << url;
94 qCInfo(LOG_AmdaProvider()) << tr("AmdaProvider::retrieveData url:") << url;
94 auto tempFile = std::make_shared<QTemporaryFile>();
95 auto tempFile = std::make_shared<QTemporaryFile>();
95
96
96 // LAMBDA
97 // LAMBDA
97 auto httpDownloadFinished
98 auto httpDownloadFinished
98 = [this, dateTime, tempFile, token](QNetworkReply *reply, QUuid dataId) noexcept {
99 = [this, dateTime, tempFile, token](QNetworkReply *reply, QUuid dataId) noexcept {
99 Q_UNUSED(dataId);
100 Q_UNUSED(dataId);
100
101
101 // Don't do anything if the reply was abort
102 // Don't do anything if the reply was abort
102 if (reply->error() != QNetworkReply::OperationCanceledError) {
103 if (reply->error() != QNetworkReply::OperationCanceledError) {
103
104
104 if (tempFile) {
105 if (tempFile) {
105 auto replyReadAll = reply->readAll();
106 auto replyReadAll = reply->readAll();
106 if (!replyReadAll.isEmpty()) {
107 if (!replyReadAll.isEmpty()) {
107 tempFile->write(replyReadAll);
108 tempFile->write(replyReadAll);
108 }
109 }
109 tempFile->close();
110 tempFile->close();
110
111
111 // Parse results file
112 // Parse results file
112 if (auto dataSeries = AmdaResultParser::readTxt(tempFile->fileName())) {
113 if (auto dataSeries = AmdaResultParser::readTxt(tempFile->fileName())) {
113 emit dataProvided(token, dataSeries, dateTime);
114 emit dataProvided(token, dataSeries, dateTime);
114 }
115 }
115 else {
116 else {
116 /// @todo ALX : debug
117 /// @todo ALX : debug
117 }
118 }
118 }
119 }
119 }
120 }
120
121
121 };
122 };
122 auto httpFinishedLambda
123 auto httpFinishedLambda
123 = [this, httpDownloadFinished, tempFile](QNetworkReply *reply, QUuid dataId) noexcept {
124 = [this, httpDownloadFinished, tempFile](QNetworkReply *reply, QUuid dataId) noexcept {
124
125
125 // Don't do anything if the reply was abort
126 // Don't do anything if the reply was abort
126 if (reply->error() != QNetworkReply::OperationCanceledError) {
127 if (reply->error() != QNetworkReply::OperationCanceledError) {
127 auto downloadFileUrl = QUrl{QString{reply->readAll()}};
128 auto downloadFileUrl = QUrl{QString{reply->readAll()}};
128
129
129
130
130 qCInfo(LOG_AmdaProvider()) << tr("AmdaProvider::retrieveData downloadFileUrl:")
131 qCInfo(LOG_AmdaProvider()) << tr("AmdaProvider::retrieveData downloadFileUrl:")
131 << downloadFileUrl;
132 << downloadFileUrl;
132 // Executes request for downloading file //
133 // Executes request for downloading file //
133
134
134 // Creates destination file
135 // Creates destination file
135 if (tempFile->open()) {
136 if (tempFile->open()) {
136 // Executes request
137 // Executes request
137 emit requestConstructed(QNetworkRequest{downloadFileUrl}, dataId,
138 emit requestConstructed(QNetworkRequest{downloadFileUrl}, dataId,
138 httpDownloadFinished);
139 httpDownloadFinished);
139 }
140 }
140 }
141 }
141 };
142 };
142
143
143 // //////////////// //
144 // //////////////// //
144 // Executes request //
145 // Executes request //
145 // //////////////// //
146 // //////////////// //
146 emit requestConstructed(QNetworkRequest{url}, token, httpFinishedLambda);
147 emit requestConstructed(QNetworkRequest{url}, token, httpFinishedLambda);
147 }
148 }
@@ -1,145 +1,152
1 #include "AmdaResultParser.h"
1 #include "AmdaResultParser.h"
2
2
3 #include <Common/DateUtils.h>
3 #include <Data/ScalarSeries.h>
4 #include <Data/ScalarSeries.h>
4
5
5 #include <QDateTime>
6 #include <QDateTime>
6 #include <QFile>
7 #include <QFile>
7 #include <QRegularExpression>
8 #include <QRegularExpression>
8
9
9 #include <cmath>
10 #include <cmath>
10
11
11 Q_LOGGING_CATEGORY(LOG_AmdaResultParser, "AmdaResultParser")
12 Q_LOGGING_CATEGORY(LOG_AmdaResultParser, "AmdaResultParser")
12
13
13 namespace {
14 namespace {
14
15
15 /// Message in result file when the file was not found on server
16 /// Message in result file when the file was not found on server
16 const auto FILE_NOT_FOUND_MESSAGE = QStringLiteral("Not Found");
17 const auto FILE_NOT_FOUND_MESSAGE = QStringLiteral("Not Found");
17
18
18 /// Format for dates in result files
19 /// Format for dates in result files
19 const auto DATE_FORMAT = QStringLiteral("yyyy-MM-ddThh:mm:ss.zzz");
20 const auto DATE_FORMAT = QStringLiteral("yyyy-MM-ddThh:mm:ss.zzz");
20
21
21 /// Separator between values in a result line
22 /// Separator between values in a result line
22 const auto RESULT_LINE_SEPARATOR = QRegularExpression{QStringLiteral("\\s+")};
23 const auto RESULT_LINE_SEPARATOR = QRegularExpression{QStringLiteral("\\s+")};
23
24
24 /// Regex to find unit in a line. Examples of valid lines:
25 /// Regex to find unit in a line. Examples of valid lines:
25 /// ... - Units : nT - ...
26 /// ... - Units : nT - ...
26 /// ... -Units:nT- ...
27 /// ... -Units:nT- ...
27 /// ... -Units: mΒ²- ...
28 /// ... -Units: mΒ²- ...
28 /// ... - Units : m/s - ...
29 /// ... - Units : m/s - ...
29 const auto UNIT_REGEX = QRegularExpression{QStringLiteral("-\\s*Units\\s*:\\s*(.+?)\\s*-")};
30 const auto UNIT_REGEX = QRegularExpression{QStringLiteral("-\\s*Units\\s*:\\s*(.+?)\\s*-")};
30
31
31 /// Converts a string date to a double date
32 /// Converts a string date to a double date
32 /// @return a double that represents the date in seconds, NaN if the string date can't be converted
33 /// @return a double that represents the date in seconds, NaN if the string date can't be converted
33 double doubleDate(const QString &stringDate) noexcept
34 double doubleDate(const QString &stringDate) noexcept
34 {
35 {
35 auto dateTime = QDateTime::fromString(stringDate, DATE_FORMAT);
36 auto dateTime = QDateTime::fromString(stringDate, DATE_FORMAT);
36 return dateTime.isValid() ? (dateTime.toMSecsSinceEpoch() / 1000.)
37 dateTime.setTimeSpec(Qt::UTC);
38 return dateTime.isValid() ? DateUtils::secondsSinceEpoch(dateTime)
37 : std::numeric_limits<double>::quiet_NaN();
39 : std::numeric_limits<double>::quiet_NaN();
38 }
40 }
39
41
42 /// Checks if a line is a comment line
43 bool isCommentLine(const QString &line)
44 {
45 return line.startsWith("#");
46 }
47
40 /**
48 /**
41 * Reads stream to retrieve x-axis unit
49 * Reads stream to retrieve x-axis unit
42 * @param stream the stream to read
50 * @param stream the stream to read
43 * @return the unit that has been read in the stream, a default unit (time unit with no label) if an
51 * @return the unit that has been read in the stream, a default unit (time unit with no label) if an
44 * error occured during reading
52 * error occured during reading
45 */
53 */
46 Unit readXAxisUnit(QTextStream &stream)
54 Unit readXAxisUnit(QTextStream &stream)
47 {
55 {
48 QString line{};
56 QString line{};
49
57
50 if (stream.readLineInto(&line)) {
58 // Searches unit in the comment lines
59 while (stream.readLineInto(&line) && isCommentLine(line)) {
51 auto match = UNIT_REGEX.match(line);
60 auto match = UNIT_REGEX.match(line);
52 if (match.hasMatch()) {
61 if (match.hasMatch()) {
53 return Unit{match.captured(1), true};
62 return Unit{match.captured(1), true};
54 }
63 }
55 else {
56 qCWarning(LOG_AmdaResultParser())
57 << QObject::tr("Can't read unit: invalid line %1").arg(line);
58 }
59 }
60 else {
61 qCWarning(LOG_AmdaResultParser()) << QObject::tr("Can't read unit: end of file");
62 }
64 }
63
65
66 qCWarning(LOG_AmdaResultParser()) << QObject::tr("The unit could not be found in the file");
67
64 // Error cases
68 // Error cases
65 return Unit{{}, true};
69 return Unit{{}, true};
66 }
70 }
67
71
68 /**
72 /**
69 * Reads stream to retrieve results
73 * Reads stream to retrieve results
70 * @param stream the stream to read
74 * @param stream the stream to read
71 * @return the pair of vectors x-axis data/values data that has been read in the stream
75 * @return the pair of vectors x-axis data/values data that has been read in the stream
72 */
76 */
73 QPair<QVector<double>, QVector<double> > readResults(QTextStream &stream)
77 QPair<QVector<double>, QVector<double> > readResults(QTextStream &stream)
74 {
78 {
75 auto xData = QVector<double>{};
79 auto xData = QVector<double>{};
76 auto valuesData = QVector<double>{};
80 auto valuesData = QVector<double>{};
77
81
78 QString line{};
82 QString line{};
83
79 while (stream.readLineInto(&line)) {
84 while (stream.readLineInto(&line)) {
80 auto lineData = line.split(RESULT_LINE_SEPARATOR, QString::SkipEmptyParts);
85 // Ignore comment lines
81 if (lineData.size() == 2) {
86 if (!isCommentLine(line)) {
82 // X : the data is converted from date to double (in secs)
87 auto lineData = line.split(RESULT_LINE_SEPARATOR, QString::SkipEmptyParts);
83 auto x = doubleDate(lineData.at(0));
88 if (lineData.size() == 2) {
84
89 // X : the data is converted from date to double (in secs)
85 // Value
90 auto x = doubleDate(lineData.at(0));
86 bool valueOk;
91
87 auto value = lineData.at(1).toDouble(&valueOk);
92 // Value
88
93 bool valueOk;
89 // Adds result only if x and value are valid
94 auto value = lineData.at(1).toDouble(&valueOk);
90 if (!std::isnan(x) && !std::isnan(value) && valueOk) {
95
91 xData.push_back(x);
96 // Adds result only if x and value are valid
92 valuesData.push_back(value);
97 if (!std::isnan(x) && !std::isnan(value) && valueOk) {
98 xData.push_back(x);
99 valuesData.push_back(value);
100 }
101 else {
102 qCWarning(LOG_AmdaResultParser())
103 << QObject::tr(
104 "Can't retrieve results from line %1: x and/or value are invalid")
105 .arg(line);
106 }
93 }
107 }
94 else {
108 else {
95 qCWarning(LOG_AmdaResultParser())
109 qCWarning(LOG_AmdaResultParser())
96 << QObject::tr(
110 << QObject::tr("Can't retrieve results from line %1: invalid line").arg(line);
97 "Can't retrieve results from line %1: x and/or value are invalid")
98 .arg(line);
99 }
111 }
100 }
112 }
101 else {
102 qCWarning(LOG_AmdaResultParser())
103 << QObject::tr("Can't retrieve results from line %1: invalid line").arg(line);
104 }
105 }
113 }
106
114
107 return qMakePair(std::move(xData), std::move(valuesData));
115 return qMakePair(std::move(xData), std::move(valuesData));
108 }
116 }
109
117
110 } // namespace
118 } // namespace
111
119
112 std::shared_ptr<IDataSeries> AmdaResultParser::readTxt(const QString &filePath) noexcept
120 std::shared_ptr<IDataSeries> AmdaResultParser::readTxt(const QString &filePath) noexcept
113 {
121 {
114 QFile file{filePath};
122 QFile file{filePath};
115
123
116 if (!file.open(QFile::ReadOnly | QIODevice::Text)) {
124 if (!file.open(QFile::ReadOnly | QIODevice::Text)) {
117 qCCritical(LOG_AmdaResultParser())
125 qCCritical(LOG_AmdaResultParser())
118 << QObject::tr("Can't retrieve AMDA data from file %1: %2")
126 << QObject::tr("Can't retrieve AMDA data from file %1: %2")
119 .arg(filePath, file.errorString());
127 .arg(filePath, file.errorString());
120 return nullptr;
128 return nullptr;
121 }
129 }
122
130
123 QTextStream stream{&file};
131 QTextStream stream{&file};
124
132
125 // Checks if the file was found on the server
133 // Checks if the file was found on the server
126 auto firstLine = stream.readLine();
134 auto firstLine = stream.readLine();
127 if (firstLine.compare(FILE_NOT_FOUND_MESSAGE) == 0) {
135 if (firstLine.compare(FILE_NOT_FOUND_MESSAGE) == 0) {
128 qCCritical(LOG_AmdaResultParser())
136 qCCritical(LOG_AmdaResultParser())
129 << QObject::tr("Can't retrieve AMDA data from file %1: file was not found on server")
137 << QObject::tr("Can't retrieve AMDA data from file %1: file was not found on server")
130 .arg(filePath);
138 .arg(filePath);
131 return nullptr;
139 return nullptr;
132 }
140 }
133
141
134 // Ignore comments lines
135 stream.readLine();
136
137 // Reads x-axis unit
142 // Reads x-axis unit
143 stream.seek(0); // returns to the beginning of the file
138 auto xAxisUnit = readXAxisUnit(stream);
144 auto xAxisUnit = readXAxisUnit(stream);
139
145
140 // Reads results
146 // Reads results
147 stream.seek(0); // returns to the beginning of the file
141 auto results = readResults(stream);
148 auto results = readResults(stream);
142
149
143 return std::make_shared<ScalarSeries>(std::move(results.first), std::move(results.second),
150 return std::make_shared<ScalarSeries>(std::move(results.first), std::move(results.second),
144 xAxisUnit, Unit{});
151 xAxisUnit, Unit{});
145 }
152 }
@@ -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}, Qt::UTC};
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)") << QStringLiteral("UnexistingFile.txt")
159 QTest::newRow("Invalid file (unexisting file)") << QStringLiteral("UnexistingFile.txt")
160 << ExpectedResults{};
160 << ExpectedResults{};
161
161
162 QTest::newRow("Invalid file (file not found on server)") << QStringLiteral("FileNotFound.txt")
162 QTest::newRow("Invalid file (file not found on server)") << QStringLiteral("FileNotFound.txt")
163 << 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"
@@ -1,101 +1,100
1 #include "CosinusProvider.h"
1 #include "CosinusProvider.h"
2
2
3 #include <Data/DataProviderParameters.h>
3 #include <Data/DataProviderParameters.h>
4 #include <Data/ScalarSeries.h>
4 #include <Data/ScalarSeries.h>
5
5
6 #include <cmath>
6 #include <cmath>
7
7
8 #include <QDateTime>
9 #include <QFuture>
8 #include <QFuture>
10 #include <QThread>
9 #include <QThread>
11 #include <QtConcurrent/QtConcurrent>
10 #include <QtConcurrent/QtConcurrent>
12
11
13 Q_LOGGING_CATEGORY(LOG_CosinusProvider, "CosinusProvider")
12 Q_LOGGING_CATEGORY(LOG_CosinusProvider, "CosinusProvider")
14
13
15 std::shared_ptr<IDataSeries> CosinusProvider::retrieveData(QUuid token, const SqpDateTime &dateTime)
14 std::shared_ptr<IDataSeries> CosinusProvider::retrieveData(QUuid token, const SqpDateTime &dateTime)
16 {
15 {
17 // TODO: Add Mutex
16 // TODO: Add Mutex
18 auto dataIndex = 0;
17 auto dataIndex = 0;
19
18
20 // Gets the timerange from the parameters
19 // Gets the timerange from the parameters
21 double freq = 100.0;
20 double freq = 100.0;
22 double start = std::ceil(dateTime.m_TStart * freq); // 100 htz
21 double start = std::ceil(dateTime.m_TStart * freq); // 100 htz
23 double end = std::floor(dateTime.m_TEnd * freq); // 100 htz
22 double end = std::floor(dateTime.m_TEnd * freq); // 100 htz
24
23
25 // We assure that timerange is valid
24 // We assure that timerange is valid
26 if (end < start) {
25 if (end < start) {
27 std::swap(start, end);
26 std::swap(start, end);
28 }
27 }
29
28
30 // Generates scalar series containing cosinus values (one value per second)
29 // Generates scalar series containing cosinus values (one value per second)
31 auto dataCount = end - start;
30 auto dataCount = end - start;
32
31
33 auto xAxisData = QVector<double>{};
32 auto xAxisData = QVector<double>{};
34 xAxisData.resize(dataCount);
33 xAxisData.resize(dataCount);
35
34
36 auto valuesData = QVector<double>{};
35 auto valuesData = QVector<double>{};
37 valuesData.resize(dataCount);
36 valuesData.resize(dataCount);
38
37
39 int progress = 0;
38 int progress = 0;
40 auto progressEnd = dataCount;
39 auto progressEnd = dataCount;
41 for (auto time = start; time < end; ++time, ++dataIndex) {
40 for (auto time = start; time < end; ++time, ++dataIndex) {
42 auto it = m_VariableToEnableProvider.find(token);
41 auto it = m_VariableToEnableProvider.find(token);
43 if (it != m_VariableToEnableProvider.end() && it.value()) {
42 if (it != m_VariableToEnableProvider.end() && it.value()) {
44 const auto timeOnFreq = time / freq;
43 const auto timeOnFreq = time / freq;
45
44
46 xAxisData.replace(dataIndex, timeOnFreq);
45 xAxisData.replace(dataIndex, timeOnFreq);
47 valuesData.replace(dataIndex, std::cos(timeOnFreq));
46 valuesData.replace(dataIndex, std::cos(timeOnFreq));
48
47
49 // progression
48 // progression
50 int currentProgress = (time - start) * 100.0 / progressEnd;
49 int currentProgress = (time - start) * 100.0 / progressEnd;
51 if (currentProgress != progress) {
50 if (currentProgress != progress) {
52 progress = currentProgress;
51 progress = currentProgress;
53
52
54 emit dataProvidedProgress(token, progress);
53 emit dataProvidedProgress(token, progress);
55 }
54 }
56 }
55 }
57 else {
56 else {
58 if (!it.value()) {
57 if (!it.value()) {
59 qCDebug(LOG_CosinusProvider())
58 qCDebug(LOG_CosinusProvider())
60 << "CosinusProvider::retrieveData: ARRET De l'acquisition detectΓ©"
59 << "CosinusProvider::retrieveData: ARRET De l'acquisition detectΓ©"
61 << end - time;
60 << end - time;
62 }
61 }
63 }
62 }
64 }
63 }
65 emit dataProvidedProgress(token, 0.0);
64 emit dataProvidedProgress(token, 0.0);
66
65
67 return std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData),
66 return std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData),
68 Unit{QStringLiteral("t"), true}, Unit{});
67 Unit{QStringLiteral("t"), true}, Unit{});
69 }
68 }
70
69
71 void CosinusProvider::requestDataLoading(QUuid token, const DataProviderParameters &parameters)
70 void CosinusProvider::requestDataLoading(QUuid token, const DataProviderParameters &parameters)
72 {
71 {
73 // TODO: Add Mutex
72 // TODO: Add Mutex
74 m_VariableToEnableProvider[token] = true;
73 m_VariableToEnableProvider[token] = true;
75 qCDebug(LOG_CosinusProvider()) << "CosinusProvider::requestDataLoading"
74 qCDebug(LOG_CosinusProvider()) << "CosinusProvider::requestDataLoading"
76 << QThread::currentThread()->objectName();
75 << QThread::currentThread()->objectName();
77 // NOTE: Try to use multithread if possible
76 // NOTE: Try to use multithread if possible
78 const auto times = parameters.m_Times;
77 const auto times = parameters.m_Times;
79
78
80 for (const auto &dateTime : qAsConst(times)) {
79 for (const auto &dateTime : qAsConst(times)) {
81 if (m_VariableToEnableProvider[token]) {
80 if (m_VariableToEnableProvider[token]) {
82 auto scalarSeries = this->retrieveData(token, dateTime);
81 auto scalarSeries = this->retrieveData(token, dateTime);
83 emit dataProvided(token, scalarSeries, dateTime);
82 emit dataProvided(token, scalarSeries, dateTime);
84 }
83 }
85 }
84 }
86 }
85 }
87
86
88 void CosinusProvider::requestDataAborting(QUuid identifier)
87 void CosinusProvider::requestDataAborting(QUuid identifier)
89 {
88 {
90 // TODO: Add Mutex
89 // TODO: Add Mutex
91 qCDebug(LOG_CosinusProvider()) << "CosinusProvider::requestDataAborting" << identifier
90 qCDebug(LOG_CosinusProvider()) << "CosinusProvider::requestDataAborting" << identifier
92 << QThread::currentThread()->objectName();
91 << QThread::currentThread()->objectName();
93 auto it = m_VariableToEnableProvider.find(identifier);
92 auto it = m_VariableToEnableProvider.find(identifier);
94 if (it != m_VariableToEnableProvider.end()) {
93 if (it != m_VariableToEnableProvider.end()) {
95 it.value() = false;
94 it.value() = false;
96 }
95 }
97 else {
96 else {
98 qCWarning(LOG_CosinusProvider())
97 qCWarning(LOG_CosinusProvider())
99 << tr("Aborting progression of inexistant identifier detected !!!");
98 << tr("Aborting progression of inexistant identifier detected !!!");
100 }
99 }
101 }
100 }
General Comments 0
You need to be logged in to leave comments. Login now