##// END OF EJS Templates
Merge pull request 189 from SCIQLOP-Initialisation develop...
leroux -
r448:f7cb609ac07f merge
parent child
Show More
@@ -0,0 +1,42
1 #ifndef SCIQLOP_RESCALEAXEOPERATION_H
2 #define SCIQLOP_RESCALEAXEOPERATION_H
3
4 #include "Visualization/IVisualizationWidgetVisitor.h"
5 #include <Data/SqpDateTime.h>
6
7 #include <Common/spimpl.h>
8
9 #include <QLoggingCategory>
10
11 #include <memory>
12
13 class Variable;
14
15 Q_DECLARE_LOGGING_CATEGORY(LOG_RescaleAxeOperation)
16
17 /**
18 * @brief The RescaleAxeOperation class defines an operation that traverses all of visualization
19 * widgets to remove a variable if they contain it
20 */
21 class RescaleAxeOperation : public IVisualizationWidgetVisitor {
22 public:
23 /**
24 * Ctor
25 * @param variable the variable to remove from widgets
26 */
27 explicit RescaleAxeOperation(std::shared_ptr<Variable> variable, const SqpDateTime &range);
28
29 void visitEnter(VisualizationWidget *widget) override final;
30 void visitLeave(VisualizationWidget *widget) override final;
31 void visitEnter(VisualizationTabWidget *tabWidget) override final;
32 void visitLeave(VisualizationTabWidget *tabWidget) override final;
33 void visitEnter(VisualizationZoneWidget *zoneWidget) override final;
34 void visitLeave(VisualizationZoneWidget *zoneWidget) override final;
35 void visit(VisualizationGraphWidget *graphWidget) override final;
36
37 private:
38 class RescaleAxeOperationPrivate;
39 spimpl::unique_impl_ptr<RescaleAxeOperationPrivate> impl;
40 };
41
42 #endif // SCIQLOP_RESCALEAXEOPERATION_H
@@ -0,0 +1,71
1 #include "Visualization/operations/RescaleAxeOperation.h"
2 #include "Visualization/VisualizationGraphWidget.h"
3
4 Q_LOGGING_CATEGORY(LOG_RescaleAxeOperation, "RescaleAxeOperation")
5
6 struct RescaleAxeOperation::RescaleAxeOperationPrivate {
7 explicit RescaleAxeOperationPrivate(std::shared_ptr<Variable> variable,
8 const SqpDateTime &range)
9 : m_Variable{variable}, m_Range{range}
10 {
11 }
12
13 std::shared_ptr<Variable> m_Variable;
14 SqpDateTime m_Range;
15 };
16
17 RescaleAxeOperation::RescaleAxeOperation(std::shared_ptr<Variable> variable,
18 const SqpDateTime &range)
19 : impl{spimpl::make_unique_impl<RescaleAxeOperationPrivate>(variable, range)}
20 {
21 }
22
23 void RescaleAxeOperation::visitEnter(VisualizationWidget *widget)
24 {
25 // VisualizationWidget is not intended to contain a variable
26 Q_UNUSED(widget)
27 }
28
29 void RescaleAxeOperation::visitLeave(VisualizationWidget *widget)
30 {
31 // VisualizationWidget is not intended to contain a variable
32 Q_UNUSED(widget)
33 }
34
35 void RescaleAxeOperation::visitEnter(VisualizationTabWidget *tabWidget)
36 {
37 // VisualizationTabWidget is not intended to contain a variable
38 Q_UNUSED(tabWidget)
39 }
40
41 void RescaleAxeOperation::visitLeave(VisualizationTabWidget *tabWidget)
42 {
43 // VisualizationTabWidget is not intended to contain a variable
44 Q_UNUSED(tabWidget)
45 }
46
47 void RescaleAxeOperation::visitEnter(VisualizationZoneWidget *zoneWidget)
48 {
49 // VisualizationZoneWidget is not intended to contain a variable
50 Q_UNUSED(zoneWidget)
51 }
52
53 void RescaleAxeOperation::visitLeave(VisualizationZoneWidget *zoneWidget)
54 {
55 // VisualizationZoneWidget is not intended to contain a variable
56 Q_UNUSED(zoneWidget)
57 }
58
59 void RescaleAxeOperation::visit(VisualizationGraphWidget *graphWidget)
60 {
61 if (graphWidget) {
62 // If the widget contains the variable, rescale it
63 if (impl->m_Variable && graphWidget->contains(*impl->m_Variable)) {
64 graphWidget->setRange(impl->m_Variable, impl->m_Range);
65 }
66 }
67 else {
68 qCCritical(LOG_RescaleAxeOperation(),
69 "Can't visit VisualizationGraphWidget : the widget is null");
70 }
71 }
@@ -0,0 +1,3
1 Not Found
2
3 The requested URL /AMDA/data/WSRESULT/imf(0)-1343153090-1343153092-60.txt was not found on this server. No newline at end of file
@@ -1,265 +1,269
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 <SidePane/SqpSidePane.h>
28 28 #include <SqpApplication.h>
29 29 #include <Time/TimeController.h>
30 30 #include <TimeWidget/TimeWidget.h>
31 31 #include <Variable/Variable.h>
32 32 #include <Variable/VariableController.h>
33 33 #include <Visualization/VisualizationController.h>
34 34
35 35 #include <QAction>
36 36 #include <QDate>
37 37 #include <QDateTime>
38 38 #include <QDir>
39 39 #include <QFileDialog>
40 40 #include <QToolBar>
41 41 #include <QToolButton>
42 42 #include <memory.h>
43 43
44 44 //#include <omp.h>
45 45 //#include <network/filedownloader.h>
46 46 //#include <qlopdatabase.h>
47 47 //#include <qlopsettings.h>
48 48 //#include <qlopgui.h>
49 49 //#include <spacedata.h>
50 50 //#include "qlopcore.h"
51 51 //#include "qlopcodecmanager.h"
52 52 //#include "cdfcodec.h"
53 53 //#include "amdatxtcodec.h"
54 54 //#include <qlopplotmanager.h>
55 55
56 56 #include "iostream"
57 57
58 58 Q_LOGGING_CATEGORY(LOG_MainWindow, "MainWindow")
59 59
60 60 namespace {
61 61 const auto LEFTMAININSPECTORWIDGETSPLITTERINDEX = 0;
62 62 const auto LEFTINSPECTORSIDEPANESPLITTERINDEX = 1;
63 63 const auto VIEWPLITTERINDEX = 2;
64 64 const auto RIGHTINSPECTORSIDEPANESPLITTERINDEX = 3;
65 65 const auto RIGHTMAININSPECTORWIDGETSPLITTERINDEX = 4;
66 66 }
67 67
68 68 class MainWindow::MainWindowPrivate {
69 69 public:
70 70 QSize m_LastOpenLeftInspectorSize;
71 71 QSize m_LastOpenRightInspectorSize;
72 72 };
73 73
74 74 MainWindow::MainWindow(QWidget *parent)
75 75 : QMainWindow{parent},
76 76 m_Ui{new Ui::MainWindow},
77 77 impl{spimpl::make_unique_impl<MainWindowPrivate>()}
78 78 {
79 79 m_Ui->setupUi(this);
80 80
81 81 m_Ui->splitter->setCollapsible(LEFTINSPECTORSIDEPANESPLITTERINDEX, false);
82 82 m_Ui->splitter->setCollapsible(RIGHTINSPECTORSIDEPANESPLITTERINDEX, false);
83 83
84 84
85 85 auto leftSidePane = m_Ui->leftInspectorSidePane->sidePane();
86 86 auto openLeftInspectorAction = new QAction{QIcon{
87 87 ":/icones/previous.png",
88 88 },
89 89 tr("Show/hide the left inspector"), this};
90 90
91 91
92 92 auto spacerLeftTop = new QWidget{};
93 93 spacerLeftTop->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
94 94
95 95 auto spacerLeftBottom = new QWidget{};
96 96 spacerLeftBottom->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
97 97
98 98 leftSidePane->addWidget(spacerLeftTop);
99 99 leftSidePane->addAction(openLeftInspectorAction);
100 100 leftSidePane->addWidget(spacerLeftBottom);
101 101
102 102
103 103 auto rightSidePane = m_Ui->rightInspectorSidePane->sidePane();
104 104 auto openRightInspectorAction = new QAction{QIcon{
105 105 ":/icones/next.png",
106 106 },
107 107 tr("Show/hide the right inspector"), this};
108 108
109 109 auto spacerRightTop = new QWidget{};
110 110 spacerRightTop->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
111 111
112 112 auto spacerRightBottom = new QWidget{};
113 113 spacerRightBottom->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
114 114
115 115 rightSidePane->addWidget(spacerRightTop);
116 116 rightSidePane->addAction(openRightInspectorAction);
117 117 rightSidePane->addWidget(spacerRightBottom);
118 118
119 119 openLeftInspectorAction->setCheckable(true);
120 120 openRightInspectorAction->setCheckable(true);
121 121
122 122 auto openInspector = [this](bool checked, bool right, auto action) {
123 123
124 124 action->setIcon(QIcon{(checked xor right) ? ":/icones/next.png" : ":/icones/previous.png"});
125 125
126 126 auto &lastInspectorSize
127 127 = right ? impl->m_LastOpenRightInspectorSize : impl->m_LastOpenLeftInspectorSize;
128 128
129 129 auto nextInspectorSize = right ? m_Ui->rightMainInspectorWidget->size()
130 130 : m_Ui->leftMainInspectorWidget->size();
131 131
132 132 // Update of the last opened geometry
133 133 if (checked) {
134 134 lastInspectorSize = nextInspectorSize;
135 135 }
136 136
137 137 auto startSize = lastInspectorSize;
138 138 auto endSize = startSize;
139 139 endSize.setWidth(0);
140 140
141 141 auto splitterInspectorIndex
142 142 = right ? RIGHTMAININSPECTORWIDGETSPLITTERINDEX : LEFTMAININSPECTORWIDGETSPLITTERINDEX;
143 143
144 144 auto currentSizes = m_Ui->splitter->sizes();
145 145 if (checked) {
146 146 // adjust sizes individually here, e.g.
147 147 currentSizes[splitterInspectorIndex] -= lastInspectorSize.width();
148 148 currentSizes[VIEWPLITTERINDEX] += lastInspectorSize.width();
149 149 m_Ui->splitter->setSizes(currentSizes);
150 150 }
151 151 else {
152 152 // adjust sizes individually here, e.g.
153 153 currentSizes[splitterInspectorIndex] += lastInspectorSize.width();
154 154 currentSizes[VIEWPLITTERINDEX] -= lastInspectorSize.width();
155 155 m_Ui->splitter->setSizes(currentSizes);
156 156 }
157 157
158 158 };
159 159
160 160
161 161 connect(openLeftInspectorAction, &QAction::triggered,
162 162 [openInspector, openLeftInspectorAction](bool checked) {
163 163 openInspector(checked, false, openLeftInspectorAction);
164 164 });
165 165 connect(openRightInspectorAction, &QAction::triggered,
166 166 [openInspector, openRightInspectorAction](bool checked) {
167 167 openInspector(checked, true, openRightInspectorAction);
168 168 });
169 169
170 170 this->menuBar()->addAction(tr("File"));
171 171 auto mainToolBar = this->addToolBar(QStringLiteral("MainToolBar"));
172 172
173 173 auto timeWidget = new TimeWidget{};
174 174 mainToolBar->addWidget(timeWidget);
175 175
176 176 // Controllers / controllers connections
177 177 connect(&sqpApp->timeController(), SIGNAL(timeUpdated(SqpDateTime)),
178 178 &sqpApp->variableController(), SLOT(onDateTimeOnSelection(SqpDateTime)));
179 179
180 180 // Widgets / controllers connections
181 181
182 182 // DataSource
183 183 connect(&sqpApp->dataSourceController(), SIGNAL(dataSourceItemSet(DataSourceItem *)),
184 184 m_Ui->dataSourceWidget, SLOT(addDataSource(DataSourceItem *)));
185 185
186 186 // Time
187 187 connect(timeWidget, SIGNAL(timeUpdated(SqpDateTime)), &sqpApp->timeController(),
188 188 SLOT(onTimeToUpdate(SqpDateTime)));
189 189
190 190 // Visualization
191 191 connect(&sqpApp->visualizationController(),
192 192 SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)), m_Ui->view,
193 193 SLOT(onVariableAboutToBeDeleted(std::shared_ptr<Variable>)));
194 194
195 connect(&sqpApp->visualizationController(),
196 SIGNAL(rangeChanged(std::shared_ptr<Variable>, const SqpDateTime &)), m_Ui->view,
197 SLOT(onRangeChanged(std::shared_ptr<Variable>, const SqpDateTime &)));
198
195 199 // Widgets / widgets connections
196 200
197 201 // For the following connections, we use DirectConnection to allow each widget that can
198 202 // potentially attach a menu to the variable's menu to do so before this menu is displayed.
199 203 // The order of connections is also important, since it determines the order in which each
200 204 // widget will attach its menu
201 205 connect(
202 206 m_Ui->variableInspectorWidget,
203 207 SIGNAL(tableMenuAboutToBeDisplayed(QMenu *, const QVector<std::shared_ptr<Variable> > &)),
204 208 m_Ui->view, SLOT(attachVariableMenu(QMenu *, const QVector<std::shared_ptr<Variable> > &)),
205 209 Qt::DirectConnection);
206 210
207 211 /* QLopGUI::registerMenuBar(menuBar());
208 212 this->setWindowIcon(QIcon(":/sciqlopLOGO.svg"));
209 213 this->m_progressWidget = new QWidget();
210 214 this->m_progressLayout = new QVBoxLayout(this->m_progressWidget);
211 215 this->m_progressWidget->setLayout(this->m_progressLayout);
212 216 this->m_progressWidget->setWindowModality(Qt::WindowModal);
213 217 m_progressThreadIds = (int*) malloc(OMP_THREADS*sizeof(int));
214 218 for(int i=0;i<OMP_THREADS;i++)
215 219 {
216 220 this->m_progress.append(new QProgressBar(this->m_progressWidget));
217 221 this->m_progress.last()->setMinimum(0);
218 222 this->m_progress.last()->setMaximum(100);
219 223 this->m_progressLayout->addWidget(this->m_progress.last());
220 224 this->m_progressWidget->hide();
221 225 this->m_progressThreadIds[i] = -1;
222 226 }
223 227 this->m_progressWidget->setWindowTitle("Loading File");
224 228 const QList<QLopService*>ServicesToLoad=QList<QLopService*>()
225 229 << QLopCore::self()
226 230 << QLopPlotManager::self()
227 231 << QLopCodecManager::self()
228 232 << FileDownloader::self()
229 233 << QLopDataBase::self()
230 234 << SpaceData::self();
231 235
232 236 CDFCodec::registerToManager();
233 237 AMDATXTCodec::registerToManager();
234 238
235 239
236 240 for(int i=0;i<ServicesToLoad.count();i++)
237 241 {
238 242 qDebug()<<ServicesToLoad.at(i)->serviceName();
239 243 ServicesToLoad.at(i)->initialize(); //must be called before getGUI
240 244 QDockWidget* wdgt=ServicesToLoad.at(i)->getGUI();
241 245 if(wdgt)
242 246 {
243 247 wdgt->setAllowedAreas(Qt::AllDockWidgetAreas);
244 248 this->addDockWidget(Qt::TopDockWidgetArea,wdgt);
245 249 }
246 250 PythonQt::self()->getMainModule().addObject(ServicesToLoad.at(i)->serviceName(),(QObject*)ServicesToLoad.at(i));
247 251 }*/
248 252 }
249 253
250 254 MainWindow::~MainWindow()
251 255 {
252 256 }
253 257
254 258
255 259 void MainWindow::changeEvent(QEvent *e)
256 260 {
257 261 QMainWindow::changeEvent(e);
258 262 switch (e->type()) {
259 263 case QEvent::LanguageChange:
260 264 m_Ui->retranslateUi(this);
261 265 break;
262 266 default:
263 267 break;
264 268 }
265 269 }
@@ -1,59 +1,72
1 1 #ifndef SCIQLOP_IDATAPROVIDER_H
2 2 #define SCIQLOP_IDATAPROVIDER_H
3 3
4 4 #include <memory>
5 5
6 6 #include <QObject>
7 7 #include <QUuid>
8 8
9 9 #include <Common/MetaTypes.h>
10 10
11 11 #include <Data/SqpDateTime.h>
12 12
13 #include <functional>
14
13 15 class DataProviderParameters;
14 16 class IDataSeries;
15 17 class QNetworkReply;
16 18 class QNetworkRequest;
17 19
18 20 /**
19 21 * @brief The IDataProvider interface aims to declare a data provider.
20 22 *
21 23 * A data provider is an entity that generates data and returns it according to various parameters
22 24 * (time interval, product to retrieve the data, etc.)
23 25 *
24 26 * @sa IDataSeries
25 27 */
26 28 class IDataProvider : public QObject {
27 29
28 30 Q_OBJECT
29 31 public:
30 32 virtual ~IDataProvider() noexcept = default;
31 33
32 34 /**
33 35 * @brief requestDataLoading provide datas for the data identified by identifier and parameters
34 36 */
35 37 virtual void requestDataLoading(QUuid identifier, const DataProviderParameters &parameters) = 0;
36 38
39 /**
40 * @brief requestDataAborting stop data loading of the data identified by identifier
41 */
42 virtual void requestDataAborting(QUuid identifier) = 0;
43
37 44 signals:
38 45 /**
39 46 * @brief dataProvided send dataSeries under dateTime and that corresponds of the data
40 47 * identified by identifier
41 48 */
42 49 void dataProvided(QUuid identifier, std::shared_ptr<IDataSeries> dateSerie,
43 50 const SqpDateTime &dateTime);
44 51
52 /**
53 * @brief dataProvided send dataSeries under dateTime and that corresponds of the data
54 * identified by identifier
55 */
56 void dataProvidedProgress(QUuid identifier, double progress);
57
45 58
46 59 /**
47 60 * @brief requestConstructed send a request for the data identified by identifier
48 61 * @callback is the methode call by the reply of the request when it is finished.
49 62 */
50 63 void requestConstructed(const QNetworkRequest &request, QUuid identifier,
51 64 std::function<void(QNetworkReply *, QUuid)> callback);
52 65 };
53 66
54 67 // Required for using shared_ptr in signals/slots
55 68 SCIQLOP_REGISTER_META_TYPE(IDATAPROVIDER_PTR_REGISTRY, std::shared_ptr<IDataProvider>)
56 69 SCIQLOP_REGISTER_META_TYPE(IDATAPROVIDER_FUNCTION_REGISTRY,
57 70 std::function<void(QNetworkReply *, QUuid)>)
58 71
59 72 #endif // SCIQLOP_IDATAPROVIDER_H
@@ -1,48 +1,50
1 1 #ifndef SCIQLOP_DATASOURCEITEMACTION_H
2 2 #define SCIQLOP_DATASOURCEITEMACTION_H
3 3
4 4 #include <Common/spimpl.h>
5 5
6 6 #include <QLoggingCategory>
7 7 #include <QObject>
8 8
9 #include <functional>
10
9 11 Q_DECLARE_LOGGING_CATEGORY(LOG_DataSourceItemAction)
10 12
11 13 class DataSourceItem;
12 14
13 15 /**
14 16 * @brief The DataSourceItemAction class represents an action on a data source item.
15 17 *
16 18 * An action is a function that will be executed when the slot execute() is called.
17 19 */
18 20 class DataSourceItemAction : public QObject {
19 21
20 22 Q_OBJECT
21 23
22 24 public:
23 25 /// Signature of the function associated to the action
24 26 using ExecuteFunction = std::function<void(DataSourceItem &dataSourceItem)>;
25 27
26 28 /**
27 29 * Ctor
28 30 * @param name the name of the action
29 31 * @param fun the function that will be called when the action is executed
30 32 * @sa execute()
31 33 */
32 34 explicit DataSourceItemAction(const QString &name, ExecuteFunction fun);
33 35
34 36 QString name() const noexcept;
35 37
36 38 /// Sets the data source item concerned by the action
37 39 void setDataSourceItem(DataSourceItem *dataSourceItem) noexcept;
38 40
39 41 public slots:
40 42 /// Executes the action
41 43 void execute();
42 44
43 45 private:
44 46 class DataSourceItemActionPrivate;
45 47 spimpl::unique_impl_ptr<DataSourceItemActionPrivate> impl;
46 48 };
47 49
48 50 #endif // SCIQLOP_DATASOURCEITEMACTION_H
@@ -1,85 +1,95
1 1 #ifndef SCIQLOP_VARIABLECONTROLLER_H
2 2 #define SCIQLOP_VARIABLECONTROLLER_H
3 3
4 4 #include <Data/SqpDateTime.h>
5 5
6 6 #include <QLoggingCategory>
7 7 #include <QObject>
8 8
9 9 #include <Common/spimpl.h>
10 10
11 11 class IDataProvider;
12 12 class QItemSelectionModel;
13 13 class TimeController;
14 14 class Variable;
15 15 class VariableModel;
16 16
17 17 Q_DECLARE_LOGGING_CATEGORY(LOG_VariableController)
18 18
19 19 /**
20 20 * @brief The VariableController class aims to handle the variables in SciQlop.
21 21 */
22 22 class VariableController : public QObject {
23 23 Q_OBJECT
24 24 public:
25 25 explicit VariableController(QObject *parent = 0);
26 26 virtual ~VariableController();
27 27
28 28 VariableModel *variableModel() noexcept;
29 29 QItemSelectionModel *variableSelectionModel() noexcept;
30 30
31 31 void setTimeController(TimeController *timeController) noexcept;
32 32
33 33 /**
34 34 * Deletes from the controller the variable passed in parameter.
35 35 *
36 36 * Delete a variable includes:
37 37 * - the deletion of the various references to the variable in SciQlop
38 38 * - the deletion of the model variable
39 39 * - the deletion of the provider associated with the variable
40 40 * - removing the cache associated with the variable
41 41 *
42 42 * @param variable the variable to delete from the controller.
43 43 */
44 44 void deleteVariable(std::shared_ptr<Variable> variable) noexcept;
45 45
46 46 /**
47 47 * Deletes from the controller the variables passed in parameter.
48 48 * @param variables the variables to delete from the controller.
49 49 * @sa deleteVariable()
50 50 */
51 51 void deleteVariables(const QVector<std::shared_ptr<Variable> > &variables) noexcept;
52 52
53 /**
54 * @brief abort the variable retrieve data progression
55 */
56 void abortProgress(std::shared_ptr<Variable> variable);
57
53 58 signals:
54 59 /// Signal emitted when a variable is about to be deleted from the controller
55 60 void variableAboutToBeDeleted(std::shared_ptr<Variable> variable);
56 61
62 /// Signal emitted when a data acquisition is requested on a range for a variable
63 void rangeChanged(std::shared_ptr<Variable> variable, const SqpDateTime &range);
64
57 65 public slots:
58 66 /// Request the data loading of the variable whithin dateTime
59 67 void onRequestDataLoading(std::shared_ptr<Variable> variable, const SqpDateTime &dateTime);
60 68 /**
61 69 * Creates a new variable and adds it to the model
62 70 * @param name the name of the new variable
63 71 * @param metadata the metadata of the new variable
64 72 * @param provider the data provider for the new variable
65 73 */
66 74 void createVariable(const QString &name, const QVariantHash &metadata,
67 75 std::shared_ptr<IDataProvider> provider) noexcept;
68 76
69 77 /// Update the temporal parameters of every selected variable to dateTime
70 78 void onDateTimeOnSelection(const SqpDateTime &dateTime);
71 79
72 80
73 81 void onVariableRetrieveDataInProgress(QUuid identifier, double progress);
74 82
83 void onAbortProgressRequested(std::shared_ptr<Variable> variable);
84
75 85 void initialize();
76 86 void finalize();
77 87
78 88 private:
79 89 void waitForFinish();
80 90
81 91 class VariableControllerPrivate;
82 92 spimpl::unique_impl_ptr<VariableControllerPrivate> impl;
83 93 };
84 94
85 95 #endif // SCIQLOP_VARIABLECONTROLLER_H
@@ -1,71 +1,79
1 1 #ifndef SCIQLOP_VARIABLEMODEL_H
2 2 #define SCIQLOP_VARIABLEMODEL_H
3 3
4 4
5 5 #include <Data/SqpDateTime.h>
6 6
7 7 #include <QAbstractTableModel>
8 8 #include <QLoggingCategory>
9 9
10 10 #include <Common/MetaTypes.h>
11 11 #include <Common/spimpl.h>
12 12
13 13 Q_DECLARE_LOGGING_CATEGORY(LOG_VariableModel)
14 14
15 15 enum VariableRoles { ProgressRole = Qt::UserRole };
16 16
17 17
18 18 class IDataSeries;
19 19 class Variable;
20 20
21 21 /**
22 22 * @brief The VariableModel class aims to hold the variables that have been created in SciQlop
23 23 */
24 24 class VariableModel : public QAbstractTableModel {
25 Q_OBJECT
25 26 public:
26 27 explicit VariableModel(QObject *parent = nullptr);
27 28
28 29 /**
29 30 * Creates a new variable in the model
30 31 * @param name the name of the new variable
31 32 * @param dateTime the dateTime of the new variable
32 33 * @param metadata the metadata associated to the new variable
33 34 * @return the pointer to the new variable
34 35 */
35 36 std::shared_ptr<Variable> createVariable(const QString &name, const SqpDateTime &dateTime,
36 37 const QVariantHash &metadata) noexcept;
37 38
38 39 /**
39 40 * Deletes a variable from the model, if it exists
40 41 * @param variable the variable to delete
41 42 */
42 43 void deleteVariable(std::shared_ptr<Variable> variable) noexcept;
43 44
44 45
45 46 std::shared_ptr<Variable> variable(int index) const;
46 47
47 48 void setDataProgress(std::shared_ptr<Variable> variable, double progress);
48 49
50
49 51 // /////////////////////////// //
50 52 // QAbstractTableModel methods //
51 53 // /////////////////////////// //
52 54
53 55 virtual int columnCount(const QModelIndex &parent = QModelIndex{}) const override;
54 56 virtual int rowCount(const QModelIndex &parent = QModelIndex{}) const override;
55 57 virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
56 58 virtual QVariant headerData(int section, Qt::Orientation orientation,
57 59 int role = Qt::DisplayRole) const override;
58 60
61
62 void abortProgress(const QModelIndex &index);
63
64 signals:
65 void abortProgessRequested(std::shared_ptr<Variable> variable);
66
59 67 private:
60 68 class VariableModelPrivate;
61 69 spimpl::unique_impl_ptr<VariableModelPrivate> impl;
62 70
63 71 private slots:
64 72 /// Slot called when data of a variable has been updated
65 73 void onVariableUpdated() noexcept;
66 74 };
67 75
68 76 // Registers QVector<int> metatype so it can be used in VariableModel::dataChanged() signal
69 77 SCIQLOP_REGISTER_META_TYPE(QVECTOR_INT_REGISTRY, QVector<int>)
70 78
71 79 #endif // SCIQLOP_VARIABLEMODEL_H
@@ -1,44 +1,49
1 1 #ifndef SCIQLOP_VISUALIZATIONCONTROLLER_H
2 2 #define SCIQLOP_VISUALIZATIONCONTROLLER_H
3 3
4 #include <Data/SqpDateTime.h>
5
4 6 #include <QLoggingCategory>
5 7 #include <QObject>
6 8 #include <QUuid>
7 9
8 10 #include <Common/spimpl.h>
9 11
10 12 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationController)
11 13
12 14 class DataSourceItem;
13 15 class Variable;
14 16
15 17 /**
16 18 * @brief The VisualizationController class aims to make the link between SciQlop and its plugins.
17 19 * This is the intermediate class that SciQlop has to use in the way to connect a data source.
18 20 * Please first use register method to initialize a plugin specified by its metadata name (JSON
19 21 * plugin source) then others specifics method will be able to access it. You can load a data source
20 22 * driver plugin then create a data source.
21 23 */
22 24 class VisualizationController : public QObject {
23 25 Q_OBJECT
24 26 public:
25 27 explicit VisualizationController(QObject *parent = 0);
26 28 virtual ~VisualizationController();
27 29
28 30 signals:
29 31 /// Signal emitted when a variable is about to be deleted from SciQlop
30 32 void variableAboutToBeDeleted(std::shared_ptr<Variable> variable);
31 33
34 /// Signal emitted when a data acquisition is requested on a range for a variable
35 void rangeChanged(std::shared_ptr<Variable> variable, const SqpDateTime &range);
36
32 37 public slots:
33 38 /// Manage init/end of the controller
34 39 void initialize();
35 40 void finalize();
36 41
37 42 private:
38 43 void waitForFinish();
39 44
40 45 class VisualizationControllerPrivate;
41 46 spimpl::unique_impl_ptr<VisualizationControllerPrivate> impl;
42 47 };
43 48
44 49 #endif // SCIQLOP_VISUALIZATIONCONTROLLER_H
@@ -1,87 +1,133
1 1 #include "Network/NetworkController.h"
2 2
3 3 #include <QMutex>
4 4 #include <QNetworkAccessManager>
5 5 #include <QNetworkReply>
6 6 #include <QNetworkRequest>
7 #include <QReadWriteLock>
7 8 #include <QThread>
8 9
9 10 #include <unordered_map>
10 11
11 12 Q_LOGGING_CATEGORY(LOG_NetworkController, "NetworkController")
12 13
13 14 struct NetworkController::NetworkControllerPrivate {
14 15 explicit NetworkControllerPrivate(NetworkController *parent) : m_WorkingMutex{} {}
15 16 QMutex m_WorkingMutex;
16 17
18 QReadWriteLock m_Lock;
17 19 std::unordered_map<QNetworkReply *, QUuid> m_NetworkReplyToVariableId;
18 20 std::unique_ptr<QNetworkAccessManager> m_AccessManager{nullptr};
21
22 void lockRead() { m_Lock.lockForRead(); }
23 void lockWrite() { m_Lock.lockForWrite(); }
24 void unlock() { m_Lock.unlock(); }
19 25 };
20 26
21 27 NetworkController::NetworkController(QObject *parent)
22 28 : QObject(parent), impl{spimpl::make_unique_impl<NetworkControllerPrivate>(this)}
23 29 {
24 30 }
25 31
26 32 void NetworkController::onProcessRequested(const QNetworkRequest &request, QUuid identifier,
27 33 std::function<void(QNetworkReply *, QUuid)> callback)
28 34 {
29 qCInfo(LOG_NetworkController()) << tr("NetworkController registered")
30 << QThread::currentThread();
35 qCDebug(LOG_NetworkController()) << tr("NetworkController registered")
36 << QThread::currentThread()->objectName();
31 37 auto reply = impl->m_AccessManager->get(request);
32 38
33 39 // Store the couple reply id
40 impl->lockWrite();
34 41 impl->m_NetworkReplyToVariableId[reply] = identifier;
42 impl->unlock();
35 43
36 44 auto onReplyFinished = [reply, this, identifier, callback]() {
37 45
38 qCInfo(LOG_NetworkController()) << tr("NetworkController onReplyFinished")
39 << QThread::currentThread();
46 qCDebug(LOG_NetworkController()) << tr("NetworkController onReplyFinished")
47 << QThread::currentThread() << reply;
48 impl->lockRead();
40 49 auto it = impl->m_NetworkReplyToVariableId.find(reply);
50 impl->unlock();
41 51 if (it != impl->m_NetworkReplyToVariableId.cend()) {
52 impl->lockWrite();
53 impl->m_NetworkReplyToVariableId.erase(reply);
54 impl->unlock();
55 // Deletes reply
42 56 callback(reply, identifier);
57 reply->deleteLater();
58
59 emit this->replyDownloadProgress(identifier, 0);
43 60 }
61
62 qCDebug(LOG_NetworkController()) << tr("NetworkController onReplyFinished END")
63 << QThread::currentThread() << reply;
44 64 };
45 65
46 66 auto onReplyProgress = [reply, this](qint64 bytesRead, qint64 totalBytes) {
47 67
48 68 double progress = (bytesRead * 100.0) / totalBytes;
69 qCDebug(LOG_NetworkController()) << tr("NetworkController onReplyProgress") << progress
70 << QThread::currentThread() << reply;
71 impl->lockRead();
49 72 auto it = impl->m_NetworkReplyToVariableId.find(reply);
73 impl->unlock();
50 74 if (it != impl->m_NetworkReplyToVariableId.cend()) {
51 75 emit this->replyDownloadProgress(it->second, progress);
52 76 }
77 qCDebug(LOG_NetworkController()) << tr("NetworkController onReplyProgress END")
78 << QThread::currentThread() << reply;
53 79 };
54 80
55 81
56 82 connect(reply, &QNetworkReply::finished, this, onReplyFinished);
57 83 connect(reply, &QNetworkReply::downloadProgress, this, onReplyProgress);
84 qCDebug(LOG_NetworkController()) << tr("NetworkController registered END")
85 << QThread::currentThread()->objectName() << reply;
58 86 }
59 87
60 88 void NetworkController::initialize()
61 89 {
62 90 qCDebug(LOG_NetworkController()) << tr("NetworkController init") << QThread::currentThread();
63 91 impl->m_WorkingMutex.lock();
64 92 impl->m_AccessManager = std::make_unique<QNetworkAccessManager>();
93
94
95 auto onReplyErrors = [this](QNetworkReply *reply, const QList<QSslError> &errors) {
96
97 qCCritical(LOG_NetworkController()) << tr("NetworkAcessManager errors: ") << errors;
98
99 };
100
101
102 connect(impl->m_AccessManager.get(), &QNetworkAccessManager::sslErrors, this, onReplyErrors);
103
65 104 qCDebug(LOG_NetworkController()) << tr("NetworkController init END");
66 105 }
67 106
68 107 void NetworkController::finalize()
69 108 {
70 109 impl->m_WorkingMutex.unlock();
71 110 }
72 111
73 112 void NetworkController::onReplyCanceled(QUuid identifier)
74 113 {
75 114 auto findReply = [identifier](const auto &entry) { return identifier == entry.second; };
115 qCDebug(LOG_NetworkController()) << tr("NetworkController onReplyCanceled")
116 << QThread::currentThread();
76 117
118
119 impl->lockRead();
77 120 auto end = impl->m_NetworkReplyToVariableId.cend();
78 121 auto it = std::find_if(impl->m_NetworkReplyToVariableId.cbegin(), end, findReply);
122 impl->unlock();
79 123 if (it != end) {
80 124 it->first->abort();
81 125 }
126 qCDebug(LOG_NetworkController()) << tr("NetworkController onReplyCanceled END")
127 << QThread::currentThread();
82 128 }
83 129
84 130 void NetworkController::waitForFinish()
85 131 {
86 132 QMutexLocker locker{&impl->m_WorkingMutex};
87 133 }
@@ -1,90 +1,90
1 1 #include "Variable/Variable.h"
2 2
3 3 #include <Data/IDataSeries.h>
4 4 #include <Data/SqpDateTime.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 12 explicit VariablePrivate(const QString &name, const SqpDateTime &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 20 SqpDateTime 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 25 Variable::Variable(const QString &name, const SqpDateTime &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 35 SqpDateTime Variable::dateTime() const noexcept
36 36 {
37 37 return impl->m_DateTime;
38 38 }
39 39
40 40 void Variable::setDateTime(const SqpDateTime &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 dataSeries->lockWrite();
59 59 impl->m_DataSeries->lockWrite();
60 60 impl->m_DataSeries->merge(dataSeries.get());
61 61 impl->m_DataSeries->unlock();
62 62 dataSeries->unlock();
63 emit updated();
63 // emit updated();
64 64 }
65 65 }
66 66
67 67 IDataSeries *Variable::dataSeries() const noexcept
68 68 {
69 69 return impl->m_DataSeries.get();
70 70 }
71 71
72 72 QVariantHash Variable::metadata() const noexcept
73 73 {
74 74 return impl->m_Metadata;
75 75 }
76 76
77 77 bool Variable::contains(const SqpDateTime &dateTime) const noexcept
78 78 {
79 79 return impl->m_DateTime.contains(dateTime);
80 80 }
81 81
82 82 bool Variable::intersect(const SqpDateTime &dateTime) const noexcept
83 83 {
84 84 return impl->m_DateTime.intersect(dateTime);
85 85 }
86 86
87 87 bool Variable::isInside(const SqpDateTime &dateTime) const noexcept
88 88 {
89 89 return dateTime.contains(SqpDateTime{impl->m_DateTime.m_TStart, impl->m_DateTime.m_TEnd});
90 90 }
@@ -1,212 +1,244
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 <QDateTime>
12 12 #include <QMutex>
13 13 #include <QThread>
14 14 #include <QUuid>
15 15 #include <QtCore/QItemSelectionModel>
16 16
17 17 #include <unordered_map>
18 18
19 19 Q_LOGGING_CATEGORY(LOG_VariableController, "VariableController")
20 20
21 21 struct VariableController::VariableControllerPrivate {
22 22 explicit VariableControllerPrivate(VariableController *parent)
23 23 : m_WorkingMutex{},
24 24 m_VariableModel{new VariableModel{parent}},
25 25 m_VariableSelectionModel{new QItemSelectionModel{m_VariableModel, parent}},
26 26 m_VariableCacheController{std::make_unique<VariableCacheController>()}
27 27 {
28 28 }
29 29
30 30 QMutex m_WorkingMutex;
31 31 /// Variable model. The VariableController has the ownership
32 32 VariableModel *m_VariableModel;
33 33 QItemSelectionModel *m_VariableSelectionModel;
34 34
35 35
36 36 TimeController *m_TimeController{nullptr};
37 37 std::unique_ptr<VariableCacheController> m_VariableCacheController;
38 38
39 39 std::unordered_map<std::shared_ptr<Variable>, std::shared_ptr<IDataProvider> >
40 40 m_VariableToProviderMap;
41 std::unordered_map<std::shared_ptr<Variable>, QUuid> m_VariableToIdentifier;
41 std::unordered_map<std::shared_ptr<Variable>, QUuid> m_VariableToIdentifierMap;
42 42 };
43 43
44 44 VariableController::VariableController(QObject *parent)
45 45 : QObject{parent}, impl{spimpl::make_unique_impl<VariableControllerPrivate>(this)}
46 46 {
47 47 qCDebug(LOG_VariableController()) << tr("VariableController construction")
48 48 << QThread::currentThread();
49
50 connect(impl->m_VariableModel, &VariableModel::abortProgessRequested, this,
51 &VariableController::onAbortProgressRequested);
49 52 }
50 53
51 54 VariableController::~VariableController()
52 55 {
53 56 qCDebug(LOG_VariableController()) << tr("VariableController destruction")
54 57 << QThread::currentThread();
55 58 this->waitForFinish();
56 59 }
57 60
58 61 VariableModel *VariableController::variableModel() noexcept
59 62 {
60 63 return impl->m_VariableModel;
61 64 }
62 65
63 66 QItemSelectionModel *VariableController::variableSelectionModel() noexcept
64 67 {
65 68 return impl->m_VariableSelectionModel;
66 69 }
67 70
68 71 void VariableController::setTimeController(TimeController *timeController) noexcept
69 72 {
70 73 impl->m_TimeController = timeController;
71 74 }
72 75
73 76 void VariableController::deleteVariable(std::shared_ptr<Variable> variable) noexcept
74 77 {
75 78 if (!variable) {
76 79 qCCritical(LOG_VariableController()) << "Can't delete variable: variable is null";
77 80 return;
78 81 }
79 82
80 83 // Spreads in SciQlop that the variable will be deleted, so that potential receivers can
81 84 // make some treatments before the deletion
82 85 emit variableAboutToBeDeleted(variable);
83 86
87 // Deletes identifier
88 impl->m_VariableToIdentifierMap.erase(variable);
89
84 90 // Deletes provider
85 91 auto nbProvidersDeleted = impl->m_VariableToProviderMap.erase(variable);
86 92 qCDebug(LOG_VariableController())
87 93 << tr("Number of providers deleted for variable %1: %2")
88 94 .arg(variable->name(), QString::number(nbProvidersDeleted));
89 95
90 96 // Clears cache
91 97 impl->m_VariableCacheController->clear(variable);
92 98
93 99 // Deletes from model
94 100 impl->m_VariableModel->deleteVariable(variable);
95 101 }
96 102
97 103 void VariableController::deleteVariables(
98 104 const QVector<std::shared_ptr<Variable> > &variables) noexcept
99 105 {
100 106 for (auto variable : qAsConst(variables)) {
101 107 deleteVariable(variable);
102 108 }
103 109 }
104 110
111 void VariableController::abortProgress(std::shared_ptr<Variable> variable)
112 {
113 }
114
105 115 void VariableController::createVariable(const QString &name, const QVariantHash &metadata,
106 116 std::shared_ptr<IDataProvider> provider) noexcept
107 117 {
108 118
109 119 if (!impl->m_TimeController) {
110 120 qCCritical(LOG_VariableController())
111 121 << tr("Impossible to create variable: The time controller is null");
112 122 return;
113 123 }
114 124
115 125 auto dateTime = impl->m_TimeController->dateTime();
116 126
117 127 if (auto newVariable = impl->m_VariableModel->createVariable(name, dateTime, metadata)) {
118 128 auto identifier = QUuid::createUuid();
119 129
120 130 // store the provider
121 131 impl->m_VariableToProviderMap[newVariable] = provider;
122 impl->m_VariableToIdentifier[newVariable] = identifier;
132 impl->m_VariableToIdentifierMap[newVariable] = identifier;
123 133
124 134 auto addDateTimeAcquired = [ this, varW = std::weak_ptr<Variable>{newVariable} ](
125 135 QUuid identifier, auto dataSeriesAcquired, auto dateTimeToPutInCache)
126 136 {
127 137 if (auto variable = varW.lock()) {
128 auto varIdentifier = impl->m_VariableToIdentifier.at(variable);
138 auto varIdentifier = impl->m_VariableToIdentifierMap.at(variable);
129 139 if (varIdentifier == identifier) {
130 140 impl->m_VariableCacheController->addDateTime(variable, dateTimeToPutInCache);
131 141 variable->setDataSeries(dataSeriesAcquired);
142 emit variable->updated();
132 143 }
133 144 }
134 145 };
135 146
136 147 connect(provider.get(), &IDataProvider::dataProvided, addDateTimeAcquired);
148 connect(provider.get(), &IDataProvider::dataProvidedProgress, this,
149 &VariableController::onVariableRetrieveDataInProgress);
137 150 this->onRequestDataLoading(newVariable, dateTime);
138 151 }
139 152 }
140 153
141 154 void VariableController::onDateTimeOnSelection(const SqpDateTime &dateTime)
142 155 {
143 156 qCDebug(LOG_VariableController()) << "VariableController::onDateTimeOnSelection"
144 157 << QThread::currentThread()->objectName();
145 158 auto selectedRows = impl->m_VariableSelectionModel->selectedRows();
146 159
147 160 for (const auto &selectedRow : qAsConst(selectedRows)) {
148 161 if (auto selectedVariable = impl->m_VariableModel->variable(selectedRow.row())) {
149 162 selectedVariable->setDateTime(dateTime);
150 163 this->onRequestDataLoading(selectedVariable, dateTime);
164
165 // notify that rescale operation has to be done
166 emit rangeChanged(selectedVariable, dateTime);
151 167 }
152 168 }
153 169 }
154 170
155 171 void VariableController::onVariableRetrieveDataInProgress(QUuid identifier, double progress)
156 172 {
157 173 auto findReply = [identifier](const auto &entry) { return identifier == entry.second; };
158 174
159 auto end = impl->m_VariableToIdentifier.cend();
160 auto it = std::find_if(impl->m_VariableToIdentifier.cbegin(), end, findReply);
175 auto end = impl->m_VariableToIdentifierMap.cend();
176 auto it = std::find_if(impl->m_VariableToIdentifierMap.cbegin(), end, findReply);
161 177 if (it != end) {
162 178 impl->m_VariableModel->setDataProgress(it->first, progress);
163 179 }
164 180 }
165 181
182 void VariableController::onAbortProgressRequested(std::shared_ptr<Variable> variable)
183 {
184 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAbortProgressRequested"
185 << QThread::currentThread()->objectName();
186
187 auto it = impl->m_VariableToIdentifierMap.find(variable);
188 if (it != impl->m_VariableToIdentifierMap.cend()) {
189 impl->m_VariableToProviderMap.at(variable)->requestDataAborting(it->second);
190 }
191 else {
192 qCWarning(LOG_VariableController())
193 << tr("Aborting progression of inexistant variable detected !!!")
194 << QThread::currentThread()->objectName();
195 }
196 }
197
166 198
167 199 void VariableController::onRequestDataLoading(std::shared_ptr<Variable> variable,
168 200 const SqpDateTime &dateTime)
169 201 {
170 202 qCDebug(LOG_VariableController()) << "VariableController::onRequestDataLoading"
171 203 << QThread::currentThread()->objectName();
172 204 // we want to load data of the variable for the dateTime.
173 205 // First we check if the cache contains some of them.
174 206 // For the other, we ask the provider to give them.
175 207 if (variable) {
176 208
177 209 auto dateTimeListNotInCache
178 210 = impl->m_VariableCacheController->provideNotInCacheDateTimeList(variable, dateTime);
179 211
180 212 if (!dateTimeListNotInCache.empty()) {
181 213 // Ask the provider for each data on the dateTimeListNotInCache
182 auto identifier = impl->m_VariableToIdentifier.at(variable);
214 auto identifier = impl->m_VariableToIdentifierMap.at(variable);
183 215 impl->m_VariableToProviderMap.at(variable)->requestDataLoading(
184 216 identifier,
185 217 DataProviderParameters{std::move(dateTimeListNotInCache), variable->metadata()});
186 218 }
187 219 else {
188 220 emit variable->updated();
189 221 }
190 222 }
191 223 else {
192 224 qCCritical(LOG_VariableController()) << tr("Impossible to load data of a variable null");
193 225 }
194 226 }
195 227
196 228
197 229 void VariableController::initialize()
198 230 {
199 231 qCDebug(LOG_VariableController()) << tr("VariableController init") << QThread::currentThread();
200 232 impl->m_WorkingMutex.lock();
201 233 qCDebug(LOG_VariableController()) << tr("VariableController init END");
202 234 }
203 235
204 236 void VariableController::finalize()
205 237 {
206 238 impl->m_WorkingMutex.unlock();
207 239 }
208 240
209 241 void VariableController::waitForFinish()
210 242 {
211 243 QMutexLocker locker{&impl->m_WorkingMutex};
212 244 }
@@ -1,235 +1,248
1 1 #include <Variable/Variable.h>
2 2 #include <Variable/VariableModel.h>
3 3
4 4 #include <Data/IDataSeries.h>
5 5
6 6 #include <QDateTime>
7 7 #include <QSize>
8 8 #include <unordered_map>
9 9
10 10 Q_LOGGING_CATEGORY(LOG_VariableModel, "VariableModel")
11 11
12 12 namespace {
13 13
14 14 // Column indexes
15 15 const auto NAME_COLUMN = 0;
16 16 const auto TSTART_COLUMN = 1;
17 17 const auto TEND_COLUMN = 2;
18 18 const auto NB_COLUMNS = 3;
19 19
20 20 // Column properties
21 21 const auto DEFAULT_HEIGHT = 25;
22 22 const auto DEFAULT_WIDTH = 100;
23 23
24 24 struct ColumnProperties {
25 25 ColumnProperties(const QString &name = {}, int width = DEFAULT_WIDTH,
26 26 int height = DEFAULT_HEIGHT)
27 27 : m_Name{name}, m_Width{width}, m_Height{height}
28 28 {
29 29 }
30 30
31 31 QString m_Name;
32 32 int m_Width;
33 33 int m_Height;
34 34 };
35 35
36 36 const auto COLUMN_PROPERTIES
37 37 = QHash<int, ColumnProperties>{{NAME_COLUMN, {QObject::tr("Name")}},
38 38 {TSTART_COLUMN, {QObject::tr("tStart"), 180}},
39 39 {TEND_COLUMN, {QObject::tr("tEnd"), 180}}};
40 40
41 41 /// Format for datetimes
42 42 const auto DATETIME_FORMAT = QStringLiteral("dd/MM/yyyy \nhh:mm:ss:zzz");
43 43
44 44
45 45 } // namespace
46 46
47 47 struct VariableModel::VariableModelPrivate {
48 48 /// Variables created in SciQlop
49 49 std::vector<std::shared_ptr<Variable> > m_Variables;
50 50 std::unordered_map<std::shared_ptr<Variable>, double> m_VariableToProgress;
51 51
52
53 52 /// Return the row index of the variable. -1 if it's not found
54 53 int indexOfVariable(Variable *variable) const noexcept;
55 54 };
56 55
57 56 VariableModel::VariableModel(QObject *parent)
58 57 : QAbstractTableModel{parent}, impl{spimpl::make_unique_impl<VariableModelPrivate>()}
59 58 {
60 59 }
61 60
62 61 std::shared_ptr<Variable> VariableModel::createVariable(const QString &name,
63 62 const SqpDateTime &dateTime,
64 63 const QVariantHash &metadata) noexcept
65 64 {
66 65 auto insertIndex = rowCount();
67 66 beginInsertRows({}, insertIndex, insertIndex);
68 67
69 68 auto variable = std::make_shared<Variable>(name, dateTime, metadata);
70 69
71 70 impl->m_Variables.push_back(variable);
72 71 connect(variable.get(), &Variable::updated, this, &VariableModel::onVariableUpdated);
73 72
74 73 endInsertRows();
75 74
76 75 return variable;
77 76 }
78 77
79 78 void VariableModel::deleteVariable(std::shared_ptr<Variable> variable) noexcept
80 79 {
81 80 if (!variable) {
82 81 qCCritical(LOG_Variable()) << "Can't delete a null variable from the model";
83 82 return;
84 83 }
85 84
86 85 // Finds variable in the model
87 86 auto begin = impl->m_Variables.cbegin();
88 87 auto end = impl->m_Variables.cend();
89 88 auto it = std::find(begin, end, variable);
90 89 if (it != end) {
91 90 auto removeIndex = std::distance(begin, it);
92 91
93 92 // Deletes variable
94 93 beginRemoveRows({}, removeIndex, removeIndex);
95 94 impl->m_Variables.erase(it);
96 95 endRemoveRows();
97 96 }
98 97 else {
99 98 qCritical(LOG_VariableModel())
100 99 << tr("Can't delete variable %1 from the model: the variable is not in the model")
101 100 .arg(variable->name());
102 101 }
102
103 // Removes variable from progress map
104 impl->m_VariableToProgress.erase(variable);
103 105 }
104 106
105 107
106 108 std::shared_ptr<Variable> VariableModel::variable(int index) const
107 109 {
108 110 return (index >= 0 && index < impl->m_Variables.size()) ? impl->m_Variables[index] : nullptr;
109 111 }
110 112
111 113 void VariableModel::setDataProgress(std::shared_ptr<Variable> variable, double progress)
112 114 {
113
115 if (progress > 0.0) {
114 116 impl->m_VariableToProgress[variable] = progress;
117 }
118 else {
119 impl->m_VariableToProgress.erase(variable);
120 }
115 121 auto modelIndex = createIndex(impl->indexOfVariable(variable.get()), NAME_COLUMN);
116 122
117 123 emit dataChanged(modelIndex, modelIndex);
118 124 }
119 125
120 126 int VariableModel::columnCount(const QModelIndex &parent) const
121 127 {
122 128 Q_UNUSED(parent);
123 129
124 130 return NB_COLUMNS;
125 131 }
126 132
127 133 int VariableModel::rowCount(const QModelIndex &parent) const
128 134 {
129 135 Q_UNUSED(parent);
130 136
131 137 return impl->m_Variables.size();
132 138 }
133 139
134 140 QVariant VariableModel::data(const QModelIndex &index, int role) const
135 141 {
136 142 if (!index.isValid()) {
137 143 return QVariant{};
138 144 }
139 145
140 146 if (index.row() < 0 || index.row() >= rowCount()) {
141 147 return QVariant{};
142 148 }
143 149
144 150 if (role == Qt::DisplayRole) {
145 151 if (auto variable = impl->m_Variables.at(index.row()).get()) {
146 152 /// Lambda function that builds the variant to return for a time value
147 153 auto dateTimeVariant = [](double time) {
148 154 auto dateTime = QDateTime::fromMSecsSinceEpoch(time * 1000.);
149 155 return dateTime.toString(DATETIME_FORMAT);
150 156 };
151 157
152 158 switch (index.column()) {
153 159 case NAME_COLUMN:
154 160 return variable->name();
155 161 case TSTART_COLUMN:
156 162 return dateTimeVariant(variable->dateTime().m_TStart);
157 163 case TEND_COLUMN:
158 164 return dateTimeVariant(variable->dateTime().m_TEnd);
159 165 default:
160 166 // No action
161 167 break;
162 168 }
163 169
164 170 qWarning(LOG_VariableModel())
165 171 << tr("Can't get data (unknown column %1)").arg(index.column());
166 172 }
167 173 else {
168 174 qWarning(LOG_VariableModel()) << tr("Can't get data (no variable)");
169 175 }
170 176 }
171 177 else if (role == VariableRoles::ProgressRole) {
172 178 if (auto variable = impl->m_Variables.at(index.row())) {
173 179
174 180 auto it = impl->m_VariableToProgress.find(variable);
175 181 if (it != impl->m_VariableToProgress.cend()) {
176 182 return it->second;
177 183 }
178 184 }
179 185 }
180 186
181 187 return QVariant{};
182 188 }
183 189
184 190 QVariant VariableModel::headerData(int section, Qt::Orientation orientation, int role) const
185 191 {
186 192 if (role != Qt::DisplayRole && role != Qt::SizeHintRole) {
187 193 return QVariant{};
188 194 }
189 195
190 196 if (orientation == Qt::Horizontal) {
191 197 auto propertiesIt = COLUMN_PROPERTIES.find(section);
192 198 if (propertiesIt != COLUMN_PROPERTIES.cend()) {
193 199 // Role is either DisplayRole or SizeHintRole
194 200 return (role == Qt::DisplayRole)
195 201 ? QVariant{propertiesIt->m_Name}
196 202 : QVariant{QSize{propertiesIt->m_Width, propertiesIt->m_Height}};
197 203 }
198 204 else {
199 205 qWarning(LOG_VariableModel())
200 206 << tr("Can't get header data (unknown column %1)").arg(section);
201 207 }
202 208 }
203 209
204 210 return QVariant{};
205 211 }
206 212
213 void VariableModel::abortProgress(const QModelIndex &index)
214 {
215 if (auto variable = impl->m_Variables.at(index.row())) {
216 emit abortProgessRequested(variable);
217 }
218 }
219
207 220 void VariableModel::onVariableUpdated() noexcept
208 221 {
209 222 // Finds variable that has been updated in the model
210 223 if (auto updatedVariable = dynamic_cast<Variable *>(sender())) {
211 224 auto updatedVariableIndex = impl->indexOfVariable(updatedVariable);
212 225
213 226 if (updatedVariableIndex > -1) {
214 227 emit dataChanged(createIndex(updatedVariableIndex, 0),
215 228 createIndex(updatedVariableIndex, columnCount() - 1));
216 229 }
217 230 }
218 231 }
219 232
220 233 int VariableModel::VariableModelPrivate::indexOfVariable(Variable *variable) const noexcept
221 234 {
222 235 auto begin = std::cbegin(m_Variables);
223 236 auto end = std::cend(m_Variables);
224 237 auto it
225 238 = std::find_if(begin, end, [variable](const auto &var) { return var.get() == variable; });
226 239
227 240 if (it != end) {
228 241 // Gets the index of the variable in the model: we assume here that views have the same
229 242 // order as the model
230 243 return std::distance(begin, it);
231 244 }
232 245 else {
233 246 return -1;
234 247 }
235 248 }
@@ -1,65 +1,82
1 1 #ifndef SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
2 2 #define SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
3 3
4 4 #include "Visualization/IVisualizationWidget.h"
5 5
6 6 #include <QLoggingCategory>
7 7 #include <QWidget>
8 8
9 9 #include <memory>
10 10
11 11 #include <Common/spimpl.h>
12 12
13 13 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationGraphWidget)
14 14
15 15 class QCPRange;
16 16 class SqpDateTime;
17 17 class Variable;
18 18
19 /**
20 * Possible types of zoom operation
21 */
22 enum class VisualizationGraphWidgetZoomType { ZoomOut, ZoomIn, PanRight, PanLeft, Unknown };
23
19 24 namespace Ui {
20 25 class VisualizationGraphWidget;
21 26 } // namespace Ui
22 27
23 28 class VisualizationGraphWidget : public QWidget, public IVisualizationWidget {
24 29 Q_OBJECT
25 30
26 31 public:
27 32 explicit VisualizationGraphWidget(const QString &name = {}, QWidget *parent = 0);
28 33 virtual ~VisualizationGraphWidget();
29 34
35 void enableSynchronize(bool enable);
36
30 37 void addVariable(std::shared_ptr<Variable> variable);
31 38 void addVariableUsingGraph(std::shared_ptr<Variable> variable);
32 39 /// Removes a variable from the graph
33 40 void removeVariable(std::shared_ptr<Variable> variable) noexcept;
34 41
42 void setRange(std::shared_ptr<Variable> variable, const SqpDateTime &range);
43 SqpDateTime graphRange() const noexcept;
44 void setGraphRange(const SqpDateTime &range);
45
35 46 // IVisualizationWidget interface
36 47 void accept(IVisualizationWidgetVisitor *visitor) override;
37 48 bool canDrop(const Variable &variable) const override;
38 49 bool contains(const Variable &variable) const override;
39 50 QString name() const override;
40 51
41 void updateDisplay(std::shared_ptr<Variable> variable);
42 52
43 53 signals:
44 54 void requestDataLoading(std::shared_ptr<Variable> variable, const SqpDateTime &dateTime);
55 void synchronize(const SqpDateTime &dateTime, const SqpDateTime &oldDateTime,
56 VisualizationGraphWidgetZoomType zoomType);
45 57
46 58
47 59 private:
48 60 Ui::VisualizationGraphWidget *ui;
49 61
50 62 class VisualizationGraphWidgetPrivate;
51 63 spimpl::unique_impl_ptr<VisualizationGraphWidgetPrivate> impl;
52 64
53 65 private slots:
54 66 /// Slot called when right clicking on the graph (displays a menu)
55 67 void onGraphMenuRequested(const QPoint &pos) noexcept;
56 68
57 void onRangeChanged(const QCPRange &t1);
69 /// Rescale the X axe to range parameter
70 void onRangeChanged(const QCPRange &t1, const QCPRange &t2);
58 71
59 72 /// Slot called when a mouse wheel was made, to perform some processing before the zoom is done
60 73 void onMouseWheel(QWheelEvent *event) noexcept;
74 /// Slot called when a mouse press was made, to activate the calibration of a graph
75 void onMousePress(QMouseEvent *event) noexcept;
76 /// Slot called when a mouse release was made, to deactivate the calibration of a graph
77 void onMouseRelease(QMouseEvent *event) noexcept;
61 78
62 79 void onDataCacheVariableUpdated();
63 80 };
64 81
65 82 #endif // SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
@@ -1,48 +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 6
6 7 #include <QLoggingCategory>
7 8 #include <QWidget>
8 9
9 10 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationWidget)
10 11
11 12 class QMenu;
12 13 class Variable;
13 14 class VisualizationTabWidget;
14 15
15 16 namespace Ui {
16 17 class VisualizationWidget;
17 18 } // namespace Ui
18 19
19 20 class VisualizationWidget : public QWidget, public IVisualizationWidget {
20 21 Q_OBJECT
21 22
22 23 public:
23 24 explicit VisualizationWidget(QWidget *parent = 0);
24 25 virtual ~VisualizationWidget();
25 26
26 27 // IVisualizationWidget interface
27 28 void accept(IVisualizationWidgetVisitor *visitor) override;
28 29 bool canDrop(const Variable &variable) const override;
29 30 bool contains(const Variable &variable) const override;
30 31 QString name() const override;
31 32
32 33 public slots:
33 34 /**
34 35 * Attaches to a menu the menu relative to the visualization of variables
35 36 * @param menu the parent menu of the generated menu
36 37 * @param variables the variables for which to generate the menu
37 38 */
38 39 void attachVariableMenu(QMenu *menu,
39 40 const QVector<std::shared_ptr<Variable> > &variables) noexcept;
40 41
41 42 /// Slot called when a variable is about to be deleted from SciQlop
42 43 void onVariableAboutToBeDeleted(std::shared_ptr<Variable> variable) noexcept;
43 44
45 void onRangeChanged(std::shared_ptr<Variable> variable, const SqpDateTime &range) noexcept;
46
44 47 private:
45 48 Ui::VisualizationWidget *ui;
46 49 };
47 50
48 51 #endif // VISUALIZATIONWIDGET_H
@@ -1,147 +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 connect(m_VariableController.get(),
42 SIGNAL(rangeChanged(std::shared_ptr<Variable>, const SqpDateTime &)),
43 m_VisualizationController.get(),
44 SIGNAL(rangeChanged(std::shared_ptr<Variable>, const SqpDateTime &)));
45
41 46
42 47 m_DataSourceController->moveToThread(&m_DataSourceControllerThread);
48 m_DataSourceControllerThread.setObjectName("DataSourceControllerThread");
43 49 m_NetworkController->moveToThread(&m_NetworkControllerThread);
50 m_NetworkControllerThread.setObjectName("NetworkControllerThread");
44 51 m_VariableController->moveToThread(&m_VariableControllerThread);
52 m_VariableControllerThread.setObjectName("VariableControllerThread");
45 53 m_VisualizationController->moveToThread(&m_VisualizationControllerThread);
54 m_VisualizationControllerThread.setObjectName("VsualizationControllerThread");
46 55
47 56
48 57 // Additionnal init
49 58 m_VariableController->setTimeController(m_TimeController.get());
50 59 }
51 60
52 61 virtual ~SqpApplicationPrivate()
53 62 {
54 63 qCInfo(LOG_SqpApplication()) << tr("SqpApplicationPrivate destruction");
55 64 m_DataSourceControllerThread.quit();
56 65 m_DataSourceControllerThread.wait();
57 66
58 67 m_NetworkControllerThread.quit();
59 68 m_NetworkControllerThread.wait();
60 69
61 70 m_VariableControllerThread.quit();
62 71 m_VariableControllerThread.wait();
63 72
64 73 m_VisualizationControllerThread.quit();
65 74 m_VisualizationControllerThread.wait();
66 75 }
67 76
68 77 std::unique_ptr<DataSourceController> m_DataSourceController;
69 78 std::unique_ptr<VariableController> m_VariableController;
70 79 std::unique_ptr<TimeController> m_TimeController;
71 80 std::unique_ptr<NetworkController> m_NetworkController;
72 81 std::unique_ptr<VisualizationController> m_VisualizationController;
73 82 QThread m_DataSourceControllerThread;
74 83 QThread m_NetworkControllerThread;
75 84 QThread m_VariableControllerThread;
76 85 QThread m_VisualizationControllerThread;
77 86 };
78 87
79 88
80 89 SqpApplication::SqpApplication(int &argc, char **argv)
81 90 : QApplication{argc, argv}, impl{spimpl::make_unique_impl<SqpApplicationPrivate>()}
82 91 {
83 92 qCDebug(LOG_SqpApplication()) << tr("SqpApplication construction") << QThread::currentThread();
84 93
85 94 connect(&impl->m_DataSourceControllerThread, &QThread::started,
86 95 impl->m_DataSourceController.get(), &DataSourceController::initialize);
87 96 connect(&impl->m_DataSourceControllerThread, &QThread::finished,
88 97 impl->m_DataSourceController.get(), &DataSourceController::finalize);
89 98
90 99 connect(&impl->m_NetworkControllerThread, &QThread::started, impl->m_NetworkController.get(),
91 100 &NetworkController::initialize);
92 101 connect(&impl->m_NetworkControllerThread, &QThread::finished, impl->m_NetworkController.get(),
93 102 &NetworkController::finalize);
94 103
95 104 connect(&impl->m_VariableControllerThread, &QThread::started, impl->m_VariableController.get(),
96 105 &VariableController::initialize);
97 106 connect(&impl->m_VariableControllerThread, &QThread::finished, impl->m_VariableController.get(),
98 107 &VariableController::finalize);
99 108
100 109 connect(&impl->m_VisualizationControllerThread, &QThread::started,
101 110 impl->m_VisualizationController.get(), &VisualizationController::initialize);
102 111 connect(&impl->m_VisualizationControllerThread, &QThread::finished,
103 112 impl->m_VisualizationController.get(), &VisualizationController::finalize);
104 113
105 114 impl->m_DataSourceControllerThread.start();
106 115 impl->m_NetworkControllerThread.start();
107 116 impl->m_VariableControllerThread.start();
108 117 impl->m_VisualizationControllerThread.start();
109
110 // Core connections:
111 // NetworkController <-> VariableController
112 connect(&sqpApp->networkController(), &NetworkController::replyDownloadProgress,
113 &sqpApp->variableController(), &VariableController::onVariableRetrieveDataInProgress);
114 118 }
115 119
116 120 SqpApplication::~SqpApplication()
117 121 {
118 122 }
119 123
120 124 void SqpApplication::initialize()
121 125 {
122 126 }
123 127
124 128 DataSourceController &SqpApplication::dataSourceController() noexcept
125 129 {
126 130 return *impl->m_DataSourceController;
127 131 }
128 132
129 133 NetworkController &SqpApplication::networkController() noexcept
130 134 {
131 135 return *impl->m_NetworkController;
132 136 }
133 137
134 138 TimeController &SqpApplication::timeController() noexcept
135 139 {
136 140 return *impl->m_TimeController;
137 141 }
138 142
139 143 VariableController &SqpApplication::variableController() noexcept
140 144 {
141 145 return *impl->m_VariableController;
142 146 }
143 147
144 148 VisualizationController &SqpApplication::visualizationController() noexcept
145 149 {
146 150 return *impl->m_VisualizationController;
147 151 }
@@ -1,140 +1,199
1 1 #include <Variable/VariableController.h>
2 2 #include <Variable/VariableInspectorWidget.h>
3 3 #include <Variable/VariableMenuHeaderWidget.h>
4 4 #include <Variable/VariableModel.h>
5 5
6 6 #include <ui_VariableInspectorWidget.h>
7 7
8 #include <QMouseEvent>
8 9 #include <QSortFilterProxyModel>
9 10 #include <QStyledItemDelegate>
10 11 #include <QWidgetAction>
11 12
12 13 #include <SqpApplication.h>
13 14
14 15 Q_LOGGING_CATEGORY(LOG_VariableInspectorWidget, "VariableInspectorWidget")
15 16
16 17
17 18 class QProgressBarItemDelegate : public QStyledItemDelegate {
18 19
19 20 public:
20 21 QProgressBarItemDelegate(QObject *parent) : QStyledItemDelegate{parent} {}
21 22
22 23 void paint(QPainter *painter, const QStyleOptionViewItem &option,
23 24 const QModelIndex &index) const
24 25 {
25 26 auto data = index.data(Qt::DisplayRole);
26 27 auto progressData = index.data(VariableRoles::ProgressRole);
27 28 if (data.isValid() && progressData.isValid()) {
28 29 auto name = data.value<QString>();
29 30 auto progress = progressData.value<double>();
30 if (progress >= 0) {
31 if (progress > 0) {
32 auto cancelButtonWidth = 20;
31 33 auto progressBarOption = QStyleOptionProgressBar{};
32 progressBarOption.rect = option.rect;
34 auto progressRect = option.rect;
35 progressRect.setWidth(progressRect.width() - cancelButtonWidth);
36 progressBarOption.rect = progressRect;
33 37 progressBarOption.minimum = 0;
34 38 progressBarOption.maximum = 100;
35 39 progressBarOption.progress = progress;
36 40 progressBarOption.text
37 41 = QString("%1 %2").arg(name).arg(QString::number(progress, 'f', 2) + "%");
38 42 progressBarOption.textVisible = true;
39 43 progressBarOption.textAlignment = Qt::AlignCenter;
40 44
45
41 46 QApplication::style()->drawControl(QStyle::CE_ProgressBar, &progressBarOption,
42 47 painter);
48
49 // Cancel button
50 auto buttonRect = QRect(progressRect.right(), option.rect.top(), cancelButtonWidth,
51 option.rect.height());
52 auto buttonOption = QStyleOptionButton{};
53 buttonOption.rect = buttonRect;
54 buttonOption.text = "X";
55
56 QApplication::style()->drawControl(QStyle::CE_PushButton, &buttonOption, painter);
57 }
58 else {
59 QStyledItemDelegate::paint(painter, option, index);
43 60 }
44 61 }
45 62 else {
46 63 QStyledItemDelegate::paint(painter, option, index);
47 64 }
48 65 }
66
67 bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option,
68 const QModelIndex &index)
69 {
70 if (event->type() == QEvent::MouseButtonRelease) {
71 auto data = index.data(Qt::DisplayRole);
72 auto progressData = index.data(VariableRoles::ProgressRole);
73 if (data.isValid() && progressData.isValid()) {
74 auto cancelButtonWidth = 20;
75 auto progressRect = option.rect;
76 progressRect.setWidth(progressRect.width() - cancelButtonWidth);
77 // Cancel button
78 auto buttonRect = QRect(progressRect.right(), option.rect.top(), cancelButtonWidth,
79 option.rect.height());
80
81 auto e = (QMouseEvent *)event;
82 auto clickX = e->x();
83 auto clickY = e->y();
84
85 auto x = buttonRect.left(); // the X coordinate
86 auto y = buttonRect.top(); // the Y coordinate
87 auto w = buttonRect.width(); // button width
88 auto h = buttonRect.height(); // button height
89
90 if (clickX > x && clickX < x + w) {
91 if (clickY > y && clickY < y + h) {
92 auto variableModel = sqpApp->variableController().variableModel();
93 variableModel->abortProgress(index);
94 }
95 }
96 else {
97 QStyledItemDelegate::editorEvent(event, model, option, index);
98 }
99 }
100 else {
101 QStyledItemDelegate::editorEvent(event, model, option, index);
102 }
103 }
104 else {
105 QStyledItemDelegate::editorEvent(event, model, option, index);
106 }
107 }
49 108 };
50 109
51 110 VariableInspectorWidget::VariableInspectorWidget(QWidget *parent)
52 111 : QWidget{parent},
53 112 ui{new Ui::VariableInspectorWidget},
54 113 m_ProgressBarItemDelegate{new QProgressBarItemDelegate{this}}
55 114 {
56 115 ui->setupUi(this);
57 116
58 117 // Sets model for table
59 118 // auto sortFilterModel = new QSortFilterProxyModel{this};
60 119 // sortFilterModel->setSourceModel(sqpApp->variableController().variableModel());
61 120
62 121 auto variableModel = sqpApp->variableController().variableModel();
63 122 ui->tableView->setModel(variableModel);
64 123
65 124 // Adds extra signal/slot between view and model, so the view can be updated instantly when
66 125 // there is a change of data in the model
67 126 connect(variableModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), this,
68 127 SLOT(refresh()));
69 128
70 129 ui->tableView->setSelectionModel(sqpApp->variableController().variableSelectionModel());
71 130 ui->tableView->setItemDelegateForColumn(0, m_ProgressBarItemDelegate);
72 131
73 132 // Fixes column sizes
74 133 auto model = ui->tableView->model();
75 134 const auto count = model->columnCount();
76 135 for (auto i = 0; i < count; ++i) {
77 136 ui->tableView->setColumnWidth(
78 137 i, model->headerData(i, Qt::Horizontal, Qt::SizeHintRole).toSize().width());
79 138 }
80 139
81 140 // Sets selection options
82 141 ui->tableView->setSelectionBehavior(QTableView::SelectRows);
83 142 ui->tableView->setSelectionMode(QTableView::ExtendedSelection);
84 143
85 144 // Connection to show a menu when right clicking on the tree
86 145 ui->tableView->setContextMenuPolicy(Qt::CustomContextMenu);
87 146 connect(ui->tableView, &QTableView::customContextMenuRequested, this,
88 147 &VariableInspectorWidget::onTableMenuRequested);
89 148 }
90 149
91 150 VariableInspectorWidget::~VariableInspectorWidget()
92 151 {
93 152 delete ui;
94 153 }
95 154
96 155 void VariableInspectorWidget::onTableMenuRequested(const QPoint &pos) noexcept
97 156 {
98 157 auto selectedRows = ui->tableView->selectionModel()->selectedRows();
99 158
100 159 // Gets the model to retrieve the underlying selected variables
101 160 auto model = sqpApp->variableController().variableModel();
102 161 auto selectedVariables = QVector<std::shared_ptr<Variable> >{};
103 162 for (const auto &selectedRow : qAsConst(selectedRows)) {
104 163 if (auto selectedVariable = model->variable(selectedRow.row())) {
105 164 selectedVariables.push_back(selectedVariable);
106 165 }
107 166 }
108 167
109 168 QMenu tableMenu{};
110 169
111 170 // Emits a signal so that potential receivers can populate the menu before displaying it
112 171 emit tableMenuAboutToBeDisplayed(&tableMenu, selectedVariables);
113 172
114 173 // Adds menu-specific actions
115 174 if (!selectedVariables.isEmpty()) {
116 175 // 'Delete' action
117 176 auto deleteFun = [&selectedVariables]() {
118 177 sqpApp->variableController().deleteVariables(selectedVariables);
119 178 };
120 179
121 180 tableMenu.addSeparator();
122 181 tableMenu.addAction(QIcon{":/icones/delete.png"}, tr("Delete"), deleteFun);
123 182 }
124 183
125 184 if (!tableMenu.isEmpty()) {
126 185 // Generates menu header (inserted before first action)
127 186 auto firstAction = tableMenu.actions().first();
128 187 auto headerAction = new QWidgetAction{&tableMenu};
129 188 headerAction->setDefaultWidget(new VariableMenuHeaderWidget{selectedVariables, &tableMenu});
130 189 tableMenu.insertAction(firstAction, headerAction);
131 190
132 191 // Displays menu
133 192 tableMenu.exec(mapToGlobal(pos));
134 193 }
135 194 }
136 195
137 196 void VariableInspectorWidget::refresh() noexcept
138 197 {
139 198 ui->tableView->viewport()->update();
140 199 }
@@ -1,160 +1,159
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 appendGraphDataUnsorted(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
29 29 return dateTicker;
30 30 }
31 31 else {
32 32 // default ticker
33 33 return QSharedPointer<QCPAxisTicker>::create();
34 34 }
35 35 }
36 36
37 37 void updateScalarData(QCPAbstractPlottable *component, ScalarSeries &scalarSeries,
38 38 const SqpDateTime &dateTime)
39 39 {
40 40 qCDebug(LOG_VisualizationGraphHelper()) << "TORM: updateScalarData"
41 41 << QThread::currentThread()->objectName();
42 42 if (auto qcpGraph = dynamic_cast<QCPGraph *>(component)) {
43 43 // Clean the graph
44 44 // NAIVE approch
45 45 scalarSeries.lockRead();
46 46 {
47 47 const auto xData = scalarSeries.xAxisData()->data();
48 48 const auto valuesData = scalarSeries.valuesData()->data();
49 49 const auto count = xData.count();
50 50 qCInfo(LOG_VisualizationGraphHelper()) << "TORM: Current points in cache"
51 51 << xData.count();
52 52
53 53 auto dataContainer = qcpGraph->data();
54 54 dataContainer->clear();
55 55 auto sqpDataContainer = QSharedPointer<SqpDataContainer>::create();
56 56 qcpGraph->setData(sqpDataContainer);
57 57
58 58 for (auto i = 0; i < count; ++i) {
59 59 const auto x = xData[i];
60 60 if (x >= dateTime.m_TStart && x <= dateTime.m_TEnd) {
61 61 sqpDataContainer->appendGraphDataUnsorted(QCPGraphData(x, valuesData[i]));
62 62 }
63 63 }
64 64 sqpDataContainer->sort();
65 65 qCInfo(LOG_VisualizationGraphHelper()) << "TORM: Current points displayed"
66 66 << sqpDataContainer->size();
67 67 }
68 68 scalarSeries.unlock();
69 69
70 70
71 71 // Display all data
72 component->rescaleAxes();
73 72 component->parentPlot()->replot();
74 73 }
75 74 else {
76 75 /// @todo DEBUG
77 76 }
78 77 }
79 78
80 79 QCPAbstractPlottable *createScalarSeriesComponent(ScalarSeries &scalarSeries, QCustomPlot &plot,
81 80 const SqpDateTime &dateTime)
82 81 {
83 82 auto component = plot.addGraph();
84 83
85 84 if (component) {
86 85 // // Graph data
87 86 component->setData(scalarSeries.xAxisData()->data(), scalarSeries.valuesData()->data(),
88 87 true);
89 88
90 89 updateScalarData(component, scalarSeries, dateTime);
91 90
92 91 // Axes properties
93 92 /// @todo : for the moment, no control is performed on the axes: the units and the tickers
94 93 /// are fixed for the default x-axis and y-axis of the plot, and according to the new graph
95 94
96 95 auto setAxisProperties = [](auto axis, const auto &unit) {
97 96 // label (unit name)
98 97 axis->setLabel(unit.m_Name);
99 98
100 99 // ticker (depending on the type of unit)
101 100 axis->setTicker(axisTicker(unit.m_TimeUnit));
102 101 };
103 102 setAxisProperties(plot.xAxis, scalarSeries.xAxisUnit());
104 103 setAxisProperties(plot.yAxis, scalarSeries.valuesUnit());
105 104
106 105 // Display all data
107 106 component->rescaleAxes();
108 107 plot.replot();
109 108 }
110 109 else {
111 110 qCDebug(LOG_VisualizationGraphHelper())
112 111 << QObject::tr("Can't create graph for the scalar series");
113 112 }
114 113
115 114 return component;
116 115 }
117 116
118 117 } // namespace
119 118
120 119 QVector<QCPAbstractPlottable *> VisualizationGraphHelper::create(std::shared_ptr<Variable> variable,
121 120 QCustomPlot &plot) noexcept
122 121 {
123 122 auto result = QVector<QCPAbstractPlottable *>{};
124 123
125 124 if (variable) {
126 125 // Gets the data series of the variable to call the creation of the right components
127 126 // according to its type
128 127 if (auto scalarSeries = dynamic_cast<ScalarSeries *>(variable->dataSeries())) {
129 128 result.append(createScalarSeriesComponent(*scalarSeries, plot, variable->dateTime()));
130 129 }
131 130 else {
132 131 qCDebug(LOG_VisualizationGraphHelper())
133 132 << QObject::tr("Can't create graph plottables : unmanaged data series type");
134 133 }
135 134 }
136 135 else {
137 136 qCDebug(LOG_VisualizationGraphHelper())
138 137 << QObject::tr("Can't create graph plottables : the variable is null");
139 138 }
140 139
141 140 return result;
142 141 }
143 142
144 143 void VisualizationGraphHelper::updateData(QVector<QCPAbstractPlottable *> plotableVect,
145 144 IDataSeries *dataSeries, const SqpDateTime &dateTime)
146 145 {
147 146 if (auto scalarSeries = dynamic_cast<ScalarSeries *>(dataSeries)) {
148 147 if (plotableVect.size() == 1) {
149 148 updateScalarData(plotableVect.at(0), *scalarSeries, dateTime);
150 149 }
151 150 else {
152 151 qCCritical(LOG_VisualizationGraphHelper()) << QObject::tr(
153 152 "Can't update Data of a scalarSeries because there is not only one component "
154 153 "associated");
155 154 }
156 155 }
157 156 else {
158 157 /// @todo DEBUG
159 158 }
160 159 }
@@ -1,285 +1,401
1 1 #include "Visualization/VisualizationGraphWidget.h"
2 2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 3 #include "Visualization/VisualizationGraphHelper.h"
4 4 #include "ui_VisualizationGraphWidget.h"
5 5
6 6 #include <Data/ArrayData.h>
7 7 #include <Data/IDataSeries.h>
8 8 #include <SqpApplication.h>
9 9 #include <Variable/Variable.h>
10 10 #include <Variable/VariableController.h>
11 11
12 12 #include <unordered_map>
13 13
14 14 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
15 15
16 16 namespace {
17 17
18 18 /// Key pressed to enable zoom on horizontal axis
19 19 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::NoModifier;
20 20
21 21 /// Key pressed to enable zoom on vertical axis
22 22 const auto VERTICAL_ZOOM_MODIFIER = Qt::ControlModifier;
23 23
24 24 } // namespace
25 25
26 26 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
27 27
28 explicit VisualizationGraphWidgetPrivate() : m_DoSynchronize{true}, m_IsCalibration{false} {}
29
30
31 // Return the operation when range changed
32 VisualizationGraphWidgetZoomType getZoomType(const QCPRange &t1, const QCPRange &t2);
33
28 34 // 1 variable -> n qcpplot
29 35 std::multimap<std::shared_ptr<Variable>, QCPAbstractPlottable *> m_VariableToPlotMultiMap;
36
37 bool m_DoSynchronize;
38 bool m_IsCalibration;
30 39 };
31 40
32 41 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
33 42 : QWidget{parent},
34 43 ui{new Ui::VisualizationGraphWidget},
35 44 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>()}
36 45 {
37 46 ui->setupUi(this);
38 47
39 48 ui->graphNameLabel->setText(name);
40 49
41 50 // 'Close' options : widget is deleted when closed
42 51 setAttribute(Qt::WA_DeleteOnClose);
43 52 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationGraphWidget::close);
44 53 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
45 54
46 55 // Set qcpplot properties :
47 56 // - Drag (on x-axis) and zoom are enabled
48 57 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
49 58 ui->widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);
50 59 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal);
60 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
61 connect(ui->widget, &QCustomPlot::mouseRelease, this,
62 &VisualizationGraphWidget::onMouseRelease);
51 63 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
52 connect(ui->widget->xAxis,
53 static_cast<void (QCPAxis::*)(const QCPRange &)>(&QCPAxis::rangeChanged), this,
54 &VisualizationGraphWidget::onRangeChanged);
64 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
65 &QCPAxis::rangeChanged),
66 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
55 67
56 68 // Activates menu when right clicking on the graph
57 69 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
58 70 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
59 71 &VisualizationGraphWidget::onGraphMenuRequested);
60 72
61 73 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
62 74 &VariableController::onRequestDataLoading);
63 75 }
64 76
65 77
66 78 VisualizationGraphWidget::~VisualizationGraphWidget()
67 79 {
68 80 delete ui;
69 81 }
70 82
83 void VisualizationGraphWidget::enableSynchronize(bool enable)
84 {
85 impl->m_DoSynchronize = enable;
86 }
87
71 88 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable)
72 89 {
73 90 // Uses delegate to create the qcpplot components according to the variable
74 91 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
75 92
76 93 for (auto createdPlottable : qAsConst(createdPlottables)) {
77 94 impl->m_VariableToPlotMultiMap.insert({variable, createdPlottable});
78 95 }
79 96
80 97 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
81 98 }
82 99 void VisualizationGraphWidget::addVariableUsingGraph(std::shared_ptr<Variable> variable)
83 100 {
84 101
85 102 // when adding a variable, we need to set its time range to the current graph range
86 103 auto grapheRange = ui->widget->xAxis->range();
87 104 auto dateTime = SqpDateTime{grapheRange.lower, grapheRange.upper};
88 105 variable->setDateTime(dateTime);
89 106
90 107 auto variableDateTimeWithTolerance = dateTime;
91 108
92 // add 10% tolerance for each side
93 auto tolerance = 0.1 * (dateTime.m_TEnd - dateTime.m_TStart);
109 // add 20% tolerance for each side
110 auto tolerance = 0.2 * (dateTime.m_TEnd - dateTime.m_TStart);
94 111 variableDateTimeWithTolerance.m_TStart -= tolerance;
95 112 variableDateTimeWithTolerance.m_TEnd += tolerance;
96 113
97 114 // Uses delegate to create the qcpplot components according to the variable
98 115 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
99 116
100 117 for (auto createdPlottable : qAsConst(createdPlottables)) {
101 118 impl->m_VariableToPlotMultiMap.insert({variable, createdPlottable});
102 119 }
103 120
104 121 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
105 122
106 123 // CHangement detected, we need to ask controller to request data loading
107 124 emit requestDataLoading(variable, variableDateTimeWithTolerance);
108 125 }
109 126
110 127 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
111 128 {
112 129 // Each component associated to the variable :
113 130 // - is removed from qcpplot (which deletes it)
114 131 // - is no longer referenced in the map
115 132 auto componentsIt = impl->m_VariableToPlotMultiMap.equal_range(variable);
116 133 for (auto it = componentsIt.first; it != componentsIt.second;) {
117 134 ui->widget->removePlottable(it->second);
118 135 it = impl->m_VariableToPlotMultiMap.erase(it);
119 136 }
120 137
121 138 // Updates graph
122 139 ui->widget->replot();
123 140 }
124 141
142 void VisualizationGraphWidget::setRange(std::shared_ptr<Variable> variable,
143 const SqpDateTime &range)
144 {
145 // Note: in case of different axes that depends on variable, we could start with a code like
146 // that:
147 // auto componentsIt = impl->m_VariableToPlotMultiMap.equal_range(variable);
148 // for (auto it = componentsIt.first; it != componentsIt.second;) {
149 // }
150 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
151 ui->widget->replot();
152 }
153
154 SqpDateTime VisualizationGraphWidget::graphRange() const noexcept
155 {
156 auto grapheRange = ui->widget->xAxis->range();
157 return SqpDateTime{grapheRange.lower, grapheRange.upper};
158 }
159
160 void VisualizationGraphWidget::setGraphRange(const SqpDateTime &range)
161 {
162 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
163 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
164 ui->widget->replot();
165 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
166 }
167
125 168 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
126 169 {
127 170 if (visitor) {
128 171 visitor->visit(this);
129 172 }
130 173 else {
131 174 qCCritical(LOG_VisualizationGraphWidget())
132 175 << tr("Can't visit widget : the visitor is null");
133 176 }
134 177 }
135 178
136 179 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
137 180 {
138 181 /// @todo : for the moment, a graph can always accomodate a variable
139 182 Q_UNUSED(variable);
140 183 return true;
141 184 }
142 185
143 186 bool VisualizationGraphWidget::contains(const Variable &variable) const
144 187 {
145 188 // Finds the variable among the keys of the map
146 189 auto variablePtr = &variable;
147 190 auto findVariable
148 191 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
149 192
150 193 auto end = impl->m_VariableToPlotMultiMap.cend();
151 194 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
152 195 return it != end;
153 196 }
154 197
155 198 QString VisualizationGraphWidget::name() const
156 199 {
157 200 return ui->graphNameLabel->text();
158 201 }
159 202
160 203 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
161 204 {
162 205 QMenu graphMenu{};
163 206
164 207 // Iterates on variables (unique keys)
165 208 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
166 209 end = impl->m_VariableToPlotMultiMap.cend();
167 210 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
168 211 // 'Remove variable' action
169 212 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
170 213 [ this, var = it->first ]() { removeVariable(var); });
171 214 }
172 215
173 216 if (!graphMenu.isEmpty()) {
174 217 graphMenu.exec(mapToGlobal(pos));
175 218 }
176 219 }
177 220
178 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1)
221 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
179 222 {
180 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::onRangeChanged")
223 qCInfo(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::onRangeChanged")
181 224 << QThread::currentThread()->objectName();
182 225
226 auto dateTimeRange = SqpDateTime{t1.lower, t1.upper};
227
228 auto zoomType = impl->getZoomType(t1, t2);
183 229 for (auto it = impl->m_VariableToPlotMultiMap.cbegin();
184 230 it != impl->m_VariableToPlotMultiMap.cend(); ++it) {
185 231
186 232 auto variable = it->first;
187 auto dateTime = SqpDateTime{t1.lower, t1.upper};
233 auto currentDateTime = dateTimeRange;
188 234
189 if (!variable->contains(dateTime)) {
235 auto toleranceFactor = 0.2;
236 auto tolerance = toleranceFactor * (currentDateTime.m_TEnd - currentDateTime.m_TStart);
237 auto variableDateTimeWithTolerance = currentDateTime;
238 variableDateTimeWithTolerance.m_TStart -= tolerance;
239 variableDateTimeWithTolerance.m_TEnd += tolerance;
190 240
191 auto variableDateTimeWithTolerance = dateTime;
192 if (!variable->isInside(dateTime)) {
241 qCDebug(LOG_VisualizationGraphWidget()) << "r" << currentDateTime;
242 qCDebug(LOG_VisualizationGraphWidget()) << "t" << variableDateTimeWithTolerance;
243 qCDebug(LOG_VisualizationGraphWidget()) << "v" << variable->dateTime();
244 // If new range with tol is upper than variable datetime parameters. we need to request new
245 // data
246 if (!variable->contains(variableDateTimeWithTolerance)) {
247
248 auto variableDateTimeWithTolerance = currentDateTime;
249 if (!variable->isInside(currentDateTime)) {
193 250 auto variableDateTime = variable->dateTime();
194 if (variableDateTime.m_TStart < dateTime.m_TStart) {
195 qCDebug(LOG_VisualizationGraphWidget()) << tr("TDetection pan to right:");
251 if (variable->contains(variableDateTimeWithTolerance)) {
252 qCDebug(LOG_VisualizationGraphWidget())
253 << tr("TORM: Detection zoom in that need request:");
254 // add 10% tolerance for each side
255 tolerance
256 = toleranceFactor * (currentDateTime.m_TEnd - currentDateTime.m_TStart);
257 variableDateTimeWithTolerance.m_TStart -= tolerance;
258 variableDateTimeWithTolerance.m_TEnd += tolerance;
259 }
260 else if (variableDateTime.m_TStart < currentDateTime.m_TStart) {
261 qCInfo(LOG_VisualizationGraphWidget()) << tr("TORM: Detection pan to right:");
196 262
197 auto diffEndToKeepDelta = dateTime.m_TEnd - variableDateTime.m_TEnd;
198 dateTime.m_TStart = variableDateTime.m_TStart + diffEndToKeepDelta;
263 auto diffEndToKeepDelta = currentDateTime.m_TEnd - variableDateTime.m_TEnd;
264 currentDateTime.m_TStart = variableDateTime.m_TStart + diffEndToKeepDelta;
199 265 // Tolerance have to be added to the right
200 // add 10% tolerance for right (end) side
201 auto tolerance = 0.1 * (dateTime.m_TEnd - dateTime.m_TStart);
266 // add tolerance for right (end) side
267 tolerance
268 = toleranceFactor * (currentDateTime.m_TEnd - currentDateTime.m_TStart);
202 269 variableDateTimeWithTolerance.m_TEnd += tolerance;
203 270 }
204 else if (variableDateTime.m_TEnd > dateTime.m_TEnd) {
205 qCDebug(LOG_VisualizationGraphWidget()) << tr("Detection pan to left: ");
206 auto diffStartToKeepDelta = variableDateTime.m_TStart - dateTime.m_TStart;
207 dateTime.m_TEnd = variableDateTime.m_TEnd - diffStartToKeepDelta;
271 else if (variableDateTime.m_TEnd > currentDateTime.m_TEnd) {
272 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: Detection pan to left: ");
273 auto diffStartToKeepDelta
274 = variableDateTime.m_TStart - currentDateTime.m_TStart;
275 currentDateTime.m_TEnd = variableDateTime.m_TEnd - diffStartToKeepDelta;
208 276 // Tolerance have to be added to the left
209 // add 10% tolerance for left (start) side
210 auto tolerance = 0.1 * (dateTime.m_TEnd - dateTime.m_TStart);
277 // add tolerance for left (start) side
278 tolerance
279 = toleranceFactor * (currentDateTime.m_TEnd - currentDateTime.m_TStart);
211 280 variableDateTimeWithTolerance.m_TStart -= tolerance;
212 281 }
213 282 else {
214 qCWarning(LOG_VisualizationGraphWidget())
283 qCCritical(LOG_VisualizationGraphWidget())
215 284 << tr("Detection anormal zoom detection: ");
216 285 }
217 286 }
218 287 else {
219 qCDebug(LOG_VisualizationGraphWidget()) << tr("Detection zoom out: ");
288 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: Detection zoom out: ");
220 289 // add 10% tolerance for each side
221 auto tolerance = 0.1 * (dateTime.m_TEnd - dateTime.m_TStart);
290 tolerance = toleranceFactor * (currentDateTime.m_TEnd - currentDateTime.m_TStart);
222 291 variableDateTimeWithTolerance.m_TStart -= tolerance;
223 292 variableDateTimeWithTolerance.m_TEnd += tolerance;
293 zoomType = VisualizationGraphWidgetZoomType::ZoomOut;
294 }
295 if (!variable->contains(dateTimeRange)) {
296 qCDebug(LOG_VisualizationGraphWidget())
297 << "TORM: Modif on variable datetime detected" << currentDateTime;
298 variable->setDateTime(currentDateTime);
224 299 }
225 variable->setDateTime(dateTime);
226 300
301 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: Request data detection: ");
227 302 // CHangement detected, we need to ask controller to request data loading
228 303 emit requestDataLoading(variable, variableDateTimeWithTolerance);
229 304 }
230 305 else {
231 qCDebug(LOG_VisualizationGraphWidget()) << tr("Detection zoom in: ");
306 qCInfo(LOG_VisualizationGraphWidget())
307 << tr("TORM: Detection zoom in that doesn't need request: ");
308 zoomType = VisualizationGraphWidgetZoomType::ZoomIn;
309 }
232 310 }
311
312 if (impl->m_DoSynchronize && !impl->m_IsCalibration) {
313 auto oldDateTime = SqpDateTime{t2.lower, t2.upper};
314 qCDebug(LOG_VisualizationGraphWidget())
315 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
316 << QThread::currentThread()->objectName();
317 emit synchronize(dateTimeRange, oldDateTime, zoomType);
233 318 }
234 319 }
235 320
236 321 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
237 322 {
238 323 auto zoomOrientations = QFlags<Qt::Orientation>{};
239 324
240 325 // Lambda that enables a zoom orientation if the key modifier related to this orientation
241 326 // has
242 327 // been pressed
243 328 auto enableOrientation
244 329 = [&zoomOrientations, event](const auto &orientation, const auto &modifier) {
245 330 auto orientationEnabled = event->modifiers().testFlag(modifier);
246 331 zoomOrientations.setFlag(orientation, orientationEnabled);
247 332 };
248 333 enableOrientation(Qt::Vertical, VERTICAL_ZOOM_MODIFIER);
249 334 enableOrientation(Qt::Horizontal, HORIZONTAL_ZOOM_MODIFIER);
250 335
251 336 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
252 337 }
253 338
339 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
340 {
341 impl->m_IsCalibration = event->modifiers().testFlag(Qt::ControlModifier);
342 }
343
344 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
345 {
346 impl->m_IsCalibration = false;
347 }
348
254 349 void VisualizationGraphWidget::onDataCacheVariableUpdated()
255 350 {
256 351 // NOTE:
257 352 // We don't want to call the method for each component of a variable unitarily, but for
258 353 // all
259 354 // its components at once (eg its three components in the case of a vector).
260 355
261 356 // The unordered_multimap does not do this easily, so the question is whether to:
262 357 // - use an ordered_multimap and the algos of std to group the values by key
263 358 // - use a map (unique keys) and store as values directly the list of components
264 359
360 auto grapheRange = ui->widget->xAxis->range();
361 auto dateTime = SqpDateTime{grapheRange.lower, grapheRange.upper};
362
265 363 for (auto it = impl->m_VariableToPlotMultiMap.cbegin();
266 364 it != impl->m_VariableToPlotMultiMap.cend(); ++it) {
267 365 auto variable = it->first;
366 qCDebug(LOG_VisualizationGraphWidget())
367 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S"
368 << variable->dateTime();
369 qCDebug(LOG_VisualizationGraphWidget())
370 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
371 if (dateTime.contains(variable->dateTime()) || dateTime.intersect(variable->dateTime())) {
372
268 373 VisualizationGraphHelper::updateData(QVector<QCPAbstractPlottable *>{} << it->second,
269 374 variable->dataSeries(), variable->dateTime());
270 375 }
271 376 }
377 }
272 378
273 void VisualizationGraphWidget::updateDisplay(std::shared_ptr<Variable> variable)
379 VisualizationGraphWidgetZoomType
380 VisualizationGraphWidget::VisualizationGraphWidgetPrivate::getZoomType(const QCPRange &t1,
381 const QCPRange &t2)
274 382 {
275 auto abstractPlotableItPair = impl->m_VariableToPlotMultiMap.equal_range(variable);
276
277 auto abstractPlotableVect = QVector<QCPAbstractPlottable *>{};
278
279 for (auto it = abstractPlotableItPair.first; it != abstractPlotableItPair.second; ++it) {
280 abstractPlotableVect.push_back(it->second);
383 // t1.lower <= t2.lower && t2.upper <= t1.upper
384 auto zoomType = VisualizationGraphWidgetZoomType::Unknown;
385 if (t1.lower <= t2.lower && t2.upper <= t1.upper) {
386 zoomType = VisualizationGraphWidgetZoomType::ZoomOut;
281 387 }
282
283 VisualizationGraphHelper::updateData(abstractPlotableVect, variable->dataSeries(),
284 variable->dateTime());
388 else if (t1.lower > t2.lower && t1.upper > t2.upper) {
389 zoomType = VisualizationGraphWidgetZoomType::PanRight;
390 }
391 else if (t1.lower < t2.lower && t1.upper < t2.upper) {
392 zoomType = VisualizationGraphWidgetZoomType::PanLeft;
393 }
394 else if (t1.lower > t2.lower && t2.upper > t1.upper) {
395 zoomType = VisualizationGraphWidgetZoomType::ZoomIn;
396 }
397 else {
398 qCCritical(LOG_VisualizationGraphWidget()) << "getZoomType: Unknown type detected";
399 }
400 return zoomType;
285 401 }
@@ -1,143 +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 #include "Visualization/operations/RescaleAxeOperation.h"
8 9 #include "Visualization/qcustomplot.h"
9 10
10 11 #include "ui_VisualizationWidget.h"
11 12
12 13 #include <QToolButton>
13 14
14 15 Q_LOGGING_CATEGORY(LOG_VisualizationWidget, "VisualizationWidget")
15 16
16 17 VisualizationWidget::VisualizationWidget(QWidget *parent)
17 18 : QWidget{parent}, ui{new Ui::VisualizationWidget}
18 19 {
19 20 ui->setupUi(this);
20 21
21 22 auto addTabViewButton = new QToolButton{ui->tabWidget};
22 23 addTabViewButton->setText(tr("Add View"));
23 24 addTabViewButton->setCursor(Qt::ArrowCursor);
24 25 ui->tabWidget->setCornerWidget(addTabViewButton, Qt::TopRightCorner);
25 26
26 27 auto enableMinimumCornerWidgetSize = [this](bool enable) {
27 28
28 29 auto tabViewCornerWidget = ui->tabWidget->cornerWidget();
29 30 auto width = enable ? tabViewCornerWidget->width() : 0;
30 31 auto height = enable ? tabViewCornerWidget->height() : 0;
31 32 tabViewCornerWidget->setMinimumHeight(height);
32 33 tabViewCornerWidget->setMinimumWidth(width);
33 34 ui->tabWidget->setMinimumHeight(height);
34 35 ui->tabWidget->setMinimumWidth(width);
35 36 };
36 37
37 38 auto addTabView = [this, enableMinimumCornerWidgetSize]() {
38 39 auto widget = new VisualizationTabWidget{QString{"View %1"}.arg(ui->tabWidget->count() + 1),
39 40 ui->tabWidget};
40 41 auto index = ui->tabWidget->addTab(widget, widget->name());
41 42 if (ui->tabWidget->count() > 0) {
42 43 enableMinimumCornerWidgetSize(false);
43 44 }
44 45 qCInfo(LOG_VisualizationWidget()) << tr("add the tab of index %1").arg(index);
45 46 };
46 47
47 48 auto removeTabView = [this, enableMinimumCornerWidgetSize](int index) {
48 49 if (ui->tabWidget->count() == 1) {
49 50 enableMinimumCornerWidgetSize(true);
50 51 }
51 52
52 53 // Removes widget from tab and closes it
53 54 auto widget = ui->tabWidget->widget(index);
54 55 ui->tabWidget->removeTab(index);
55 56 if (widget) {
56 57 widget->close();
57 58 }
58 59
59 60 qCInfo(LOG_VisualizationWidget()) << tr("remove the tab of index %1").arg(index);
60 61
61 62 };
62 63
63 64 ui->tabWidget->setTabsClosable(true);
64 65
65 66 connect(addTabViewButton, &QToolButton::clicked, addTabView);
66 67 connect(ui->tabWidget, &QTabWidget::tabCloseRequested, removeTabView);
67 68
68 69 // Adds default tab
69 70 addTabView();
70 71 }
71 72
72 73 VisualizationWidget::~VisualizationWidget()
73 74 {
74 75 delete ui;
75 76 }
76 77
77 78 void VisualizationWidget::accept(IVisualizationWidgetVisitor *visitor)
78 79 {
79 80 if (visitor) {
80 81 visitor->visitEnter(this);
81 82
82 83 // Apply visitor for tab children
83 84 for (auto i = 0; i < ui->tabWidget->count(); ++i) {
84 85 // Widgets different from tabs are not visited (no action)
85 86 if (auto visualizationTabWidget
86 87 = dynamic_cast<VisualizationTabWidget *>(ui->tabWidget->widget(i))) {
87 88 visualizationTabWidget->accept(visitor);
88 89 }
89 90 }
90 91
91 92 visitor->visitLeave(this);
92 93 }
93 94 else {
94 95 qCCritical(LOG_VisualizationWidget()) << tr("Can't visit widget : the visitor is null");
95 96 }
96 97 }
97 98
98 99 bool VisualizationWidget::canDrop(const Variable &variable) const
99 100 {
100 101 // The main widget can never accomodate a variable
101 102 Q_UNUSED(variable);
102 103 return false;
103 104 }
104 105
105 106 bool VisualizationWidget::contains(const Variable &variable) const
106 107 {
107 108 Q_UNUSED(variable);
108 109 return false;
109 110 }
110 111
111 112 QString VisualizationWidget::name() const
112 113 {
113 114 return QStringLiteral("MainView");
114 115 }
115 116
116 117 void VisualizationWidget::attachVariableMenu(
117 118 QMenu *menu, const QVector<std::shared_ptr<Variable> > &variables) noexcept
118 119 {
119 120 // Menu is generated only if there is a single variable
120 121 if (variables.size() == 1) {
121 122 if (auto variable = variables.first()) {
122 123 // Generates the actions that make it possible to visualize the variable
123 124 auto generateVariableMenuOperation = GenerateVariableMenuOperation{menu, variable};
124 125 accept(&generateVariableMenuOperation);
125 126 }
126 127 else {
127 128 qCCritical(LOG_VisualizationWidget()) << tr(
128 129 "Can't generate the menu relative to the visualization: the variable is null");
129 130 }
130 131 }
131 132 else {
132 133 qCDebug(LOG_VisualizationWidget())
133 134 << tr("No generation of the menu related to the visualization: several variables are "
134 135 "selected");
135 136 }
136 137 }
137 138
138 139 void VisualizationWidget::onVariableAboutToBeDeleted(std::shared_ptr<Variable> variable) noexcept
139 140 {
140 141 // Calls the operation of removing all references to the variable in the visualization
141 142 auto removeVariableOperation = RemoveVariableOperation{variable};
142 143 accept(&removeVariableOperation);
143 144 }
145
146 void VisualizationWidget::onRangeChanged(std::shared_ptr<Variable> variable,
147 const SqpDateTime &range) noexcept
148 {
149 // Calls the operation of rescaling all graph that contrains variable in the visualization
150 auto rescaleVariableOperation = RescaleAxeOperation{variable, range};
151 accept(&rescaleVariableOperation);
152 }
@@ -1,111 +1,200
1 1 #include "Visualization/VisualizationZoneWidget.h"
2
3 #include "Data/SqpDateTime.h"
4
2 5 #include "Visualization/IVisualizationWidgetVisitor.h"
6 #include "Visualization/VisualizationGraphWidget.h"
3 7 #include "ui_VisualizationZoneWidget.h"
4 8
5 #include "Visualization/VisualizationGraphWidget.h"
6 9
7 10 #include <SqpApplication.h>
8 11
9 12 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
10 13
11 14 namespace {
12 15
13 16 /// Minimum height for graph added in zones (in pixels)
14 17 const auto GRAPH_MINIMUM_HEIGHT = 300;
15 18
16 19 /// Generates a default name for a new graph, according to the number of graphs already displayed in
17 20 /// the zone
18 21 QString defaultGraphName(const QLayout &layout)
19 22 {
20 23 auto count = 0;
21 24 for (auto i = 0; i < layout.count(); ++i) {
22 25 if (dynamic_cast<VisualizationGraphWidget *>(layout.itemAt(i)->widget())) {
23 26 count++;
24 27 }
25 28 }
26 29
27 30 return QObject::tr("Graph %1").arg(count + 1);
28 31 }
29 32
30 33 } // namespace
31 34
32 35 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
33 36 : QWidget{parent}, ui{new Ui::VisualizationZoneWidget}
34 37 {
35 38 ui->setupUi(this);
36 39
37 40 ui->zoneNameLabel->setText(name);
38 41
39 42 // 'Close' options : widget is deleted when closed
40 43 setAttribute(Qt::WA_DeleteOnClose);
41 44 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
42 45 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
43 46 }
44 47
45 48 VisualizationZoneWidget::~VisualizationZoneWidget()
46 49 {
47 50 delete ui;
48 51 }
49 52
50 53 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
51 54 {
52 55 ui->visualizationZoneFrame->layout()->addWidget(graphWidget);
53 56 }
54 57
55 58 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
56 59 {
57 60 auto graphWidget = new VisualizationGraphWidget{
58 61 defaultGraphName(*ui->visualizationZoneFrame->layout()), this};
59 62
63
60 64 // Set graph properties
61 65 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
62 66 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
63 67
64 68 this->addGraph(graphWidget);
65 69
66 70 graphWidget->addVariable(variable);
67 71
72 // Lambda to synchronize zone widget
73 auto synchronizeZoneWidget = [this, graphWidget](const SqpDateTime &dateTime,
74 const SqpDateTime &oldDateTime,
75 VisualizationGraphWidgetZoomType zoomType) {
76 auto frameLayout = ui->visualizationZoneFrame->layout();
77 for (auto i = 0; i < frameLayout->count(); ++i) {
78 auto graphChild
79 = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
80 if (graphChild && (graphChild != graphWidget)) {
81
82 auto graphChildRange = graphChild->graphRange();
83 switch (zoomType) {
84 case VisualizationGraphWidgetZoomType::ZoomIn: {
85 auto deltaLeft = dateTime.m_TStart - oldDateTime.m_TStart;
86 auto deltaRight = oldDateTime.m_TEnd - dateTime.m_TEnd;
87 graphChildRange.m_TStart += deltaLeft;
88 graphChildRange.m_TEnd -= deltaRight;
89 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomIn");
90 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
91 << deltaLeft;
92 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
93 << deltaRight;
94 qCCritical(LOG_VisualizationZoneWidget())
95 << tr("TORM: dt") << dateTime.m_TEnd - dateTime.m_TStart;
96
97 break;
98 }
99
100 case VisualizationGraphWidgetZoomType::ZoomOut: {
101 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomOut");
102 auto deltaLeft = oldDateTime.m_TStart - dateTime.m_TStart;
103 auto deltaRight = dateTime.m_TEnd - oldDateTime.m_TEnd;
104 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
105 << deltaLeft;
106 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
107 << deltaRight;
108 qCCritical(LOG_VisualizationZoneWidget())
109 << tr("TORM: dt") << dateTime.m_TEnd - dateTime.m_TStart;
110 graphChildRange.m_TStart -= deltaLeft;
111 graphChildRange.m_TEnd += deltaRight;
112 break;
113 }
114 case VisualizationGraphWidgetZoomType::PanRight: {
115 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: PanRight");
116 auto deltaRight = dateTime.m_TEnd - oldDateTime.m_TEnd;
117 graphChildRange.m_TStart += deltaRight;
118 graphChildRange.m_TEnd += deltaRight;
119 qCCritical(LOG_VisualizationZoneWidget())
120 << tr("TORM: dt") << dateTime.m_TEnd - dateTime.m_TStart;
121 break;
122 }
123 case VisualizationGraphWidgetZoomType::PanLeft: {
124 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: PanLeft");
125 auto deltaLeft = oldDateTime.m_TStart - dateTime.m_TStart;
126 graphChildRange.m_TStart -= deltaLeft;
127 graphChildRange.m_TEnd -= deltaLeft;
128 break;
129 }
130 case VisualizationGraphWidgetZoomType::Unknown: {
131 qCCritical(LOG_VisualizationZoneWidget())
132 << tr("Impossible to synchronize: zoom type unknown");
133 break;
134 }
135 default:
136 qCCritical(LOG_VisualizationZoneWidget())
137 << tr("Impossible to synchronize: zoom type not take into account");
138 // No action
139 break;
140 }
141 graphChild->enableSynchronize(false);
142 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: Range before: ")
143 << graphChild->graphRange();
144 qCCritical(LOG_VisualizationZoneWidget()) << tr("TORM: Range after : ")
145 << graphChildRange;
146 qCCritical(LOG_VisualizationZoneWidget())
147 << tr("TORM: child dt") << graphChildRange.m_TEnd - graphChildRange.m_TStart;
148 graphChild->setGraphRange(graphChildRange);
149 graphChild->enableSynchronize(true);
150 }
151 }
152 };
153
154 // connection for synchronization
155 connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
156
68 157 return graphWidget;
69 158 }
70 159
71 160 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
72 161 {
73 162 if (visitor) {
74 163 visitor->visitEnter(this);
75 164
76 165 // Apply visitor to graph children
77 166 auto layout = ui->visualizationZoneFrame->layout();
78 167 for (auto i = 0; i < layout->count(); ++i) {
79 168 if (auto item = layout->itemAt(i)) {
80 169 // Widgets different from graphs are not visited (no action)
81 170 if (auto visualizationGraphWidget
82 171 = dynamic_cast<VisualizationGraphWidget *>(item->widget())) {
83 172 visualizationGraphWidget->accept(visitor);
84 173 }
85 174 }
86 175 }
87 176
88 177 visitor->visitLeave(this);
89 178 }
90 179 else {
91 180 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
92 181 }
93 182 }
94 183
95 184 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
96 185 {
97 186 // A tab can always accomodate a variable
98 187 Q_UNUSED(variable);
99 188 return true;
100 189 }
101 190
102 191 bool VisualizationZoneWidget::contains(const Variable &variable) const
103 192 {
104 193 Q_UNUSED(variable);
105 194 return false;
106 195 }
107 196
108 197 QString VisualizationZoneWidget::name() const
109 198 {
110 199 return ui->zoneNameLabel->text();
111 200 }
@@ -1,28 +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 void requestDataAborting(QUuid identifier) override;
25
24 26 private:
25 27 void retrieveData(QUuid token, const SqpDateTime &dateTime, const QVariantHash &data);
26 28 };
27 29
28 30 #endif // SCIQLOP_AMDAPROVIDER_H
@@ -1,129 +1,148
1 1 #include "AmdaProvider.h"
2 2 #include "AmdaDefs.h"
3 3 #include "AmdaResultParser.h"
4 4
5 5 #include <Data/DataProviderParameters.h>
6 6 #include <Network/NetworkController.h>
7 7 #include <SqpApplication.h>
8 8 #include <Variable/Variable.h>
9 9
10 10 #include <QNetworkAccessManager>
11 11 #include <QNetworkReply>
12 12 #include <QTemporaryFile>
13 13 #include <QThread>
14 14
15 15 Q_LOGGING_CATEGORY(LOG_AmdaProvider, "AmdaProvider")
16 16
17 17 namespace {
18 18
19 19 /// URL format for a request on AMDA server. The parameters are as follows:
20 20 /// - %1: start date
21 21 /// - %2: end date
22 22 /// - %3: parameter id
23 23 const auto AMDA_URL_FORMAT = QStringLiteral(
24 24 "http://amda.irap.omp.eu/php/rest/"
25 25 "getParameter.php?startTime=%1&stopTime=%2&parameterID=%3&sampling=60&outputFormat=ASCII&"
26 26 "timeFormat=ISO8601&gzip=0");
27 27
28 28 /// Dates format passed in the URL (e.g 2013-09-23T09:00)
29 const auto AMDA_TIME_FORMAT = QStringLiteral("yyyy-MM-ddThh:ss");
29 const auto AMDA_TIME_FORMAT = QStringLiteral("yyyy-MM-ddThh:mm:ss");
30 30
31 31 /// Formats a time to a date that can be passed in URL
32 32 QString dateFormat(double sqpDateTime) noexcept
33 33 {
34 34 auto dateTime = QDateTime::fromMSecsSinceEpoch(sqpDateTime * 1000.);
35 35 return dateTime.toString(AMDA_TIME_FORMAT);
36 36 }
37 37
38 38 } // namespace
39 39
40 40 AmdaProvider::AmdaProvider()
41 41 {
42 42 qCDebug(LOG_NetworkController()) << tr("AmdaProvider::AmdaProvider")
43 43 << 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
52
53 connect(&sqpApp->networkController(), SIGNAL(replyDownloadProgress(QUuid, double)), this,
54 SIGNAL(dataProvidedProgress(QUuid, double)));
51 55 }
52 56 }
53 57
54 58 void AmdaProvider::requestDataLoading(QUuid token, const DataProviderParameters &parameters)
55 59 {
56 60 // NOTE: Try to use multithread if possible
57 61 const auto times = parameters.m_Times;
58 62 const auto data = parameters.m_Data;
59 63 for (const auto &dateTime : qAsConst(times)) {
60 64 retrieveData(token, dateTime, data);
61 65 }
62 66 }
63 67
68 void AmdaProvider::requestDataAborting(QUuid identifier)
69 {
70 if (auto app = sqpApp) {
71 auto &networkController = app->networkController();
72 networkController.onReplyCanceled(identifier);
73 }
74 }
75
64 76 void AmdaProvider::retrieveData(QUuid token, const SqpDateTime &dateTime, const QVariantHash &data)
65 77 {
66 78 // Retrieves product ID from data: if the value is invalid, no request is made
67 79 auto productId = data.value(AMDA_XML_ID_KEY).toString();
68 80 if (productId.isNull()) {
69 81 qCCritical(LOG_AmdaProvider()) << tr("Can't retrieve data: unknown product id");
70 82 return;
71 83 }
84 qCInfo(LOG_AmdaProvider()) << tr("AmdaProvider::retrieveData") << dateTime;
72 85
73 86 // /////////// //
74 87 // Creates URL //
75 88 // /////////// //
76 89
77 90 auto startDate = dateFormat(dateTime.m_TStart);
78 91 auto endDate = dateFormat(dateTime.m_TEnd);
79 92
80 93 auto url = QUrl{QString{AMDA_URL_FORMAT}.arg(startDate, endDate, productId)};
81
94 qCInfo(LOG_AmdaProvider()) << tr("AmdaProvider::retrieveData url:") << url;
82 95 auto tempFile = std::make_shared<QTemporaryFile>();
83 96
84 97 // LAMBDA
85 98 auto httpDownloadFinished
86 99 = [this, dateTime, tempFile, token](QNetworkReply *reply, QUuid dataId) noexcept {
87 100 Q_UNUSED(dataId);
88 101
102 // Don't do anything if the reply was abort
103 if (reply->error() != QNetworkReply::OperationCanceledError) {
104
89 105 if (tempFile) {
90 106 auto replyReadAll = reply->readAll();
91 107 if (!replyReadAll.isEmpty()) {
92 108 tempFile->write(replyReadAll);
93 109 }
94 110 tempFile->close();
95 111
96 112 // Parse results file
97 113 if (auto dataSeries = AmdaResultParser::readTxt(tempFile->fileName())) {
98 114 emit dataProvided(token, dataSeries, dateTime);
99 115 }
100 116 else {
101 117 /// @todo ALX : debug
102 118 }
103 119 }
120 }
104 121
105 // Deletes reply
106 reply->deleteLater();
107 reply = nullptr;
108 122 };
109 auto httpFinishedLambda = [this, httpDownloadFinished, tempFile](QNetworkReply *reply,
110 QUuid dataId) noexcept {
123 auto httpFinishedLambda
124 = [this, httpDownloadFinished, tempFile](QNetworkReply *reply, QUuid dataId) noexcept {
111 125
126 // Don't do anything if the reply was abort
127 if (reply->error() != QNetworkReply::OperationCanceledError) {
112 128 auto downloadFileUrl = QUrl{QString{reply->readAll()}};
113 // Deletes old reply
114 reply->deleteLater();
115 129
130
131 qCInfo(LOG_AmdaProvider()) << tr("AmdaProvider::retrieveData downloadFileUrl:")
132 << downloadFileUrl;
116 133 // Executes request for downloading file //
117 134
118 135 // Creates destination file
119 136 if (tempFile->open()) {
120 137 // Executes request
121 emit requestConstructed(QNetworkRequest{downloadFileUrl}, dataId, httpDownloadFinished);
138 emit requestConstructed(QNetworkRequest{downloadFileUrl}, dataId,
139 httpDownloadFinished);
140 }
122 141 }
123 142 };
124 143
125 144 // //////////////// //
126 145 // Executes request //
127 146 // //////////////// //
128 147 emit requestConstructed(QNetworkRequest{url}, token, httpFinishedLambda);
129 148 }
@@ -1,134 +1,145
1 1 #include "AmdaResultParser.h"
2 2
3 3 #include <Data/ScalarSeries.h>
4 4
5 5 #include <QDateTime>
6 6 #include <QFile>
7 7 #include <QRegularExpression>
8 8
9 9 #include <cmath>
10 10
11 11 Q_LOGGING_CATEGORY(LOG_AmdaResultParser, "AmdaResultParser")
12 12
13 13 namespace {
14 14
15 /// Message in result file when the file was not found on server
16 const auto FILE_NOT_FOUND_MESSAGE = QStringLiteral("Not Found");
17
15 18 /// Format for dates in result files
16 19 const auto DATE_FORMAT = QStringLiteral("yyyy-MM-ddThh:mm:ss.zzz");
17 20
18 21 /// Separator between values in a result line
19 22 const auto RESULT_LINE_SEPARATOR = QRegularExpression{QStringLiteral("\\s+")};
20 23
21 24 /// Regex to find unit in a line. Examples of valid lines:
22 25 /// ... - Units : nT - ...
23 26 /// ... -Units:nT- ...
24 27 /// ... -Units: m²- ...
25 28 /// ... - Units : m/s - ...
26 29 const auto UNIT_REGEX = QRegularExpression{QStringLiteral("-\\s*Units\\s*:\\s*(.+?)\\s*-")};
27 30
28 31 /// Converts a string date to a double date
29 32 /// @return a double that represents the date in seconds, NaN if the string date can't be converted
30 33 double doubleDate(const QString &stringDate) noexcept
31 34 {
32 35 auto dateTime = QDateTime::fromString(stringDate, DATE_FORMAT);
33 36 return dateTime.isValid() ? (dateTime.toMSecsSinceEpoch() / 1000.)
34 37 : std::numeric_limits<double>::quiet_NaN();
35 38 }
36 39
37 40 /**
38 41 * Reads stream to retrieve x-axis unit
39 42 * @param stream the stream to read
40 43 * @return the unit that has been read in the stream, a default unit (time unit with no label) if an
41 44 * error occured during reading
42 45 */
43 46 Unit readXAxisUnit(QTextStream &stream)
44 47 {
45 48 QString line{};
46 49
47 50 if (stream.readLineInto(&line)) {
48 51 auto match = UNIT_REGEX.match(line);
49 52 if (match.hasMatch()) {
50 53 return Unit{match.captured(1), true};
51 54 }
52 55 else {
53 56 qCWarning(LOG_AmdaResultParser())
54 57 << QObject::tr("Can't read unit: invalid line %1").arg(line);
55 58 }
56 59 }
57 60 else {
58 61 qCWarning(LOG_AmdaResultParser()) << QObject::tr("Can't read unit: end of file");
59 62 }
60 63
61 64 // Error cases
62 65 return Unit{{}, true};
63 66 }
64 67
65 68 /**
66 69 * Reads stream to retrieve results
67 70 * @param stream the stream to read
68 71 * @return the pair of vectors x-axis data/values data that has been read in the stream
69 72 */
70 73 QPair<QVector<double>, QVector<double> > readResults(QTextStream &stream)
71 74 {
72 75 auto xData = QVector<double>{};
73 76 auto valuesData = QVector<double>{};
74 77
75 78 QString line{};
76 79 while (stream.readLineInto(&line)) {
77 80 auto lineData = line.split(RESULT_LINE_SEPARATOR, QString::SkipEmptyParts);
78 81 if (lineData.size() == 2) {
79 82 // X : the data is converted from date to double (in secs)
80 83 auto x = doubleDate(lineData.at(0));
81 84
82 85 // Value
83 86 bool valueOk;
84 87 auto value = lineData.at(1).toDouble(&valueOk);
85 88
86 89 // Adds result only if x and value are valid
87 90 if (!std::isnan(x) && !std::isnan(value) && valueOk) {
88 91 xData.push_back(x);
89 92 valuesData.push_back(value);
90 93 }
91 94 else {
92 95 qCWarning(LOG_AmdaResultParser())
93 96 << QObject::tr(
94 97 "Can't retrieve results from line %1: x and/or value are invalid")
95 98 .arg(line);
96 99 }
97 100 }
98 101 else {
99 102 qCWarning(LOG_AmdaResultParser())
100 103 << QObject::tr("Can't retrieve results from line %1: invalid line").arg(line);
101 104 }
102 105 }
103 106
104 107 return qMakePair(std::move(xData), std::move(valuesData));
105 108 }
106 109
107 110 } // namespace
108 111
109 112 std::shared_ptr<IDataSeries> AmdaResultParser::readTxt(const QString &filePath) noexcept
110 113 {
111 114 QFile file{filePath};
112 115
113 116 if (!file.open(QFile::ReadOnly | QIODevice::Text)) {
114 117 qCCritical(LOG_AmdaResultParser())
115 118 << QObject::tr("Can't retrieve AMDA data from file %1: %2")
116 119 .arg(filePath, file.errorString());
117 120 return nullptr;
118 121 }
119 122
120 123 QTextStream stream{&file};
121 124
122 // Ignore first two lines (comments lines)
123 stream.readLine();
125 // Checks if the file was found on the server
126 auto firstLine = stream.readLine();
127 if (firstLine.compare(FILE_NOT_FOUND_MESSAGE) == 0) {
128 qCCritical(LOG_AmdaResultParser())
129 << QObject::tr("Can't retrieve AMDA data from file %1: file was not found on server")
130 .arg(filePath);
131 return nullptr;
132 }
133
134 // Ignore comments lines
124 135 stream.readLine();
125 136
126 137 // Reads x-axis unit
127 138 auto xAxisUnit = readXAxisUnit(stream);
128 139
129 140 // Reads results
130 141 auto results = readResults(stream);
131 142
132 143 return std::make_shared<ScalarSeries>(std::move(results.first), std::move(results.second),
133 144 xAxisUnit, Unit{});
134 145 }
@@ -1,179 +1,182
1 1 #include "AmdaResultParser.h"
2 2
3 3 #include <Data/ScalarSeries.h>
4 4
5 5 #include <QObject>
6 6 #include <QtTest>
7 7
8 8 namespace {
9 9
10 10 /// Path for the tests
11 11 const auto TESTS_RESOURCES_PATH
12 12 = QFileInfo{QString{AMDA_TESTS_RESOURCES_DIR}, "TestAmdaResultParser"}.absoluteFilePath();
13 13
14 14 QString inputFilePath(const QString &inputFileName)
15 15 {
16 16 return QFileInfo{TESTS_RESOURCES_PATH, inputFileName}.absoluteFilePath();
17 17 }
18 18
19 19 struct ExpectedResults {
20 20 explicit ExpectedResults() = default;
21 21
22 22 /// Ctor with QVector<QDateTime> as x-axis data. Datetimes are converted to doubles
23 23 explicit ExpectedResults(Unit xAxisUnit, Unit valuesUnit, const QVector<QDateTime> &xAxisData,
24 24 QVector<double> valuesData)
25 25 : m_ParsingOK{true},
26 26 m_XAxisUnit{xAxisUnit},
27 27 m_ValuesUnit{valuesUnit},
28 28 m_XAxisData{},
29 29 m_ValuesData{std::move(valuesData)}
30 30 {
31 31 // Converts QVector<QDateTime> to QVector<double>
32 32 std::transform(xAxisData.cbegin(), xAxisData.cend(), std::back_inserter(m_XAxisData),
33 33 [](const auto &dateTime) { return dateTime.toMSecsSinceEpoch() / 1000.; });
34 34 }
35 35
36 36 /**
37 37 * Validates a DataSeries compared to the expected results
38 38 * @param results the DataSeries to validate
39 39 */
40 40 void validate(std::shared_ptr<IDataSeries> results)
41 41 {
42 42 if (m_ParsingOK) {
43 43 auto scalarSeries = dynamic_cast<ScalarSeries *>(results.get());
44 44 QVERIFY(scalarSeries != nullptr);
45 45
46 46 // Checks units
47 47 QVERIFY(scalarSeries->xAxisUnit() == m_XAxisUnit);
48 48 QVERIFY(scalarSeries->valuesUnit() == m_ValuesUnit);
49 49
50 50 // Checks values
51 51 QVERIFY(scalarSeries->xAxisData()->data() == m_XAxisData);
52 52 QVERIFY(scalarSeries->valuesData()->data() == m_ValuesData);
53 53 }
54 54 else {
55 55 QVERIFY(results == nullptr);
56 56 }
57 57 }
58 58
59 59 // Parsing was successfully completed
60 60 bool m_ParsingOK{false};
61 61 // Expected x-axis unit
62 62 Unit m_XAxisUnit{};
63 63 // Expected values unit
64 64 Unit m_ValuesUnit{};
65 65 // Expected x-axis data
66 66 QVector<double> m_XAxisData{};
67 67 // Expected values data
68 68 QVector<double> m_ValuesData{};
69 69 };
70 70
71 71 } // namespace
72 72
73 73 Q_DECLARE_METATYPE(ExpectedResults)
74 74
75 75 class TestAmdaResultParser : public QObject {
76 76 Q_OBJECT
77 77 private slots:
78 78 /// Input test data
79 79 /// @sa testTxtJson()
80 80 void testReadTxt_data();
81 81
82 82 /// Tests parsing of a TXT file
83 83 void testReadTxt();
84 84 };
85 85
86 86 void TestAmdaResultParser::testReadTxt_data()
87 87 {
88 88 // ////////////// //
89 89 // Test structure //
90 90 // ////////////// //
91 91
92 92 // Name of TXT file to read
93 93 QTest::addColumn<QString>("inputFileName");
94 94 // Expected results
95 95 QTest::addColumn<ExpectedResults>("expectedResults");
96 96
97 97 // ////////// //
98 98 // Test cases //
99 99 // ////////// //
100 100
101 101 auto dateTime = [](int year, int month, int day, int hours, int minutes, int seconds) {
102 102 return QDateTime{{year, month, day}, {hours, minutes, seconds}};
103 103 };
104 104
105 105 // Valid file
106 106 QTest::newRow("Valid file")
107 107 << QStringLiteral("ValidScalar1.txt")
108 108 << ExpectedResults{
109 109 Unit{QStringLiteral("nT"), true}, Unit{},
110 110 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 0, 30), dateTime(2013, 9, 23, 9, 1, 30),
111 111 dateTime(2013, 9, 23, 9, 2, 30), dateTime(2013, 9, 23, 9, 3, 30),
112 112 dateTime(2013, 9, 23, 9, 4, 30), dateTime(2013, 9, 23, 9, 5, 30),
113 113 dateTime(2013, 9, 23, 9, 6, 30), dateTime(2013, 9, 23, 9, 7, 30),
114 114 dateTime(2013, 9, 23, 9, 8, 30), dateTime(2013, 9, 23, 9, 9, 30)},
115 115 QVector<double>{-2.83950, -2.71850, -2.52150, -2.57633, -2.58050, -2.48325, -2.63025,
116 116 -2.55800, -2.43250, -2.42200}};
117 117
118 118 // Valid files but with some invalid lines (wrong unit, wrong values, etc.)
119 119 QTest::newRow("No unit file") << QStringLiteral("NoUnit.txt")
120 120 << ExpectedResults{Unit{QStringLiteral(""), true}, Unit{},
121 121 QVector<QDateTime>{}, QVector<double>{}};
122 122 QTest::newRow("Wrong unit file")
123 123 << QStringLiteral("WrongUnit.txt")
124 124 << ExpectedResults{Unit{QStringLiteral(""), true}, Unit{},
125 125 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 0, 30),
126 126 dateTime(2013, 9, 23, 9, 1, 30),
127 127 dateTime(2013, 9, 23, 9, 2, 30)},
128 128 QVector<double>{-2.83950, -2.71850, -2.52150}};
129 129
130 130 QTest::newRow("Wrong results file (date of first line is invalid")
131 131 << QStringLiteral("WrongDate.txt")
132 132 << ExpectedResults{
133 133 Unit{QStringLiteral("nT"), true}, Unit{},
134 134 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)},
135 135 QVector<double>{-2.71850, -2.52150}};
136 136
137 137 QTest::newRow("Wrong results file (too many values for first line")
138 138 << QStringLiteral("TooManyValues.txt")
139 139 << ExpectedResults{
140 140 Unit{QStringLiteral("nT"), true}, Unit{},
141 141 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)},
142 142 QVector<double>{-2.71850, -2.52150}};
143 143
144 144 QTest::newRow("Wrong results file (value of first line is invalid")
145 145 << QStringLiteral("WrongValue.txt")
146 146 << ExpectedResults{
147 147 Unit{QStringLiteral("nT"), true}, Unit{},
148 148 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)},
149 149 QVector<double>{-2.71850, -2.52150}};
150 150
151 151 QTest::newRow("Wrong results file (value of first line is NaN")
152 152 << QStringLiteral("NaNValue.txt")
153 153 << ExpectedResults{
154 154 Unit{QStringLiteral("nT"), true}, Unit{},
155 155 QVector<QDateTime>{dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)},
156 156 QVector<double>{-2.71850, -2.52150}};
157 157
158 // Invalid file
158 // Invalid files
159 159 QTest::newRow("Invalid file (unexisting file)") << QStringLiteral("UnexistingFile.txt")
160 160 << ExpectedResults{};
161
162 QTest::newRow("Invalid file (file not found on server)") << QStringLiteral("FileNotFound.txt")
163 << ExpectedResults{};
161 164 }
162 165
163 166 void TestAmdaResultParser::testReadTxt()
164 167 {
165 168 QFETCH(QString, inputFileName);
166 169 QFETCH(ExpectedResults, expectedResults);
167 170
168 171 // Parses file
169 172 auto filePath = inputFilePath(inputFileName);
170 173 auto results = AmdaResultParser::readTxt(filePath);
171 174
172 175 // ///////////////// //
173 176 // Validates results //
174 177 // ///////////////// //
175 178 expectedResults.validate(results);
176 179 }
177 180
178 181 QTEST_MAIN(TestAmdaResultParser)
179 182 #include "TestAmdaResultParser.moc"
@@ -1,25 +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 #include <QUuid>
9 10
11 #include <QHash>
10 12 Q_DECLARE_LOGGING_CATEGORY(LOG_CosinusProvider)
11 13
12 14 /**
13 15 * @brief The CosinusProvider class is an example of how a data provider can generate data
14 16 */
15 17 class SCIQLOP_MOCKPLUGIN_EXPORT CosinusProvider : public IDataProvider {
16 18 public:
19 /// @sa IDataProvider::requestDataLoading(). The current impl isn't thread safe.
17 20 void requestDataLoading(QUuid token, const DataProviderParameters &parameters) override;
18 21
19 22
23 /// @sa IDataProvider::requestDataAborting(). The current impl isn't thread safe.
24 void requestDataAborting(QUuid identifier) override;
25
26
20 27 private:
21 /// @sa IDataProvider::retrieveData()
22 std::shared_ptr<IDataSeries> retrieveData(const SqpDateTime &dateTime) const;
28 std::shared_ptr<IDataSeries> retrieveData(QUuid token, const SqpDateTime &dateTime);
29
30 QHash<QUuid, bool> m_VariableToEnableProvider;
23 31 };
24 32
25 33 #endif // SCIQLOP_COSINUSPROVIDER_H
@@ -1,48 +1,95
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 <QDateTime>
9 #include <QFuture>
9 10 #include <QThread>
11 #include <QtConcurrent/QtConcurrent>
10 12
11 13 Q_LOGGING_CATEGORY(LOG_CosinusProvider, "CosinusProvider")
12 14
13 std::shared_ptr<IDataSeries> CosinusProvider::retrieveData(const SqpDateTime &dateTime) const
15 std::shared_ptr<IDataSeries> CosinusProvider::retrieveData(QUuid token, const SqpDateTime &dateTime)
14 16 {
17 // TODO: Add Mutex
15 18 auto dataIndex = 0;
16 19
17 20 // Gets the timerange from the parameters
18 21 double freq = 100.0;
19 22 double start = dateTime.m_TStart * freq; // 100 htz
20 23 double end = dateTime.m_TEnd * freq; // 100 htz
21 24
22 25 // We assure that timerange is valid
23 26 if (end < start) {
24 27 std::swap(start, end);
25 28 }
26 29
27 30 // Generates scalar series containing cosinus values (one value per second)
28 31 auto scalarSeries
29 32 = std::make_shared<ScalarSeries>(end - start, Unit{QStringLiteral("t"), true}, Unit{});
30 33
34
35 int progress = 0;
36 auto progressEnd = end - start;
31 37 for (auto time = start; time < end; ++time, ++dataIndex) {
38 auto it = m_VariableToEnableProvider.find(token);
39 if (it != m_VariableToEnableProvider.end() && it.value()) {
32 40 const auto timeOnFreq = time / freq;
33 41 scalarSeries->setData(dataIndex, timeOnFreq, std::cos(timeOnFreq));
42
43 // progression
44 int currentProgress = (time - start) * 100.0 / progressEnd;
45 if (currentProgress != progress) {
46 progress = currentProgress;
47
48 emit dataProvidedProgress(token, progress);
49 }
50 }
51 else {
52 if (!it.value()) {
53 qCDebug(LOG_CosinusProvider())
54 << "CosinusProvider::retrieveData: ARRET De l'acquisition detecté"
55 << end - time;
34 56 }
57 }
58 }
59 emit dataProvidedProgress(token, 0.0);
60
61
35 62 return scalarSeries;
36 63 }
37 64
38 65 void CosinusProvider::requestDataLoading(QUuid token, const DataProviderParameters &parameters)
39 66 {
67 // TODO: Add Mutex
68 m_VariableToEnableProvider[token] = true;
40 69 qCDebug(LOG_CosinusProvider()) << "CosinusProvider::requestDataLoading"
41 70 << QThread::currentThread()->objectName();
42 71 // NOTE: Try to use multithread if possible
43 72 const auto times = parameters.m_Times;
73
44 74 for (const auto &dateTime : qAsConst(times)) {
45 auto scalarSeries = this->retrieveData(dateTime);
75 if (m_VariableToEnableProvider[token]) {
76 auto scalarSeries = this->retrieveData(token, dateTime);
46 77 emit dataProvided(token, scalarSeries, dateTime);
47 78 }
48 79 }
80 }
81
82 void CosinusProvider::requestDataAborting(QUuid identifier)
83 {
84 // TODO: Add Mutex
85 qCDebug(LOG_CosinusProvider()) << "CosinusProvider::requestDataAborting" << identifier
86 << QThread::currentThread()->objectName();
87 auto it = m_VariableToEnableProvider.find(identifier);
88 if (it != m_VariableToEnableProvider.end()) {
89 it.value() = false;
90 }
91 else {
92 qCWarning(LOG_CosinusProvider())
93 << tr("Aborting progression of inexistant identifier detected !!!");
94 }
95 }
General Comments 0
You need to be logged in to leave comments. Login now