##// END OF EJS Templates
Merge branch 'feature/SqpDateTimeToSqpRange' into develop
perrinel -
r513:333dc2b889b2 merge
parent child
Show More
@@ -1,254 +1,254
1 1 /*------------------------------------------------------------------------------
2 2 -- This file is a part of the SciQLop Software
3 3 -- Copyright (C) 2017, Plasma Physics Laboratory - CNRS
4 4 --
5 5 -- This program is free software; you can redistribute it and/or modify
6 6 -- it under the terms of the GNU General Public License as published by
7 7 -- the Free Software Foundation; either version 2 of the License, or
8 8 -- (at your option) any later version.
9 9 --
10 10 -- This program is distributed in the hope that it will be useful,
11 11 -- but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 13 -- GNU General Public License for more details.
14 14 --
15 15 -- You should have received a copy of the GNU General Public License
16 16 -- along with this program; if not, write to the Free Software
17 17 -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 18 -------------------------------------------------------------------------------*/
19 19 /*-- Author : Alexis Jeandet
20 20 -- Mail : alexis.jeandet@member.fsf.org
21 21 ----------------------------------------------------------------------------*/
22 22 #include "MainWindow.h"
23 23 #include "ui_MainWindow.h"
24 24
25 25 #include <DataSource/DataSourceController.h>
26 26 #include <DataSource/DataSourceWidget.h>
27 27 #include <Settings/SqpSettingsDialog.h>
28 28 #include <Settings/SqpSettingsGeneralWidget.h>
29 29 #include <SidePane/SqpSidePane.h>
30 30 #include <SqpApplication.h>
31 31 #include <Time/TimeController.h>
32 32 #include <TimeWidget/TimeWidget.h>
33 33 #include <Variable/Variable.h>
34 34 #include <Variable/VariableController.h>
35 35 #include <Visualization/VisualizationController.h>
36 36
37 37 #include <QAction>
38 38 #include <QDate>
39 39 #include <QDir>
40 40 #include <QFileDialog>
41 41 #include <QToolBar>
42 42 #include <QToolButton>
43 43 #include <memory.h>
44 44
45 45 #include "iostream"
46 46
47 47 Q_LOGGING_CATEGORY(LOG_MainWindow, "MainWindow")
48 48
49 49 namespace {
50 50 const auto LEFTMAININSPECTORWIDGETSPLITTERINDEX = 0;
51 51 const auto LEFTINSPECTORSIDEPANESPLITTERINDEX = 1;
52 52 const auto VIEWPLITTERINDEX = 2;
53 53 const auto RIGHTINSPECTORSIDEPANESPLITTERINDEX = 3;
54 54 const auto RIGHTMAININSPECTORWIDGETSPLITTERINDEX = 4;
55 55 }
56 56
57 57 class MainWindow::MainWindowPrivate {
58 58 public:
59 59 explicit MainWindowPrivate(MainWindow *mainWindow)
60 60 : m_LastOpenLeftInspectorSize{},
61 61 m_LastOpenRightInspectorSize{},
62 62 m_GeneralSettingsWidget{new SqpSettingsGeneralWidget{mainWindow}},
63 63 m_SettingsDialog{new SqpSettingsDialog{mainWindow}}
64 64 {
65 65 }
66 66
67 67 QSize m_LastOpenLeftInspectorSize;
68 68 QSize m_LastOpenRightInspectorSize;
69 69 /// General settings widget. MainWindow has the ownership
70 70 SqpSettingsGeneralWidget *m_GeneralSettingsWidget;
71 71 /// Settings dialog. MainWindow has the ownership
72 72 SqpSettingsDialog *m_SettingsDialog;
73 73 };
74 74
75 75 MainWindow::MainWindow(QWidget *parent)
76 76 : QMainWindow{parent},
77 77 m_Ui{new Ui::MainWindow},
78 78 impl{spimpl::make_unique_impl<MainWindowPrivate>(this)}
79 79 {
80 80 m_Ui->setupUi(this);
81 81
82 82 m_Ui->splitter->setCollapsible(LEFTINSPECTORSIDEPANESPLITTERINDEX, false);
83 83 m_Ui->splitter->setCollapsible(RIGHTINSPECTORSIDEPANESPLITTERINDEX, false);
84 84
85 85
86 86 auto leftSidePane = m_Ui->leftInspectorSidePane->sidePane();
87 87 auto openLeftInspectorAction = new QAction{QIcon{
88 88 ":/icones/previous.png",
89 89 },
90 90 tr("Show/hide the left inspector"), this};
91 91
92 92
93 93 auto spacerLeftTop = new QWidget{};
94 94 spacerLeftTop->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
95 95
96 96 auto spacerLeftBottom = new QWidget{};
97 97 spacerLeftBottom->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
98 98
99 99 leftSidePane->addWidget(spacerLeftTop);
100 100 leftSidePane->addAction(openLeftInspectorAction);
101 101 leftSidePane->addWidget(spacerLeftBottom);
102 102
103 103
104 104 auto rightSidePane = m_Ui->rightInspectorSidePane->sidePane();
105 105 auto openRightInspectorAction = new QAction{QIcon{
106 106 ":/icones/next.png",
107 107 },
108 108 tr("Show/hide the right inspector"), this};
109 109
110 110 auto spacerRightTop = new QWidget{};
111 111 spacerRightTop->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
112 112
113 113 auto spacerRightBottom = new QWidget{};
114 114 spacerRightBottom->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
115 115
116 116 rightSidePane->addWidget(spacerRightTop);
117 117 rightSidePane->addAction(openRightInspectorAction);
118 118 rightSidePane->addWidget(spacerRightBottom);
119 119
120 120 openLeftInspectorAction->setCheckable(true);
121 121 openRightInspectorAction->setCheckable(true);
122 122
123 123 auto openInspector = [this](bool checked, bool right, auto action) {
124 124
125 125 action->setIcon(QIcon{(checked xor right) ? ":/icones/next.png" : ":/icones/previous.png"});
126 126
127 127 auto &lastInspectorSize
128 128 = right ? impl->m_LastOpenRightInspectorSize : impl->m_LastOpenLeftInspectorSize;
129 129
130 130 auto nextInspectorSize = right ? m_Ui->rightMainInspectorWidget->size()
131 131 : m_Ui->leftMainInspectorWidget->size();
132 132
133 133 // Update of the last opened geometry
134 134 if (checked) {
135 135 lastInspectorSize = nextInspectorSize;
136 136 }
137 137
138 138 auto startSize = lastInspectorSize;
139 139 auto endSize = startSize;
140 140 endSize.setWidth(0);
141 141
142 142 auto splitterInspectorIndex
143 143 = right ? RIGHTMAININSPECTORWIDGETSPLITTERINDEX : LEFTMAININSPECTORWIDGETSPLITTERINDEX;
144 144
145 145 auto currentSizes = m_Ui->splitter->sizes();
146 146 if (checked) {
147 147 // adjust sizes individually here, e.g.
148 148 currentSizes[splitterInspectorIndex] -= lastInspectorSize.width();
149 149 currentSizes[VIEWPLITTERINDEX] += lastInspectorSize.width();
150 150 m_Ui->splitter->setSizes(currentSizes);
151 151 }
152 152 else {
153 153 // adjust sizes individually here, e.g.
154 154 currentSizes[splitterInspectorIndex] += lastInspectorSize.width();
155 155 currentSizes[VIEWPLITTERINDEX] -= lastInspectorSize.width();
156 156 m_Ui->splitter->setSizes(currentSizes);
157 157 }
158 158
159 159 };
160 160
161 161
162 162 connect(openLeftInspectorAction, &QAction::triggered,
163 163 [openInspector, openLeftInspectorAction](bool checked) {
164 164 openInspector(checked, false, openLeftInspectorAction);
165 165 });
166 166 connect(openRightInspectorAction, &QAction::triggered,
167 167 [openInspector, openRightInspectorAction](bool checked) {
168 168 openInspector(checked, true, openRightInspectorAction);
169 169 });
170 170
171 171 // //// //
172 172 // Menu //
173 173 // //// //
174 174 this->menuBar()->addAction(tr("File"));
175 175 auto toolsMenu = this->menuBar()->addMenu(tr("Tools"));
176 176 toolsMenu->addAction(tr("Settings..."), [this]() {
177 177 // Loads settings
178 178 impl->m_SettingsDialog->loadSettings();
179 179
180 180 // Open settings dialog and save settings if the dialog is accepted
181 181 if (impl->m_SettingsDialog->exec() == QDialog::Accepted) {
182 182 impl->m_SettingsDialog->saveSettings();
183 183 }
184 184
185 185 });
186 186
187 187 auto mainToolBar = this->addToolBar(QStringLiteral("MainToolBar"));
188 188
189 189 auto timeWidget = new TimeWidget{};
190 190 mainToolBar->addWidget(timeWidget);
191 191
192 192 // //////// //
193 193 // Settings //
194 194 // //////// //
195 195
196 196 // Registers "general settings" widget to the settings dialog
197 197 impl->m_SettingsDialog->registerWidget(QStringLiteral("General"),
198 198 impl->m_GeneralSettingsWidget);
199 199
200 200 // /////////// //
201 201 // Connections //
202 202 // /////////// //
203 203
204 204 // Controllers / controllers connections
205 connect(&sqpApp->timeController(), SIGNAL(timeUpdated(SqpDateTime)),
206 &sqpApp->variableController(), SLOT(onDateTimeOnSelection(SqpDateTime)));
205 connect(&sqpApp->timeController(), SIGNAL(timeUpdated(SqpRange)), &sqpApp->variableController(),
206 SLOT(onDateTimeOnSelection(SqpRange)));
207 207
208 208 // Widgets / controllers connections
209 209
210 210 // DataSource
211 211 connect(&sqpApp->dataSourceController(), SIGNAL(dataSourceItemSet(DataSourceItem *)),
212 212 m_Ui->dataSourceWidget, SLOT(addDataSource(DataSourceItem *)));
213 213
214 214 // Time
215 connect(timeWidget, SIGNAL(timeUpdated(SqpDateTime)), &sqpApp->timeController(),
216 SLOT(onTimeToUpdate(SqpDateTime)));
215 connect(timeWidget, SIGNAL(timeUpdated(SqpRange)), &sqpApp->timeController(),
216 SLOT(onTimeToUpdate(SqpRange)));
217 217
218 218 // Visualization
219 219 connect(&sqpApp->visualizationController(),
220 220 SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)), m_Ui->view,
221 221 SLOT(onVariableAboutToBeDeleted(std::shared_ptr<Variable>)));
222 222
223 223 connect(&sqpApp->visualizationController(),
224 SIGNAL(rangeChanged(std::shared_ptr<Variable>, const SqpDateTime &)), m_Ui->view,
225 SLOT(onRangeChanged(std::shared_ptr<Variable>, const SqpDateTime &)));
224 SIGNAL(rangeChanged(std::shared_ptr<Variable>, const SqpRange &)), m_Ui->view,
225 SLOT(onRangeChanged(std::shared_ptr<Variable>, const SqpRange &)));
226 226
227 227 // Widgets / widgets connections
228 228
229 229 // For the following connections, we use DirectConnection to allow each widget that can
230 230 // potentially attach a menu to the variable's menu to do so before this menu is displayed.
231 231 // The order of connections is also important, since it determines the order in which each
232 232 // widget will attach its menu
233 233 connect(
234 234 m_Ui->variableInspectorWidget,
235 235 SIGNAL(tableMenuAboutToBeDisplayed(QMenu *, const QVector<std::shared_ptr<Variable> > &)),
236 236 m_Ui->view, SLOT(attachVariableMenu(QMenu *, const QVector<std::shared_ptr<Variable> > &)),
237 237 Qt::DirectConnection);
238 238 }
239 239
240 240 MainWindow::~MainWindow()
241 241 {
242 242 }
243 243
244 244 void MainWindow::changeEvent(QEvent *e)
245 245 {
246 246 QMainWindow::changeEvent(e);
247 247 switch (e->type()) {
248 248 case QEvent::LanguageChange:
249 249 m_Ui->retranslateUi(this);
250 250 break;
251 251 default:
252 252 break;
253 253 }
254 254 }
@@ -1,18 +1,18
1 1 #ifndef SCIQLOP_DATAPROVIDERPARAMETERS_H
2 2 #define SCIQLOP_DATAPROVIDERPARAMETERS_H
3 3
4 #include "SqpDateTime.h"
4 #include "SqpRange.h"
5 5
6 6 /**
7 7 * @brief The DataProviderParameters struct holds the information needed to retrieve data from a
8 8 * data provider
9 9 * @sa IDataProvider
10 10 */
11 11 struct DataProviderParameters {
12 12 /// Times for which retrieve data
13 QVector<SqpDateTime> m_Times;
13 QVector<SqpRange> m_Times;
14 14 /// Extra data that can be used by the provider to retrieve data
15 15 QVariantHash m_Data;
16 16 };
17 17
18 18 #endif // SCIQLOP_DATAPROVIDERPARAMETERS_H
@@ -1,74 +1,74
1 1 #ifndef SCIQLOP_IDATAPROVIDER_H
2 2 #define SCIQLOP_IDATAPROVIDER_H
3 3
4 4 #include "CoreGlobal.h"
5 5
6 6 #include <memory>
7 7
8 8 #include <QObject>
9 9 #include <QUuid>
10 10
11 11 #include <Common/MetaTypes.h>
12 12
13 #include <Data/SqpDateTime.h>
13 #include <Data/SqpRange.h>
14 14
15 15 #include <functional>
16 16
17 17 class DataProviderParameters;
18 18 class IDataSeries;
19 19 class QNetworkReply;
20 20 class QNetworkRequest;
21 21
22 22 /**
23 23 * @brief The IDataProvider interface aims to declare a data provider.
24 24 *
25 25 * A data provider is an entity that generates data and returns it according to various parameters
26 26 * (time interval, product to retrieve the data, etc.)
27 27 *
28 28 * @sa IDataSeries
29 29 */
30 30 class SCIQLOP_CORE_EXPORT IDataProvider : public QObject {
31 31
32 32 Q_OBJECT
33 33 public:
34 34 virtual ~IDataProvider() noexcept = default;
35 35
36 36 /**
37 37 * @brief requestDataLoading provide datas for the data identified by identifier and parameters
38 38 */
39 39 virtual void requestDataLoading(QUuid identifier, const DataProviderParameters &parameters) = 0;
40 40
41 41 /**
42 42 * @brief requestDataAborting stop data loading of the data identified by identifier
43 43 */
44 44 virtual void requestDataAborting(QUuid identifier) = 0;
45 45
46 46 signals:
47 47 /**
48 48 * @brief dataProvided send dataSeries under dateTime and that corresponds of the data
49 49 * identified by identifier
50 50 */
51 51 void dataProvided(QUuid identifier, std::shared_ptr<IDataSeries> dateSerie,
52 const SqpDateTime &dateTime);
52 const SqpRange &dateTime);
53 53
54 54 /**
55 55 * @brief dataProvided send dataSeries under dateTime and that corresponds of the data
56 56 * identified by identifier
57 57 */
58 58 void dataProvidedProgress(QUuid identifier, double progress);
59 59
60 60
61 61 /**
62 62 * @brief requestConstructed send a request for the data identified by identifier
63 63 * @callback is the methode call by the reply of the request when it is finished.
64 64 */
65 65 void requestConstructed(const QNetworkRequest &request, QUuid identifier,
66 66 std::function<void(QNetworkReply *, QUuid)> callback);
67 67 };
68 68
69 69 // Required for using shared_ptr in signals/slots
70 70 SCIQLOP_REGISTER_META_TYPE(IDATAPROVIDER_PTR_REGISTRY, std::shared_ptr<IDataProvider>)
71 71 SCIQLOP_REGISTER_META_TYPE(IDATAPROVIDER_FUNCTION_REGISTRY,
72 72 std::function<void(QNetworkReply *, QUuid)>)
73 73
74 74 #endif // SCIQLOP_IDATAPROVIDER_H
@@ -1,43 +1,43
1 #ifndef SCIQLOP_SQPDATETIME_H
2 #define SCIQLOP_SQPDATETIME_H
1 #ifndef SCIQLOP_SQPRANGE_H
2 #define SCIQLOP_SQPRANGE_H
3 3
4 4 #include <QObject>
5 5
6 6 #include <QDebug>
7 7
8 8 #include <Common/DateUtils.h>
9 9 #include <Common/MetaTypes.h>
10 10
11 11 /**
12 * @brief The SqpDateTime struct holds the information of time parameters
12 * @brief The SqpRange struct holds the information of time parameters
13 13 */
14 struct SqpDateTime {
14 struct SqpRange {
15 15 /// Start time (UTC)
16 16 double m_TStart;
17 17 /// End time (UTC)
18 18 double m_TEnd;
19 19
20 bool contains(const SqpDateTime &dateTime) const noexcept
20 bool contains(const SqpRange &dateTime) const noexcept
21 21 {
22 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 SqpRange &dateTime) const noexcept
26 26 {
27 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, SqpRange obj)
32 32 {
33 33 auto tendDateTimeStart = DateUtils::dateTime(obj.m_TStart);
34 34 auto tendDateTimeEnd = DateUtils::dateTime(obj.m_TEnd);
35 35
36 36 d << "ts: " << tendDateTimeStart << " te: " << tendDateTimeEnd;
37 37 return d;
38 38 }
39 39
40 40 // Required for using shared_ptr in signals/slots
41 SCIQLOP_REGISTER_META_TYPE(SQPDATETIME_REGISTRY, SqpDateTime)
41 SCIQLOP_REGISTER_META_TYPE(SQPRANGE_REGISTRY, SqpRange)
42 42
43 #endif // SCIQLOP_SQPDATETIME_H
43 #endif // SCIQLOP_SQPRANGE_H
@@ -1,42 +1,42
1 1 #ifndef SCIQLOP_TIMECONTROLLER_H
2 2 #define SCIQLOP_TIMECONTROLLER_H
3 3
4 4 #include "CoreGlobal.h"
5 5
6 #include <Data/SqpDateTime.h>
6 #include <Data/SqpRange.h>
7 7
8 8 #include <QLoggingCategory>
9 9 #include <QObject>
10 10
11 11 #include <Common/spimpl.h>
12 12
13 13
14 14 Q_DECLARE_LOGGING_CATEGORY(LOG_TimeController)
15 15
16 16 /**
17 17 * @brief The TimeController class aims to handle the Time parameters notification in SciQlop.
18 18 */
19 19 class SCIQLOP_CORE_EXPORT TimeController : public QObject {
20 20 Q_OBJECT
21 21 public:
22 22 explicit TimeController(QObject *parent = 0);
23 23
24 SqpDateTime dateTime() const noexcept;
24 SqpRange dateTime() const noexcept;
25 25
26 26 signals:
27 27 /// Signal emitted to notify that time parameters has beed updated
28 void timeUpdated(SqpDateTime time);
28 void timeUpdated(SqpRange time);
29 29
30 30 public slots:
31 31 /// Slot called when a new dateTime has been defined.
32 void onTimeToUpdate(SqpDateTime dateTime);
32 void onTimeToUpdate(SqpRange dateTime);
33 33
34 34 /// Slot called when the dateTime has to be notified. Call timeUpdated signal
35 35 void onTimeNotify();
36 36
37 37 private:
38 38 class TimeControllerPrivate;
39 39 spimpl::unique_impl_ptr<TimeControllerPrivate> impl;
40 40 };
41 41
42 42 #endif // SCIQLOP_TIMECONTROLLER_H
@@ -1,57 +1,57
1 1 #ifndef SCIQLOP_VARIABLE_H
2 2 #define SCIQLOP_VARIABLE_H
3 3
4 4 #include "CoreGlobal.h"
5 5
6 #include <Data/SqpDateTime.h>
6 #include <Data/SqpRange.h>
7 7
8 8 #include <QLoggingCategory>
9 9 #include <QObject>
10 10
11 11 #include <Common/MetaTypes.h>
12 12 #include <Common/spimpl.h>
13 13
14 14 Q_DECLARE_LOGGING_CATEGORY(LOG_Variable)
15 15
16 16 class IDataSeries;
17 17 class QString;
18 18
19 19 /**
20 20 * @brief The Variable class represents a variable in SciQlop.
21 21 */
22 22 class SCIQLOP_CORE_EXPORT Variable : public QObject {
23 23
24 24 Q_OBJECT
25 25
26 26 public:
27 explicit Variable(const QString &name, const SqpDateTime &dateTime,
27 explicit Variable(const QString &name, const SqpRange &dateTime,
28 28 const QVariantHash &metadata = {});
29 29
30 30 QString name() const noexcept;
31 SqpDateTime dateTime() const noexcept;
32 void setDateTime(const SqpDateTime &dateTime) noexcept;
31 SqpRange dateTime() const noexcept;
32 void setDateTime(const SqpRange &dateTime) noexcept;
33 33
34 34 /// @return the data of the variable, nullptr if there is no data
35 35 IDataSeries *dataSeries() const noexcept;
36 36
37 37 QVariantHash metadata() const noexcept;
38 38
39 bool contains(const SqpDateTime &dateTime) const noexcept;
40 bool intersect(const SqpDateTime &dateTime) const noexcept;
41 bool isInside(const SqpDateTime &dateTime) const noexcept;
39 bool contains(const SqpRange &dateTime) const noexcept;
40 bool intersect(const SqpRange &dateTime) const noexcept;
41 bool isInside(const SqpRange &dateTime) const noexcept;
42 42
43 43 public slots:
44 44 void setDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept;
45 45
46 46 signals:
47 47 void updated();
48 48
49 49 private:
50 50 class VariablePrivate;
51 51 spimpl::unique_impl_ptr<VariablePrivate> impl;
52 52 };
53 53
54 54 // Required for using shared_ptr in signals/slots
55 55 SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_REGISTRY, std::shared_ptr<Variable>)
56 56
57 57 #endif // SCIQLOP_VARIABLE_H
@@ -1,45 +1,45
1 1 #ifndef SCIQLOP_VARIABLECACHECONTROLLER_H
2 2 #define SCIQLOP_VARIABLECACHECONTROLLER_H
3 3
4 4 #include "CoreGlobal.h"
5 5
6 6 #include <QLoggingCategory>
7 7 #include <QObject>
8 8
9 #include <Data/SqpDateTime.h>
9 #include <Data/SqpRange.h>
10 10
11 11 #include <QLoggingCategory>
12 12
13 13 #include <Common/spimpl.h>
14 14
15 15 Q_DECLARE_LOGGING_CATEGORY(LOG_VariableCacheController)
16 16
17 17 class Variable;
18 18
19 19 /// This class aims to store in the cache all of the dateTime already requested to the variable.
20 20 class SCIQLOP_CORE_EXPORT VariableCacheController : public QObject {
21 21 Q_OBJECT
22 22 public:
23 23 explicit VariableCacheController(QObject *parent = 0);
24 24
25 25
26 void addDateTime(std::shared_ptr<Variable> variable, const SqpDateTime &dateTime);
26 void addDateTime(std::shared_ptr<Variable> variable, const SqpRange &dateTime);
27 27
28 28 /// Clears cache concerning a variable
29 29 void clear(std::shared_ptr<Variable> variable) noexcept;
30 30
31 31 /// Return all of the SqpDataTime part of the dateTime whose are not in the cache
32 QVector<SqpDateTime> provideNotInCacheDateTimeList(std::shared_ptr<Variable> variable,
33 const SqpDateTime &dateTime);
32 QVector<SqpRange> provideNotInCacheDateTimeList(std::shared_ptr<Variable> variable,
33 const SqpRange &dateTime);
34 34
35 35
36 QVector<SqpDateTime> dateCacheList(std::shared_ptr<Variable> variable) const noexcept;
36 QVector<SqpRange> dateCacheList(std::shared_ptr<Variable> variable) const noexcept;
37 37
38 38 void displayCache(std::shared_ptr<Variable> variable) const;
39 39
40 40 private:
41 41 class VariableCacheControllerPrivate;
42 42 spimpl::unique_impl_ptr<VariableCacheControllerPrivate> impl;
43 43 };
44 44
45 45 #endif // SCIQLOP_VARIABLECACHECONTROLLER_H
@@ -1,97 +1,97
1 1 #ifndef SCIQLOP_VARIABLECONTROLLER_H
2 2 #define SCIQLOP_VARIABLECONTROLLER_H
3 3
4 4 #include "CoreGlobal.h"
5 5
6 #include <Data/SqpDateTime.h>
6 #include <Data/SqpRange.h>
7 7
8 8 #include <QLoggingCategory>
9 9 #include <QObject>
10 10
11 11 #include <Common/spimpl.h>
12 12
13 13 class IDataProvider;
14 14 class QItemSelectionModel;
15 15 class TimeController;
16 16 class Variable;
17 17 class VariableModel;
18 18
19 19 Q_DECLARE_LOGGING_CATEGORY(LOG_VariableController)
20 20
21 21 /**
22 22 * @brief The VariableController class aims to handle the variables in SciQlop.
23 23 */
24 24 class SCIQLOP_CORE_EXPORT VariableController : public QObject {
25 25 Q_OBJECT
26 26 public:
27 27 explicit VariableController(QObject *parent = 0);
28 28 virtual ~VariableController();
29 29
30 30 VariableModel *variableModel() noexcept;
31 31 QItemSelectionModel *variableSelectionModel() noexcept;
32 32
33 33 void setTimeController(TimeController *timeController) noexcept;
34 34
35 35 /**
36 36 * Deletes from the controller the variable passed in parameter.
37 37 *
38 38 * Delete a variable includes:
39 39 * - the deletion of the various references to the variable in SciQlop
40 40 * - the deletion of the model variable
41 41 * - the deletion of the provider associated with the variable
42 42 * - removing the cache associated with the variable
43 43 *
44 44 * @param variable the variable to delete from the controller.
45 45 */
46 46 void deleteVariable(std::shared_ptr<Variable> variable) noexcept;
47 47
48 48 /**
49 49 * Deletes from the controller the variables passed in parameter.
50 50 * @param variables the variables to delete from the controller.
51 51 * @sa deleteVariable()
52 52 */
53 53 void deleteVariables(const QVector<std::shared_ptr<Variable> > &variables) noexcept;
54 54
55 55 /**
56 56 * @brief abort the variable retrieve data progression
57 57 */
58 58 void abortProgress(std::shared_ptr<Variable> variable);
59 59
60 60 signals:
61 61 /// Signal emitted when a variable is about to be deleted from the controller
62 62 void variableAboutToBeDeleted(std::shared_ptr<Variable> variable);
63 63
64 64 /// Signal emitted when a data acquisition is requested on a range for a variable
65 void rangeChanged(std::shared_ptr<Variable> variable, const SqpDateTime &range);
65 void rangeChanged(std::shared_ptr<Variable> variable, const SqpRange &range);
66 66
67 67 public slots:
68 68 /// Request the data loading of the variable whithin dateTime
69 void onRequestDataLoading(std::shared_ptr<Variable> variable, const SqpDateTime &dateTime);
69 void onRequestDataLoading(std::shared_ptr<Variable> variable, const SqpRange &dateTime);
70 70 /**
71 71 * Creates a new variable and adds it to the model
72 72 * @param name the name of the new variable
73 73 * @param metadata the metadata of the new variable
74 74 * @param provider the data provider for the new variable
75 75 */
76 76 void createVariable(const QString &name, const QVariantHash &metadata,
77 77 std::shared_ptr<IDataProvider> provider) noexcept;
78 78
79 79 /// Update the temporal parameters of every selected variable to dateTime
80 void onDateTimeOnSelection(const SqpDateTime &dateTime);
80 void onDateTimeOnSelection(const SqpRange &dateTime);
81 81
82 82
83 83 void onVariableRetrieveDataInProgress(QUuid identifier, double progress);
84 84
85 85 void onAbortProgressRequested(std::shared_ptr<Variable> variable);
86 86
87 87 void initialize();
88 88 void finalize();
89 89
90 90 private:
91 91 void waitForFinish();
92 92
93 93 class VariableControllerPrivate;
94 94 spimpl::unique_impl_ptr<VariableControllerPrivate> impl;
95 95 };
96 96
97 97 #endif // SCIQLOP_VARIABLECONTROLLER_H
@@ -1,80 +1,80
1 1 #ifndef SCIQLOP_VARIABLEMODEL_H
2 2 #define SCIQLOP_VARIABLEMODEL_H
3 3
4 4 #include "CoreGlobal.h"
5 5
6 #include <Data/SqpDateTime.h>
6 #include <Data/SqpRange.h>
7 7
8 8 #include <QAbstractTableModel>
9 9 #include <QLoggingCategory>
10 10
11 11 #include <Common/MetaTypes.h>
12 12 #include <Common/spimpl.h>
13 13
14 14 Q_DECLARE_LOGGING_CATEGORY(LOG_VariableModel)
15 15
16 16 enum VariableRoles { ProgressRole = Qt::UserRole };
17 17
18 18
19 19 class IDataSeries;
20 20 class Variable;
21 21
22 22 /**
23 23 * @brief The VariableModel class aims to hold the variables that have been created in SciQlop
24 24 */
25 25 class SCIQLOP_CORE_EXPORT VariableModel : public QAbstractTableModel {
26 26 Q_OBJECT
27 27 public:
28 28 explicit VariableModel(QObject *parent = nullptr);
29 29
30 30 /**
31 31 * Creates a new variable in the model
32 32 * @param name the name of the new variable
33 33 * @param dateTime the dateTime of the new variable
34 34 * @param metadata the metadata associated to the new variable
35 35 * @return the pointer to the new variable
36 36 */
37 std::shared_ptr<Variable> createVariable(const QString &name, const SqpDateTime &dateTime,
37 std::shared_ptr<Variable> createVariable(const QString &name, const SqpRange &dateTime,
38 38 const QVariantHash &metadata) noexcept;
39 39
40 40 /**
41 41 * Deletes a variable from the model, if it exists
42 42 * @param variable the variable to delete
43 43 */
44 44 void deleteVariable(std::shared_ptr<Variable> variable) noexcept;
45 45
46 46
47 47 std::shared_ptr<Variable> variable(int index) const;
48 48
49 49 void setDataProgress(std::shared_ptr<Variable> variable, double progress);
50 50
51 51
52 52 // /////////////////////////// //
53 53 // QAbstractTableModel methods //
54 54 // /////////////////////////// //
55 55
56 56 virtual int columnCount(const QModelIndex &parent = QModelIndex{}) const override;
57 57 virtual int rowCount(const QModelIndex &parent = QModelIndex{}) const override;
58 58 virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
59 59 virtual QVariant headerData(int section, Qt::Orientation orientation,
60 60 int role = Qt::DisplayRole) const override;
61 61
62 62
63 63 void abortProgress(const QModelIndex &index);
64 64
65 65 signals:
66 66 void abortProgessRequested(std::shared_ptr<Variable> variable);
67 67
68 68 private:
69 69 class VariableModelPrivate;
70 70 spimpl::unique_impl_ptr<VariableModelPrivate> impl;
71 71
72 72 private slots:
73 73 /// Slot called when data of a variable has been updated
74 74 void onVariableUpdated() noexcept;
75 75 };
76 76
77 77 // Registers QVector<int> metatype so it can be used in VariableModel::dataChanged() signal
78 78 SCIQLOP_REGISTER_META_TYPE(QVECTOR_INT_REGISTRY, QVector<int>)
79 79
80 80 #endif // SCIQLOP_VARIABLEMODEL_H
@@ -1,51 +1,51
1 1 #ifndef SCIQLOP_VISUALIZATIONCONTROLLER_H
2 2 #define SCIQLOP_VISUALIZATIONCONTROLLER_H
3 3
4 4 #include "CoreGlobal.h"
5 5
6 #include <Data/SqpDateTime.h>
6 #include <Data/SqpRange.h>
7 7
8 8 #include <QLoggingCategory>
9 9 #include <QObject>
10 10 #include <QUuid>
11 11
12 12 #include <Common/spimpl.h>
13 13
14 14 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationController)
15 15
16 16 class DataSourceItem;
17 17 class Variable;
18 18
19 19 /**
20 20 * @brief The VisualizationController class aims to make the link between SciQlop and its plugins.
21 21 * This is the intermediate class that SciQlop has to use in the way to connect a data source.
22 22 * Please first use register method to initialize a plugin specified by its metadata name (JSON
23 23 * plugin source) then others specifics method will be able to access it. You can load a data source
24 24 * driver plugin then create a data source.
25 25 */
26 26 class SCIQLOP_CORE_EXPORT VisualizationController : public QObject {
27 27 Q_OBJECT
28 28 public:
29 29 explicit VisualizationController(QObject *parent = 0);
30 30 virtual ~VisualizationController();
31 31
32 32 signals:
33 33 /// Signal emitted when a variable is about to be deleted from SciQlop
34 34 void variableAboutToBeDeleted(std::shared_ptr<Variable> variable);
35 35
36 36 /// Signal emitted when a data acquisition is requested on a range for a variable
37 void rangeChanged(std::shared_ptr<Variable> variable, const SqpDateTime &range);
37 void rangeChanged(std::shared_ptr<Variable> variable, const SqpRange &range);
38 38
39 39 public slots:
40 40 /// Manage init/end of the controller
41 41 void initialize();
42 42 void finalize();
43 43
44 44 private:
45 45 void waitForFinish();
46 46
47 47 class VisualizationControllerPrivate;
48 48 spimpl::unique_impl_ptr<VisualizationControllerPrivate> impl;
49 49 };
50 50
51 51 #endif // SCIQLOP_VISUALIZATIONCONTROLLER_H
@@ -1,29 +1,29
1 1 #include "Time/TimeController.h"
2 2
3 3 Q_LOGGING_CATEGORY(LOG_TimeController, "TimeController")
4 4
5 5 struct TimeController::TimeControllerPrivate {
6 6
7 SqpDateTime m_DateTime;
7 SqpRange m_DateTime;
8 8 };
9 9
10 10 TimeController::TimeController(QObject *parent)
11 11 : QObject{parent}, impl{spimpl::make_unique_impl<TimeControllerPrivate>()}
12 12 {
13 13 qCDebug(LOG_TimeController()) << tr("TimeController construction");
14 14 }
15 15
16 SqpDateTime TimeController::dateTime() const noexcept
16 SqpRange TimeController::dateTime() const noexcept
17 17 {
18 18 return impl->m_DateTime;
19 19 }
20 20
21 void TimeController::onTimeToUpdate(SqpDateTime dateTime)
21 void TimeController::onTimeToUpdate(SqpRange dateTime)
22 22 {
23 23 impl->m_DateTime = dateTime;
24 24 }
25 25
26 26 void TimeController::onTimeNotify()
27 27 {
28 28 emit timeUpdated(impl->m_DateTime);
29 29 }
@@ -1,86 +1,86
1 1 #include "Variable/Variable.h"
2 2
3 3 #include <Data/IDataSeries.h>
4 #include <Data/SqpDateTime.h>
4 #include <Data/SqpRange.h>
5 5
6 6 #include <QReadWriteLock>
7 7 #include <QThread>
8 8
9 9 Q_LOGGING_CATEGORY(LOG_Variable, "Variable")
10 10
11 11 struct Variable::VariablePrivate {
12 explicit VariablePrivate(const QString &name, const SqpDateTime &dateTime,
12 explicit VariablePrivate(const QString &name, const SqpRange &dateTime,
13 13 const QVariantHash &metadata)
14 14 : m_Name{name}, m_DateTime{dateTime}, m_Metadata{metadata}, m_DataSeries{nullptr}
15 15 {
16 16 }
17 17
18 18 QString m_Name;
19 19
20 SqpDateTime m_DateTime; // The dateTime available in the view and loaded. not the cache.
20 SqpRange m_DateTime; // The dateTime available in the view and loaded. not the cache.
21 21 QVariantHash m_Metadata;
22 22 std::unique_ptr<IDataSeries> m_DataSeries;
23 23 };
24 24
25 Variable::Variable(const QString &name, const SqpDateTime &dateTime, const QVariantHash &metadata)
25 Variable::Variable(const QString &name, const SqpRange &dateTime, const QVariantHash &metadata)
26 26 : impl{spimpl::make_unique_impl<VariablePrivate>(name, dateTime, metadata)}
27 27 {
28 28 }
29 29
30 30 QString Variable::name() const noexcept
31 31 {
32 32 return impl->m_Name;
33 33 }
34 34
35 SqpDateTime Variable::dateTime() const noexcept
35 SqpRange Variable::dateTime() const noexcept
36 36 {
37 37 return impl->m_DateTime;
38 38 }
39 39
40 void Variable::setDateTime(const SqpDateTime &dateTime) noexcept
40 void Variable::setDateTime(const SqpRange &dateTime) noexcept
41 41 {
42 42 impl->m_DateTime = dateTime;
43 43 }
44 44
45 45 void Variable::setDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept
46 46 {
47 47 qCDebug(LOG_Variable()) << "Variable::setDataSeries" << QThread::currentThread()->objectName();
48 48 if (!dataSeries) {
49 49 /// @todo ALX : log
50 50 return;
51 51 }
52 52
53 53 // Inits the data series of the variable
54 54 if (!impl->m_DataSeries) {
55 55 impl->m_DataSeries = dataSeries->clone();
56 56 }
57 57 else {
58 58 impl->m_DataSeries->merge(dataSeries.get());
59 59 // emit updated();
60 60 }
61 61 }
62 62
63 63 IDataSeries *Variable::dataSeries() const noexcept
64 64 {
65 65 return impl->m_DataSeries.get();
66 66 }
67 67
68 68 QVariantHash Variable::metadata() const noexcept
69 69 {
70 70 return impl->m_Metadata;
71 71 }
72 72
73 bool Variable::contains(const SqpDateTime &dateTime) const noexcept
73 bool Variable::contains(const SqpRange &dateTime) const noexcept
74 74 {
75 75 return impl->m_DateTime.contains(dateTime);
76 76 }
77 77
78 bool Variable::intersect(const SqpDateTime &dateTime) const noexcept
78 bool Variable::intersect(const SqpRange &dateTime) const noexcept
79 79 {
80 80 return impl->m_DateTime.intersect(dateTime);
81 81 }
82 82
83 bool Variable::isInside(const SqpDateTime &dateTime) const noexcept
83 bool Variable::isInside(const SqpRange &dateTime) const noexcept
84 84 {
85 return dateTime.contains(SqpDateTime{impl->m_DateTime.m_TStart, impl->m_DateTime.m_TEnd});
85 return dateTime.contains(SqpRange{impl->m_DateTime.m_TStart, impl->m_DateTime.m_TEnd});
86 86 }
@@ -1,228 +1,225
1 1 #include "Variable/VariableCacheController.h"
2 2
3 3 #include "Variable/Variable.h"
4 4 #include <unordered_map>
5 5
6 6 #include <QThread>
7 7 Q_LOGGING_CATEGORY(LOG_VariableCacheController, "VariableCacheController")
8 8
9 9 struct VariableCacheController::VariableCacheControllerPrivate {
10 10
11 std::unordered_map<std::shared_ptr<Variable>, QVector<SqpDateTime> >
12 m_VariableToSqpDateTimeListMap;
11 std::unordered_map<std::shared_ptr<Variable>, QVector<SqpRange> > m_VariableToSqpRangeListMap;
13 12
14 void addInCacheDataByEnd(const SqpDateTime &dateTime, QVector<SqpDateTime> &dateTimeList,
15 QVector<SqpDateTime> &notInCache, int cacheIndex,
16 double currentTStart);
13 void addInCacheDataByEnd(const SqpRange &dateTime, QVector<SqpRange> &dateTimeList,
14 QVector<SqpRange> &notInCache, int cacheIndex, double currentTStart);
17 15
18 void addInCacheDataByStart(const SqpDateTime &dateTime, QVector<SqpDateTime> &dateTimeList,
19 QVector<SqpDateTime> &notInCache, int cacheIndex,
20 double currentTStart);
16 void addInCacheDataByStart(const SqpRange &dateTime, QVector<SqpRange> &dateTimeList,
17 QVector<SqpRange> &notInCache, int cacheIndex, double currentTStart);
21 18
22 19
23 void addDateTimeRecurse(const SqpDateTime &dateTime, QVector<SqpDateTime> &dateTimeList,
20 void addDateTimeRecurse(const SqpRange &dateTime, QVector<SqpRange> &dateTimeList,
24 21 int cacheIndex);
25 22 };
26 23
27 24
28 25 VariableCacheController::VariableCacheController(QObject *parent)
29 26 : QObject{parent}, impl{spimpl::make_unique_impl<VariableCacheControllerPrivate>()}
30 27 {
31 28 }
32 29
33 30 void VariableCacheController::addDateTime(std::shared_ptr<Variable> variable,
34 const SqpDateTime &dateTime)
31 const SqpRange &dateTime)
35 32 {
36 33 qCDebug(LOG_VariableCacheController()) << "VariableCacheController::addDateTime"
37 34 << QThread::currentThread()->objectName();
38 35 if (variable) {
39 auto findVariableIte = impl->m_VariableToSqpDateTimeListMap.find(variable);
40 if (findVariableIte == impl->m_VariableToSqpDateTimeListMap.end()) {
41 impl->m_VariableToSqpDateTimeListMap[variable].push_back(dateTime);
36 auto findVariableIte = impl->m_VariableToSqpRangeListMap.find(variable);
37 if (findVariableIte == impl->m_VariableToSqpRangeListMap.end()) {
38 impl->m_VariableToSqpRangeListMap[variable].push_back(dateTime);
42 39 }
43 40 else {
44 41
45 // addDateTime modify the list<SqpDateTime> of the variable in a way to ensure
42 // addDateTime modify the list<SqpRange> of the variable in a way to ensure
46 43 // that the list is ordered : l(0) < l(1). We assume also a < b
47 // (with a & b of type SqpDateTime) means ts(b) > te(a)
44 // (with a & b of type SqpRange) means ts(b) > te(a)
48 45
49 46 // The algorithm will try the merge of two interval:
50 47 // - dateTime will be compare with the first interval of the list:
51 48 // A: if it is inferior, it will be inserted and it's finished.
52 49 // B: if it is in intersection, it will be merge then the merged one
53 50 // will be compared to the next interval. The old one is remove from the list
54 51 // C: if it is superior, we do the same with the next interval of the list
55 52
56 53 try {
57 impl->addDateTimeRecurse(dateTime,
58 impl->m_VariableToSqpDateTimeListMap.at(variable), 0);
54 impl->addDateTimeRecurse(dateTime, impl->m_VariableToSqpRangeListMap.at(variable),
55 0);
59 56 }
60 57 catch (const std::out_of_range &e) {
61 58 qCWarning(LOG_VariableCacheController()) << "addDateTime" << e.what();
62 59 }
63 60 }
64 61 }
65 62 }
66 63
67 64 void VariableCacheController::clear(std::shared_ptr<Variable> variable) noexcept
68 65 {
69 66 if (!variable) {
70 67 qCCritical(LOG_VariableCacheController()) << "Can't clear variable cache: variable is null";
71 68 return;
72 69 }
73 70
74 auto nbEntries = impl->m_VariableToSqpDateTimeListMap.erase(variable);
71 auto nbEntries = impl->m_VariableToSqpRangeListMap.erase(variable);
75 72
76 73 auto clearCacheMessage
77 74 = (nbEntries != 0)
78 75 ? tr("Variable cache cleared for variable %1").arg(variable->name())
79 76 : tr("No deletion of variable cache: no cache was associated with the variable");
80 77 qCDebug(LOG_VariableCacheController()) << clearCacheMessage;
81 78 }
82 79
83 QVector<SqpDateTime>
80 QVector<SqpRange>
84 81 VariableCacheController::provideNotInCacheDateTimeList(std::shared_ptr<Variable> variable,
85 const SqpDateTime &dateTime)
82 const SqpRange &dateTime)
86 83 {
87 84 qCDebug(LOG_VariableCacheController())
88 85 << "VariableCacheController::provideNotInCacheDateTimeList"
89 86 << QThread::currentThread()->objectName();
90 auto notInCache = QVector<SqpDateTime>{};
87 auto notInCache = QVector<SqpRange>{};
91 88
92 89 // This algorithm is recursif. The idea is to localise the start time then the end time in the
93 90 // list of date time request associated to the variable
94 91 // We assume that the list is ordered in a way that l(0) < l(1). We assume also a < b
95 // (with a & b of type SqpDateTime) means ts(b) > te(a)
96 auto it = impl->m_VariableToSqpDateTimeListMap.find(variable);
97 if (it != impl->m_VariableToSqpDateTimeListMap.end()) {
92 // (with a & b of type SqpRange) means ts(b) > te(a)
93 auto it = impl->m_VariableToSqpRangeListMap.find(variable);
94 if (it != impl->m_VariableToSqpRangeListMap.end()) {
98 95 impl->addInCacheDataByStart(dateTime, it->second, notInCache, 0, dateTime.m_TStart);
99 96 }
100 97 else {
101 98 notInCache << dateTime;
102 99 }
103 100
104 101 return notInCache;
105 102 }
106 103
107 QVector<SqpDateTime>
104 QVector<SqpRange>
108 105 VariableCacheController::dateCacheList(std::shared_ptr<Variable> variable) const noexcept
109 106 {
110 107 qCDebug(LOG_VariableCacheController()) << "VariableCacheController::dateCacheList"
111 108 << QThread::currentThread()->objectName();
112 109 try {
113 return impl->m_VariableToSqpDateTimeListMap.at(variable);
110 return impl->m_VariableToSqpRangeListMap.at(variable);
114 111 }
115 112 catch (const std::out_of_range &e) {
116 113 qCWarning(LOG_VariableCacheController()) << e.what();
117 return QVector<SqpDateTime>{};
114 return QVector<SqpRange>{};
118 115 }
119 116 }
120 117
121 118 void VariableCacheController::VariableCacheControllerPrivate::addDateTimeRecurse(
122 const SqpDateTime &dateTime, QVector<SqpDateTime> &dateTimeList, int cacheIndex)
119 const SqpRange &dateTime, QVector<SqpRange> &dateTimeList, int cacheIndex)
123 120 {
124 121 const auto dateTimeListSize = dateTimeList.count();
125 122 if (cacheIndex >= dateTimeListSize) {
126 123 dateTimeList.push_back(dateTime);
127 124 // there is no anymore interval to compore, we can just push_back it
128 125 return;
129 126 }
130 127
131 128 auto currentDateTime = dateTimeList[cacheIndex];
132 129
133 130 if (dateTime.m_TEnd < currentDateTime.m_TStart) {
134 131 // The compared one is < to current one compared, we can insert it
135 132 dateTimeList.insert(cacheIndex, dateTime);
136 133 }
137 134 else if (dateTime.m_TStart > currentDateTime.m_TEnd) {
138 135 // The compared one is > to current one compared we can comparet if to the next one
139 136 addDateTimeRecurse(dateTime, dateTimeList, ++cacheIndex);
140 137 }
141 138 else {
142 139 // Merge cases: we need to merge the two interval, remove the old one from the list then
143 140 // rerun the algo from this index with the merged interval
144 141 auto mTStart = std::min(dateTime.m_TStart, currentDateTime.m_TStart);
145 142 auto mTEnd = std::max(dateTime.m_TEnd, currentDateTime.m_TEnd);
146 auto mergeDateTime = SqpDateTime{mTStart, mTEnd};
143 auto mergeDateTime = SqpRange{mTStart, mTEnd};
147 144
148 145 dateTimeList.remove(cacheIndex);
149 146 addDateTimeRecurse(mergeDateTime, dateTimeList, cacheIndex);
150 147 }
151 148 }
152 149
153 150
154 151 void VariableCacheController::VariableCacheControllerPrivate::addInCacheDataByEnd(
155 const SqpDateTime &dateTime, QVector<SqpDateTime> &dateTimeList,
156 QVector<SqpDateTime> &notInCache, int cacheIndex, double currentTStart)
152 const SqpRange &dateTime, QVector<SqpRange> &dateTimeList, QVector<SqpRange> &notInCache,
153 int cacheIndex, double currentTStart)
157 154 {
158 155 const auto dateTimeListSize = dateTimeList.count();
159 156 if (cacheIndex >= dateTimeListSize) {
160 157 if (currentTStart < dateTime.m_TEnd) {
161 158
162 159 // te localised after all other interval: The last interval is [currentTsart, te]
163 notInCache.push_back(SqpDateTime{currentTStart, dateTime.m_TEnd});
160 notInCache.push_back(SqpRange{currentTStart, dateTime.m_TEnd});
164 161 }
165 162 return;
166 163 }
167 164
168 165 auto currentDateTimeJ = dateTimeList[cacheIndex];
169 166 if (dateTime.m_TEnd <= currentDateTimeJ.m_TStart) {
170 167 // te localised between to interval: The last interval is [currentTsart, te]
171 notInCache.push_back(SqpDateTime{currentTStart, dateTime.m_TEnd});
168 notInCache.push_back(SqpRange{currentTStart, dateTime.m_TEnd});
172 169 }
173 170 else {
174 notInCache.push_back(SqpDateTime{currentTStart, currentDateTimeJ.m_TStart});
171 notInCache.push_back(SqpRange{currentTStart, currentDateTimeJ.m_TStart});
175 172 if (dateTime.m_TEnd > currentDateTimeJ.m_TEnd) {
176 173 // te not localised before the current interval: we need to look at the next interval
177 174 addInCacheDataByEnd(dateTime, dateTimeList, notInCache, ++cacheIndex,
178 175 currentDateTimeJ.m_TEnd);
179 176 }
180 177 }
181 178 }
182 179
183 180 void VariableCacheController::VariableCacheControllerPrivate::addInCacheDataByStart(
184 const SqpDateTime &dateTime, QVector<SqpDateTime> &dateTimeList,
185 QVector<SqpDateTime> &notInCache, int cacheIndex, double currentTStart)
181 const SqpRange &dateTime, QVector<SqpRange> &dateTimeList, QVector<SqpRange> &notInCache,
182 int cacheIndex, double currentTStart)
186 183 {
187 184 const auto dateTimeListSize = dateTimeList.count();
188 185 if (cacheIndex >= dateTimeListSize) {
189 186 // ts localised after all other interval: The last interval is [ts, te]
190 notInCache.push_back(SqpDateTime{currentTStart, dateTime.m_TEnd});
187 notInCache.push_back(SqpRange{currentTStart, dateTime.m_TEnd});
191 188 return;
192 189 }
193 190
194 191 auto currentDateTimeI = dateTimeList[cacheIndex];
195 192 if (currentTStart < currentDateTimeI.m_TStart) {
196 193
197 194 // ts localised between to interval: let's localized te
198 195 addInCacheDataByEnd(dateTime, dateTimeList, notInCache, cacheIndex, currentTStart);
199 196 }
200 197 else if (currentTStart < currentDateTimeI.m_TEnd) {
201 198 if (dateTime.m_TEnd > currentDateTimeI.m_TEnd) {
202 199 // ts not localised before the current interval: we need to look at the next interval
203 200 // We can assume now current tstart is the last interval tend, because data between them
204 201 // are
205 202 // in the cache
206 203 addInCacheDataByStart(dateTime, dateTimeList, notInCache, ++cacheIndex,
207 204 currentDateTimeI.m_TEnd);
208 205 }
209 206 }
210 207 else {
211 208 // ts not localised before the current interval: we need to look at the next interval
212 209 addInCacheDataByStart(dateTime, dateTimeList, notInCache, ++cacheIndex, currentTStart);
213 210 }
214 211 }
215 212
216 213
217 214 void VariableCacheController::displayCache(std::shared_ptr<Variable> variable) const
218 215 {
219 auto variableDateTimeList = impl->m_VariableToSqpDateTimeListMap.find(variable);
220 if (variableDateTimeList != impl->m_VariableToSqpDateTimeListMap.end()) {
216 auto variableDateTimeList = impl->m_VariableToSqpRangeListMap.find(variable);
217 if (variableDateTimeList != impl->m_VariableToSqpRangeListMap.end()) {
221 218 qCInfo(LOG_VariableCacheController()) << tr("VariableCacheController::displayCache")
222 219 << variableDateTimeList->second;
223 220 }
224 221 else {
225 222 qCWarning(LOG_VariableCacheController())
226 223 << tr("Cannot display a variable that is not in the cache");
227 224 }
228 225 }
@@ -1,243 +1,243
1 1 #include <Variable/Variable.h>
2 2 #include <Variable/VariableCacheController.h>
3 3 #include <Variable/VariableController.h>
4 4 #include <Variable/VariableModel.h>
5 5
6 6 #include <Data/DataProviderParameters.h>
7 7 #include <Data/IDataProvider.h>
8 8 #include <Data/IDataSeries.h>
9 9 #include <Time/TimeController.h>
10 10
11 11 #include <QMutex>
12 12 #include <QThread>
13 13 #include <QUuid>
14 14 #include <QtCore/QItemSelectionModel>
15 15
16 16 #include <unordered_map>
17 17
18 18 Q_LOGGING_CATEGORY(LOG_VariableController, "VariableController")
19 19
20 20 struct VariableController::VariableControllerPrivate {
21 21 explicit VariableControllerPrivate(VariableController *parent)
22 22 : m_WorkingMutex{},
23 23 m_VariableModel{new VariableModel{parent}},
24 24 m_VariableSelectionModel{new QItemSelectionModel{m_VariableModel, parent}},
25 25 m_VariableCacheController{std::make_unique<VariableCacheController>()}
26 26 {
27 27 }
28 28
29 29 QMutex m_WorkingMutex;
30 30 /// Variable model. The VariableController has the ownership
31 31 VariableModel *m_VariableModel;
32 32 QItemSelectionModel *m_VariableSelectionModel;
33 33
34 34
35 35 TimeController *m_TimeController{nullptr};
36 36 std::unique_ptr<VariableCacheController> m_VariableCacheController;
37 37
38 38 std::unordered_map<std::shared_ptr<Variable>, std::shared_ptr<IDataProvider> >
39 39 m_VariableToProviderMap;
40 40 std::unordered_map<std::shared_ptr<Variable>, QUuid> m_VariableToIdentifierMap;
41 41 };
42 42
43 43 VariableController::VariableController(QObject *parent)
44 44 : QObject{parent}, impl{spimpl::make_unique_impl<VariableControllerPrivate>(this)}
45 45 {
46 46 qCDebug(LOG_VariableController()) << tr("VariableController construction")
47 47 << QThread::currentThread();
48 48
49 49 connect(impl->m_VariableModel, &VariableModel::abortProgessRequested, this,
50 50 &VariableController::onAbortProgressRequested);
51 51 }
52 52
53 53 VariableController::~VariableController()
54 54 {
55 55 qCDebug(LOG_VariableController()) << tr("VariableController destruction")
56 56 << QThread::currentThread();
57 57 this->waitForFinish();
58 58 }
59 59
60 60 VariableModel *VariableController::variableModel() noexcept
61 61 {
62 62 return impl->m_VariableModel;
63 63 }
64 64
65 65 QItemSelectionModel *VariableController::variableSelectionModel() noexcept
66 66 {
67 67 return impl->m_VariableSelectionModel;
68 68 }
69 69
70 70 void VariableController::setTimeController(TimeController *timeController) noexcept
71 71 {
72 72 impl->m_TimeController = timeController;
73 73 }
74 74
75 75 void VariableController::deleteVariable(std::shared_ptr<Variable> variable) noexcept
76 76 {
77 77 if (!variable) {
78 78 qCCritical(LOG_VariableController()) << "Can't delete variable: variable is null";
79 79 return;
80 80 }
81 81
82 82 // Spreads in SciQlop that the variable will be deleted, so that potential receivers can
83 83 // make some treatments before the deletion
84 84 emit variableAboutToBeDeleted(variable);
85 85
86 86 // Deletes identifier
87 87 impl->m_VariableToIdentifierMap.erase(variable);
88 88
89 89 // Deletes provider
90 90 auto nbProvidersDeleted = impl->m_VariableToProviderMap.erase(variable);
91 91 qCDebug(LOG_VariableController())
92 92 << tr("Number of providers deleted for variable %1: %2")
93 93 .arg(variable->name(), QString::number(nbProvidersDeleted));
94 94
95 95 // Clears cache
96 96 impl->m_VariableCacheController->clear(variable);
97 97
98 98 // Deletes from model
99 99 impl->m_VariableModel->deleteVariable(variable);
100 100 }
101 101
102 102 void VariableController::deleteVariables(
103 103 const QVector<std::shared_ptr<Variable> > &variables) noexcept
104 104 {
105 105 for (auto variable : qAsConst(variables)) {
106 106 deleteVariable(variable);
107 107 }
108 108 }
109 109
110 110 void VariableController::abortProgress(std::shared_ptr<Variable> variable)
111 111 {
112 112 }
113 113
114 114 void VariableController::createVariable(const QString &name, const QVariantHash &metadata,
115 115 std::shared_ptr<IDataProvider> provider) noexcept
116 116 {
117 117
118 118 if (!impl->m_TimeController) {
119 119 qCCritical(LOG_VariableController())
120 120 << tr("Impossible to create variable: The time controller is null");
121 121 return;
122 122 }
123 123
124 124 auto dateTime = impl->m_TimeController->dateTime();
125 125
126 126 if (auto newVariable = impl->m_VariableModel->createVariable(name, dateTime, metadata)) {
127 127 auto identifier = QUuid::createUuid();
128 128
129 129 // store the provider
130 130 impl->m_VariableToProviderMap[newVariable] = provider;
131 131 impl->m_VariableToIdentifierMap[newVariable] = identifier;
132 132
133 133 auto addDateTimeAcquired = [ this, varW = std::weak_ptr<Variable>{newVariable} ](
134 134 QUuid identifier, auto dataSeriesAcquired, auto dateTimeToPutInCache)
135 135 {
136 136 if (auto variable = varW.lock()) {
137 137 auto varIdentifier = impl->m_VariableToIdentifierMap.at(variable);
138 138 if (varIdentifier == identifier) {
139 139 impl->m_VariableCacheController->addDateTime(variable, dateTimeToPutInCache);
140 140 variable->setDataSeries(dataSeriesAcquired);
141 141 emit variable->updated();
142 142 }
143 143 }
144 144 };
145 145
146 146 connect(provider.get(), &IDataProvider::dataProvided, addDateTimeAcquired);
147 147 connect(provider.get(), &IDataProvider::dataProvidedProgress, this,
148 148 &VariableController::onVariableRetrieveDataInProgress);
149 149 this->onRequestDataLoading(newVariable, dateTime);
150 150 }
151 151 }
152 152
153 void VariableController::onDateTimeOnSelection(const SqpDateTime &dateTime)
153 void VariableController::onDateTimeOnSelection(const SqpRange &dateTime)
154 154 {
155 155 qCDebug(LOG_VariableController()) << "VariableController::onDateTimeOnSelection"
156 156 << QThread::currentThread()->objectName();
157 157 auto selectedRows = impl->m_VariableSelectionModel->selectedRows();
158 158
159 159 for (const auto &selectedRow : qAsConst(selectedRows)) {
160 160 if (auto selectedVariable = impl->m_VariableModel->variable(selectedRow.row())) {
161 161 selectedVariable->setDateTime(dateTime);
162 162 this->onRequestDataLoading(selectedVariable, dateTime);
163 163
164 164 // notify that rescale operation has to be done
165 165 emit rangeChanged(selectedVariable, dateTime);
166 166 }
167 167 }
168 168 }
169 169
170 170 void VariableController::onVariableRetrieveDataInProgress(QUuid identifier, double progress)
171 171 {
172 172 auto findReply = [identifier](const auto &entry) { return identifier == entry.second; };
173 173
174 174 auto end = impl->m_VariableToIdentifierMap.cend();
175 175 auto it = std::find_if(impl->m_VariableToIdentifierMap.cbegin(), end, findReply);
176 176 if (it != end) {
177 177 impl->m_VariableModel->setDataProgress(it->first, progress);
178 178 }
179 179 }
180 180
181 181 void VariableController::onAbortProgressRequested(std::shared_ptr<Variable> variable)
182 182 {
183 183 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAbortProgressRequested"
184 184 << QThread::currentThread()->objectName();
185 185
186 186 auto it = impl->m_VariableToIdentifierMap.find(variable);
187 187 if (it != impl->m_VariableToIdentifierMap.cend()) {
188 188 impl->m_VariableToProviderMap.at(variable)->requestDataAborting(it->second);
189 189 }
190 190 else {
191 191 qCWarning(LOG_VariableController())
192 192 << tr("Aborting progression of inexistant variable detected !!!")
193 193 << QThread::currentThread()->objectName();
194 194 }
195 195 }
196 196
197 197
198 198 void VariableController::onRequestDataLoading(std::shared_ptr<Variable> variable,
199 const SqpDateTime &dateTime)
199 const SqpRange &dateTime)
200 200 {
201 201 qCDebug(LOG_VariableController()) << "VariableController::onRequestDataLoading"
202 202 << QThread::currentThread()->objectName();
203 203 // we want to load data of the variable for the dateTime.
204 204 // First we check if the cache contains some of them.
205 205 // For the other, we ask the provider to give them.
206 206 if (variable) {
207 207
208 208 auto dateTimeListNotInCache
209 209 = impl->m_VariableCacheController->provideNotInCacheDateTimeList(variable, dateTime);
210 210
211 211 if (!dateTimeListNotInCache.empty()) {
212 212 // Ask the provider for each data on the dateTimeListNotInCache
213 213 auto identifier = impl->m_VariableToIdentifierMap.at(variable);
214 214 impl->m_VariableToProviderMap.at(variable)->requestDataLoading(
215 215 identifier,
216 216 DataProviderParameters{std::move(dateTimeListNotInCache), variable->metadata()});
217 217 }
218 218 else {
219 219 emit variable->updated();
220 220 }
221 221 }
222 222 else {
223 223 qCCritical(LOG_VariableController()) << tr("Impossible to load data of a variable null");
224 224 }
225 225 }
226 226
227 227
228 228 void VariableController::initialize()
229 229 {
230 230 qCDebug(LOG_VariableController()) << tr("VariableController init") << QThread::currentThread();
231 231 impl->m_WorkingMutex.lock();
232 232 qCDebug(LOG_VariableController()) << tr("VariableController init END");
233 233 }
234 234
235 235 void VariableController::finalize()
236 236 {
237 237 impl->m_WorkingMutex.unlock();
238 238 }
239 239
240 240 void VariableController::waitForFinish()
241 241 {
242 242 QMutexLocker locker{&impl->m_WorkingMutex};
243 243 }
@@ -1,249 +1,249
1 1 #include <Variable/Variable.h>
2 2 #include <Variable/VariableModel.h>
3 3
4 4 #include <Common/DateUtils.h>
5 5
6 6 #include <Data/IDataSeries.h>
7 7
8 8 #include <QSize>
9 9 #include <unordered_map>
10 10
11 11 Q_LOGGING_CATEGORY(LOG_VariableModel, "VariableModel")
12 12
13 13 namespace {
14 14
15 15 // Column indexes
16 16 const auto NAME_COLUMN = 0;
17 17 const auto TSTART_COLUMN = 1;
18 18 const auto TEND_COLUMN = 2;
19 19 const auto NB_COLUMNS = 3;
20 20
21 21 // Column properties
22 22 const auto DEFAULT_HEIGHT = 25;
23 23 const auto DEFAULT_WIDTH = 100;
24 24
25 25 struct ColumnProperties {
26 26 ColumnProperties(const QString &name = {}, int width = DEFAULT_WIDTH,
27 27 int height = DEFAULT_HEIGHT)
28 28 : m_Name{name}, m_Width{width}, m_Height{height}
29 29 {
30 30 }
31 31
32 32 QString m_Name;
33 33 int m_Width;
34 34 int m_Height;
35 35 };
36 36
37 37 const auto COLUMN_PROPERTIES
38 38 = QHash<int, ColumnProperties>{{NAME_COLUMN, {QObject::tr("Name")}},
39 39 {TSTART_COLUMN, {QObject::tr("tStart"), 180}},
40 40 {TEND_COLUMN, {QObject::tr("tEnd"), 180}}};
41 41
42 42 /// Format for datetimes
43 43 const auto DATETIME_FORMAT = QStringLiteral("dd/MM/yyyy \nhh:mm:ss:zzz");
44 44
45 45
46 46 } // namespace
47 47
48 48 struct VariableModel::VariableModelPrivate {
49 49 /// Variables created in SciQlop
50 50 std::vector<std::shared_ptr<Variable> > m_Variables;
51 51 std::unordered_map<std::shared_ptr<Variable>, double> m_VariableToProgress;
52 52
53 53 /// Return the row index of the variable. -1 if it's not found
54 54 int indexOfVariable(Variable *variable) const noexcept;
55 55 };
56 56
57 57 VariableModel::VariableModel(QObject *parent)
58 58 : QAbstractTableModel{parent}, impl{spimpl::make_unique_impl<VariableModelPrivate>()}
59 59 {
60 60 }
61 61
62 62 std::shared_ptr<Variable> VariableModel::createVariable(const QString &name,
63 const SqpDateTime &dateTime,
63 const SqpRange &dateTime,
64 64 const QVariantHash &metadata) noexcept
65 65 {
66 66 auto insertIndex = rowCount();
67 67 beginInsertRows({}, insertIndex, insertIndex);
68 68
69 69 auto variable = std::make_shared<Variable>(name, dateTime, metadata);
70 70
71 71 impl->m_Variables.push_back(variable);
72 72 connect(variable.get(), &Variable::updated, this, &VariableModel::onVariableUpdated);
73 73
74 74 endInsertRows();
75 75
76 76 return variable;
77 77 }
78 78
79 79 void VariableModel::deleteVariable(std::shared_ptr<Variable> variable) noexcept
80 80 {
81 81 if (!variable) {
82 82 qCCritical(LOG_Variable()) << "Can't delete a null variable from the model";
83 83 return;
84 84 }
85 85
86 86 // Finds variable in the model
87 87 auto begin = impl->m_Variables.cbegin();
88 88 auto end = impl->m_Variables.cend();
89 89 auto it = std::find(begin, end, variable);
90 90 if (it != end) {
91 91 auto removeIndex = std::distance(begin, it);
92 92
93 93 // Deletes variable
94 94 beginRemoveRows({}, removeIndex, removeIndex);
95 95 impl->m_Variables.erase(it);
96 96 endRemoveRows();
97 97 }
98 98 else {
99 99 qCritical(LOG_VariableModel())
100 100 << tr("Can't delete variable %1 from the model: the variable is not in the model")
101 101 .arg(variable->name());
102 102 }
103 103
104 104 // Removes variable from progress map
105 105 impl->m_VariableToProgress.erase(variable);
106 106 }
107 107
108 108
109 109 std::shared_ptr<Variable> VariableModel::variable(int index) const
110 110 {
111 111 return (index >= 0 && index < impl->m_Variables.size()) ? impl->m_Variables[index] : nullptr;
112 112 }
113 113
114 114 void VariableModel::setDataProgress(std::shared_ptr<Variable> variable, double progress)
115 115 {
116 116 if (progress > 0.0) {
117 117 impl->m_VariableToProgress[variable] = progress;
118 118 }
119 119 else {
120 120 impl->m_VariableToProgress.erase(variable);
121 121 }
122 122 auto modelIndex = createIndex(impl->indexOfVariable(variable.get()), NAME_COLUMN);
123 123
124 124 emit dataChanged(modelIndex, modelIndex);
125 125 }
126 126
127 127 int VariableModel::columnCount(const QModelIndex &parent) const
128 128 {
129 129 Q_UNUSED(parent);
130 130
131 131 return NB_COLUMNS;
132 132 }
133 133
134 134 int VariableModel::rowCount(const QModelIndex &parent) const
135 135 {
136 136 Q_UNUSED(parent);
137 137
138 138 return impl->m_Variables.size();
139 139 }
140 140
141 141 QVariant VariableModel::data(const QModelIndex &index, int role) const
142 142 {
143 143 if (!index.isValid()) {
144 144 return QVariant{};
145 145 }
146 146
147 147 if (index.row() < 0 || index.row() >= rowCount()) {
148 148 return QVariant{};
149 149 }
150 150
151 151 if (role == Qt::DisplayRole) {
152 152 if (auto variable = impl->m_Variables.at(index.row()).get()) {
153 153 /// Lambda function that builds the variant to return for a time value
154 154 auto dateTimeVariant = [](double secs) {
155 155 auto dateTime = DateUtils::dateTime(secs);
156 156 return dateTime.toString(DATETIME_FORMAT);
157 157 };
158 158
159 159 switch (index.column()) {
160 160 case NAME_COLUMN:
161 161 return variable->name();
162 162 case TSTART_COLUMN:
163 163 return dateTimeVariant(variable->dateTime().m_TStart);
164 164 case TEND_COLUMN:
165 165 return dateTimeVariant(variable->dateTime().m_TEnd);
166 166 default:
167 167 // No action
168 168 break;
169 169 }
170 170
171 171 qWarning(LOG_VariableModel())
172 172 << tr("Can't get data (unknown column %1)").arg(index.column());
173 173 }
174 174 else {
175 175 qWarning(LOG_VariableModel()) << tr("Can't get data (no variable)");
176 176 }
177 177 }
178 178 else if (role == VariableRoles::ProgressRole) {
179 179 if (auto variable = impl->m_Variables.at(index.row())) {
180 180
181 181 auto it = impl->m_VariableToProgress.find(variable);
182 182 if (it != impl->m_VariableToProgress.cend()) {
183 183 return it->second;
184 184 }
185 185 }
186 186 }
187 187
188 188 return QVariant{};
189 189 }
190 190
191 191 QVariant VariableModel::headerData(int section, Qt::Orientation orientation, int role) const
192 192 {
193 193 if (role != Qt::DisplayRole && role != Qt::SizeHintRole) {
194 194 return QVariant{};
195 195 }
196 196
197 197 if (orientation == Qt::Horizontal) {
198 198 auto propertiesIt = COLUMN_PROPERTIES.find(section);
199 199 if (propertiesIt != COLUMN_PROPERTIES.cend()) {
200 200 // Role is either DisplayRole or SizeHintRole
201 201 return (role == Qt::DisplayRole)
202 202 ? QVariant{propertiesIt->m_Name}
203 203 : QVariant{QSize{propertiesIt->m_Width, propertiesIt->m_Height}};
204 204 }
205 205 else {
206 206 qWarning(LOG_VariableModel())
207 207 << tr("Can't get header data (unknown column %1)").arg(section);
208 208 }
209 209 }
210 210
211 211 return QVariant{};
212 212 }
213 213
214 214 void VariableModel::abortProgress(const QModelIndex &index)
215 215 {
216 216 if (auto variable = impl->m_Variables.at(index.row())) {
217 217 emit abortProgessRequested(variable);
218 218 }
219 219 }
220 220
221 221 void VariableModel::onVariableUpdated() noexcept
222 222 {
223 223 // Finds variable that has been updated in the model
224 224 if (auto updatedVariable = dynamic_cast<Variable *>(sender())) {
225 225 auto updatedVariableIndex = impl->indexOfVariable(updatedVariable);
226 226
227 227 if (updatedVariableIndex > -1) {
228 228 emit dataChanged(createIndex(updatedVariableIndex, 0),
229 229 createIndex(updatedVariableIndex, columnCount() - 1));
230 230 }
231 231 }
232 232 }
233 233
234 234 int VariableModel::VariableModelPrivate::indexOfVariable(Variable *variable) const noexcept
235 235 {
236 236 auto begin = std::cbegin(m_Variables);
237 237 auto end = std::cend(m_Variables);
238 238 auto it
239 239 = std::find_if(begin, end, [variable](const auto &var) { return var.get() == variable; });
240 240
241 241 if (it != end) {
242 242 // Gets the index of the variable in the model: we assume here that views have the same
243 243 // order as the model
244 244 return std::distance(begin, it);
245 245 }
246 246 else {
247 247 return -1;
248 248 }
249 249 }
@@ -1,353 +1,353
1 1 #include <Variable/Variable.h>
2 2 #include <Variable/VariableCacheController.h>
3 3
4 4 #include <QObject>
5 5 #include <QtTest>
6 6
7 7 #include <memory>
8 8
9 9 class TestVariableCacheController : public QObject {
10 10 Q_OBJECT
11 11
12 12 private slots:
13 13 void testProvideNotInCacheDateTimeList();
14 14
15 15 void testAddDateTime();
16 16 };
17 17
18 18
19 19 void TestVariableCacheController::testProvideNotInCacheDateTimeList()
20 20 {
21 21 VariableCacheController variableCacheController{};
22 22
23 23 auto ts0 = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 0, 0}};
24 24 auto te0 = QDateTime{QDate{2017, 01, 01}, QTime{2, 4, 0, 0}};
25 auto sqp0 = SqpDateTime{static_cast<double>(ts0.toMSecsSinceEpoch()),
26 static_cast<double>(te0.toMSecsSinceEpoch())};
25 auto sqp0 = SqpRange{static_cast<double>(ts0.toMSecsSinceEpoch()),
26 static_cast<double>(te0.toMSecsSinceEpoch())};
27 27
28 28 auto ts1 = QDateTime{QDate{2017, 01, 01}, QTime{2, 6, 0, 0}};
29 29 auto te1 = QDateTime{QDate{2017, 01, 01}, QTime{2, 8, 0, 0}};
30 auto sqp1 = SqpDateTime{static_cast<double>(ts1.toMSecsSinceEpoch()),
31 static_cast<double>(te1.toMSecsSinceEpoch())};
30 auto sqp1 = SqpRange{static_cast<double>(ts1.toMSecsSinceEpoch()),
31 static_cast<double>(te1.toMSecsSinceEpoch())};
32 32
33 33 auto ts2 = QDateTime{QDate{2017, 01, 01}, QTime{2, 18, 0, 0}};
34 34 auto te2 = QDateTime{QDate{2017, 01, 01}, QTime{2, 20, 0, 0}};
35 auto sqp2 = SqpDateTime{static_cast<double>(ts2.toMSecsSinceEpoch()),
36 static_cast<double>(te2.toMSecsSinceEpoch())};
35 auto sqp2 = SqpRange{static_cast<double>(ts2.toMSecsSinceEpoch()),
36 static_cast<double>(te2.toMSecsSinceEpoch())};
37 37
38 38 auto var0 = std::make_shared<Variable>("", sqp0);
39 39
40 40 variableCacheController.addDateTime(var0, sqp0);
41 41 variableCacheController.addDateTime(var0, sqp1);
42 42 variableCacheController.addDateTime(var0, sqp2);
43 43
44 44 // first case [ts,te] < ts0
45 45 auto ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 0, 0, 0}};
46 46 auto te = QDateTime{QDate{2017, 01, 01}, QTime{2, 1, 0, 0}};
47 auto sqp = SqpDateTime{static_cast<double>(ts.toMSecsSinceEpoch()),
48 static_cast<double>(te.toMSecsSinceEpoch())};
47 auto sqp = SqpRange{static_cast<double>(ts.toMSecsSinceEpoch()),
48 static_cast<double>(te.toMSecsSinceEpoch())};
49 49
50 50
51 51 auto notInCach = variableCacheController.provideNotInCacheDateTimeList(var0, sqp);
52 52
53 53 QCOMPARE(notInCach.size(), 1);
54 54 auto notInCacheSqp = notInCach.first();
55 55 QCOMPARE(notInCacheSqp.m_TStart, static_cast<double>(ts.toMSecsSinceEpoch()));
56 56 QCOMPARE(notInCacheSqp.m_TEnd, static_cast<double>(te.toMSecsSinceEpoch()));
57 57
58 58
59 59 // second case ts < ts0 && ts0 < te <= te0
60 60 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 0, 0, 0}};
61 61 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 30, 0}};
62 sqp = SqpDateTime{static_cast<double>(ts.toMSecsSinceEpoch()),
63 static_cast<double>(te.toMSecsSinceEpoch())};
62 sqp = SqpRange{static_cast<double>(ts.toMSecsSinceEpoch()),
63 static_cast<double>(te.toMSecsSinceEpoch())};
64 64
65 65
66 66 notInCach = variableCacheController.provideNotInCacheDateTimeList(var0, sqp);
67 67
68 68 QCOMPARE(notInCach.size(), 1);
69 69 notInCacheSqp = notInCach.first();
70 70 QCOMPARE(notInCacheSqp.m_TStart, static_cast<double>(ts.toMSecsSinceEpoch()));
71 71 QCOMPARE(notInCacheSqp.m_TEnd, static_cast<double>(ts0.toMSecsSinceEpoch()));
72 72
73 73 // 3th case ts < ts0 && te0 < te <= ts1
74 74 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 0, 0, 0}};
75 75 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 5, 0, 0}};
76 sqp = SqpDateTime{static_cast<double>(ts.toMSecsSinceEpoch()),
77 static_cast<double>(te.toMSecsSinceEpoch())};
76 sqp = SqpRange{static_cast<double>(ts.toMSecsSinceEpoch()),
77 static_cast<double>(te.toMSecsSinceEpoch())};
78 78
79 79
80 80 notInCach = variableCacheController.provideNotInCacheDateTimeList(var0, sqp);
81 81
82 82 QCOMPARE(notInCach.size(), 2);
83 83 notInCacheSqp = notInCach.first();
84 84 QCOMPARE(notInCacheSqp.m_TStart, static_cast<double>(ts.toMSecsSinceEpoch()));
85 85 QCOMPARE(notInCacheSqp.m_TEnd, static_cast<double>(ts0.toMSecsSinceEpoch()));
86 86
87 87 notInCacheSqp = notInCach.at(1);
88 88 QCOMPARE(notInCacheSqp.m_TStart, static_cast<double>(te0.toMSecsSinceEpoch()));
89 89 QCOMPARE(notInCacheSqp.m_TEnd, static_cast<double>(te.toMSecsSinceEpoch()));
90 90
91 91 // 4th case ts < ts0 && ts1 < te <= te1
92 92 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 0, 0, 0}};
93 93 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 7, 0, 0}};
94 sqp = SqpDateTime{static_cast<double>(ts.toMSecsSinceEpoch()),
95 static_cast<double>(te.toMSecsSinceEpoch())};
94 sqp = SqpRange{static_cast<double>(ts.toMSecsSinceEpoch()),
95 static_cast<double>(te.toMSecsSinceEpoch())};
96 96
97 97
98 98 notInCach = variableCacheController.provideNotInCacheDateTimeList(var0, sqp);
99 99
100 100 QCOMPARE(notInCach.size(), 2);
101 101 notInCacheSqp = notInCach.first();
102 102 QCOMPARE(notInCacheSqp.m_TStart, static_cast<double>(ts.toMSecsSinceEpoch()));
103 103 QCOMPARE(notInCacheSqp.m_TEnd, static_cast<double>(ts0.toMSecsSinceEpoch()));
104 104
105 105 notInCacheSqp = notInCach.at(1);
106 106 QCOMPARE(notInCacheSqp.m_TStart, static_cast<double>(te0.toMSecsSinceEpoch()));
107 107 QCOMPARE(notInCacheSqp.m_TEnd, static_cast<double>(ts1.toMSecsSinceEpoch()));
108 108
109 109 // 5th case ts < ts0 && te3 < te
110 110 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 0, 0, 0}};
111 111 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 22, 0, 0}};
112 sqp = SqpDateTime{static_cast<double>(ts.toMSecsSinceEpoch()),
113 static_cast<double>(te.toMSecsSinceEpoch())};
112 sqp = SqpRange{static_cast<double>(ts.toMSecsSinceEpoch()),
113 static_cast<double>(te.toMSecsSinceEpoch())};
114 114
115 115
116 116 notInCach = variableCacheController.provideNotInCacheDateTimeList(var0, sqp);
117 117
118 118 QCOMPARE(notInCach.size(), 4);
119 119 notInCacheSqp = notInCach.first();
120 120 QCOMPARE(notInCacheSqp.m_TStart, static_cast<double>(ts.toMSecsSinceEpoch()));
121 121 QCOMPARE(notInCacheSqp.m_TEnd, static_cast<double>(ts0.toMSecsSinceEpoch()));
122 122
123 123 notInCacheSqp = notInCach.at(1);
124 124 QCOMPARE(notInCacheSqp.m_TStart, static_cast<double>(te0.toMSecsSinceEpoch()));
125 125 QCOMPARE(notInCacheSqp.m_TEnd, static_cast<double>(ts1.toMSecsSinceEpoch()));
126 126
127 127 notInCacheSqp = notInCach.at(2);
128 128 QCOMPARE(notInCacheSqp.m_TStart, static_cast<double>(te1.toMSecsSinceEpoch()));
129 129 QCOMPARE(notInCacheSqp.m_TEnd, static_cast<double>(ts2.toMSecsSinceEpoch()));
130 130
131 131 notInCacheSqp = notInCach.at(3);
132 132 QCOMPARE(notInCacheSqp.m_TStart, static_cast<double>(te2.toMSecsSinceEpoch()));
133 133 QCOMPARE(notInCacheSqp.m_TEnd, static_cast<double>(te.toMSecsSinceEpoch()));
134 134
135 135
136 136 // 6th case ts2 < ts
137 137 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 45, 0, 0}};
138 138 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 47, 0, 0}};
139 sqp = SqpDateTime{static_cast<double>(ts.toMSecsSinceEpoch()),
140 static_cast<double>(te.toMSecsSinceEpoch())};
139 sqp = SqpRange{static_cast<double>(ts.toMSecsSinceEpoch()),
140 static_cast<double>(te.toMSecsSinceEpoch())};
141 141
142 142
143 143 notInCach = variableCacheController.provideNotInCacheDateTimeList(var0, sqp);
144 144
145 145 QCOMPARE(notInCach.size(), 1);
146 146 notInCacheSqp = notInCach.first();
147 147 QCOMPARE(notInCacheSqp.m_TStart, static_cast<double>(ts.toMSecsSinceEpoch()));
148 148 QCOMPARE(notInCacheSqp.m_TEnd, static_cast<double>(te.toMSecsSinceEpoch()));
149 149
150 150 // 7th case ts = te0 && te < ts1
151 151 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 4, 0, 0}};
152 152 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 5, 0, 0}};
153 sqp = SqpDateTime{static_cast<double>(ts.toMSecsSinceEpoch()),
154 static_cast<double>(te.toMSecsSinceEpoch())};
153 sqp = SqpRange{static_cast<double>(ts.toMSecsSinceEpoch()),
154 static_cast<double>(te.toMSecsSinceEpoch())};
155 155
156 156
157 157 notInCach = variableCacheController.provideNotInCacheDateTimeList(var0, sqp);
158 158
159 159 QCOMPARE(notInCach.size(), 1);
160 160 notInCacheSqp = notInCach.first();
161 161 QCOMPARE(notInCacheSqp.m_TStart, static_cast<double>(te0.toMSecsSinceEpoch()));
162 162 QCOMPARE(notInCacheSqp.m_TEnd, static_cast<double>(te.toMSecsSinceEpoch()));
163 163
164 164 // 8th case ts0 < ts < te0 && te < ts1
165 165 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 30, 0}};
166 166 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 5, 0, 0}};
167 sqp = SqpDateTime{static_cast<double>(ts.toMSecsSinceEpoch()),
168 static_cast<double>(te.toMSecsSinceEpoch())};
167 sqp = SqpRange{static_cast<double>(ts.toMSecsSinceEpoch()),
168 static_cast<double>(te.toMSecsSinceEpoch())};
169 169
170 170
171 171 notInCach = variableCacheController.provideNotInCacheDateTimeList(var0, sqp);
172 172
173 173 QCOMPARE(notInCach.size(), 1);
174 174 notInCacheSqp = notInCach.first();
175 175 QCOMPARE(notInCacheSqp.m_TStart, static_cast<double>(te0.toMSecsSinceEpoch()));
176 176 QCOMPARE(notInCacheSqp.m_TEnd, static_cast<double>(te.toMSecsSinceEpoch()));
177 177
178 178 // 9th case ts0 < ts < te0 && ts1 < te < te1
179 179 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 30, 0}};
180 180 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 7, 0, 0}};
181 sqp = SqpDateTime{static_cast<double>(ts.toMSecsSinceEpoch()),
182 static_cast<double>(te.toMSecsSinceEpoch())};
181 sqp = SqpRange{static_cast<double>(ts.toMSecsSinceEpoch()),
182 static_cast<double>(te.toMSecsSinceEpoch())};
183 183
184 184
185 185 notInCach = variableCacheController.provideNotInCacheDateTimeList(var0, sqp);
186 186
187 187 QCOMPARE(notInCach.size(), 1);
188 188 notInCacheSqp = notInCach.first();
189 189 QCOMPARE(notInCacheSqp.m_TStart, static_cast<double>(te0.toMSecsSinceEpoch()));
190 190 QCOMPARE(notInCacheSqp.m_TEnd, static_cast<double>(ts1.toMSecsSinceEpoch()));
191 191
192 192 // 10th case te1 < ts < te < ts2
193 193 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 9, 0, 0}};
194 194 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 10, 0, 0}};
195 sqp = SqpDateTime{static_cast<double>(ts.toMSecsSinceEpoch()),
196 static_cast<double>(te.toMSecsSinceEpoch())};
195 sqp = SqpRange{static_cast<double>(ts.toMSecsSinceEpoch()),
196 static_cast<double>(te.toMSecsSinceEpoch())};
197 197
198 198
199 199 notInCach = variableCacheController.provideNotInCacheDateTimeList(var0, sqp);
200 200
201 201 QCOMPARE(notInCach.size(), 1);
202 202 notInCacheSqp = notInCach.first();
203 203 QCOMPARE(notInCacheSqp.m_TStart, static_cast<double>(ts.toMSecsSinceEpoch()));
204 204 QCOMPARE(notInCacheSqp.m_TEnd, static_cast<double>(te.toMSecsSinceEpoch()));
205 205
206 206 // 11th case te0 < ts < ts1 && te3 < te
207 207 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 5, 0, 0}};
208 208 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 47, 0, 0}};
209 sqp = SqpDateTime{static_cast<double>(ts.toMSecsSinceEpoch()),
210 static_cast<double>(te.toMSecsSinceEpoch())};
209 sqp = SqpRange{static_cast<double>(ts.toMSecsSinceEpoch()),
210 static_cast<double>(te.toMSecsSinceEpoch())};
211 211
212 212
213 213 notInCach = variableCacheController.provideNotInCacheDateTimeList(var0, sqp);
214 214
215 215 QCOMPARE(notInCach.size(), 3);
216 216 notInCacheSqp = notInCach.first();
217 217 QCOMPARE(notInCacheSqp.m_TStart, static_cast<double>(ts.toMSecsSinceEpoch()));
218 218 QCOMPARE(notInCacheSqp.m_TEnd, static_cast<double>(ts1.toMSecsSinceEpoch()));
219 219
220 220 notInCacheSqp = notInCach.at(1);
221 221 QCOMPARE(notInCacheSqp.m_TStart, static_cast<double>(te1.toMSecsSinceEpoch()));
222 222 QCOMPARE(notInCacheSqp.m_TEnd, static_cast<double>(ts2.toMSecsSinceEpoch()));
223 223
224 224 notInCacheSqp = notInCach.at(2);
225 225 QCOMPARE(notInCacheSqp.m_TStart, static_cast<double>(te2.toMSecsSinceEpoch()));
226 226 QCOMPARE(notInCacheSqp.m_TEnd, static_cast<double>(te.toMSecsSinceEpoch()));
227 227
228 228 // 12th case te0 < ts < ts1 && te3 < te
229 229 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 5, 0, 0}};
230 230 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 10, 0, 0}};
231 sqp = SqpDateTime{static_cast<double>(ts.toMSecsSinceEpoch()),
232 static_cast<double>(te.toMSecsSinceEpoch())};
231 sqp = SqpRange{static_cast<double>(ts.toMSecsSinceEpoch()),
232 static_cast<double>(te.toMSecsSinceEpoch())};
233 233
234 234 notInCach = variableCacheController.provideNotInCacheDateTimeList(var0, sqp);
235 235
236 236 QCOMPARE(notInCach.size(), 2);
237 237 notInCacheSqp = notInCach.first();
238 238 QCOMPARE(notInCacheSqp.m_TStart, static_cast<double>(ts.toMSecsSinceEpoch()));
239 239 QCOMPARE(notInCacheSqp.m_TEnd, static_cast<double>(ts1.toMSecsSinceEpoch()));
240 240
241 241 notInCacheSqp = notInCach.at(1);
242 242 QCOMPARE(notInCacheSqp.m_TStart, static_cast<double>(te1.toMSecsSinceEpoch()));
243 243 QCOMPARE(notInCacheSqp.m_TEnd, static_cast<double>(te.toMSecsSinceEpoch()));
244 244
245 245
246 246 // 12th case ts0 < ts < te0
247 247 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 10, 0}};
248 248 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 50, 0}};
249 sqp = SqpDateTime{static_cast<double>(ts.toMSecsSinceEpoch()),
250 static_cast<double>(te.toMSecsSinceEpoch())};
249 sqp = SqpRange{static_cast<double>(ts.toMSecsSinceEpoch()),
250 static_cast<double>(te.toMSecsSinceEpoch())};
251 251
252 252 notInCach = variableCacheController.provideNotInCacheDateTimeList(var0, sqp);
253 253 QCOMPARE(notInCach.size(), 0);
254 254 }
255 255
256 256
257 257 void TestVariableCacheController::testAddDateTime()
258 258 {
259 259 VariableCacheController variableCacheController{};
260 260
261 261 auto ts0 = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 0, 0}};
262 262 auto te0 = QDateTime{QDate{2017, 01, 01}, QTime{2, 4, 0, 0}};
263 auto sqp0 = SqpDateTime{static_cast<double>(ts0.toMSecsSinceEpoch()),
264 static_cast<double>(te0.toMSecsSinceEpoch())};
263 auto sqp0 = SqpRange{static_cast<double>(ts0.toMSecsSinceEpoch()),
264 static_cast<double>(te0.toMSecsSinceEpoch())};
265 265
266 266 auto ts1 = QDateTime{QDate{2017, 01, 01}, QTime{2, 6, 0, 0}};
267 267 auto te1 = QDateTime{QDate{2017, 01, 01}, QTime{2, 8, 0, 0}};
268 auto sqp1 = SqpDateTime{static_cast<double>(ts1.toMSecsSinceEpoch()),
269 static_cast<double>(te1.toMSecsSinceEpoch())};
268 auto sqp1 = SqpRange{static_cast<double>(ts1.toMSecsSinceEpoch()),
269 static_cast<double>(te1.toMSecsSinceEpoch())};
270 270
271 271 auto ts2 = QDateTime{QDate{2017, 01, 01}, QTime{2, 18, 0, 0}};
272 272 auto te2 = QDateTime{QDate{2017, 01, 01}, QTime{2, 20, 0, 0}};
273 auto sqp2 = SqpDateTime{static_cast<double>(ts2.toMSecsSinceEpoch()),
274 static_cast<double>(te2.toMSecsSinceEpoch())};
273 auto sqp2 = SqpRange{static_cast<double>(ts2.toMSecsSinceEpoch()),
274 static_cast<double>(te2.toMSecsSinceEpoch())};
275 275
276 276 auto ts01 = QDateTime{QDate{2017, 01, 01}, QTime{2, 4, 0, 0}};
277 277 auto te01 = QDateTime{QDate{2017, 01, 01}, QTime{2, 6, 0, 0}};
278 auto sqp01 = SqpDateTime{static_cast<double>(ts01.toMSecsSinceEpoch()),
279 static_cast<double>(te01.toMSecsSinceEpoch())};
278 auto sqp01 = SqpRange{static_cast<double>(ts01.toMSecsSinceEpoch()),
279 static_cast<double>(te01.toMSecsSinceEpoch())};
280 280
281 281 auto ts3 = QDateTime{QDate{2017, 01, 01}, QTime{2, 14, 0, 0}};
282 282 auto te3 = QDateTime{QDate{2017, 01, 01}, QTime{2, 16, 0, 0}};
283 auto sqp3 = SqpDateTime{static_cast<double>(ts3.toMSecsSinceEpoch()),
284 static_cast<double>(te3.toMSecsSinceEpoch())};
283 auto sqp3 = SqpRange{static_cast<double>(ts3.toMSecsSinceEpoch()),
284 static_cast<double>(te3.toMSecsSinceEpoch())};
285 285
286 286 auto ts03 = QDateTime{QDate{2017, 01, 01}, QTime{2, 4, 0, 0}};
287 287 auto te03 = QDateTime{QDate{2017, 01, 01}, QTime{2, 22, 0, 0}};
288 auto sqp03 = SqpDateTime{static_cast<double>(ts03.toMSecsSinceEpoch()),
289 static_cast<double>(te03.toMSecsSinceEpoch())};
288 auto sqp03 = SqpRange{static_cast<double>(ts03.toMSecsSinceEpoch()),
289 static_cast<double>(te03.toMSecsSinceEpoch())};
290 290
291 291
292 292 auto var0 = std::make_shared<Variable>("", sqp0);
293 293
294 294
295 295 // First case: add the first interval to the variable :sqp0
296 296 variableCacheController.addDateTime(var0, sqp0);
297 297 auto dateCacheList = variableCacheController.dateCacheList(var0);
298 298 QCOMPARE(dateCacheList.count(), 1);
299 299 auto dateCache = dateCacheList.at(0);
300 300 QCOMPARE(dateCache.m_TStart, static_cast<double>(ts0.toMSecsSinceEpoch()));
301 301 QCOMPARE(dateCache.m_TEnd, static_cast<double>(te0.toMSecsSinceEpoch()));
302 302
303 303 // 2nd case: add a second interval : sqp1 > sqp0
304 304 variableCacheController.addDateTime(var0, sqp1);
305 305 dateCacheList = variableCacheController.dateCacheList(var0);
306 306 QCOMPARE(dateCacheList.count(), 2);
307 307 dateCache = dateCacheList.at(0);
308 308 QCOMPARE(dateCache.m_TStart, static_cast<double>(ts0.toMSecsSinceEpoch()));
309 309 QCOMPARE(dateCache.m_TEnd, static_cast<double>(te0.toMSecsSinceEpoch()));
310 310
311 311 dateCache = dateCacheList.at(1);
312 312 QCOMPARE(dateCache.m_TStart, static_cast<double>(ts1.toMSecsSinceEpoch()));
313 313 QCOMPARE(dateCache.m_TEnd, static_cast<double>(te1.toMSecsSinceEpoch()));
314 314
315 315 // 3th case: merge sqp0 & sqp1 with sqp01
316 316 variableCacheController.addDateTime(var0, sqp01);
317 317 dateCacheList = variableCacheController.dateCacheList(var0);
318 318 QCOMPARE(dateCacheList.count(), 1);
319 319 dateCache = dateCacheList.at(0);
320 320 QCOMPARE(dateCache.m_TStart, static_cast<double>(ts0.toMSecsSinceEpoch()));
321 321 QCOMPARE(dateCache.m_TEnd, static_cast<double>(te1.toMSecsSinceEpoch()));
322 322
323 323
324 324 // 4th case: add a second interval : sqp1 > sqp0
325 325 variableCacheController.addDateTime(var0, sqp2);
326 326 variableCacheController.addDateTime(var0, sqp3);
327 327 dateCacheList = variableCacheController.dateCacheList(var0);
328 328 QCOMPARE(dateCacheList.count(), 3);
329 329 dateCache = dateCacheList.at(0);
330 330 QCOMPARE(dateCache.m_TStart, static_cast<double>(ts0.toMSecsSinceEpoch()));
331 331 QCOMPARE(dateCache.m_TEnd, static_cast<double>(te1.toMSecsSinceEpoch()));
332 332
333 333 dateCache = dateCacheList.at(1);
334 334 QCOMPARE(dateCache.m_TStart, static_cast<double>(ts3.toMSecsSinceEpoch()));
335 335 QCOMPARE(dateCache.m_TEnd, static_cast<double>(te3.toMSecsSinceEpoch()));
336 336
337 337 dateCache = dateCacheList.at(2);
338 338 QCOMPARE(dateCache.m_TStart, static_cast<double>(ts2.toMSecsSinceEpoch()));
339 339 QCOMPARE(dateCache.m_TEnd, static_cast<double>(te2.toMSecsSinceEpoch()));
340 340
341 341
342 342 // 5th case: merge all interval
343 343 variableCacheController.addDateTime(var0, sqp03);
344 344 dateCacheList = variableCacheController.dateCacheList(var0);
345 345 QCOMPARE(dateCacheList.count(), 1);
346 346 dateCache = dateCacheList.at(0);
347 347 QCOMPARE(dateCache.m_TStart, static_cast<double>(ts0.toMSecsSinceEpoch()));
348 348 QCOMPARE(dateCache.m_TEnd, static_cast<double>(te03.toMSecsSinceEpoch()));
349 349 }
350 350
351 351
352 352 QTEST_MAIN(TestVariableCacheController)
353 353 #include "TestVariableCacheController.moc"
@@ -1,32 +1,32
1 1 #ifndef SCIQLOP_TIMEWIDGET_H
2 2 #define SCIQLOP_TIMEWIDGET_H
3 3
4 4 #include <QWidget>
5 5
6 #include <Data/SqpDateTime.h>
6 #include <Data/SqpRange.h>
7 7
8 8 namespace Ui {
9 9 class TimeWidget;
10 10 } // Ui
11 11
12 12 class TimeWidget : public QWidget {
13 13 Q_OBJECT
14 14
15 15 public:
16 16 explicit TimeWidget(QWidget *parent = 0);
17 17 virtual ~TimeWidget();
18 18
19 19 signals:
20 20 /// Signal emitted when the time parameters has beed updated
21 void timeUpdated(SqpDateTime time);
21 void timeUpdated(SqpRange time);
22 22
23 23 public slots:
24 24 /// slot called when time parameters update has ben requested
25 25 void onTimeUpdateRequested();
26 26
27 27
28 28 private:
29 29 Ui::TimeWidget *ui;
30 30 };
31 31
32 32 #endif // SCIQLOP_ SQPSIDEPANE_H
@@ -1,38 +1,38
1 1 #ifndef SCIQLOP_VISUALIZATIONGRAPHHELPER_H
2 2 #define SCIQLOP_VISUALIZATIONGRAPHHELPER_H
3 3
4 #include <Data/SqpDateTime.h>
4 #include <Data/SqpRange.h>
5 5
6 6 #include <QLoggingCategory>
7 7 #include <QVector>
8 8
9 9 #include <memory>
10 10
11 11 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationGraphHelper)
12 12
13 13 class IDataSeries;
14 14 class QCPAbstractPlottable;
15 15 class QCustomPlot;
16 16 class Variable;
17 17
18 18 /**
19 19 * @brief The VisualizationGraphHelper class aims to create the QCustomPlot components relative to a
20 20 * variable, depending on the data series of this variable
21 21 */
22 22 struct VisualizationGraphHelper {
23 23 /**
24 24 * Creates (if possible) the QCustomPlot components relative to the variable passed in
25 25 * parameter, and adds these to the plot passed in parameter.
26 26 * @param variable the variable for which to create the components
27 27 * @param plot the plot in which to add the created components. It takes ownership of these
28 28 * components.
29 29 * @return the list of the components created
30 30 */
31 31 static QVector<QCPAbstractPlottable *> create(std::shared_ptr<Variable> variable,
32 32 QCustomPlot &plot) noexcept;
33 33
34 34 static void updateData(QVector<QCPAbstractPlottable *> plotableVect, IDataSeries *dataSeries,
35 const SqpDateTime &dateTime);
35 const SqpRange &dateTime);
36 36 };
37 37
38 38 #endif // SCIQLOP_VISUALIZATIONGRAPHHELPER_H
@@ -1,84 +1,84
1 1 #ifndef SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
2 2 #define SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
3 3
4 4 #include "Visualization/IVisualizationWidget.h"
5 5
6 6 #include <QLoggingCategory>
7 7 #include <QWidget>
8 8
9 9 #include <memory>
10 10
11 11 #include <Common/spimpl.h>
12 12
13 13 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationGraphWidget)
14 14
15 15 class QCPRange;
16 class SqpDateTime;
16 class SqpRange;
17 17 class Variable;
18 18
19 19 /**
20 20 * Possible types of zoom operation
21 21 */
22 22 enum class VisualizationGraphWidgetZoomType { ZoomOut, ZoomIn, PanRight, PanLeft, Unknown };
23 23
24 24 namespace Ui {
25 25 class VisualizationGraphWidget;
26 26 } // namespace Ui
27 27
28 28 class VisualizationGraphWidget : public QWidget, public IVisualizationWidget {
29 29 Q_OBJECT
30 30
31 31 public:
32 32 explicit VisualizationGraphWidget(const QString &name = {}, QWidget *parent = 0);
33 33 virtual ~VisualizationGraphWidget();
34 34
35 35 void enableSynchronize(bool enable);
36 36
37 37 void addVariable(std::shared_ptr<Variable> variable);
38 38 void addVariableUsingGraph(std::shared_ptr<Variable> variable);
39 39 /// Removes a variable from the graph
40 40 void removeVariable(std::shared_ptr<Variable> variable) noexcept;
41 41
42 void setRange(std::shared_ptr<Variable> variable, const SqpDateTime &range);
43 SqpDateTime graphRange() const noexcept;
44 void setGraphRange(const SqpDateTime &range);
42 void setRange(std::shared_ptr<Variable> variable, const SqpRange &range);
43 SqpRange graphRange() const noexcept;
44 void setGraphRange(const SqpRange &range);
45 45
46 46 // IVisualizationWidget interface
47 47 void accept(IVisualizationWidgetVisitor *visitor) override;
48 48 bool canDrop(const Variable &variable) const override;
49 49 bool contains(const Variable &variable) const override;
50 50 QString name() const override;
51 51
52 52
53 53 signals:
54 void requestDataLoading(std::shared_ptr<Variable> variable, const SqpDateTime &dateTime);
55 void synchronize(const SqpDateTime &dateTime, const SqpDateTime &oldDateTime,
54 void requestDataLoading(std::shared_ptr<Variable> variable, const SqpRange &dateTime);
55 void synchronize(const SqpRange &dateTime, const SqpRange &oldDateTime,
56 56 VisualizationGraphWidgetZoomType zoomType);
57 57
58 58
59 59 private:
60 60 Ui::VisualizationGraphWidget *ui;
61 61
62 62 class VisualizationGraphWidgetPrivate;
63 63 spimpl::unique_impl_ptr<VisualizationGraphWidgetPrivate> impl;
64 64
65 65 private slots:
66 66 /// Slot called when right clicking on the graph (displays a menu)
67 67 void onGraphMenuRequested(const QPoint &pos) noexcept;
68 68
69 69 /// Rescale the X axe to range parameter
70 70 void onRangeChanged(const QCPRange &t1, const QCPRange &t2);
71 71
72 72 /// Slot called when a mouse move was made
73 73 void onMouseMove(QMouseEvent *event) noexcept;
74 74 /// Slot called when a mouse wheel was made, to perform some processing before the zoom is done
75 75 void onMouseWheel(QWheelEvent *event) noexcept;
76 76 /// Slot called when a mouse press was made, to activate the calibration of a graph
77 77 void onMousePress(QMouseEvent *event) noexcept;
78 78 /// Slot called when a mouse release was made, to deactivate the calibration of a graph
79 79 void onMouseRelease(QMouseEvent *event) noexcept;
80 80
81 81 void onDataCacheVariableUpdated();
82 82 };
83 83
84 84 #endif // SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
@@ -1,51 +1,51
1 1 #ifndef SCIQLOP_VISUALIZATIONWIDGET_H
2 2 #define SCIQLOP_VISUALIZATIONWIDGET_H
3 3
4 4 #include "Visualization/IVisualizationWidget.h"
5 #include <Data/SqpDateTime.h>
5 #include <Data/SqpRange.h>
6 6
7 7 #include <QLoggingCategory>
8 8 #include <QWidget>
9 9
10 10 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationWidget)
11 11
12 12 class QMenu;
13 13 class Variable;
14 14 class VisualizationTabWidget;
15 15
16 16 namespace Ui {
17 17 class VisualizationWidget;
18 18 } // namespace Ui
19 19
20 20 class VisualizationWidget : public QWidget, public IVisualizationWidget {
21 21 Q_OBJECT
22 22
23 23 public:
24 24 explicit VisualizationWidget(QWidget *parent = 0);
25 25 virtual ~VisualizationWidget();
26 26
27 27 // IVisualizationWidget interface
28 28 void accept(IVisualizationWidgetVisitor *visitor) override;
29 29 bool canDrop(const Variable &variable) const override;
30 30 bool contains(const Variable &variable) const override;
31 31 QString name() const override;
32 32
33 33 public slots:
34 34 /**
35 35 * Attaches to a menu the menu relative to the visualization of variables
36 36 * @param menu the parent menu of the generated menu
37 37 * @param variables the variables for which to generate the menu
38 38 */
39 39 void attachVariableMenu(QMenu *menu,
40 40 const QVector<std::shared_ptr<Variable> > &variables) noexcept;
41 41
42 42 /// Slot called when a variable is about to be deleted from SciQlop
43 43 void onVariableAboutToBeDeleted(std::shared_ptr<Variable> variable) noexcept;
44 44
45 void onRangeChanged(std::shared_ptr<Variable> variable, const SqpDateTime &range) noexcept;
45 void onRangeChanged(std::shared_ptr<Variable> variable, const SqpRange &range) noexcept;
46 46
47 47 private:
48 48 Ui::VisualizationWidget *ui;
49 49 };
50 50
51 51 #endif // VISUALIZATIONWIDGET_H
@@ -1,42 +1,42
1 1 #ifndef SCIQLOP_RESCALEAXEOPERATION_H
2 2 #define SCIQLOP_RESCALEAXEOPERATION_H
3 3
4 4 #include "Visualization/IVisualizationWidgetVisitor.h"
5 #include <Data/SqpDateTime.h>
5 #include <Data/SqpRange.h>
6 6
7 7 #include <Common/spimpl.h>
8 8
9 9 #include <QLoggingCategory>
10 10
11 11 #include <memory>
12 12
13 13 class Variable;
14 14
15 15 Q_DECLARE_LOGGING_CATEGORY(LOG_RescaleAxeOperation)
16 16
17 17 /**
18 18 * @brief The RescaleAxeOperation class defines an operation that traverses all of visualization
19 19 * widgets to remove a variable if they contain it
20 20 */
21 21 class RescaleAxeOperation : public IVisualizationWidgetVisitor {
22 22 public:
23 23 /**
24 24 * Ctor
25 25 * @param variable the variable to remove from widgets
26 26 */
27 explicit RescaleAxeOperation(std::shared_ptr<Variable> variable, const SqpDateTime &range);
27 explicit RescaleAxeOperation(std::shared_ptr<Variable> variable, const SqpRange &range);
28 28
29 29 void visitEnter(VisualizationWidget *widget) override final;
30 30 void visitLeave(VisualizationWidget *widget) override final;
31 31 void visitEnter(VisualizationTabWidget *tabWidget) override final;
32 32 void visitLeave(VisualizationTabWidget *tabWidget) override final;
33 33 void visitEnter(VisualizationZoneWidget *zoneWidget) override final;
34 34 void visitLeave(VisualizationZoneWidget *zoneWidget) override final;
35 35 void visit(VisualizationGraphWidget *graphWidget) override final;
36 36
37 37 private:
38 38 class RescaleAxeOperationPrivate;
39 39 spimpl::unique_impl_ptr<RescaleAxeOperationPrivate> impl;
40 40 };
41 41
42 42 #endif // SCIQLOP_RESCALEAXEOPERATION_H
@@ -1,151 +1,151
1 1 #include "SqpApplication.h"
2 2
3 3 #include <Data/IDataProvider.h>
4 4 #include <DataSource/DataSourceController.h>
5 5 #include <Network/NetworkController.h>
6 6 #include <QThread>
7 7 #include <Time/TimeController.h>
8 8 #include <Variable/Variable.h>
9 9 #include <Variable/VariableController.h>
10 10 #include <Visualization/VisualizationController.h>
11 11
12 12 Q_LOGGING_CATEGORY(LOG_SqpApplication, "SqpApplication")
13 13
14 14 class SqpApplication::SqpApplicationPrivate {
15 15 public:
16 16 SqpApplicationPrivate()
17 17 : m_DataSourceController{std::make_unique<DataSourceController>()},
18 18 m_NetworkController{std::make_unique<NetworkController>()},
19 19 m_TimeController{std::make_unique<TimeController>()},
20 20 m_VariableController{std::make_unique<VariableController>()},
21 21 m_VisualizationController{std::make_unique<VisualizationController>()}
22 22 {
23 23 // /////////////////////////////// //
24 24 // Connections between controllers //
25 25 // /////////////////////////////// //
26 26
27 27 // VariableController <-> DataSourceController
28 28 connect(m_DataSourceController.get(),
29 29 SIGNAL(variableCreationRequested(const QString &, const QVariantHash &,
30 30 std::shared_ptr<IDataProvider>)),
31 31 m_VariableController.get(),
32 32 SLOT(createVariable(const QString &, const QVariantHash &,
33 33 std::shared_ptr<IDataProvider>)));
34 34
35 35 // VariableController <-> VisualizationController
36 36 connect(m_VariableController.get(),
37 37 SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)),
38 38 m_VisualizationController.get(),
39 39 SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)), Qt::DirectConnection);
40 40
41 41 connect(m_VariableController.get(),
42 SIGNAL(rangeChanged(std::shared_ptr<Variable>, const SqpDateTime &)),
42 SIGNAL(rangeChanged(std::shared_ptr<Variable>, const SqpRange &)),
43 43 m_VisualizationController.get(),
44 SIGNAL(rangeChanged(std::shared_ptr<Variable>, const SqpDateTime &)));
44 SIGNAL(rangeChanged(std::shared_ptr<Variable>, const SqpRange &)));
45 45
46 46
47 47 m_DataSourceController->moveToThread(&m_DataSourceControllerThread);
48 48 m_DataSourceControllerThread.setObjectName("DataSourceControllerThread");
49 49 m_NetworkController->moveToThread(&m_NetworkControllerThread);
50 50 m_NetworkControllerThread.setObjectName("NetworkControllerThread");
51 51 m_VariableController->moveToThread(&m_VariableControllerThread);
52 52 m_VariableControllerThread.setObjectName("VariableControllerThread");
53 53 m_VisualizationController->moveToThread(&m_VisualizationControllerThread);
54 54 m_VisualizationControllerThread.setObjectName("VsualizationControllerThread");
55 55
56 56
57 57 // Additionnal init
58 58 m_VariableController->setTimeController(m_TimeController.get());
59 59 }
60 60
61 61 virtual ~SqpApplicationPrivate()
62 62 {
63 63 qCInfo(LOG_SqpApplication()) << tr("SqpApplicationPrivate destruction");
64 64 m_DataSourceControllerThread.quit();
65 65 m_DataSourceControllerThread.wait();
66 66
67 67 m_NetworkControllerThread.quit();
68 68 m_NetworkControllerThread.wait();
69 69
70 70 m_VariableControllerThread.quit();
71 71 m_VariableControllerThread.wait();
72 72
73 73 m_VisualizationControllerThread.quit();
74 74 m_VisualizationControllerThread.wait();
75 75 }
76 76
77 77 std::unique_ptr<DataSourceController> m_DataSourceController;
78 78 std::unique_ptr<VariableController> m_VariableController;
79 79 std::unique_ptr<TimeController> m_TimeController;
80 80 std::unique_ptr<NetworkController> m_NetworkController;
81 81 std::unique_ptr<VisualizationController> m_VisualizationController;
82 82 QThread m_DataSourceControllerThread;
83 83 QThread m_NetworkControllerThread;
84 84 QThread m_VariableControllerThread;
85 85 QThread m_VisualizationControllerThread;
86 86 };
87 87
88 88
89 89 SqpApplication::SqpApplication(int &argc, char **argv)
90 90 : QApplication{argc, argv}, impl{spimpl::make_unique_impl<SqpApplicationPrivate>()}
91 91 {
92 92 qCDebug(LOG_SqpApplication()) << tr("SqpApplication construction") << QThread::currentThread();
93 93
94 94 connect(&impl->m_DataSourceControllerThread, &QThread::started,
95 95 impl->m_DataSourceController.get(), &DataSourceController::initialize);
96 96 connect(&impl->m_DataSourceControllerThread, &QThread::finished,
97 97 impl->m_DataSourceController.get(), &DataSourceController::finalize);
98 98
99 99 connect(&impl->m_NetworkControllerThread, &QThread::started, impl->m_NetworkController.get(),
100 100 &NetworkController::initialize);
101 101 connect(&impl->m_NetworkControllerThread, &QThread::finished, impl->m_NetworkController.get(),
102 102 &NetworkController::finalize);
103 103
104 104 connect(&impl->m_VariableControllerThread, &QThread::started, impl->m_VariableController.get(),
105 105 &VariableController::initialize);
106 106 connect(&impl->m_VariableControllerThread, &QThread::finished, impl->m_VariableController.get(),
107 107 &VariableController::finalize);
108 108
109 109 connect(&impl->m_VisualizationControllerThread, &QThread::started,
110 110 impl->m_VisualizationController.get(), &VisualizationController::initialize);
111 111 connect(&impl->m_VisualizationControllerThread, &QThread::finished,
112 112 impl->m_VisualizationController.get(), &VisualizationController::finalize);
113 113
114 114 impl->m_DataSourceControllerThread.start();
115 115 impl->m_NetworkControllerThread.start();
116 116 impl->m_VariableControllerThread.start();
117 117 impl->m_VisualizationControllerThread.start();
118 118 }
119 119
120 120 SqpApplication::~SqpApplication()
121 121 {
122 122 }
123 123
124 124 void SqpApplication::initialize()
125 125 {
126 126 }
127 127
128 128 DataSourceController &SqpApplication::dataSourceController() noexcept
129 129 {
130 130 return *impl->m_DataSourceController;
131 131 }
132 132
133 133 NetworkController &SqpApplication::networkController() noexcept
134 134 {
135 135 return *impl->m_NetworkController;
136 136 }
137 137
138 138 TimeController &SqpApplication::timeController() noexcept
139 139 {
140 140 return *impl->m_TimeController;
141 141 }
142 142
143 143 VariableController &SqpApplication::variableController() noexcept
144 144 {
145 145 return *impl->m_VariableController;
146 146 }
147 147
148 148 VisualizationController &SqpApplication::visualizationController() noexcept
149 149 {
150 150 return *impl->m_VisualizationController;
151 151 }
@@ -1,50 +1,50
1 1 #include "TimeWidget/TimeWidget.h"
2 2 #include "ui_TimeWidget.h"
3 3
4 4 #include <Common/DateUtils.h>
5 5 #include <SqpApplication.h>
6 6 #include <Time/TimeController.h>
7 7
8 8 TimeWidget::TimeWidget(QWidget *parent) : QWidget{parent}, ui{new Ui::TimeWidget}
9 9 {
10 10 ui->setupUi(this);
11 11
12 12 ui->applyToolButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_DialogApplyButton));
13 13
14 14 // Connection
15 15 connect(ui->startDateTimeEdit, &QDateTimeEdit::dateTimeChanged, this,
16 16 &TimeWidget::onTimeUpdateRequested);
17 17
18 18 connect(ui->endDateTimeEdit, &QDateTimeEdit::dateTimeChanged, this,
19 19 &TimeWidget::onTimeUpdateRequested);
20 20
21 21
22 22 connect(ui->applyToolButton, &QToolButton::clicked, &sqpApp->timeController(),
23 23 &TimeController::onTimeNotify);
24 24
25 25 // Initialisation
26 26 auto endDateTime = QDateTime::currentDateTimeUtc();
27 27 auto startDateTime = endDateTime.addSecs(-3600); // one hour before
28 28
29 29 ui->startDateTimeEdit->setDateTime(startDateTime);
30 30 ui->endDateTimeEdit->setDateTime(endDateTime);
31 31
32 auto dateTime = SqpDateTime{DateUtils::secondsSinceEpoch(startDateTime),
33 DateUtils::secondsSinceEpoch(endDateTime)};
32 auto dateTime = SqpRange{DateUtils::secondsSinceEpoch(startDateTime),
33 DateUtils::secondsSinceEpoch(endDateTime)};
34 34
35 35 sqpApp->timeController().onTimeToUpdate(dateTime);
36 36 }
37 37
38 38
39 39 TimeWidget::~TimeWidget()
40 40 {
41 41 delete ui;
42 42 }
43 43
44 44 void TimeWidget::onTimeUpdateRequested()
45 45 {
46 auto dateTime = SqpDateTime{DateUtils::secondsSinceEpoch(ui->startDateTimeEdit->dateTime()),
47 DateUtils::secondsSinceEpoch(ui->endDateTimeEdit->dateTime())};
46 auto dateTime = SqpRange{DateUtils::secondsSinceEpoch(ui->startDateTimeEdit->dateTime()),
47 DateUtils::secondsSinceEpoch(ui->endDateTimeEdit->dateTime())};
48 48
49 49 emit timeUpdated(std::move(dateTime));
50 50 }
@@ -1,162 +1,162
1 1 #include "Visualization/VisualizationGraphHelper.h"
2 2 #include "Visualization/qcustomplot.h"
3 3
4 4 #include <Data/ScalarSeries.h>
5 5
6 6 #include <Variable/Variable.h>
7 7
8 8 Q_LOGGING_CATEGORY(LOG_VisualizationGraphHelper, "VisualizationGraphHelper")
9 9
10 10 namespace {
11 11
12 12 class SqpDataContainer : public QCPGraphDataContainer {
13 13 public:
14 14 void appendGraphData(const QCPGraphData &data) { mData.append(data); }
15 15 };
16 16
17 17
18 18 /// Format for datetimes on a axis
19 19 const auto DATETIME_TICKER_FORMAT = QStringLiteral("yyyy/MM/dd \nhh:mm:ss");
20 20
21 21 /// Generates the appropriate ticker for an axis, depending on whether the axis displays time or
22 22 /// non-time data
23 23 QSharedPointer<QCPAxisTicker> axisTicker(bool isTimeAxis)
24 24 {
25 25 if (isTimeAxis) {
26 26 auto dateTicker = QSharedPointer<QCPAxisTickerDateTime>::create();
27 27 dateTicker->setDateTimeFormat(DATETIME_TICKER_FORMAT);
28 28 dateTicker->setDateTimeSpec(Qt::UTC);
29 29
30 30 return dateTicker;
31 31 }
32 32 else {
33 33 // default ticker
34 34 return QSharedPointer<QCPAxisTicker>::create();
35 35 }
36 36 }
37 37
38 38 void updateScalarData(QCPAbstractPlottable *component, ScalarSeries &scalarSeries,
39 const SqpDateTime &dateTime)
39 const SqpRange &dateTime)
40 40 {
41 41 qCDebug(LOG_VisualizationGraphHelper()) << "TORM: updateScalarData"
42 42 << QThread::currentThread()->objectName();
43 43 if (auto qcpGraph = dynamic_cast<QCPGraph *>(component)) {
44 44 scalarSeries.lockRead();
45 45 {
46 46 const auto &xData = scalarSeries.xAxisData()->cdata();
47 47 const auto &valuesData = scalarSeries.valuesData()->cdata();
48 48
49 49 auto xDataBegin = xData.cbegin();
50 50 auto xDataEnd = xData.cend();
51 51
52 52 qCInfo(LOG_VisualizationGraphHelper()) << "TORM: Current points in cache"
53 53 << xData.count();
54 54
55 55 auto sqpDataContainer = QSharedPointer<SqpDataContainer>::create();
56 56 qcpGraph->setData(sqpDataContainer);
57 57
58 58 auto lowerIt = std::lower_bound(xDataBegin, xDataEnd, dateTime.m_TStart);
59 59 auto upperIt = std::upper_bound(xDataBegin, xDataEnd, dateTime.m_TEnd);
60 60 auto distance = std::distance(xDataBegin, lowerIt);
61 61
62 62 auto valuesDataIt = valuesData.cbegin() + distance;
63 63 for (auto xAxisDataIt = lowerIt; xAxisDataIt != upperIt;
64 64 ++xAxisDataIt, ++valuesDataIt) {
65 65 sqpDataContainer->appendGraphData(QCPGraphData(*xAxisDataIt, *valuesDataIt));
66 66 }
67 67
68 68 qCInfo(LOG_VisualizationGraphHelper()) << "TORM: Current points displayed"
69 69 << sqpDataContainer->size();
70 70 }
71 71 scalarSeries.unlock();
72 72
73 73
74 74 // Display all data
75 75 component->parentPlot()->replot();
76 76 }
77 77 else {
78 78 /// @todo DEBUG
79 79 }
80 80 }
81 81
82 82 QCPAbstractPlottable *createScalarSeriesComponent(ScalarSeries &scalarSeries, QCustomPlot &plot,
83 const SqpDateTime &dateTime)
83 const SqpRange &dateTime)
84 84 {
85 85 auto component = plot.addGraph();
86 86
87 87 if (component) {
88 88 // // Graph data
89 89 component->setData(scalarSeries.xAxisData()->data(), scalarSeries.valuesData()->data(),
90 90 true);
91 91
92 92 updateScalarData(component, scalarSeries, dateTime);
93 93
94 94 // Axes properties
95 95 /// @todo : for the moment, no control is performed on the axes: the units and the tickers
96 96 /// are fixed for the default x-axis and y-axis of the plot, and according to the new graph
97 97
98 98 auto setAxisProperties = [](auto axis, const auto &unit) {
99 99 // label (unit name)
100 100 axis->setLabel(unit.m_Name);
101 101
102 102 // ticker (depending on the type of unit)
103 103 axis->setTicker(axisTicker(unit.m_TimeUnit));
104 104 };
105 105 setAxisProperties(plot.xAxis, scalarSeries.xAxisUnit());
106 106 setAxisProperties(plot.yAxis, scalarSeries.valuesUnit());
107 107
108 108 // Display all data
109 109 component->rescaleAxes();
110 110 plot.replot();
111 111 }
112 112 else {
113 113 qCDebug(LOG_VisualizationGraphHelper())
114 114 << QObject::tr("Can't create graph for the scalar series");
115 115 }
116 116
117 117 return component;
118 118 }
119 119
120 120 } // namespace
121 121
122 122 QVector<QCPAbstractPlottable *> VisualizationGraphHelper::create(std::shared_ptr<Variable> variable,
123 123 QCustomPlot &plot) noexcept
124 124 {
125 125 auto result = QVector<QCPAbstractPlottable *>{};
126 126
127 127 if (variable) {
128 128 // Gets the data series of the variable to call the creation of the right components
129 129 // according to its type
130 130 if (auto scalarSeries = dynamic_cast<ScalarSeries *>(variable->dataSeries())) {
131 131 result.append(createScalarSeriesComponent(*scalarSeries, plot, variable->dateTime()));
132 132 }
133 133 else {
134 134 qCDebug(LOG_VisualizationGraphHelper())
135 135 << QObject::tr("Can't create graph plottables : unmanaged data series type");
136 136 }
137 137 }
138 138 else {
139 139 qCDebug(LOG_VisualizationGraphHelper())
140 140 << QObject::tr("Can't create graph plottables : the variable is null");
141 141 }
142 142
143 143 return result;
144 144 }
145 145
146 146 void VisualizationGraphHelper::updateData(QVector<QCPAbstractPlottable *> plotableVect,
147 IDataSeries *dataSeries, const SqpDateTime &dateTime)
147 IDataSeries *dataSeries, const SqpRange &dateTime)
148 148 {
149 149 if (auto scalarSeries = dynamic_cast<ScalarSeries *>(dataSeries)) {
150 150 if (plotableVect.size() == 1) {
151 151 updateScalarData(plotableVect.at(0), *scalarSeries, dateTime);
152 152 }
153 153 else {
154 154 qCCritical(LOG_VisualizationGraphHelper()) << QObject::tr(
155 155 "Can't update Data of a scalarSeries because there is not only one component "
156 156 "associated");
157 157 }
158 158 }
159 159 else {
160 160 /// @todo DEBUG
161 161 }
162 162 }
@@ -1,428 +1,427
1 1 #include "Visualization/VisualizationGraphWidget.h"
2 2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 3 #include "Visualization/VisualizationGraphHelper.h"
4 4 #include "Visualization/VisualizationGraphRenderingDelegate.h"
5 5 #include "ui_VisualizationGraphWidget.h"
6 6
7 7 #include <Data/ArrayData.h>
8 8 #include <Data/IDataSeries.h>
9 9 #include <Settings/SqpSettingsDefs.h>
10 10 #include <SqpApplication.h>
11 11 #include <Variable/Variable.h>
12 12 #include <Variable/VariableController.h>
13 13
14 14 #include <unordered_map>
15 15
16 16 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
17 17
18 18 namespace {
19 19
20 20 /// Key pressed to enable zoom on horizontal axis
21 21 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::NoModifier;
22 22
23 23 /// Key pressed to enable zoom on vertical axis
24 24 const auto VERTICAL_ZOOM_MODIFIER = Qt::ControlModifier;
25 25
26 26 /// Gets a tolerance value from application settings. If the setting can't be found, the default
27 27 /// value passed in parameter is returned
28 28 double toleranceValue(const QString &key, double defaultValue) noexcept
29 29 {
30 30 return QSettings{}.value(key, defaultValue).toDouble();
31 31 }
32 32
33 33 } // namespace
34 34
35 35 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
36 36
37 37 explicit VisualizationGraphWidgetPrivate()
38 38 : m_DoSynchronize{true}, m_IsCalibration{false}, m_RenderingDelegate{nullptr}
39 39 {
40 40 }
41 41
42 42 // Return the operation when range changed
43 43 VisualizationGraphWidgetZoomType getZoomType(const QCPRange &t1, const QCPRange &t2);
44 44
45 45 // 1 variable -> n qcpplot
46 46 std::multimap<std::shared_ptr<Variable>, QCPAbstractPlottable *> m_VariableToPlotMultiMap;
47 47 bool m_DoSynchronize;
48 48 bool m_IsCalibration;
49 49 QCPItemTracer *m_TextTracer;
50 50 /// Delegate used to attach rendering features to the plot
51 51 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
52 52 };
53 53
54 54 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
55 55 : QWidget{parent},
56 56 ui{new Ui::VisualizationGraphWidget},
57 57 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>()}
58 58 {
59 59 ui->setupUi(this);
60 60
61 61 // The delegate must be initialized after the ui as it uses the plot
62 62 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*ui->widget);
63 63
64 64 ui->graphNameLabel->setText(name);
65 65
66 66 // 'Close' options : widget is deleted when closed
67 67 setAttribute(Qt::WA_DeleteOnClose);
68 68 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationGraphWidget::close);
69 69 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
70 70
71 71 // Set qcpplot properties :
72 72 // - Drag (on x-axis) and zoom are enabled
73 73 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
74 74 ui->widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);
75 75 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal);
76 76
77 77 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
78 78 connect(ui->widget, &QCustomPlot::mouseRelease, this,
79 79 &VisualizationGraphWidget::onMouseRelease);
80 80 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
81 81 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
82 82 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
83 83 &QCPAxis::rangeChanged),
84 84 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
85 85
86 86 // Activates menu when right clicking on the graph
87 87 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
88 88 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
89 89 &VisualizationGraphWidget::onGraphMenuRequested);
90 90
91 91 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
92 92 &VariableController::onRequestDataLoading);
93 93 }
94 94
95 95
96 96 VisualizationGraphWidget::~VisualizationGraphWidget()
97 97 {
98 98 delete ui;
99 99 }
100 100
101 101 void VisualizationGraphWidget::enableSynchronize(bool enable)
102 102 {
103 103 impl->m_DoSynchronize = enable;
104 104 }
105 105
106 106 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable)
107 107 {
108 108 // Uses delegate to create the qcpplot components according to the variable
109 109 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
110 110
111 111 for (auto createdPlottable : qAsConst(createdPlottables)) {
112 112 impl->m_VariableToPlotMultiMap.insert({variable, createdPlottable});
113 113 }
114 114
115 115 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
116 116 }
117 117 void VisualizationGraphWidget::addVariableUsingGraph(std::shared_ptr<Variable> variable)
118 118 {
119 119
120 120 // when adding a variable, we need to set its time range to the current graph range
121 121 auto grapheRange = ui->widget->xAxis->range();
122 auto dateTime = SqpDateTime{grapheRange.lower, grapheRange.upper};
122 auto dateTime = SqpRange{grapheRange.lower, grapheRange.upper};
123 123 variable->setDateTime(dateTime);
124 124
125 125 auto variableDateTimeWithTolerance = dateTime;
126 126
127 127 // add tolerance for each side
128 128 auto toleranceFactor
129 129 = toleranceValue(GENERAL_TOLERANCE_AT_INIT_KEY, GENERAL_TOLERANCE_AT_INIT_DEFAULT_VALUE);
130 130 auto tolerance = toleranceFactor * (dateTime.m_TEnd - dateTime.m_TStart);
131 131 variableDateTimeWithTolerance.m_TStart -= tolerance;
132 132 variableDateTimeWithTolerance.m_TEnd += tolerance;
133 133
134 134 // Uses delegate to create the qcpplot components according to the variable
135 135 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
136 136
137 137 for (auto createdPlottable : qAsConst(createdPlottables)) {
138 138 impl->m_VariableToPlotMultiMap.insert({variable, createdPlottable});
139 139 }
140 140
141 141 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
142 142
143 143 // CHangement detected, we need to ask controller to request data loading
144 144 emit requestDataLoading(variable, variableDateTimeWithTolerance);
145 145 }
146 146
147 147 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
148 148 {
149 149 // Each component associated to the variable :
150 150 // - is removed from qcpplot (which deletes it)
151 151 // - is no longer referenced in the map
152 152 auto componentsIt = impl->m_VariableToPlotMultiMap.equal_range(variable);
153 153 for (auto it = componentsIt.first; it != componentsIt.second;) {
154 154 ui->widget->removePlottable(it->second);
155 155 it = impl->m_VariableToPlotMultiMap.erase(it);
156 156 }
157 157
158 158 // Updates graph
159 159 ui->widget->replot();
160 160 }
161 161
162 void VisualizationGraphWidget::setRange(std::shared_ptr<Variable> variable,
163 const SqpDateTime &range)
162 void VisualizationGraphWidget::setRange(std::shared_ptr<Variable> variable, const SqpRange &range)
164 163 {
165 164 // Note: in case of different axes that depends on variable, we could start with a code like
166 165 // that:
167 166 // auto componentsIt = impl->m_VariableToPlotMultiMap.equal_range(variable);
168 167 // for (auto it = componentsIt.first; it != componentsIt.second;) {
169 168 // }
170 169 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
171 170 ui->widget->replot();
172 171 }
173 172
174 SqpDateTime VisualizationGraphWidget::graphRange() const noexcept
173 SqpRange VisualizationGraphWidget::graphRange() const noexcept
175 174 {
176 175 auto grapheRange = ui->widget->xAxis->range();
177 return SqpDateTime{grapheRange.lower, grapheRange.upper};
176 return SqpRange{grapheRange.lower, grapheRange.upper};
178 177 }
179 178
180 void VisualizationGraphWidget::setGraphRange(const SqpDateTime &range)
179 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
181 180 {
182 181 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
183 182 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
184 183 ui->widget->replot();
185 184 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
186 185 }
187 186
188 187 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
189 188 {
190 189 if (visitor) {
191 190 visitor->visit(this);
192 191 }
193 192 else {
194 193 qCCritical(LOG_VisualizationGraphWidget())
195 194 << tr("Can't visit widget : the visitor is null");
196 195 }
197 196 }
198 197
199 198 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
200 199 {
201 200 /// @todo : for the moment, a graph can always accomodate a variable
202 201 Q_UNUSED(variable);
203 202 return true;
204 203 }
205 204
206 205 bool VisualizationGraphWidget::contains(const Variable &variable) const
207 206 {
208 207 // Finds the variable among the keys of the map
209 208 auto variablePtr = &variable;
210 209 auto findVariable
211 210 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
212 211
213 212 auto end = impl->m_VariableToPlotMultiMap.cend();
214 213 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
215 214 return it != end;
216 215 }
217 216
218 217 QString VisualizationGraphWidget::name() const
219 218 {
220 219 return ui->graphNameLabel->text();
221 220 }
222 221
223 222 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
224 223 {
225 224 QMenu graphMenu{};
226 225
227 226 // Iterates on variables (unique keys)
228 227 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
229 228 end = impl->m_VariableToPlotMultiMap.cend();
230 229 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
231 230 // 'Remove variable' action
232 231 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
233 232 [ this, var = it->first ]() { removeVariable(var); });
234 233 }
235 234
236 235 if (!graphMenu.isEmpty()) {
237 236 graphMenu.exec(mapToGlobal(pos));
238 237 }
239 238 }
240 239
241 240 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
242 241 {
243 242 qCInfo(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::onRangeChanged")
244 243 << QThread::currentThread()->objectName();
245 244
246 auto dateTimeRange = SqpDateTime{t1.lower, t1.upper};
245 auto dateTimeRange = SqpRange{t1.lower, t1.upper};
247 246
248 247 auto zoomType = impl->getZoomType(t1, t2);
249 248 for (auto it = impl->m_VariableToPlotMultiMap.cbegin();
250 249 it != impl->m_VariableToPlotMultiMap.cend(); ++it) {
251 250
252 251 auto variable = it->first;
253 252 auto currentDateTime = dateTimeRange;
254 253
255 254 auto toleranceFactor = toleranceValue(GENERAL_TOLERANCE_AT_UPDATE_KEY,
256 255 GENERAL_TOLERANCE_AT_UPDATE_DEFAULT_VALUE);
257 256 auto tolerance = toleranceFactor * (currentDateTime.m_TEnd - currentDateTime.m_TStart);
258 257 auto variableDateTimeWithTolerance = currentDateTime;
259 258 variableDateTimeWithTolerance.m_TStart -= tolerance;
260 259 variableDateTimeWithTolerance.m_TEnd += tolerance;
261 260
262 261 qCDebug(LOG_VisualizationGraphWidget()) << "r" << currentDateTime;
263 262 qCDebug(LOG_VisualizationGraphWidget()) << "t" << variableDateTimeWithTolerance;
264 263 qCDebug(LOG_VisualizationGraphWidget()) << "v" << variable->dateTime();
265 264 // If new range with tol is upper than variable datetime parameters. we need to request new
266 265 // data
267 266 if (!variable->contains(variableDateTimeWithTolerance)) {
268 267
269 268 auto variableDateTimeWithTolerance = currentDateTime;
270 269 if (!variable->isInside(currentDateTime)) {
271 270 auto variableDateTime = variable->dateTime();
272 271 if (variable->contains(variableDateTimeWithTolerance)) {
273 272 qCDebug(LOG_VisualizationGraphWidget())
274 273 << tr("TORM: Detection zoom in that need request:");
275 274 // add tolerance for each side
276 275 tolerance
277 276 = toleranceFactor * (currentDateTime.m_TEnd - currentDateTime.m_TStart);
278 277 variableDateTimeWithTolerance.m_TStart -= tolerance;
279 278 variableDateTimeWithTolerance.m_TEnd += tolerance;
280 279 }
281 280 else if (variableDateTime.m_TStart < currentDateTime.m_TStart) {
282 281 qCInfo(LOG_VisualizationGraphWidget()) << tr("TORM: Detection pan to right:");
283 282
284 283 auto diffEndToKeepDelta = currentDateTime.m_TEnd - variableDateTime.m_TEnd;
285 284 currentDateTime.m_TStart = variableDateTime.m_TStart + diffEndToKeepDelta;
286 285 // Tolerance have to be added to the right
287 286 // add tolerance for right (end) side
288 287 tolerance
289 288 = toleranceFactor * (currentDateTime.m_TEnd - currentDateTime.m_TStart);
290 289 variableDateTimeWithTolerance.m_TEnd += tolerance;
291 290 }
292 291 else if (variableDateTime.m_TEnd > currentDateTime.m_TEnd) {
293 292 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: Detection pan to left: ");
294 293 auto diffStartToKeepDelta
295 294 = variableDateTime.m_TStart - currentDateTime.m_TStart;
296 295 currentDateTime.m_TEnd = variableDateTime.m_TEnd - diffStartToKeepDelta;
297 296 // Tolerance have to be added to the left
298 297 // add tolerance for left (start) side
299 298 tolerance
300 299 = toleranceFactor * (currentDateTime.m_TEnd - currentDateTime.m_TStart);
301 300 variableDateTimeWithTolerance.m_TStart -= tolerance;
302 301 }
303 302 else {
304 303 qCCritical(LOG_VisualizationGraphWidget())
305 304 << tr("Detection anormal zoom detection: ");
306 305 }
307 306 }
308 307 else {
309 308 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: Detection zoom out: ");
310 309 // add tolerance for each side
311 310 tolerance = toleranceFactor * (currentDateTime.m_TEnd - currentDateTime.m_TStart);
312 311 variableDateTimeWithTolerance.m_TStart -= tolerance;
313 312 variableDateTimeWithTolerance.m_TEnd += tolerance;
314 313 zoomType = VisualizationGraphWidgetZoomType::ZoomOut;
315 314 }
316 315 if (!variable->contains(dateTimeRange)) {
317 316 qCDebug(LOG_VisualizationGraphWidget())
318 317 << "TORM: Modif on variable datetime detected" << currentDateTime;
319 318 variable->setDateTime(currentDateTime);
320 319 }
321 320
322 321 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: Request data detection: ");
323 322 // CHangement detected, we need to ask controller to request data loading
324 323 emit requestDataLoading(variable, variableDateTimeWithTolerance);
325 324 }
326 325 else {
327 326 qCInfo(LOG_VisualizationGraphWidget())
328 327 << tr("TORM: Detection zoom in that doesn't need request: ");
329 328 zoomType = VisualizationGraphWidgetZoomType::ZoomIn;
330 329 }
331 330 }
332 331
333 332 if (impl->m_DoSynchronize && !impl->m_IsCalibration) {
334 auto oldDateTime = SqpDateTime{t2.lower, t2.upper};
333 auto oldDateTime = SqpRange{t2.lower, t2.upper};
335 334 qCDebug(LOG_VisualizationGraphWidget())
336 335 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
337 336 << QThread::currentThread()->objectName();
338 337 emit synchronize(dateTimeRange, oldDateTime, zoomType);
339 338 }
340 339 }
341 340
342 341 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
343 342 {
344 343 // Handles plot rendering when mouse is moving
345 344 impl->m_RenderingDelegate->onMouseMove(event);
346 345 }
347 346
348 347 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
349 348 {
350 349 auto zoomOrientations = QFlags<Qt::Orientation>{};
351 350
352 351 // Lambda that enables a zoom orientation if the key modifier related to this orientation
353 352 // has
354 353 // been pressed
355 354 auto enableOrientation
356 355 = [&zoomOrientations, event](const auto &orientation, const auto &modifier) {
357 356 auto orientationEnabled = event->modifiers().testFlag(modifier);
358 357 zoomOrientations.setFlag(orientation, orientationEnabled);
359 358 };
360 359 enableOrientation(Qt::Vertical, VERTICAL_ZOOM_MODIFIER);
361 360 enableOrientation(Qt::Horizontal, HORIZONTAL_ZOOM_MODIFIER);
362 361
363 362 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
364 363 }
365 364
366 365 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
367 366 {
368 367 impl->m_IsCalibration = event->modifiers().testFlag(Qt::ControlModifier);
369 368 }
370 369
371 370 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
372 371 {
373 372 impl->m_IsCalibration = false;
374 373 }
375 374
376 375 void VisualizationGraphWidget::onDataCacheVariableUpdated()
377 376 {
378 377 // NOTE:
379 378 // We don't want to call the method for each component of a variable unitarily, but for
380 379 // all
381 380 // its components at once (eg its three components in the case of a vector).
382 381
383 382 // The unordered_multimap does not do this easily, so the question is whether to:
384 383 // - use an ordered_multimap and the algos of std to group the values by key
385 384 // - use a map (unique keys) and store as values directly the list of components
386 385
387 386 auto grapheRange = ui->widget->xAxis->range();
388 auto dateTime = SqpDateTime{grapheRange.lower, grapheRange.upper};
387 auto dateTime = SqpRange{grapheRange.lower, grapheRange.upper};
389 388
390 389 for (auto it = impl->m_VariableToPlotMultiMap.cbegin();
391 390 it != impl->m_VariableToPlotMultiMap.cend(); ++it) {
392 391 auto variable = it->first;
393 392 qCDebug(LOG_VisualizationGraphWidget())
394 393 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S"
395 394 << variable->dateTime();
396 395 qCDebug(LOG_VisualizationGraphWidget())
397 396 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
398 397 if (dateTime.contains(variable->dateTime()) || dateTime.intersect(variable->dateTime())) {
399 398
400 399 VisualizationGraphHelper::updateData(QVector<QCPAbstractPlottable *>{} << it->second,
401 400 variable->dataSeries(), variable->dateTime());
402 401 }
403 402 }
404 403 }
405 404
406 405 VisualizationGraphWidgetZoomType
407 406 VisualizationGraphWidget::VisualizationGraphWidgetPrivate::getZoomType(const QCPRange &t1,
408 407 const QCPRange &t2)
409 408 {
410 409 // t1.lower <= t2.lower && t2.upper <= t1.upper
411 410 auto zoomType = VisualizationGraphWidgetZoomType::Unknown;
412 411 if (t1.lower <= t2.lower && t2.upper <= t1.upper) {
413 412 zoomType = VisualizationGraphWidgetZoomType::ZoomOut;
414 413 }
415 414 else if (t1.lower > t2.lower && t1.upper > t2.upper) {
416 415 zoomType = VisualizationGraphWidgetZoomType::PanRight;
417 416 }
418 417 else if (t1.lower < t2.lower && t1.upper < t2.upper) {
419 418 zoomType = VisualizationGraphWidgetZoomType::PanLeft;
420 419 }
421 420 else if (t1.lower > t2.lower && t2.upper > t1.upper) {
422 421 zoomType = VisualizationGraphWidgetZoomType::ZoomIn;
423 422 }
424 423 else {
425 424 qCCritical(LOG_VisualizationGraphWidget()) << "getZoomType: Unknown type detected";
426 425 }
427 426 return zoomType;
428 427 }
@@ -1,152 +1,152
1 1 #include "Visualization/VisualizationWidget.h"
2 2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 3 #include "Visualization/VisualizationGraphWidget.h"
4 4 #include "Visualization/VisualizationTabWidget.h"
5 5 #include "Visualization/VisualizationZoneWidget.h"
6 6 #include "Visualization/operations/GenerateVariableMenuOperation.h"
7 7 #include "Visualization/operations/RemoveVariableOperation.h"
8 8 #include "Visualization/operations/RescaleAxeOperation.h"
9 9 #include "Visualization/qcustomplot.h"
10 10
11 11 #include "ui_VisualizationWidget.h"
12 12
13 13 #include <QToolButton>
14 14
15 15 Q_LOGGING_CATEGORY(LOG_VisualizationWidget, "VisualizationWidget")
16 16
17 17 VisualizationWidget::VisualizationWidget(QWidget *parent)
18 18 : QWidget{parent}, ui{new Ui::VisualizationWidget}
19 19 {
20 20 ui->setupUi(this);
21 21
22 22 auto addTabViewButton = new QToolButton{ui->tabWidget};
23 23 addTabViewButton->setText(tr("Add View"));
24 24 addTabViewButton->setCursor(Qt::ArrowCursor);
25 25 ui->tabWidget->setCornerWidget(addTabViewButton, Qt::TopRightCorner);
26 26
27 27 auto enableMinimumCornerWidgetSize = [this](bool enable) {
28 28
29 29 auto tabViewCornerWidget = ui->tabWidget->cornerWidget();
30 30 auto width = enable ? tabViewCornerWidget->width() : 0;
31 31 auto height = enable ? tabViewCornerWidget->height() : 0;
32 32 tabViewCornerWidget->setMinimumHeight(height);
33 33 tabViewCornerWidget->setMinimumWidth(width);
34 34 ui->tabWidget->setMinimumHeight(height);
35 35 ui->tabWidget->setMinimumWidth(width);
36 36 };
37 37
38 38 auto addTabView = [this, enableMinimumCornerWidgetSize]() {
39 39 auto widget = new VisualizationTabWidget{QString{"View %1"}.arg(ui->tabWidget->count() + 1),
40 40 ui->tabWidget};
41 41 auto index = ui->tabWidget->addTab(widget, widget->name());
42 42 if (ui->tabWidget->count() > 0) {
43 43 enableMinimumCornerWidgetSize(false);
44 44 }
45 45 qCInfo(LOG_VisualizationWidget()) << tr("add the tab of index %1").arg(index);
46 46 };
47 47
48 48 auto removeTabView = [this, enableMinimumCornerWidgetSize](int index) {
49 49 if (ui->tabWidget->count() == 1) {
50 50 enableMinimumCornerWidgetSize(true);
51 51 }
52 52
53 53 // Removes widget from tab and closes it
54 54 auto widget = ui->tabWidget->widget(index);
55 55 ui->tabWidget->removeTab(index);
56 56 if (widget) {
57 57 widget->close();
58 58 }
59 59
60 60 qCInfo(LOG_VisualizationWidget()) << tr("remove the tab of index %1").arg(index);
61 61
62 62 };
63 63
64 64 ui->tabWidget->setTabsClosable(true);
65 65
66 66 connect(addTabViewButton, &QToolButton::clicked, addTabView);
67 67 connect(ui->tabWidget, &QTabWidget::tabCloseRequested, removeTabView);
68 68
69 69 // Adds default tab
70 70 addTabView();
71 71 }
72 72
73 73 VisualizationWidget::~VisualizationWidget()
74 74 {
75 75 delete ui;
76 76 }
77 77
78 78 void VisualizationWidget::accept(IVisualizationWidgetVisitor *visitor)
79 79 {
80 80 if (visitor) {
81 81 visitor->visitEnter(this);
82 82
83 83 // Apply visitor for tab children
84 84 for (auto i = 0; i < ui->tabWidget->count(); ++i) {
85 85 // Widgets different from tabs are not visited (no action)
86 86 if (auto visualizationTabWidget
87 87 = dynamic_cast<VisualizationTabWidget *>(ui->tabWidget->widget(i))) {
88 88 visualizationTabWidget->accept(visitor);
89 89 }
90 90 }
91 91
92 92 visitor->visitLeave(this);
93 93 }
94 94 else {
95 95 qCCritical(LOG_VisualizationWidget()) << tr("Can't visit widget : the visitor is null");
96 96 }
97 97 }
98 98
99 99 bool VisualizationWidget::canDrop(const Variable &variable) const
100 100 {
101 101 // The main widget can never accomodate a variable
102 102 Q_UNUSED(variable);
103 103 return false;
104 104 }
105 105
106 106 bool VisualizationWidget::contains(const Variable &variable) const
107 107 {
108 108 Q_UNUSED(variable);
109 109 return false;
110 110 }
111 111
112 112 QString VisualizationWidget::name() const
113 113 {
114 114 return QStringLiteral("MainView");
115 115 }
116 116
117 117 void VisualizationWidget::attachVariableMenu(
118 118 QMenu *menu, const QVector<std::shared_ptr<Variable> > &variables) noexcept
119 119 {
120 120 // Menu is generated only if there is a single variable
121 121 if (variables.size() == 1) {
122 122 if (auto variable = variables.first()) {
123 123 // Generates the actions that make it possible to visualize the variable
124 124 auto generateVariableMenuOperation = GenerateVariableMenuOperation{menu, variable};
125 125 accept(&generateVariableMenuOperation);
126 126 }
127 127 else {
128 128 qCCritical(LOG_VisualizationWidget()) << tr(
129 129 "Can't generate the menu relative to the visualization: the variable is null");
130 130 }
131 131 }
132 132 else {
133 133 qCDebug(LOG_VisualizationWidget())
134 134 << tr("No generation of the menu related to the visualization: several variables are "
135 135 "selected");
136 136 }
137 137 }
138 138
139 139 void VisualizationWidget::onVariableAboutToBeDeleted(std::shared_ptr<Variable> variable) noexcept
140 140 {
141 141 // Calls the operation of removing all references to the variable in the visualization
142 142 auto removeVariableOperation = RemoveVariableOperation{variable};
143 143 accept(&removeVariableOperation);
144 144 }
145 145
146 146 void VisualizationWidget::onRangeChanged(std::shared_ptr<Variable> variable,
147 const SqpDateTime &range) noexcept
147 const SqpRange &range) noexcept
148 148 {
149 149 // Calls the operation of rescaling all graph that contrains variable in the visualization
150 150 auto rescaleVariableOperation = RescaleAxeOperation{variable, range};
151 151 accept(&rescaleVariableOperation);
152 152 }
@@ -1,200 +1,200
1 1 #include "Visualization/VisualizationZoneWidget.h"
2 2
3 #include "Data/SqpDateTime.h"
3 #include "Data/SqpRange.h"
4 4
5 5 #include "Visualization/IVisualizationWidgetVisitor.h"
6 6 #include "Visualization/VisualizationGraphWidget.h"
7 7 #include "ui_VisualizationZoneWidget.h"
8 8
9 9
10 10 #include <SqpApplication.h>
11 11
12 12 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
13 13
14 14 namespace {
15 15
16 16 /// Minimum height for graph added in zones (in pixels)
17 17 const auto GRAPH_MINIMUM_HEIGHT = 300;
18 18
19 19 /// Generates a default name for a new graph, according to the number of graphs already displayed in
20 20 /// the zone
21 21 QString defaultGraphName(const QLayout &layout)
22 22 {
23 23 auto count = 0;
24 24 for (auto i = 0; i < layout.count(); ++i) {
25 25 if (dynamic_cast<VisualizationGraphWidget *>(layout.itemAt(i)->widget())) {
26 26 count++;
27 27 }
28 28 }
29 29
30 30 return QObject::tr("Graph %1").arg(count + 1);
31 31 }
32 32
33 33 } // namespace
34 34
35 35 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
36 36 : QWidget{parent}, ui{new Ui::VisualizationZoneWidget}
37 37 {
38 38 ui->setupUi(this);
39 39
40 40 ui->zoneNameLabel->setText(name);
41 41
42 42 // 'Close' options : widget is deleted when closed
43 43 setAttribute(Qt::WA_DeleteOnClose);
44 44 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
45 45 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
46 46 }
47 47
48 48 VisualizationZoneWidget::~VisualizationZoneWidget()
49 49 {
50 50 delete ui;
51 51 }
52 52
53 53 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
54 54 {
55 55 ui->visualizationZoneFrame->layout()->addWidget(graphWidget);
56 56 }
57 57
58 58 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
59 59 {
60 60 auto graphWidget = new VisualizationGraphWidget{
61 61 defaultGraphName(*ui->visualizationZoneFrame->layout()), this};
62 62
63 63
64 64 // Set graph properties
65 65 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
66 66 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
67 67
68 68 this->addGraph(graphWidget);
69 69
70 70 graphWidget->addVariable(variable);
71 71
72 72 // Lambda to synchronize zone widget
73 auto synchronizeZoneWidget = [this, graphWidget](const SqpDateTime &dateTime,
74 const SqpDateTime &oldDateTime,
73 auto synchronizeZoneWidget = [this, graphWidget](const SqpRange &dateTime,
74 const SqpRange &oldDateTime,
75 75 VisualizationGraphWidgetZoomType zoomType) {
76 76 auto frameLayout = ui->visualizationZoneFrame->layout();
77 77 for (auto i = 0; i < frameLayout->count(); ++i) {
78 78 auto graphChild
79 79 = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
80 80 if (graphChild && (graphChild != graphWidget)) {
81 81
82 82 auto graphChildRange = graphChild->graphRange();
83 83 switch (zoomType) {
84 84 case VisualizationGraphWidgetZoomType::ZoomIn: {
85 85 auto deltaLeft = dateTime.m_TStart - oldDateTime.m_TStart;
86 86 auto deltaRight = oldDateTime.m_TEnd - dateTime.m_TEnd;
87 87 graphChildRange.m_TStart += deltaLeft;
88 88 graphChildRange.m_TEnd -= deltaRight;
89 89 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomIn");
90 90 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
91 91 << deltaLeft;
92 92 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
93 93 << deltaRight;
94 94 qCCritical(LOG_VisualizationZoneWidget())
95 95 << tr("TORM: dt") << dateTime.m_TEnd - dateTime.m_TStart;
96 96
97 97 break;
98 98 }
99 99
100 100 case VisualizationGraphWidgetZoomType::ZoomOut: {
101 101 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomOut");
102 102 auto deltaLeft = oldDateTime.m_TStart - dateTime.m_TStart;
103 103 auto deltaRight = dateTime.m_TEnd - oldDateTime.m_TEnd;
104 104 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
105 105 << deltaLeft;
106 106 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
107 107 << deltaRight;
108 108 qCCritical(LOG_VisualizationZoneWidget())
109 109 << tr("TORM: dt") << dateTime.m_TEnd - dateTime.m_TStart;
110 110 graphChildRange.m_TStart -= deltaLeft;
111 111 graphChildRange.m_TEnd += deltaRight;
112 112 break;
113 113 }
114 114 case VisualizationGraphWidgetZoomType::PanRight: {
115 115 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: PanRight");
116 116 auto deltaRight = dateTime.m_TEnd - oldDateTime.m_TEnd;
117 117 graphChildRange.m_TStart += deltaRight;
118 118 graphChildRange.m_TEnd += deltaRight;
119 119 qCCritical(LOG_VisualizationZoneWidget())
120 120 << tr("TORM: dt") << dateTime.m_TEnd - dateTime.m_TStart;
121 121 break;
122 122 }
123 123 case VisualizationGraphWidgetZoomType::PanLeft: {
124 124 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: PanLeft");
125 125 auto deltaLeft = oldDateTime.m_TStart - dateTime.m_TStart;
126 126 graphChildRange.m_TStart -= deltaLeft;
127 127 graphChildRange.m_TEnd -= deltaLeft;
128 128 break;
129 129 }
130 130 case VisualizationGraphWidgetZoomType::Unknown: {
131 131 qCCritical(LOG_VisualizationZoneWidget())
132 132 << tr("Impossible to synchronize: zoom type unknown");
133 133 break;
134 134 }
135 135 default:
136 136 qCCritical(LOG_VisualizationZoneWidget())
137 137 << tr("Impossible to synchronize: zoom type not take into account");
138 138 // No action
139 139 break;
140 140 }
141 141 graphChild->enableSynchronize(false);
142 142 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: Range before: ")
143 143 << graphChild->graphRange();
144 144 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: Range after : ")
145 145 << graphChildRange;
146 146 qCCritical(LOG_VisualizationZoneWidget())
147 147 << tr("TORM: child dt") << graphChildRange.m_TEnd - graphChildRange.m_TStart;
148 148 graphChild->setGraphRange(graphChildRange);
149 149 graphChild->enableSynchronize(true);
150 150 }
151 151 }
152 152 };
153 153
154 154 // connection for synchronization
155 155 connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
156 156
157 157 return graphWidget;
158 158 }
159 159
160 160 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
161 161 {
162 162 if (visitor) {
163 163 visitor->visitEnter(this);
164 164
165 165 // Apply visitor to graph children
166 166 auto layout = ui->visualizationZoneFrame->layout();
167 167 for (auto i = 0; i < layout->count(); ++i) {
168 168 if (auto item = layout->itemAt(i)) {
169 169 // Widgets different from graphs are not visited (no action)
170 170 if (auto visualizationGraphWidget
171 171 = dynamic_cast<VisualizationGraphWidget *>(item->widget())) {
172 172 visualizationGraphWidget->accept(visitor);
173 173 }
174 174 }
175 175 }
176 176
177 177 visitor->visitLeave(this);
178 178 }
179 179 else {
180 180 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
181 181 }
182 182 }
183 183
184 184 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
185 185 {
186 186 // A tab can always accomodate a variable
187 187 Q_UNUSED(variable);
188 188 return true;
189 189 }
190 190
191 191 bool VisualizationZoneWidget::contains(const Variable &variable) const
192 192 {
193 193 Q_UNUSED(variable);
194 194 return false;
195 195 }
196 196
197 197 QString VisualizationZoneWidget::name() const
198 198 {
199 199 return ui->zoneNameLabel->text();
200 200 }
@@ -1,71 +1,69
1 1 #include "Visualization/operations/RescaleAxeOperation.h"
2 2 #include "Visualization/VisualizationGraphWidget.h"
3 3
4 4 Q_LOGGING_CATEGORY(LOG_RescaleAxeOperation, "RescaleAxeOperation")
5 5
6 6 struct RescaleAxeOperation::RescaleAxeOperationPrivate {
7 explicit RescaleAxeOperationPrivate(std::shared_ptr<Variable> variable,
8 const SqpDateTime &range)
7 explicit RescaleAxeOperationPrivate(std::shared_ptr<Variable> variable, const SqpRange &range)
9 8 : m_Variable{variable}, m_Range{range}
10 9 {
11 10 }
12 11
13 12 std::shared_ptr<Variable> m_Variable;
14 SqpDateTime m_Range;
13 SqpRange m_Range;
15 14 };
16 15
17 RescaleAxeOperation::RescaleAxeOperation(std::shared_ptr<Variable> variable,
18 const SqpDateTime &range)
16 RescaleAxeOperation::RescaleAxeOperation(std::shared_ptr<Variable> variable, const SqpRange &range)
19 17 : impl{spimpl::make_unique_impl<RescaleAxeOperationPrivate>(variable, range)}
20 18 {
21 19 }
22 20
23 21 void RescaleAxeOperation::visitEnter(VisualizationWidget *widget)
24 22 {
25 23 // VisualizationWidget is not intended to contain a variable
26 24 Q_UNUSED(widget)
27 25 }
28 26
29 27 void RescaleAxeOperation::visitLeave(VisualizationWidget *widget)
30 28 {
31 29 // VisualizationWidget is not intended to contain a variable
32 30 Q_UNUSED(widget)
33 31 }
34 32
35 33 void RescaleAxeOperation::visitEnter(VisualizationTabWidget *tabWidget)
36 34 {
37 35 // VisualizationTabWidget is not intended to contain a variable
38 36 Q_UNUSED(tabWidget)
39 37 }
40 38
41 39 void RescaleAxeOperation::visitLeave(VisualizationTabWidget *tabWidget)
42 40 {
43 41 // VisualizationTabWidget is not intended to contain a variable
44 42 Q_UNUSED(tabWidget)
45 43 }
46 44
47 45 void RescaleAxeOperation::visitEnter(VisualizationZoneWidget *zoneWidget)
48 46 {
49 47 // VisualizationZoneWidget is not intended to contain a variable
50 48 Q_UNUSED(zoneWidget)
51 49 }
52 50
53 51 void RescaleAxeOperation::visitLeave(VisualizationZoneWidget *zoneWidget)
54 52 {
55 53 // VisualizationZoneWidget is not intended to contain a variable
56 54 Q_UNUSED(zoneWidget)
57 55 }
58 56
59 57 void RescaleAxeOperation::visit(VisualizationGraphWidget *graphWidget)
60 58 {
61 59 if (graphWidget) {
62 60 // If the widget contains the variable, rescale it
63 61 if (impl->m_Variable && graphWidget->contains(*impl->m_Variable)) {
64 62 graphWidget->setRange(impl->m_Variable, impl->m_Range);
65 63 }
66 64 }
67 65 else {
68 66 qCCritical(LOG_RescaleAxeOperation(),
69 67 "Can't visit VisualizationGraphWidget : the widget is null");
70 68 }
71 69 }
@@ -1,30 +1,30
1 1 #ifndef SCIQLOP_AMDAPROVIDER_H
2 2 #define SCIQLOP_AMDAPROVIDER_H
3 3
4 4 #include "AmdaGlobal.h"
5 5
6 6 #include <Data/IDataProvider.h>
7 7
8 8 #include <QLoggingCategory>
9 9
10 10
11 11 Q_DECLARE_LOGGING_CATEGORY(LOG_AmdaProvider)
12 12
13 13 class QNetworkReply;
14 14
15 15 /**
16 16 * @brief The AmdaProvider class is an example of how a data provider can generate data
17 17 */
18 18 class SCIQLOP_AMDA_EXPORT AmdaProvider : public IDataProvider {
19 19 public:
20 20 explicit AmdaProvider();
21 21
22 22 void requestDataLoading(QUuid token, const DataProviderParameters &parameters) override;
23 23
24 24 void requestDataAborting(QUuid identifier) override;
25 25
26 26 private:
27 void retrieveData(QUuid token, const SqpDateTime &dateTime, const QVariantHash &data);
27 void retrieveData(QUuid token, const SqpRange &dateTime, const QVariantHash &data);
28 28 };
29 29
30 30 #endif // SCIQLOP_AMDAPROVIDER_H
@@ -1,148 +1,148
1 1 #include "AmdaProvider.h"
2 2 #include "AmdaDefs.h"
3 3 #include "AmdaResultParser.h"
4 4
5 5 #include <Common/DateUtils.h>
6 6 #include <Data/DataProviderParameters.h>
7 7 #include <Network/NetworkController.h>
8 8 #include <SqpApplication.h>
9 9 #include <Variable/Variable.h>
10 10
11 11 #include <QNetworkAccessManager>
12 12 #include <QNetworkReply>
13 13 #include <QTemporaryFile>
14 14 #include <QThread>
15 15
16 16 Q_LOGGING_CATEGORY(LOG_AmdaProvider, "AmdaProvider")
17 17
18 18 namespace {
19 19
20 20 /// URL format for a request on AMDA server. The parameters are as follows:
21 21 /// - %1: start date
22 22 /// - %2: end date
23 23 /// - %3: parameter id
24 24 const auto AMDA_URL_FORMAT = QStringLiteral(
25 25 "http://amda.irap.omp.eu/php/rest/"
26 26 "getParameter.php?startTime=%1&stopTime=%2&parameterID=%3&outputFormat=ASCII&"
27 27 "timeFormat=ISO8601&gzip=0");
28 28
29 29 /// Dates format passed in the URL (e.g 2013-09-23T09:00)
30 30 const auto AMDA_TIME_FORMAT = QStringLiteral("yyyy-MM-ddThh:mm:ss");
31 31
32 32 /// Formats a time to a date that can be passed in URL
33 QString dateFormat(double sqpDateTime) noexcept
33 QString dateFormat(double sqpRange) noexcept
34 34 {
35 auto dateTime = DateUtils::dateTime(sqpDateTime);
35 auto dateTime = DateUtils::dateTime(sqpRange);
36 36 return dateTime.toString(AMDA_TIME_FORMAT);
37 37 }
38 38
39 39 } // namespace
40 40
41 41 AmdaProvider::AmdaProvider()
42 42 {
43 43 qCDebug(LOG_AmdaProvider()) << tr("AmdaProvider::AmdaProvider") << QThread::currentThread();
44 44 if (auto app = sqpApp) {
45 45 auto &networkController = app->networkController();
46 46 connect(this, SIGNAL(requestConstructed(QNetworkRequest, QUuid,
47 47 std::function<void(QNetworkReply *, QUuid)>)),
48 48 &networkController,
49 49 SLOT(onProcessRequested(QNetworkRequest, QUuid,
50 50 std::function<void(QNetworkReply *, QUuid)>)));
51 51
52 52
53 53 connect(&sqpApp->networkController(), SIGNAL(replyDownloadProgress(QUuid, double)), this,
54 54 SIGNAL(dataProvidedProgress(QUuid, double)));
55 55 }
56 56 }
57 57
58 58 void AmdaProvider::requestDataLoading(QUuid token, const DataProviderParameters &parameters)
59 59 {
60 60 // NOTE: Try to use multithread if possible
61 61 const auto times = parameters.m_Times;
62 62 const auto data = parameters.m_Data;
63 63 for (const auto &dateTime : qAsConst(times)) {
64 64 retrieveData(token, dateTime, data);
65 65 }
66 66 }
67 67
68 68 void AmdaProvider::requestDataAborting(QUuid identifier)
69 69 {
70 70 if (auto app = sqpApp) {
71 71 auto &networkController = app->networkController();
72 72 networkController.onReplyCanceled(identifier);
73 73 }
74 74 }
75 75
76 void AmdaProvider::retrieveData(QUuid token, const SqpDateTime &dateTime, const QVariantHash &data)
76 void AmdaProvider::retrieveData(QUuid token, const SqpRange &dateTime, const QVariantHash &data)
77 77 {
78 78 // Retrieves product ID from data: if the value is invalid, no request is made
79 79 auto productId = data.value(AMDA_XML_ID_KEY).toString();
80 80 if (productId.isNull()) {
81 81 qCCritical(LOG_AmdaProvider()) << tr("Can't retrieve data: unknown product id");
82 82 return;
83 83 }
84 84 qCInfo(LOG_AmdaProvider()) << tr("AmdaProvider::retrieveData") << dateTime;
85 85
86 86 // /////////// //
87 87 // Creates URL //
88 88 // /////////// //
89 89
90 90 auto startDate = dateFormat(dateTime.m_TStart);
91 91 auto endDate = dateFormat(dateTime.m_TEnd);
92 92
93 93 auto url = QUrl{QString{AMDA_URL_FORMAT}.arg(startDate, endDate, productId)};
94 94 qCInfo(LOG_AmdaProvider()) << tr("AmdaProvider::retrieveData url:") << url;
95 95 auto tempFile = std::make_shared<QTemporaryFile>();
96 96
97 97 // LAMBDA
98 98 auto httpDownloadFinished
99 99 = [this, dateTime, tempFile, token](QNetworkReply *reply, QUuid dataId) noexcept {
100 100 Q_UNUSED(dataId);
101 101
102 102 // Don't do anything if the reply was abort
103 103 if (reply->error() != QNetworkReply::OperationCanceledError) {
104 104
105 105 if (tempFile) {
106 106 auto replyReadAll = reply->readAll();
107 107 if (!replyReadAll.isEmpty()) {
108 108 tempFile->write(replyReadAll);
109 109 }
110 110 tempFile->close();
111 111
112 112 // Parse results file
113 113 if (auto dataSeries = AmdaResultParser::readTxt(tempFile->fileName())) {
114 114 emit dataProvided(token, dataSeries, dateTime);
115 115 }
116 116 else {
117 117 /// @todo ALX : debug
118 118 }
119 119 }
120 120 }
121 121
122 122 };
123 123 auto httpFinishedLambda
124 124 = [this, httpDownloadFinished, tempFile](QNetworkReply *reply, QUuid dataId) noexcept {
125 125
126 126 // Don't do anything if the reply was abort
127 127 if (reply->error() != QNetworkReply::OperationCanceledError) {
128 128 auto downloadFileUrl = QUrl{QString{reply->readAll()}};
129 129
130 130
131 131 qCInfo(LOG_AmdaProvider()) << tr("AmdaProvider::retrieveData downloadFileUrl:")
132 132 << downloadFileUrl;
133 133 // Executes request for downloading file //
134 134
135 135 // Creates destination file
136 136 if (tempFile->open()) {
137 137 // Executes request
138 138 emit requestConstructed(QNetworkRequest{downloadFileUrl}, dataId,
139 139 httpDownloadFinished);
140 140 }
141 141 }
142 142 };
143 143
144 144 // //////////////// //
145 145 // Executes request //
146 146 // //////////////// //
147 147 emit requestConstructed(QNetworkRequest{url}, token, httpFinishedLambda);
148 148 }
@@ -1,33 +1,33
1 1 #ifndef SCIQLOP_COSINUSPROVIDER_H
2 2 #define SCIQLOP_COSINUSPROVIDER_H
3 3
4 4 #include "MockPluginGlobal.h"
5 5
6 6 #include <Data/IDataProvider.h>
7 7
8 8 #include <QLoggingCategory>
9 9 #include <QUuid>
10 10
11 11 #include <QHash>
12 12 Q_DECLARE_LOGGING_CATEGORY(LOG_CosinusProvider)
13 13
14 14 /**
15 15 * @brief The CosinusProvider class is an example of how a data provider can generate data
16 16 */
17 17 class SCIQLOP_MOCKPLUGIN_EXPORT CosinusProvider : public IDataProvider {
18 18 public:
19 19 /// @sa IDataProvider::requestDataLoading(). The current impl isn't thread safe.
20 20 void requestDataLoading(QUuid token, const DataProviderParameters &parameters) override;
21 21
22 22
23 23 /// @sa IDataProvider::requestDataAborting(). The current impl isn't thread safe.
24 24 void requestDataAborting(QUuid identifier) override;
25 25
26 26
27 27 private:
28 std::shared_ptr<IDataSeries> retrieveData(QUuid token, const SqpDateTime &dateTime);
28 std::shared_ptr<IDataSeries> retrieveData(QUuid token, const SqpRange &dateTime);
29 29
30 30 QHash<QUuid, bool> m_VariableToEnableProvider;
31 31 };
32 32
33 33 #endif // SCIQLOP_COSINUSPROVIDER_H
@@ -1,100 +1,100
1 1 #include "CosinusProvider.h"
2 2
3 3 #include <Data/DataProviderParameters.h>
4 4 #include <Data/ScalarSeries.h>
5 5
6 6 #include <cmath>
7 7
8 8 #include <QFuture>
9 9 #include <QThread>
10 10 #include <QtConcurrent/QtConcurrent>
11 11
12 12 Q_LOGGING_CATEGORY(LOG_CosinusProvider, "CosinusProvider")
13 13
14 std::shared_ptr<IDataSeries> CosinusProvider::retrieveData(QUuid token, const SqpDateTime &dateTime)
14 std::shared_ptr<IDataSeries> CosinusProvider::retrieveData(QUuid token, const SqpRange &dateTime)
15 15 {
16 16 // TODO: Add Mutex
17 17 auto dataIndex = 0;
18 18
19 19 // Gets the timerange from the parameters
20 20 double freq = 100.0;
21 21 double start = std::ceil(dateTime.m_TStart * freq); // 100 htz
22 22 double end = std::floor(dateTime.m_TEnd * freq); // 100 htz
23 23
24 24 // We assure that timerange is valid
25 25 if (end < start) {
26 26 std::swap(start, end);
27 27 }
28 28
29 29 // Generates scalar series containing cosinus values (one value per second)
30 30 auto dataCount = end - start;
31 31
32 32 auto xAxisData = QVector<double>{};
33 33 xAxisData.resize(dataCount);
34 34
35 35 auto valuesData = QVector<double>{};
36 36 valuesData.resize(dataCount);
37 37
38 38 int progress = 0;
39 39 auto progressEnd = dataCount;
40 40 for (auto time = start; time < end; ++time, ++dataIndex) {
41 41 auto it = m_VariableToEnableProvider.find(token);
42 42 if (it != m_VariableToEnableProvider.end() && it.value()) {
43 43 const auto timeOnFreq = time / freq;
44 44
45 45 xAxisData.replace(dataIndex, timeOnFreq);
46 46 valuesData.replace(dataIndex, std::cos(timeOnFreq));
47 47
48 48 // progression
49 49 int currentProgress = (time - start) * 100.0 / progressEnd;
50 50 if (currentProgress != progress) {
51 51 progress = currentProgress;
52 52
53 53 emit dataProvidedProgress(token, progress);
54 54 }
55 55 }
56 56 else {
57 57 if (!it.value()) {
58 58 qCDebug(LOG_CosinusProvider())
59 59 << "CosinusProvider::retrieveData: ARRET De l'acquisition detecté"
60 60 << end - time;
61 61 }
62 62 }
63 63 }
64 64 emit dataProvidedProgress(token, 0.0);
65 65
66 66 return std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData),
67 67 Unit{QStringLiteral("t"), true}, Unit{});
68 68 }
69 69
70 70 void CosinusProvider::requestDataLoading(QUuid token, const DataProviderParameters &parameters)
71 71 {
72 72 // TODO: Add Mutex
73 73 m_VariableToEnableProvider[token] = true;
74 74 qCDebug(LOG_CosinusProvider()) << "CosinusProvider::requestDataLoading"
75 75 << QThread::currentThread()->objectName();
76 76 // NOTE: Try to use multithread if possible
77 77 const auto times = parameters.m_Times;
78 78
79 79 for (const auto &dateTime : qAsConst(times)) {
80 80 if (m_VariableToEnableProvider[token]) {
81 81 auto scalarSeries = this->retrieveData(token, dateTime);
82 82 emit dataProvided(token, scalarSeries, dateTime);
83 83 }
84 84 }
85 85 }
86 86
87 87 void CosinusProvider::requestDataAborting(QUuid identifier)
88 88 {
89 89 // TODO: Add Mutex
90 90 qCDebug(LOG_CosinusProvider()) << "CosinusProvider::requestDataAborting" << identifier
91 91 << QThread::currentThread()->objectName();
92 92 auto it = m_VariableToEnableProvider.find(identifier);
93 93 if (it != m_VariableToEnableProvider.end()) {
94 94 it.value() = false;
95 95 }
96 96 else {
97 97 qCWarning(LOG_CosinusProvider())
98 98 << tr("Aborting progression of inexistant identifier detected !!!");
99 99 }
100 100 }
General Comments 0
You need to be logged in to leave comments. Login now