##// END OF EJS Templates
Merge branch 'feature/CatalogueGuiPart5' into develop
trabillard -
r1349:aa6b3e9d2907 merge
parent child
Show More
@@ -0,0 +1,26
1 #ifndef SCIQLOP_DATASERIESTYPE_H
2 #define SCIQLOP_DATASERIESTYPE_H
3
4 #include <QString>
5
6 enum class DataSeriesType { SCALAR, SPECTROGRAM, VECTOR, UNKNOWN };
7
8 struct DataSeriesTypeUtils {
9 static DataSeriesType fromString(const QString &type)
10 {
11 if (type == QStringLiteral("scalar")) {
12 return DataSeriesType::SCALAR;
13 }
14 else if (type == QStringLiteral("spectrogram")) {
15 return DataSeriesType::SPECTROGRAM;
16 }
17 else if (type == QStringLiteral("vector")) {
18 return DataSeriesType::VECTOR;
19 }
20 else {
21 return DataSeriesType::UNKNOWN;
22 }
23 }
24 };
25
26 #endif // SCIQLOP_DATASERIESTYPE_H
@@ -1,405 +1,405
1 /*------------------------------------------------------------------------------
1 /*------------------------------------------------------------------------------
2 -- This file is a part of the SciQLop Software
2 -- This file is a part of the SciQLop Software
3 -- Copyright (C) 2017, Plasma Physics Laboratory - CNRS
3 -- Copyright (C) 2017, Plasma Physics Laboratory - CNRS
4 --
4 --
5 -- This program is free software; you can redistribute it and/or modify
5 -- This program is free software; you can redistribute it and/or modify
6 -- it under the terms of the GNU General Public License as published by
6 -- it under the terms of the GNU General Public License as published by
7 -- the Free Software Foundation; either version 2 of the License, or
7 -- the Free Software Foundation; either version 2 of the License, or
8 -- (at your option) any later version.
8 -- (at your option) any later version.
9 --
9 --
10 -- This program is distributed in the hope that it will be useful,
10 -- This program is distributed in the hope that it will be useful,
11 -- but WITHOUT ANY WARRANTY; without even the implied warranty of
11 -- but WITHOUT ANY WARRANTY; without even the implied warranty of
12 -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 -- GNU General Public License for more details.
13 -- GNU General Public License for more details.
14 --
14 --
15 -- You should have received a copy of the GNU General Public License
15 -- You should have received a copy of the GNU General Public License
16 -- along with this program; if not, write to the Free Software
16 -- along with this program; if not, write to the Free Software
17 -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 -------------------------------------------------------------------------------*/
18 -------------------------------------------------------------------------------*/
19 /*-- Author : Alexis Jeandet
19 /*-- Author : Alexis Jeandet
20 -- Mail : alexis.jeandet@member.fsf.org
20 -- Mail : alexis.jeandet@member.fsf.org
21 ----------------------------------------------------------------------------*/
21 ----------------------------------------------------------------------------*/
22 #include "MainWindow.h"
22 #include "MainWindow.h"
23 #include "ui_MainWindow.h"
23 #include "ui_MainWindow.h"
24
24
25 #include <Catalogue/CatalogueController.h>
25 #include <Catalogue/CatalogueController.h>
26 #include <Catalogue/CatalogueExplorer.h>
26 #include <Catalogue/CatalogueExplorer.h>
27 #include <DataSource/DataSourceController.h>
27 #include <DataSource/DataSourceController.h>
28 #include <DataSource/DataSourceWidget.h>
28 #include <DataSource/DataSourceWidget.h>
29 #include <Settings/SqpSettingsDialog.h>
29 #include <Settings/SqpSettingsDialog.h>
30 #include <Settings/SqpSettingsGeneralWidget.h>
30 #include <Settings/SqpSettingsGeneralWidget.h>
31 #include <SidePane/SqpSidePane.h>
31 #include <SidePane/SqpSidePane.h>
32 #include <SqpApplication.h>
32 #include <SqpApplication.h>
33 #include <Time/TimeController.h>
33 #include <Time/TimeController.h>
34 #include <TimeWidget/TimeWidget.h>
34 #include <TimeWidget/TimeWidget.h>
35 #include <Variable/Variable.h>
35 #include <Variable/Variable.h>
36 #include <Variable/VariableController.h>
36 #include <Variable/VariableController.h>
37 #include <Visualization/VisualizationController.h>
37 #include <Visualization/VisualizationController.h>
38
38
39 #include <QAction>
39 #include <QAction>
40 #include <QCloseEvent>
40 #include <QCloseEvent>
41 #include <QDate>
41 #include <QDate>
42 #include <QDir>
42 #include <QDir>
43 #include <QFileDialog>
43 #include <QFileDialog>
44 #include <QMessageBox>
44 #include <QMessageBox>
45 #include <QToolBar>
45 #include <QToolBar>
46 #include <QToolButton>
46 #include <QToolButton>
47 #include <memory.h>
47 #include <memory.h>
48
48
49 #include "iostream"
49 #include "iostream"
50
50
51 Q_LOGGING_CATEGORY(LOG_MainWindow, "MainWindow")
51 Q_LOGGING_CATEGORY(LOG_MainWindow, "MainWindow")
52
52
53 namespace {
53 namespace {
54 const auto LEFTMAININSPECTORWIDGETSPLITTERINDEX = 0;
54 const auto LEFTMAININSPECTORWIDGETSPLITTERINDEX = 0;
55 const auto LEFTINSPECTORSIDEPANESPLITTERINDEX = 1;
55 const auto LEFTINSPECTORSIDEPANESPLITTERINDEX = 1;
56 const auto VIEWPLITTERINDEX = 2;
56 const auto VIEWPLITTERINDEX = 2;
57 const auto RIGHTINSPECTORSIDEPANESPLITTERINDEX = 3;
57 const auto RIGHTINSPECTORSIDEPANESPLITTERINDEX = 3;
58 const auto RIGHTMAININSPECTORWIDGETSPLITTERINDEX = 4;
58 const auto RIGHTMAININSPECTORWIDGETSPLITTERINDEX = 4;
59 }
59 }
60
60
61 class MainWindow::MainWindowPrivate {
61 class MainWindow::MainWindowPrivate {
62 public:
62 public:
63 explicit MainWindowPrivate(MainWindow *mainWindow)
63 explicit MainWindowPrivate(MainWindow *mainWindow)
64 : m_LastOpenLeftInspectorSize{},
64 : m_LastOpenLeftInspectorSize{},
65 m_LastOpenRightInspectorSize{},
65 m_LastOpenRightInspectorSize{},
66 m_GeneralSettingsWidget{new SqpSettingsGeneralWidget{mainWindow}},
66 m_GeneralSettingsWidget{new SqpSettingsGeneralWidget{mainWindow}},
67 m_SettingsDialog{new SqpSettingsDialog{mainWindow}},
67 m_SettingsDialog{new SqpSettingsDialog{mainWindow}},
68 m_CatalogExplorer{new CatalogueExplorer{mainWindow}}
68 m_CatalogExplorer{new CatalogueExplorer{mainWindow}}
69 {
69 {
70 }
70 }
71
71
72 QSize m_LastOpenLeftInspectorSize;
72 QSize m_LastOpenLeftInspectorSize;
73 QSize m_LastOpenRightInspectorSize;
73 QSize m_LastOpenRightInspectorSize;
74 /// General settings widget. MainWindow has the ownership
74 /// General settings widget. MainWindow has the ownership
75 SqpSettingsGeneralWidget *m_GeneralSettingsWidget;
75 SqpSettingsGeneralWidget *m_GeneralSettingsWidget;
76 /// Settings dialog. MainWindow has the ownership
76 /// Settings dialog. MainWindow has the ownership
77 SqpSettingsDialog *m_SettingsDialog;
77 SqpSettingsDialog *m_SettingsDialog;
78 /// Catalogue dialog. MainWindow has the ownership
78 /// Catalogue dialog. MainWindow has the ownership
79 CatalogueExplorer *m_CatalogExplorer;
79 CatalogueExplorer *m_CatalogExplorer;
80
80
81 bool checkDataToSave(QWidget *parentWidget);
81 bool checkDataToSave(QWidget *parentWidget);
82 };
82 };
83
83
84 MainWindow::MainWindow(QWidget *parent)
84 MainWindow::MainWindow(QWidget *parent)
85 : QMainWindow{parent},
85 : QMainWindow{parent},
86 m_Ui{new Ui::MainWindow},
86 m_Ui{new Ui::MainWindow},
87 impl{spimpl::make_unique_impl<MainWindowPrivate>(this)}
87 impl{spimpl::make_unique_impl<MainWindowPrivate>(this)}
88 {
88 {
89 m_Ui->setupUi(this);
89 m_Ui->setupUi(this);
90
90
91 m_Ui->splitter->setCollapsible(LEFTINSPECTORSIDEPANESPLITTERINDEX, false);
91 m_Ui->splitter->setCollapsible(LEFTINSPECTORSIDEPANESPLITTERINDEX, false);
92 m_Ui->splitter->setCollapsible(RIGHTINSPECTORSIDEPANESPLITTERINDEX, false);
92 m_Ui->splitter->setCollapsible(RIGHTINSPECTORSIDEPANESPLITTERINDEX, false);
93
93
94 impl->m_CatalogExplorer->setVisualizationWidget(m_Ui->view);
94 impl->m_CatalogExplorer->setVisualizationWidget(m_Ui->view);
95
95
96
96
97 auto leftSidePane = m_Ui->leftInspectorSidePane->sidePane();
97 auto leftSidePane = m_Ui->leftInspectorSidePane->sidePane();
98 auto openLeftInspectorAction = new QAction{QIcon{
98 auto openLeftInspectorAction = new QAction{QIcon{
99 ":/icones/previous.png",
99 ":/icones/previous.png",
100 },
100 },
101 tr("Show/hide the left inspector"), this};
101 tr("Show/hide the left inspector"), this};
102
102
103
103
104 auto spacerLeftTop = new QWidget{};
104 auto spacerLeftTop = new QWidget{};
105 spacerLeftTop->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
105 spacerLeftTop->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
106
106
107 auto spacerLeftBottom = new QWidget{};
107 auto spacerLeftBottom = new QWidget{};
108 spacerLeftBottom->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
108 spacerLeftBottom->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
109
109
110 leftSidePane->addWidget(spacerLeftTop);
110 leftSidePane->addWidget(spacerLeftTop);
111 leftSidePane->addAction(openLeftInspectorAction);
111 leftSidePane->addAction(openLeftInspectorAction);
112 leftSidePane->addWidget(spacerLeftBottom);
112 leftSidePane->addWidget(spacerLeftBottom);
113
113
114
114
115 auto rightSidePane = m_Ui->rightInspectorSidePane->sidePane();
115 auto rightSidePane = m_Ui->rightInspectorSidePane->sidePane();
116 auto openRightInspectorAction = new QAction{QIcon{
116 auto openRightInspectorAction = new QAction{QIcon{
117 ":/icones/next.png",
117 ":/icones/next.png",
118 },
118 },
119 tr("Show/hide the right inspector"), this};
119 tr("Show/hide the right inspector"), this};
120
120
121 auto spacerRightTop = new QWidget{};
121 auto spacerRightTop = new QWidget{};
122 spacerRightTop->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
122 spacerRightTop->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
123
123
124 auto spacerRightBottom = new QWidget{};
124 auto spacerRightBottom = new QWidget{};
125 spacerRightBottom->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
125 spacerRightBottom->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
126
126
127 rightSidePane->addWidget(spacerRightTop);
127 rightSidePane->addWidget(spacerRightTop);
128 rightSidePane->addAction(openRightInspectorAction);
128 rightSidePane->addAction(openRightInspectorAction);
129 rightSidePane->addWidget(spacerRightBottom);
129 rightSidePane->addWidget(spacerRightBottom);
130
130
131 openLeftInspectorAction->setCheckable(true);
131 openLeftInspectorAction->setCheckable(true);
132 openRightInspectorAction->setCheckable(true);
132 openRightInspectorAction->setCheckable(true);
133
133
134 auto openInspector = [this](bool checked, bool right, auto action) {
134 auto openInspector = [this](bool checked, bool right, auto action) {
135
135
136 action->setIcon(QIcon{(checked xor right) ? ":/icones/next.png" : ":/icones/previous.png"});
136 action->setIcon(QIcon{(checked xor right) ? ":/icones/next.png" : ":/icones/previous.png"});
137
137
138 auto &lastInspectorSize
138 auto &lastInspectorSize
139 = right ? impl->m_LastOpenRightInspectorSize : impl->m_LastOpenLeftInspectorSize;
139 = right ? impl->m_LastOpenRightInspectorSize : impl->m_LastOpenLeftInspectorSize;
140
140
141 auto nextInspectorSize = right ? m_Ui->rightMainInspectorWidget->size()
141 auto nextInspectorSize = right ? m_Ui->rightMainInspectorWidget->size()
142 : m_Ui->leftMainInspectorWidget->size();
142 : m_Ui->leftMainInspectorWidget->size();
143
143
144 // Update of the last opened geometry
144 // Update of the last opened geometry
145 if (checked) {
145 if (checked) {
146 lastInspectorSize = nextInspectorSize;
146 lastInspectorSize = nextInspectorSize;
147 }
147 }
148
148
149 auto startSize = lastInspectorSize;
149 auto startSize = lastInspectorSize;
150 auto endSize = startSize;
150 auto endSize = startSize;
151 endSize.setWidth(0);
151 endSize.setWidth(0);
152
152
153 auto splitterInspectorIndex
153 auto splitterInspectorIndex
154 = right ? RIGHTMAININSPECTORWIDGETSPLITTERINDEX : LEFTMAININSPECTORWIDGETSPLITTERINDEX;
154 = right ? RIGHTMAININSPECTORWIDGETSPLITTERINDEX : LEFTMAININSPECTORWIDGETSPLITTERINDEX;
155
155
156 auto currentSizes = m_Ui->splitter->sizes();
156 auto currentSizes = m_Ui->splitter->sizes();
157 if (checked) {
157 if (checked) {
158 // adjust sizes individually here, e.g.
158 // adjust sizes individually here, e.g.
159 currentSizes[splitterInspectorIndex] -= lastInspectorSize.width();
159 currentSizes[splitterInspectorIndex] -= lastInspectorSize.width();
160 currentSizes[VIEWPLITTERINDEX] += lastInspectorSize.width();
160 currentSizes[VIEWPLITTERINDEX] += lastInspectorSize.width();
161 m_Ui->splitter->setSizes(currentSizes);
161 m_Ui->splitter->setSizes(currentSizes);
162 }
162 }
163 else {
163 else {
164 // adjust sizes individually here, e.g.
164 // adjust sizes individually here, e.g.
165 currentSizes[splitterInspectorIndex] += lastInspectorSize.width();
165 currentSizes[splitterInspectorIndex] += lastInspectorSize.width();
166 currentSizes[VIEWPLITTERINDEX] -= lastInspectorSize.width();
166 currentSizes[VIEWPLITTERINDEX] -= lastInspectorSize.width();
167 m_Ui->splitter->setSizes(currentSizes);
167 m_Ui->splitter->setSizes(currentSizes);
168 }
168 }
169
169
170 };
170 };
171
171
172
172
173 connect(openLeftInspectorAction, &QAction::triggered,
173 connect(openLeftInspectorAction, &QAction::triggered,
174 [openInspector, openLeftInspectorAction](bool checked) {
174 [openInspector, openLeftInspectorAction](bool checked) {
175 openInspector(checked, false, openLeftInspectorAction);
175 openInspector(checked, false, openLeftInspectorAction);
176 });
176 });
177 connect(openRightInspectorAction, &QAction::triggered,
177 connect(openRightInspectorAction, &QAction::triggered,
178 [openInspector, openRightInspectorAction](bool checked) {
178 [openInspector, openRightInspectorAction](bool checked) {
179 openInspector(checked, true, openRightInspectorAction);
179 openInspector(checked, true, openRightInspectorAction);
180 });
180 });
181
181
182 // //////////////// //
182 // //////////////// //
183 // Menu and Toolbar //
183 // Menu and Toolbar //
184 // //////////////// //
184 // //////////////// //
185 this->menuBar()->addAction(tr("File"));
185 this->menuBar()->addAction(tr("File"));
186 auto toolsMenu = this->menuBar()->addMenu(tr("Tools"));
186 auto toolsMenu = this->menuBar()->addMenu(tr("Tools"));
187 toolsMenu->addAction(tr("Settings..."), [this]() {
187 toolsMenu->addAction(tr("Settings..."), [this]() {
188 // Loads settings
188 // Loads settings
189 impl->m_SettingsDialog->loadSettings();
189 impl->m_SettingsDialog->loadSettings();
190
190
191 // Open settings dialog and save settings if the dialog is accepted
191 // Open settings dialog and save settings if the dialog is accepted
192 if (impl->m_SettingsDialog->exec() == QDialog::Accepted) {
192 if (impl->m_SettingsDialog->exec() == QDialog::Accepted) {
193 impl->m_SettingsDialog->saveSettings();
193 impl->m_SettingsDialog->saveSettings();
194 }
194 }
195
195
196 });
196 });
197
197
198 auto mainToolBar = this->addToolBar(QStringLiteral("MainToolBar"));
198 auto mainToolBar = this->addToolBar(QStringLiteral("MainToolBar"));
199
199
200 auto timeWidget = new TimeWidget{};
200 auto timeWidget = new TimeWidget{};
201 mainToolBar->addWidget(timeWidget);
201 mainToolBar->addWidget(timeWidget);
202
202
203 // Interaction modes
203 // Interaction modes
204 auto actionPointerMode = new QAction{QIcon(":/icones/pointer.png"), "Move", this};
204 auto actionPointerMode = new QAction{QIcon(":/icones/pointer.png"), "Move", this};
205 actionPointerMode->setCheckable(true);
205 actionPointerMode->setCheckable(true);
206 actionPointerMode->setChecked(sqpApp->plotsInteractionMode()
206 actionPointerMode->setChecked(sqpApp->plotsInteractionMode()
207 == SqpApplication::PlotsInteractionMode::None);
207 == SqpApplication::PlotsInteractionMode::None);
208 connect(actionPointerMode, &QAction::triggered,
208 connect(actionPointerMode, &QAction::triggered,
209 []() { sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::None); });
209 []() { sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::None); });
210
210
211 auto actionZoomMode = new QAction{QIcon(":/icones/zoom.png"), "Zoom", this};
211 auto actionZoomMode = new QAction{QIcon(":/icones/zoom.png"), "Zoom", this};
212 actionZoomMode->setCheckable(true);
212 actionZoomMode->setCheckable(true);
213 actionZoomMode->setChecked(sqpApp->plotsInteractionMode()
213 actionZoomMode->setChecked(sqpApp->plotsInteractionMode()
214 == SqpApplication::PlotsInteractionMode::ZoomBox);
214 == SqpApplication::PlotsInteractionMode::ZoomBox);
215 connect(actionZoomMode, &QAction::triggered, []() {
215 connect(actionZoomMode, &QAction::triggered, []() {
216 sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::ZoomBox);
216 sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::ZoomBox);
217 });
217 });
218
218
219 auto actionOrganisationMode = new QAction{QIcon(":/icones/drag.png"), "Organize", this};
219 auto actionOrganisationMode = new QAction{QIcon(":/icones/drag.png"), "Organize", this};
220 actionOrganisationMode->setCheckable(true);
220 actionOrganisationMode->setCheckable(true);
221 actionOrganisationMode->setChecked(sqpApp->plotsInteractionMode()
221 actionOrganisationMode->setChecked(sqpApp->plotsInteractionMode()
222 == SqpApplication::PlotsInteractionMode::DragAndDrop);
222 == SqpApplication::PlotsInteractionMode::DragAndDrop);
223 connect(actionOrganisationMode, &QAction::triggered, []() {
223 connect(actionOrganisationMode, &QAction::triggered, []() {
224 sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::DragAndDrop);
224 sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::DragAndDrop);
225 });
225 });
226
226
227 auto actionZonesMode = new QAction{QIcon(":/icones/rectangle.png"), "Zones", this};
227 auto actionZonesMode = new QAction{QIcon(":/icones/rectangle.png"), "Zones", this};
228 actionZonesMode->setCheckable(true);
228 actionZonesMode->setCheckable(true);
229 actionZonesMode->setChecked(sqpApp->plotsInteractionMode()
229 actionZonesMode->setChecked(sqpApp->plotsInteractionMode()
230 == SqpApplication::PlotsInteractionMode::SelectionZones);
230 == SqpApplication::PlotsInteractionMode::SelectionZones);
231 connect(actionZonesMode, &QAction::triggered, []() {
231 connect(actionZonesMode, &QAction::triggered, []() {
232 sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::SelectionZones);
232 sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::SelectionZones);
233 });
233 });
234
234
235 auto modeActionGroup = new QActionGroup{this};
235 auto modeActionGroup = new QActionGroup{this};
236 modeActionGroup->addAction(actionZoomMode);
236 modeActionGroup->addAction(actionZoomMode);
237 modeActionGroup->addAction(actionZonesMode);
237 modeActionGroup->addAction(actionZonesMode);
238 modeActionGroup->addAction(actionOrganisationMode);
238 modeActionGroup->addAction(actionOrganisationMode);
239 modeActionGroup->addAction(actionPointerMode);
239 modeActionGroup->addAction(actionPointerMode);
240 modeActionGroup->setExclusive(true);
240 modeActionGroup->setExclusive(true);
241
241
242 mainToolBar->addSeparator();
242 mainToolBar->addSeparator();
243 mainToolBar->addAction(actionPointerMode);
243 mainToolBar->addAction(actionPointerMode);
244 mainToolBar->addAction(actionZoomMode);
244 mainToolBar->addAction(actionZoomMode);
245 mainToolBar->addAction(actionOrganisationMode);
245 mainToolBar->addAction(actionOrganisationMode);
246 mainToolBar->addAction(actionZonesMode);
246 mainToolBar->addAction(actionZonesMode);
247 mainToolBar->addSeparator();
247 mainToolBar->addSeparator();
248
248
249 // Cursors
249 // Cursors
250 auto btnCursor = new QToolButton{this};
250 auto btnCursor = new QToolButton{this};
251 btnCursor->setIcon(QIcon(":/icones/cursor.png"));
251 btnCursor->setIcon(QIcon(":/icones/cursor.png"));
252 btnCursor->setText("Cursor");
252 btnCursor->setText("Cursor");
253 btnCursor->setToolTip("Cursor");
253 btnCursor->setToolTip("Cursor");
254 btnCursor->setPopupMode(QToolButton::InstantPopup);
254 btnCursor->setPopupMode(QToolButton::InstantPopup);
255 auto cursorMenu = new QMenu("CursorMenu", this);
255 auto cursorMenu = new QMenu("CursorMenu", this);
256 btnCursor->setMenu(cursorMenu);
256 btnCursor->setMenu(cursorMenu);
257
257
258 auto noCursorAction = cursorMenu->addAction("No Cursor");
258 auto noCursorAction = cursorMenu->addAction("No Cursor");
259 noCursorAction->setCheckable(true);
259 noCursorAction->setCheckable(true);
260 noCursorAction->setChecked(sqpApp->plotsCursorMode()
260 noCursorAction->setChecked(sqpApp->plotsCursorMode()
261 == SqpApplication::PlotsCursorMode::NoCursor);
261 == SqpApplication::PlotsCursorMode::NoCursor);
262 connect(noCursorAction, &QAction::triggered,
262 connect(noCursorAction, &QAction::triggered,
263 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::NoCursor); });
263 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::NoCursor); });
264
264
265 cursorMenu->addSeparator();
265 cursorMenu->addSeparator();
266 auto verticalCursorAction = cursorMenu->addAction("Vertical Cursor");
266 auto verticalCursorAction = cursorMenu->addAction("Vertical Cursor");
267 verticalCursorAction->setCheckable(true);
267 verticalCursorAction->setCheckable(true);
268 verticalCursorAction->setChecked(sqpApp->plotsCursorMode()
268 verticalCursorAction->setChecked(sqpApp->plotsCursorMode()
269 == SqpApplication::PlotsCursorMode::Vertical);
269 == SqpApplication::PlotsCursorMode::Vertical);
270 connect(verticalCursorAction, &QAction::triggered,
270 connect(verticalCursorAction, &QAction::triggered,
271 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Vertical); });
271 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Vertical); });
272
272
273 auto temporalCursorAction = cursorMenu->addAction("Temporal Cursor");
273 auto temporalCursorAction = cursorMenu->addAction("Temporal Cursor");
274 temporalCursorAction->setCheckable(true);
274 temporalCursorAction->setCheckable(true);
275 temporalCursorAction->setChecked(sqpApp->plotsCursorMode()
275 temporalCursorAction->setChecked(sqpApp->plotsCursorMode()
276 == SqpApplication::PlotsCursorMode::Temporal);
276 == SqpApplication::PlotsCursorMode::Temporal);
277 connect(temporalCursorAction, &QAction::triggered,
277 connect(temporalCursorAction, &QAction::triggered,
278 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Temporal); });
278 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Temporal); });
279
279
280 auto horizontalCursorAction = cursorMenu->addAction("Horizontal Cursor");
280 auto horizontalCursorAction = cursorMenu->addAction("Horizontal Cursor");
281 horizontalCursorAction->setCheckable(true);
281 horizontalCursorAction->setCheckable(true);
282 horizontalCursorAction->setChecked(sqpApp->plotsCursorMode()
282 horizontalCursorAction->setChecked(sqpApp->plotsCursorMode()
283 == SqpApplication::PlotsCursorMode::Horizontal);
283 == SqpApplication::PlotsCursorMode::Horizontal);
284 connect(horizontalCursorAction, &QAction::triggered,
284 connect(horizontalCursorAction, &QAction::triggered,
285 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Horizontal); });
285 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Horizontal); });
286
286
287 auto crossCursorAction = cursorMenu->addAction("Cross Cursor");
287 auto crossCursorAction = cursorMenu->addAction("Cross Cursor");
288 crossCursorAction->setCheckable(true);
288 crossCursorAction->setCheckable(true);
289 crossCursorAction->setChecked(sqpApp->plotsCursorMode()
289 crossCursorAction->setChecked(sqpApp->plotsCursorMode()
290 == SqpApplication::PlotsCursorMode::Cross);
290 == SqpApplication::PlotsCursorMode::Cross);
291 connect(crossCursorAction, &QAction::triggered,
291 connect(crossCursorAction, &QAction::triggered,
292 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Cross); });
292 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Cross); });
293
293
294 mainToolBar->addWidget(btnCursor);
294 mainToolBar->addWidget(btnCursor);
295
295
296 auto cursorModeActionGroup = new QActionGroup{this};
296 auto cursorModeActionGroup = new QActionGroup{this};
297 cursorModeActionGroup->setExclusive(true);
297 cursorModeActionGroup->setExclusive(true);
298 cursorModeActionGroup->addAction(noCursorAction);
298 cursorModeActionGroup->addAction(noCursorAction);
299 cursorModeActionGroup->addAction(verticalCursorAction);
299 cursorModeActionGroup->addAction(verticalCursorAction);
300 cursorModeActionGroup->addAction(temporalCursorAction);
300 cursorModeActionGroup->addAction(temporalCursorAction);
301 cursorModeActionGroup->addAction(horizontalCursorAction);
301 cursorModeActionGroup->addAction(horizontalCursorAction);
302 cursorModeActionGroup->addAction(crossCursorAction);
302 cursorModeActionGroup->addAction(crossCursorAction);
303
303
304 // Catalog
304 // Catalog
305 mainToolBar->addSeparator();
305 mainToolBar->addSeparator();
306 mainToolBar->addAction(QIcon(":/icones/catalogue.png"), "Catalogues",
306 mainToolBar->addAction(QIcon(":/icones/catalogue.png"), "Catalogues",
307 [this]() { impl->m_CatalogExplorer->show(); });
307 [this]() { impl->m_CatalogExplorer->show(); });
308
308
309 // //////// //
309 // //////// //
310 // Settings //
310 // Settings //
311 // //////// //
311 // //////// //
312
312
313 // Registers "general settings" widget to the settings dialog
313 // Registers "general settings" widget to the settings dialog
314 impl->m_SettingsDialog->registerWidget(QStringLiteral("General"),
314 impl->m_SettingsDialog->registerWidget(QStringLiteral("General"),
315 impl->m_GeneralSettingsWidget);
315 impl->m_GeneralSettingsWidget);
316
316
317 // /////////// //
317 // /////////// //
318 // Connections //
318 // Connections //
319 // /////////// //
319 // /////////// //
320
320
321 // Controllers / controllers connections
321 // Controllers / controllers connections
322 connect(&sqpApp->timeController(), SIGNAL(timeUpdated(SqpRange)), &sqpApp->variableController(),
322 connect(&sqpApp->timeController(), SIGNAL(timeUpdated(SqpRange)), &sqpApp->variableController(),
323 SLOT(onDateTimeOnSelection(SqpRange)));
323 SLOT(onDateTimeOnSelection(SqpRange)));
324
324
325 // Widgets / controllers connections
325 // Widgets / controllers connections
326
326
327 // DataSource
327 // DataSource
328 connect(&sqpApp->dataSourceController(), SIGNAL(dataSourceItemSet(DataSourceItem *)),
328 connect(&sqpApp->dataSourceController(), SIGNAL(dataSourceItemSet(DataSourceItem *)),
329 m_Ui->dataSourceWidget, SLOT(addDataSource(DataSourceItem *)));
329 m_Ui->dataSourceWidget, SLOT(addDataSource(DataSourceItem *)));
330
330
331 // Time
331 // Time
332 connect(timeWidget, SIGNAL(timeUpdated(SqpRange)), &sqpApp->timeController(),
332 connect(timeWidget, SIGNAL(timeUpdated(SqpRange)), &sqpApp->timeController(),
333 SLOT(onTimeToUpdate(SqpRange)));
333 SLOT(onTimeToUpdate(SqpRange)));
334
334
335 // Visualization
335 // Visualization
336 connect(&sqpApp->visualizationController(),
336 connect(&sqpApp->visualizationController(),
337 SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)), m_Ui->view,
337 SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)), m_Ui->view,
338 SLOT(onVariableAboutToBeDeleted(std::shared_ptr<Variable>)));
338 SLOT(onVariableAboutToBeDeleted(std::shared_ptr<Variable>)));
339
339
340 connect(&sqpApp->visualizationController(),
340 connect(&sqpApp->visualizationController(),
341 SIGNAL(rangeChanged(std::shared_ptr<Variable>, const SqpRange &)), m_Ui->view,
341 SIGNAL(rangeChanged(std::shared_ptr<Variable>, const SqpRange &)), m_Ui->view,
342 SLOT(onRangeChanged(std::shared_ptr<Variable>, const SqpRange &)));
342 SLOT(onRangeChanged(std::shared_ptr<Variable>, const SqpRange &)));
343
343
344 // Widgets / widgets connections
344 // Widgets / widgets connections
345
345
346 // For the following connections, we use DirectConnection to allow each widget that can
346 // For the following connections, we use DirectConnection to allow each widget that can
347 // potentially attach a menu to the variable's menu to do so before this menu is displayed.
347 // potentially attach a menu to the variable's menu to do so before this menu is displayed.
348 // The order of connections is also important, since it determines the order in which each
348 // The order of connections is also important, since it determines the order in which each
349 // widget will attach its menu
349 // widget will attach its menu
350 connect(
350 connect(
351 m_Ui->variableInspectorWidget,
351 m_Ui->variableInspectorWidget,
352 SIGNAL(tableMenuAboutToBeDisplayed(QMenu *, const QVector<std::shared_ptr<Variable> > &)),
352 SIGNAL(tableMenuAboutToBeDisplayed(QMenu *, const QVector<std::shared_ptr<Variable> > &)),
353 m_Ui->view, SLOT(attachVariableMenu(QMenu *, const QVector<std::shared_ptr<Variable> > &)),
353 m_Ui->view, SLOT(attachVariableMenu(QMenu *, const QVector<std::shared_ptr<Variable> > &)),
354 Qt::DirectConnection);
354 Qt::DirectConnection);
355 }
355 }
356
356
357 MainWindow::~MainWindow()
357 MainWindow::~MainWindow()
358 {
358 {
359 }
359 }
360
360
361 void MainWindow::changeEvent(QEvent *e)
361 void MainWindow::changeEvent(QEvent *e)
362 {
362 {
363 QMainWindow::changeEvent(e);
363 QMainWindow::changeEvent(e);
364 switch (e->type()) {
364 switch (e->type()) {
365 case QEvent::LanguageChange:
365 case QEvent::LanguageChange:
366 m_Ui->retranslateUi(this);
366 m_Ui->retranslateUi(this);
367 break;
367 break;
368 default:
368 default:
369 break;
369 break;
370 }
370 }
371 }
371 }
372
372
373 void MainWindow::closeEvent(QCloseEvent *event)
373 void MainWindow::closeEvent(QCloseEvent *event)
374 {
374 {
375 if (!impl->checkDataToSave(this)) {
375 if (!impl->checkDataToSave(this)) {
376 event->ignore();
376 event->ignore();
377 }
377 }
378 else {
378 else {
379 event->accept();
379 event->accept();
380 }
380 }
381 }
381 }
382
382
383 bool MainWindow::MainWindowPrivate::checkDataToSave(QWidget *parentWidget)
383 bool MainWindow::MainWindowPrivate::checkDataToSave(QWidget *parentWidget)
384 {
384 {
385 auto hasChanges = sqpApp->catalogueController().hasChanges();
385 auto hasChanges = sqpApp->catalogueController().hasChanges();
386 if (hasChanges) {
386 if (hasChanges) {
387 // There are some unsaved changes
387 // There are some unsaved changes
388 switch (QMessageBox::question(
388 switch (QMessageBox::question(
389 parentWidget, "Save changes",
389 parentWidget, tr("Save changes"),
390 tr("The catalogue controller unsaved changes.\nDo you want to save them ?"),
390 tr("The catalogue controller has unsaved changes.\nDo you want to save them ?"),
391 QMessageBox::SaveAll | QMessageBox::Discard | QMessageBox::Cancel,
391 QMessageBox::SaveAll | QMessageBox::Discard | QMessageBox::Cancel,
392 QMessageBox::SaveAll)) {
392 QMessageBox::SaveAll)) {
393 case QMessageBox::SaveAll:
393 case QMessageBox::SaveAll:
394 sqpApp->catalogueController().saveAll();
394 sqpApp->catalogueController().saveAll();
395 break;
395 break;
396 case QMessageBox::Discard:
396 case QMessageBox::Discard:
397 break;
397 break;
398 case QMessageBox::Cancel:
398 case QMessageBox::Cancel:
399 default:
399 default:
400 return false;
400 return false;
401 }
401 }
402 }
402 }
403
403
404 return true;
404 return true;
405 }
405 }
@@ -1,102 +1,106
1 #ifndef SCIQLOP_DATASOURCECONTROLLER_H
1 #ifndef SCIQLOP_DATASOURCECONTROLLER_H
2 #define SCIQLOP_DATASOURCECONTROLLER_H
2 #define SCIQLOP_DATASOURCECONTROLLER_H
3
3
4 #include "CoreGlobal.h"
4 #include "CoreGlobal.h"
5
5
6 #include <QLoggingCategory>
6 #include <QLoggingCategory>
7 #include <QObject>
7 #include <QObject>
8 #include <QUuid>
8 #include <QUuid>
9
9
10 #include <Common/spimpl.h>
10 #include <Common/spimpl.h>
11
11
12 Q_DECLARE_LOGGING_CATEGORY(LOG_DataSourceController)
12 Q_DECLARE_LOGGING_CATEGORY(LOG_DataSourceController)
13
13
14 class DataSourceItem;
14 class DataSourceItem;
15 class IDataProvider;
15 class IDataProvider;
16
16
17 /**
17 /**
18 * @brief The DataSourceController class aims to make the link between SciQlop and its plugins. This
18 * @brief The DataSourceController class aims to make the link between SciQlop and its plugins. This
19 * is the intermediate class that SciQlop has to use in the way to connect a data source. Please
19 * is the intermediate class that SciQlop has to use in the way to connect a data source. Please
20 * first use register method to initialize a plugin specified by its metadata name (JSON plugin
20 * first use register method to initialize a plugin specified by its metadata name (JSON plugin
21 * source) then others specifics method will be able to access it. You can load a data source driver
21 * source) then others specifics method will be able to access it. You can load a data source driver
22 * plugin then create a data source.
22 * plugin then create a data source.
23 */
23 */
24 class SCIQLOP_CORE_EXPORT DataSourceController : public QObject {
24 class SCIQLOP_CORE_EXPORT DataSourceController : public QObject {
25 Q_OBJECT
25 Q_OBJECT
26 public:
26 public:
27 explicit DataSourceController(QObject *parent = 0);
27 explicit DataSourceController(QObject *parent = 0);
28 virtual ~DataSourceController();
28 virtual ~DataSourceController();
29
29
30 /**
30 /**
31 * Registers a data source. The method delivers a unique id that can be used afterwards to
31 * Registers a data source. The method delivers a unique id that can be used afterwards to
32 * access to the data source properties (structure, connection parameters, data provider, etc.)
32 * access to the data source properties (structure, connection parameters, data provider, etc.)
33 * @param dataSourceName the name of the data source
33 * @param dataSourceName the name of the data source
34 * @return the unique id with which the data source has been registered
34 * @return the unique id with which the data source has been registered
35 */
35 */
36 QUuid registerDataSource(const QString &dataSourceName) noexcept;
36 QUuid registerDataSource(const QString &dataSourceName) noexcept;
37
37
38 /**
38 /**
39 * Sets the structure of a data source. The controller takes ownership of the structure.
39 * Sets the structure of a data source. The controller takes ownership of the structure.
40 * @param dataSourceUid the unique id with which the data source has been registered into the
40 * @param dataSourceUid the unique id with which the data source has been registered into the
41 * controller. If it is invalid, the method has no effect.
41 * controller. If it is invalid, the method has no effect.
42 * @param dataSourceItem the structure of the data source. It must be not null to be registered
42 * @param dataSourceItem the structure of the data source. It must be not null to be registered
43 * @sa registerDataSource()
43 * @sa registerDataSource()
44 */
44 */
45 void setDataSourceItem(const QUuid &dataSourceUid,
45 void setDataSourceItem(const QUuid &dataSourceUid,
46 std::unique_ptr<DataSourceItem> dataSourceItem) noexcept;
46 std::unique_ptr<DataSourceItem> dataSourceItem) noexcept;
47
47
48 /**
48 /**
49 * Sets the data provider used to retrieve data from of a data source. The controller takes
49 * Sets the data provider used to retrieve data from of a data source. The controller takes
50 * ownership of the provider.
50 * ownership of the provider.
51 * @param dataSourceUid the unique id with which the data source has been registered into the
51 * @param dataSourceUid the unique id with which the data source has been registered into the
52 * controller. If it is invalid, the method has no effect.
52 * controller. If it is invalid, the method has no effect.
53 * @param dataProvider the provider of the data source
53 * @param dataProvider the provider of the data source
54 * @sa registerDataSource()
54 * @sa registerDataSource()
55 */
55 */
56 void setDataProvider(const QUuid &dataSourceUid,
56 void setDataProvider(const QUuid &dataSourceUid,
57 std::unique_ptr<IDataProvider> dataProvider) noexcept;
57 std::unique_ptr<IDataProvider> dataProvider) noexcept;
58
58
59 /**
59 /**
60 * Loads an item (product) as a variable in SciQlop
60 * Loads an item (product) as a variable in SciQlop
61 * @param dataSourceUid the unique id of the data source containing the item. It is used to get
61 * @param dataSourceUid the unique id of the data source containing the item. It is used to get
62 * the data provider associated to the data source, and pass it to for the variable creation
62 * the data provider associated to the data source, and pass it to for the variable creation
63 * @param productItem the item to load
63 * @param productItem the item to load
64 */
64 */
65 void loadProductItem(const QUuid &dataSourceUid, const DataSourceItem &productItem) noexcept;
65 void loadProductItem(const QUuid &dataSourceUid, const DataSourceItem &productItem) noexcept;
66
66
67 /// Returns the MIME data associated to a list of product meta data
67 /// Returns the MIME data associated to a list of product meta data
68 static QByteArray mimeDataForProductsData(const QVariantList &productsData);
68 static QByteArray mimeDataForProductsData(const QVariantList &productsData);
69
69
70 /// Returns the list of meta data contained in a MIME data
70 /// Returns the list of meta data contained in a MIME data
71 static QVariantList productsDataForMimeData(const QByteArray &mimeData);
71 static QVariantList productsDataForMimeData(const QByteArray &mimeData);
72
72
73 public slots:
73 public slots:
74 /// Manage init/end of the controller
74 /// Manage init/end of the controller
75 void initialize();
75 void initialize();
76 void finalize();
76 void finalize();
77
77
78 /// Request the creation of a variable from the ID_DATA_KEY of a product
79 void requestVariableFromProductIdKey(const QString &datasourceIdKey);
80
81 /// Request the creation of a variable from metadata of a product
78 void requestVariable(const QVariantHash &productData);
82 void requestVariable(const QVariantHash &productData);
79
83
80 signals:
84 signals:
81 /// Signal emitted when a structure has been set for a data source
85 /// Signal emitted when a structure has been set for a data source
82 void dataSourceItemSet(DataSourceItem *dataSourceItem);
86 void dataSourceItemSet(DataSourceItem *dataSourceItem);
83
87
84 /**
88 /**
85 * Signal emitted when a variable creation is asked for a product
89 * Signal emitted when a variable creation is asked for a product
86 * @param variableName the name of the variable
90 * @param variableName the name of the variable
87 * @param variableMetadata the metadata of the variable
91 * @param variableMetadata the metadata of the variable
88 * @param variableProvider the provider that will be used to retrieve the data of the variable
92 * @param variableProvider the provider that will be used to retrieve the data of the variable
89 * (can be null)
93 * (can be null)
90 */
94 */
91 void variableCreationRequested(const QString &variableName,
95 void variableCreationRequested(const QString &variableName,
92 const QVariantHash &variableMetadata,
96 const QVariantHash &variableMetadata,
93 std::shared_ptr<IDataProvider> variableProvider);
97 std::shared_ptr<IDataProvider> variableProvider);
94
98
95 private:
99 private:
96 void waitForFinish();
100 void waitForFinish();
97
101
98 class DataSourceControllerPrivate;
102 class DataSourceControllerPrivate;
99 spimpl::unique_impl_ptr<DataSourceControllerPrivate> impl;
103 spimpl::unique_impl_ptr<DataSourceControllerPrivate> impl;
100 };
104 };
101
105
102 #endif // SCIQLOP_DATASOURCECONTROLLER_H
106 #endif // SCIQLOP_DATASOURCECONTROLLER_H
@@ -1,156 +1,164
1 #ifndef SCIQLOP_DATASOURCEITEM_H
1 #ifndef SCIQLOP_DATASOURCEITEM_H
2 #define SCIQLOP_DATASOURCEITEM_H
2 #define SCIQLOP_DATASOURCEITEM_H
3
3
4 #include "CoreGlobal.h"
4 #include "CoreGlobal.h"
5
5
6 #include <Common/spimpl.h>
6 #include <Common/spimpl.h>
7
7
8 #include <QVariant>
8 #include <QVariant>
9 #include <QVector>
9 #include <QVector>
10
10
11 class DataSourceItemAction;
11 class DataSourceItemAction;
12
12
13 /**
13 /**
14 * Possible types of an item
14 * Possible types of an item
15 */
15 */
16 enum class DataSourceItemType { NODE, PRODUCT, COMPONENT };
16 enum class DataSourceItemType { NODE, PRODUCT, COMPONENT };
17
17
18 /**
18 /**
19 * @brief The DataSourceItem class aims to represent a structure element of a data source.
19 * @brief The DataSourceItem class aims to represent a structure element of a data source.
20 * A data source has a tree structure that is made up of a main DataSourceItem object (root)
20 * A data source has a tree structure that is made up of a main DataSourceItem object (root)
21 * containing other DataSourceItem objects (children).
21 * containing other DataSourceItem objects (children).
22 * For each DataSourceItem can be associated a set of data representing it.
22 * For each DataSourceItem can be associated a set of data representing it.
23 */
23 */
24 class SCIQLOP_CORE_EXPORT DataSourceItem {
24 class SCIQLOP_CORE_EXPORT DataSourceItem {
25 public:
25 public:
26 /// Key associated with the name of the item
26 /// Key associated with the name of the item
27 static const QString NAME_DATA_KEY;
27 static const QString NAME_DATA_KEY;
28 /// Key associated with the plugin of the item
28 /// Key associated with the plugin of the item
29 static const QString PLUGIN_DATA_KEY;
29 static const QString PLUGIN_DATA_KEY;
30 /// Key associated with a unique id of the plugin
30 /// Key associated with a unique id of the plugin
31 static const QString ID_DATA_KEY;
31 static const QString ID_DATA_KEY;
32
32
33 explicit DataSourceItem(DataSourceItemType type, const QString &name);
33 explicit DataSourceItem(DataSourceItemType type, const QString &name);
34 explicit DataSourceItem(DataSourceItemType type, QVariantHash data = {});
34 explicit DataSourceItem(DataSourceItemType type, QVariantHash data = {});
35
35
36 std::unique_ptr<DataSourceItem> clone() const;
36 std::unique_ptr<DataSourceItem> clone() const;
37
37
38 /// @return the actions of the item as a vector
38 /// @return the actions of the item as a vector
39 QVector<DataSourceItemAction *> actions() const noexcept;
39 QVector<DataSourceItemAction *> actions() const noexcept;
40
40
41 /**
41 /**
42 * Adds an action to the item. The item takes ownership of the action, and the action is
42 * Adds an action to the item. The item takes ownership of the action, and the action is
43 * automatically associated to the item
43 * automatically associated to the item
44 * @param action the action to add
44 * @param action the action to add
45 */
45 */
46 void addAction(std::unique_ptr<DataSourceItemAction> action) noexcept;
46 void addAction(std::unique_ptr<DataSourceItemAction> action) noexcept;
47
47
48 /**
48 /**
49 * Adds a child to the item. The item takes ownership of the child.
49 * Adds a child to the item. The item takes ownership of the child.
50 * @param child the child to add
50 * @param child the child to add
51 */
51 */
52 void appendChild(std::unique_ptr<DataSourceItem> child) noexcept;
52 void appendChild(std::unique_ptr<DataSourceItem> child) noexcept;
53
53
54 /**
54 /**
55 * Returns the item's child associated to an index
55 * Returns the item's child associated to an index
56 * @param childIndex the index to search
56 * @param childIndex the index to search
57 * @return a pointer to the child if index is valid, nullptr otherwise
57 * @return a pointer to the child if index is valid, nullptr otherwise
58 */
58 */
59 DataSourceItem *child(int childIndex) const noexcept;
59 DataSourceItem *child(int childIndex) const noexcept;
60
60
61 int childCount() const noexcept;
61 int childCount() const noexcept;
62
62
63 /**
63 /**
64 * Get the data associated to a key
64 * Get the data associated to a key
65 * @param key the key to search
65 * @param key the key to search
66 * @return the data found if key is valid, default QVariant otherwise
66 * @return the data found if key is valid, default QVariant otherwise
67 */
67 */
68 QVariant data(const QString &key) const noexcept;
68 QVariant data(const QString &key) const noexcept;
69
69
70 /// Gets all data
70 /// Gets all data
71 QVariantHash data() const noexcept;
71 QVariantHash data() const noexcept;
72
72
73 /**
73 /**
74 * Merge in the item the source item passed as parameter.
74 * Merge in the item the source item passed as parameter.
75 *
75 *
76 * The merge is done by adding as child of the item the complete tree represented by the source
76 * The merge is done by adding as child of the item the complete tree represented by the source
77 * item. If a part of the tree already exists in the item (based on the name of the nodes), it
77 * item. If a part of the tree already exists in the item (based on the name of the nodes), it
78 * is merged by completing the existing tree by items "leaves" (products, components or nodes
78 * is merged by completing the existing tree by items "leaves" (products, components or nodes
79 * with no child).
79 * with no child).
80 *
80 *
81 * For example, with item representing the tree:
81 * For example, with item representing the tree:
82 * R (root node)
82 * R (root node)
83 * - N1 (node)
83 * - N1 (node)
84 * -- N11 (node)
84 * -- N11 (node)
85 * --- P1 (product)
85 * --- P1 (product)
86 * --- P2 (product)
86 * --- P2 (product)
87 * - N2 (node)
87 * - N2 (node)
88 *
88 *
89 * and the source item representing the tree:
89 * and the source item representing the tree:
90 * N1 (root node)
90 * N1 (root node)
91 * - N11 (node)
91 * - N11 (node)
92 * -- P3 (product)
92 * -- P3 (product)
93 * - N12 (node)
93 * - N12 (node)
94 *
94 *
95 * The leaves of the source item to merge into the item are N1/N11/P3 and N1/N12 => we therefore
95 * The leaves of the source item to merge into the item are N1/N11/P3 and N1/N12 => we therefore
96 * have the following merge result:
96 * have the following merge result:
97 * R
97 * R
98 * - N1
98 * - N1
99 * -- N11
99 * -- N11
100 * --- P1
100 * --- P1
101 * --- P2
101 * --- P2
102 * --- P3 (added leaf)
102 * --- P3 (added leaf)
103 * -- N12 (added leaf)
103 * -- N12 (added leaf)
104 *
104 *
105 * @param item the source item
105 * @param item the source item
106 * @remarks No control is performed on products or components that are merged into the same tree
106 * @remarks No control is performed on products or components that are merged into the same tree
107 * part (two products or components may have the same name)
107 * part (two products or components may have the same name)
108 * @remarks the merge is made by copy (source item is not changed and still exists after the
108 * @remarks the merge is made by copy (source item is not changed and still exists after the
109 * operation)
109 * operation)
110 */
110 */
111 void merge(const DataSourceItem &item);
111 void merge(const DataSourceItem &item);
112
112
113 bool isRoot() const noexcept;
113 bool isRoot() const noexcept;
114
114
115 QString name() const noexcept;
115 QString name() const noexcept;
116
116
117 /**
117 /**
118 * Get the item's parent
118 * Get the item's parent
119 * @return a pointer to the parent if it exists, nullptr if the item is a root
119 * @return a pointer to the parent if it exists, nullptr if the item is a root
120 */
120 */
121 DataSourceItem *parentItem() const noexcept;
121 DataSourceItem *parentItem() const noexcept;
122
122
123 /**
123 /**
124 * Gets the item's root
124 * Gets the item's root
125 * @return the top parent, the item itself if it's the root item
125 * @return the top parent, the item itself if it's the root item
126 */
126 */
127 const DataSourceItem &rootItem() const noexcept;
127 const DataSourceItem &rootItem() const noexcept;
128
128
129 /**
129 /**
130 * Sets or appends a value to a key
130 * Sets or appends a value to a key
131 * @param key the key
131 * @param key the key
132 * @param value the value
132 * @param value the value
133 * @param append if true, the value is added to the values already existing for the key,
133 * @param append if true, the value is added to the values already existing for the key,
134 * otherwise it replaces the existing values
134 * otherwise it replaces the existing values
135 */
135 */
136 void setData(const QString &key, const QVariant &value, bool append = false) noexcept;
136 void setData(const QString &key, const QVariant &value, bool append = false) noexcept;
137
137
138 DataSourceItemType type() const noexcept;
138 DataSourceItemType type() const noexcept;
139
139
140 /**
140 /**
141 * @brief Searches the first child matching the specified data.
141 * @brief Searches the first child matching the specified data.
142 * @param data The data to search.
142 * @param data The data to search.
143 * @param recursive So the search recursively.
143 * @param recursive So the search recursively.
144 * @return the item matching the data or nullptr if it was not found.
144 * @return the item matching the data or nullptr if it was not found.
145 */
145 */
146 DataSourceItem *findItem(const QVariantHash &data, bool recursive);
146 DataSourceItem *findItem(const QVariantHash &data, bool recursive);
147
147
148 /**
149 * @brief Searches the first child matching the specified \p ID_DATA_KEY in its metadata.
150 * @param id The id to search.
151 * @param recursive So the search recursively.
152 * @return the item matching the data or nullptr if it was not found.
153 */
154 DataSourceItem *findItem(const QString &datasourceIdKey, bool recursive);
155
148 bool operator==(const DataSourceItem &other);
156 bool operator==(const DataSourceItem &other);
149 bool operator!=(const DataSourceItem &other);
157 bool operator!=(const DataSourceItem &other);
150
158
151 private:
159 private:
152 class DataSourceItemPrivate;
160 class DataSourceItemPrivate;
153 spimpl::unique_impl_ptr<DataSourceItemPrivate> impl;
161 spimpl::unique_impl_ptr<DataSourceItemPrivate> impl;
154 };
162 };
155
163
156 #endif // SCIQLOP_DATASOURCEITEMMODEL_H
164 #endif // SCIQLOP_DATASOURCEITEMMODEL_H
@@ -1,89 +1,95
1 #ifndef SCIQLOP_VARIABLE_H
1 #ifndef SCIQLOP_VARIABLE_H
2 #define SCIQLOP_VARIABLE_H
2 #define SCIQLOP_VARIABLE_H
3
3
4 #include "CoreGlobal.h"
4 #include "CoreGlobal.h"
5
5
6 #include <Data/DataSeriesIterator.h>
6 #include <Data/DataSeriesIterator.h>
7 #include <Data/DataSeriesType.h>
7 #include <Data/SqpRange.h>
8 #include <Data/SqpRange.h>
8
9
9 #include <QLoggingCategory>
10 #include <QLoggingCategory>
10 #include <QObject>
11 #include <QObject>
11
12
12 #include <Common/MetaTypes.h>
13 #include <Common/MetaTypes.h>
13 #include <Common/spimpl.h>
14 #include <Common/spimpl.h>
14
15
15 Q_DECLARE_LOGGING_CATEGORY(LOG_Variable)
16 Q_DECLARE_LOGGING_CATEGORY(LOG_Variable)
16
17
17 class IDataSeries;
18 class IDataSeries;
18 class QString;
19 class QString;
19
20
20 /**
21 /**
21 * @brief The Variable class represents a variable in SciQlop.
22 * @brief The Variable class represents a variable in SciQlop.
22 */
23 */
23 class SCIQLOP_CORE_EXPORT Variable : public QObject {
24 class SCIQLOP_CORE_EXPORT Variable : public QObject {
24
25
25 Q_OBJECT
26 Q_OBJECT
26
27
27 public:
28 public:
28 explicit Variable(const QString &name, const QVariantHash &metadata = {});
29 explicit Variable(const QString &name, const QVariantHash &metadata = {});
29
30
30 /// Copy ctor
31 /// Copy ctor
31 explicit Variable(const Variable &other);
32 explicit Variable(const Variable &other);
32
33
33 std::shared_ptr<Variable> clone() const;
34 std::shared_ptr<Variable> clone() const;
34
35
35 QString name() const noexcept;
36 QString name() const noexcept;
36 void setName(const QString &name) noexcept;
37 void setName(const QString &name) noexcept;
37 SqpRange range() const noexcept;
38 SqpRange range() const noexcept;
38 void setRange(const SqpRange &range) noexcept;
39 void setRange(const SqpRange &range) noexcept;
39 SqpRange cacheRange() const noexcept;
40 SqpRange cacheRange() const noexcept;
40 void setCacheRange(const SqpRange &cacheRange) noexcept;
41 void setCacheRange(const SqpRange &cacheRange) noexcept;
41
42
42 /// @return the number of points hold by the variable. The number of points is updated each time
43 /// @return the number of points hold by the variable. The number of points is updated each time
43 /// the data series changes
44 /// the data series changes
44 int nbPoints() const noexcept;
45 int nbPoints() const noexcept;
45
46
46 /// Returns the real range of the variable, i.e. the min and max x-axis values of the data
47 /// Returns the real range of the variable, i.e. the min and max x-axis values of the data
47 /// series between the range of the variable. The real range is updated each time the variable
48 /// series between the range of the variable. The real range is updated each time the variable
48 /// range or the data series changed
49 /// range or the data series changed
49 /// @return the real range, invalid range if the data series is null or empty
50 /// @return the real range, invalid range if the data series is null or empty
50 /// @sa setDataSeries()
51 /// @sa setDataSeries()
51 /// @sa setRange()
52 /// @sa setRange()
52 SqpRange realRange() const noexcept;
53 SqpRange realRange() const noexcept;
53
54
54 /// @return the data of the variable, nullptr if there is no data
55 /// @return the data of the variable, nullptr if there is no data
55 std::shared_ptr<IDataSeries> dataSeries() const noexcept;
56 std::shared_ptr<IDataSeries> dataSeries() const noexcept;
56
57
58 /// @return the type of data that the variable holds
59 DataSeriesType type() const noexcept;
60
57 QVariantHash metadata() const noexcept;
61 QVariantHash metadata() const noexcept;
58
62
59 bool contains(const SqpRange &range) const noexcept;
63 bool contains(const SqpRange &range) const noexcept;
60 bool intersect(const SqpRange &range) const noexcept;
64 bool intersect(const SqpRange &range) const noexcept;
61 bool isInside(const SqpRange &range) const noexcept;
65 bool isInside(const SqpRange &range) const noexcept;
62
66
63 bool cacheContains(const SqpRange &range) const noexcept;
67 bool cacheContains(const SqpRange &range) const noexcept;
64 bool cacheIntersect(const SqpRange &range) const noexcept;
68 bool cacheIntersect(const SqpRange &range) const noexcept;
65 bool cacheIsInside(const SqpRange &range) const noexcept;
69 bool cacheIsInside(const SqpRange &range) const noexcept;
66
70
67 QVector<SqpRange> provideNotInCacheRangeList(const SqpRange &range) const noexcept;
71 QVector<SqpRange> provideNotInCacheRangeList(const SqpRange &range) const noexcept;
68 QVector<SqpRange> provideInCacheRangeList(const SqpRange &range) const noexcept;
72 QVector<SqpRange> provideInCacheRangeList(const SqpRange &range) const noexcept;
69 void mergeDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept;
73 void mergeDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept;
70
74
71 static QVector<SqpRange> provideNotInCacheRangeList(const SqpRange &oldRange,
75 static QVector<SqpRange> provideNotInCacheRangeList(const SqpRange &oldRange,
72 const SqpRange &nextRange);
76 const SqpRange &nextRange);
73
77
74 static QVector<SqpRange> provideInCacheRangeList(const SqpRange &oldRange,
78 static QVector<SqpRange> provideInCacheRangeList(const SqpRange &oldRange,
75 const SqpRange &nextRange);
79 const SqpRange &nextRange);
76
80
77 signals:
81 signals:
78 void updated();
82 void updated();
83 /// Signal emitted when when the data series of the variable is loaded for the first time
84 void dataInitialized();
79
85
80 private:
86 private:
81 class VariablePrivate;
87 class VariablePrivate;
82 spimpl::unique_impl_ptr<VariablePrivate> impl;
88 spimpl::unique_impl_ptr<VariablePrivate> impl;
83 };
89 };
84
90
85 // Required for using shared_ptr in signals/slots
91 // Required for using shared_ptr in signals/slots
86 SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_REGISTRY, std::shared_ptr<Variable>)
92 SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_REGISTRY, std::shared_ptr<Variable>)
87 SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_VECTOR_REGISTRY, QVector<std::shared_ptr<Variable> >)
93 SCIQLOP_REGISTER_META_TYPE(VARIABLE_PTR_VECTOR_REGISTRY, QVector<std::shared_ptr<Variable> >)
88
94
89 #endif // SCIQLOP_VARIABLE_H
95 #endif // SCIQLOP_VARIABLE_H
@@ -1,142 +1,144
1 #ifndef SCIQLOP_VARIABLECONTROLLER_H
1 #ifndef SCIQLOP_VARIABLECONTROLLER_H
2 #define SCIQLOP_VARIABLECONTROLLER_H
2 #define SCIQLOP_VARIABLECONTROLLER_H
3
3
4 #include "CoreGlobal.h"
4 #include "CoreGlobal.h"
5
5
6 #include <Data/AcquisitionDataPacket.h>
6 #include <Data/AcquisitionDataPacket.h>
7 #include <Data/SqpRange.h>
7 #include <Data/SqpRange.h>
8
8
9 #include <QLoggingCategory>
9 #include <QLoggingCategory>
10 #include <QObject>
10 #include <QObject>
11 #include <QUuid>
11 #include <QUuid>
12
12
13 #include <Common/spimpl.h>
13 #include <Common/spimpl.h>
14
14
15 class IDataProvider;
15 class IDataProvider;
16 class QItemSelectionModel;
16 class QItemSelectionModel;
17 class TimeController;
17 class TimeController;
18 class Variable;
18 class Variable;
19 class VariableModel;
19 class VariableModel;
20
20
21 Q_DECLARE_LOGGING_CATEGORY(LOG_VariableController)
21 Q_DECLARE_LOGGING_CATEGORY(LOG_VariableController)
22
22
23
23
24 /**
24 /**
25 * Possible types of zoom operation
25 * Possible types of zoom operation
26 */
26 */
27 enum class AcquisitionZoomType { ZoomOut, ZoomIn, PanRight, PanLeft, Unknown };
27 enum class AcquisitionZoomType { ZoomOut, ZoomIn, PanRight, PanLeft, Unknown };
28
28
29
29
30 /**
30 /**
31 * @brief The VariableController class aims to handle the variables in SciQlop.
31 * @brief The VariableController class aims to handle the variables in SciQlop.
32 */
32 */
33 class SCIQLOP_CORE_EXPORT VariableController : public QObject {
33 class SCIQLOP_CORE_EXPORT VariableController : public QObject {
34 Q_OBJECT
34 Q_OBJECT
35 public:
35 public:
36 explicit VariableController(QObject *parent = 0);
36 explicit VariableController(QObject *parent = 0);
37 virtual ~VariableController();
37 virtual ~VariableController();
38
38
39 VariableModel *variableModel() noexcept;
39 VariableModel *variableModel() noexcept;
40 QItemSelectionModel *variableSelectionModel() noexcept;
40 QItemSelectionModel *variableSelectionModel() noexcept;
41
41
42 void setTimeController(TimeController *timeController) noexcept;
42 void setTimeController(TimeController *timeController) noexcept;
43
43
44 /**
44 /**
45 * Clones the variable passed in parameter and adds the duplicate to the controller
45 * Clones the variable passed in parameter and adds the duplicate to the controller
46 * @param variable the variable to duplicate
46 * @param variable the variable to duplicate
47 * @return the duplicate created, nullptr if the variable couldn't be created
47 * @return the duplicate created, nullptr if the variable couldn't be created
48 */
48 */
49 std::shared_ptr<Variable> cloneVariable(std::shared_ptr<Variable> variable) noexcept;
49 std::shared_ptr<Variable> cloneVariable(std::shared_ptr<Variable> variable) noexcept;
50
50
51 /**
52 * Deletes from the controller the variable passed in parameter.
53 *
54 * Delete a variable includes:
55 * - the deletion of the various references to the variable in SciQlop
56 * - the deletion of the model variable
57 * - the deletion of the provider associated with the variable
58 * - removing the cache associated with the variable
59 *
60 * @param variable the variable to delete from the controller.
61 */
62 void deleteVariable(std::shared_ptr<Variable> variable) noexcept;
63
64 /**
65 * Deletes from the controller the variables passed in parameter.
66 * @param variables the variables to delete from the controller.
67 * @sa deleteVariable()
68 */
69 void deleteVariables(const QVector<std::shared_ptr<Variable> > &variables) noexcept;
70
71 /// Returns the MIME data associated to a list of variables
51 /// Returns the MIME data associated to a list of variables
72 QByteArray mimeDataForVariables(const QList<std::shared_ptr<Variable> > &variables) const;
52 QByteArray mimeDataForVariables(const QList<std::shared_ptr<Variable> > &variables) const;
73
53
74 /// Returns the list of variables contained in a MIME data
54 /// Returns the list of variables contained in a MIME data
75 QList<std::shared_ptr<Variable> > variablesForMimeData(const QByteArray &mimeData) const;
55 QList<std::shared_ptr<Variable> > variablesForMimeData(const QByteArray &mimeData) const;
76
56
77 static AcquisitionZoomType getZoomType(const SqpRange &range, const SqpRange &oldRange);
57 static AcquisitionZoomType getZoomType(const SqpRange &range, const SqpRange &oldRange);
78 signals:
58 signals:
79 /// Signal emitted when a variable is about to be deleted from the controller
59 /// Signal emitted when a variable is about to be deleted from the controller
80 void variableAboutToBeDeleted(std::shared_ptr<Variable> variable);
60 void variableAboutToBeDeleted(std::shared_ptr<Variable> variable);
81
61
82 /// Signal emitted when a data acquisition is requested on a range for a variable
62 /// Signal emitted when a data acquisition is requested on a range for a variable
83 void rangeChanged(std::shared_ptr<Variable> variable, const SqpRange &range);
63 void rangeChanged(std::shared_ptr<Variable> variable, const SqpRange &range);
84
64
85 /// Signal emitted when a sub range of the cacheRange of the variable can be displayed
65 /// Signal emitted when a sub range of the cacheRange of the variable can be displayed
86 void updateVarDisplaying(std::shared_ptr<Variable> variable, const SqpRange &range);
66 void updateVarDisplaying(std::shared_ptr<Variable> variable, const SqpRange &range);
87
67
88 /// Signal emitted when all acquisitions related to the variables have been completed (whether
68 /// Signal emitted when all acquisitions related to the variables have been completed (whether
89 /// validated, canceled, or failed)
69 /// validated, canceled, or failed)
90 void acquisitionFinished();
70 void acquisitionFinished();
91
71
72 void variableAdded(const std::shared_ptr<Variable> &variable);
73
92 public slots:
74 public slots:
75 /**
76 * Deletes from the controller the variable passed in parameter.
77 *
78 * Delete a variable includes:
79 * - the deletion of the various references to the variable in SciQlop
80 * - the deletion of the model variable
81 * - the deletion of the provider associated with the variable
82 * - removing the cache associated with the variable
83 *
84 * @param variable the variable to delete from the controller.
85 */
86 void deleteVariable(std::shared_ptr<Variable> variable) noexcept;
87
88 /**
89 * Deletes from the controller the variables passed in parameter.
90 * @param variables the variables to delete from the controller.
91 * @sa deleteVariable()
92 */
93 void deleteVariables(const QVector<std::shared_ptr<Variable> > &variables) noexcept;
94
93 /// Request the data loading of the variable whithin range
95 /// Request the data loading of the variable whithin range
94 void onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables, const SqpRange &range,
96 void onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables, const SqpRange &range,
95 bool synchronise);
97 bool synchronise);
96 /**
98 /**
97 * Creates a new variable and adds it to the model
99 * Creates a new variable and adds it to the model
98 * @param name the name of the new variable
100 * @param name the name of the new variable
99 * @param metadata the metadata of the new variable
101 * @param metadata the metadata of the new variable
100 * @param provider the data provider for the new variable
102 * @param provider the data provider for the new variable
101 * @return the pointer to the new variable or nullptr if the creation failed
103 * @return the pointer to the new variable or nullptr if the creation failed
102 */
104 */
103 std::shared_ptr<Variable> createVariable(const QString &name, const QVariantHash &metadata,
105 std::shared_ptr<Variable> createVariable(const QString &name, const QVariantHash &metadata,
104 std::shared_ptr<IDataProvider> provider) noexcept;
106 std::shared_ptr<IDataProvider> provider) noexcept;
105
107
106 /// Update the temporal parameters of every selected variable to dateTime
108 /// Update the temporal parameters of every selected variable to dateTime
107 void onDateTimeOnSelection(const SqpRange &dateTime);
109 void onDateTimeOnSelection(const SqpRange &dateTime);
108
110
109 /// Update the temporal parameters of the specified variable
111 /// Update the temporal parameters of the specified variable
110 void onUpdateDateTime(std::shared_ptr<Variable> variable, const SqpRange &dateTime);
112 void onUpdateDateTime(std::shared_ptr<Variable> variable, const SqpRange &dateTime);
111
113
112
114
113 void onDataProvided(QUuid vIdentifier, const SqpRange &rangeRequested,
115 void onDataProvided(QUuid vIdentifier, const SqpRange &rangeRequested,
114 const SqpRange &cacheRangeRequested,
116 const SqpRange &cacheRangeRequested,
115 QVector<AcquisitionDataPacket> dataAcquired);
117 QVector<AcquisitionDataPacket> dataAcquired);
116
118
117 void onVariableRetrieveDataInProgress(QUuid identifier, double progress);
119 void onVariableRetrieveDataInProgress(QUuid identifier, double progress);
118
120
119 /// Cancel the current request for the variable
121 /// Cancel the current request for the variable
120 void onAbortProgressRequested(std::shared_ptr<Variable> variable);
122 void onAbortProgressRequested(std::shared_ptr<Variable> variable);
121 void onAbortAcquisitionRequested(QUuid vIdentifier);
123 void onAbortAcquisitionRequested(QUuid vIdentifier);
122
124
123 // synchronization group methods
125 // synchronization group methods
124 void onAddSynchronizationGroupId(QUuid synchronizationGroupId);
126 void onAddSynchronizationGroupId(QUuid synchronizationGroupId);
125 void onRemoveSynchronizationGroupId(QUuid synchronizationGroupId);
127 void onRemoveSynchronizationGroupId(QUuid synchronizationGroupId);
126 void onAddSynchronized(std::shared_ptr<Variable> variable, QUuid synchronizationGroupId);
128 void onAddSynchronized(std::shared_ptr<Variable> variable, QUuid synchronizationGroupId);
127
129
128 /// Desynchronizes the variable of the group whose identifier is passed in parameter
130 /// Desynchronizes the variable of the group whose identifier is passed in parameter
129 /// @remarks the method does nothing if the variable is not part of the group
131 /// @remarks the method does nothing if the variable is not part of the group
130 void desynchronize(std::shared_ptr<Variable> variable, QUuid synchronizationGroupId);
132 void desynchronize(std::shared_ptr<Variable> variable, QUuid synchronizationGroupId);
131
133
132 void initialize();
134 void initialize();
133 void finalize();
135 void finalize();
134
136
135 private:
137 private:
136 void waitForFinish();
138 void waitForFinish();
137
139
138 class VariableControllerPrivate;
140 class VariableControllerPrivate;
139 spimpl::unique_impl_ptr<VariableControllerPrivate> impl;
141 spimpl::unique_impl_ptr<VariableControllerPrivate> impl;
140 };
142 };
141
143
142 #endif // SCIQLOP_VARIABLECONTROLLER_H
144 #endif // SCIQLOP_VARIABLECONTROLLER_H
@@ -1,169 +1,197
1 #include "DataSource/DataSourceController.h"
1 #include "DataSource/DataSourceController.h"
2 #include "DataSource/DataSourceItem.h"
2 #include "DataSource/DataSourceItem.h"
3
3
4 #include <Data/IDataProvider.h>
4 #include <Data/IDataProvider.h>
5
5
6 #include <QMutex>
6 #include <QMutex>
7 #include <QThread>
7 #include <QThread>
8
8
9 #include <QDataStream>
9 #include <QDataStream>
10 #include <QDir>
10 #include <QDir>
11 #include <QStandardPaths>
11 #include <QStandardPaths>
12
12
13 Q_LOGGING_CATEGORY(LOG_DataSourceController, "DataSourceController")
13 Q_LOGGING_CATEGORY(LOG_DataSourceController, "DataSourceController")
14
14
15 class DataSourceController::DataSourceControllerPrivate {
15 class DataSourceController::DataSourceControllerPrivate {
16 public:
16 public:
17 QMutex m_WorkingMutex;
17 QMutex m_WorkingMutex;
18 /// Data sources registered
18 /// Data sources registered
19 QHash<QUuid, QString> m_DataSources;
19 QHash<QUuid, QString> m_DataSources;
20 /// Data sources structures
20 /// Data sources structures
21 std::map<QUuid, std::unique_ptr<DataSourceItem> > m_DataSourceItems;
21 std::map<QUuid, std::unique_ptr<DataSourceItem> > m_DataSourceItems;
22 /// Data providers registered
22 /// Data providers registered
23 /// @remarks Data providers are stored as shared_ptr as they can be sent to a variable and
23 /// @remarks Data providers are stored as shared_ptr as they can be sent to a variable and
24 /// continue to live without necessarily the data source controller
24 /// continue to live without necessarily the data source controller
25 std::map<QUuid, std::shared_ptr<IDataProvider> > m_DataProviders;
25 std::map<QUuid, std::shared_ptr<IDataProvider> > m_DataProviders;
26
26
27 // Search for the first datasource item matching the specified data
27 // Search for the first datasource item matching the specified data
28 DataSourceItem *findDataSourceItem(const QVariantHash &data)
28 DataSourceItem *findDataSourceItem(const QVariantHash &data)
29 {
29 {
30 DataSourceItem *sourceItem = nullptr;
30 DataSourceItem *sourceItem = nullptr;
31 for (const auto &item : m_DataSourceItems) {
31 for (const auto &item : m_DataSourceItems) {
32 sourceItem = item.second->findItem(data, true);
32 sourceItem = item.second->findItem(data, true);
33 if (sourceItem) {
33 if (sourceItem) {
34 break;
34 break;
35 }
35 }
36 }
36 }
37
37
38 return sourceItem;
38 return sourceItem;
39 }
39 }
40
41 // Search for the first datasource item matching the specified ID_DATA_KEY
42 DataSourceItem *findDataSourceItem(const QString &datasourceIdKey)
43 {
44 DataSourceItem *sourceItem = nullptr;
45 for (const auto &item : m_DataSourceItems) {
46 sourceItem = item.second->findItem(datasourceIdKey, true);
47 if (sourceItem) {
48 break;
49 }
50 }
51
52 return sourceItem;
53 }
40 };
54 };
41
55
42 DataSourceController::DataSourceController(QObject *parent)
56 DataSourceController::DataSourceController(QObject *parent)
43 : impl{spimpl::make_unique_impl<DataSourceControllerPrivate>()}
57 : impl{spimpl::make_unique_impl<DataSourceControllerPrivate>()}
44 {
58 {
45 qCDebug(LOG_DataSourceController()) << tr("DataSourceController construction")
59 qCDebug(LOG_DataSourceController()) << tr("DataSourceController construction")
46 << QThread::currentThread();
60 << QThread::currentThread();
47 }
61 }
48
62
49 DataSourceController::~DataSourceController()
63 DataSourceController::~DataSourceController()
50 {
64 {
51 qCDebug(LOG_DataSourceController()) << tr("DataSourceController destruction")
65 qCDebug(LOG_DataSourceController()) << tr("DataSourceController destruction")
52 << QThread::currentThread();
66 << QThread::currentThread();
53 this->waitForFinish();
67 this->waitForFinish();
54 }
68 }
55
69
56 QUuid DataSourceController::registerDataSource(const QString &dataSourceName) noexcept
70 QUuid DataSourceController::registerDataSource(const QString &dataSourceName) noexcept
57 {
71 {
58 auto dataSourceUid = QUuid::createUuid();
72 auto dataSourceUid = QUuid::createUuid();
59 impl->m_DataSources.insert(dataSourceUid, dataSourceName);
73 impl->m_DataSources.insert(dataSourceUid, dataSourceName);
60
74
61 return dataSourceUid;
75 return dataSourceUid;
62 }
76 }
63
77
64 void DataSourceController::setDataSourceItem(
78 void DataSourceController::setDataSourceItem(
65 const QUuid &dataSourceUid, std::unique_ptr<DataSourceItem> dataSourceItem) noexcept
79 const QUuid &dataSourceUid, std::unique_ptr<DataSourceItem> dataSourceItem) noexcept
66 {
80 {
67 if (!dataSourceItem) {
81 if (!dataSourceItem) {
68 qCWarning(LOG_DataSourceController())
82 qCWarning(LOG_DataSourceController())
69 << tr("Data source item can't be registered (null item)");
83 << tr("Data source item can't be registered (null item)");
70 return;
84 return;
71 }
85 }
72
86
73 if (impl->m_DataSources.contains(dataSourceUid)) {
87 if (impl->m_DataSources.contains(dataSourceUid)) {
74 // The data provider is implicitly converted to a shared_ptr
88 // The data provider is implicitly converted to a shared_ptr
75 impl->m_DataSourceItems.insert(std::make_pair(dataSourceUid, std::move(dataSourceItem)));
89 impl->m_DataSourceItems.insert(std::make_pair(dataSourceUid, std::move(dataSourceItem)));
76
90
77 // Retrieves the data source item to emit the signal with it
91 // Retrieves the data source item to emit the signal with it
78 auto it = impl->m_DataSourceItems.find(dataSourceUid);
92 auto it = impl->m_DataSourceItems.find(dataSourceUid);
79 if (it != impl->m_DataSourceItems.end()) {
93 if (it != impl->m_DataSourceItems.end()) {
80 emit dataSourceItemSet(it->second.get());
94 emit dataSourceItemSet(it->second.get());
81 }
95 }
82 }
96 }
83 else {
97 else {
84 qCWarning(LOG_DataSourceController()) << tr("Can't set data source item for uid %1 : no "
98 qCWarning(LOG_DataSourceController()) << tr("Can't set data source item for uid %1 : no "
85 "data source has been registered with the uid")
99 "data source has been registered with the uid")
86 .arg(dataSourceUid.toString());
100 .arg(dataSourceUid.toString());
87 }
101 }
88 }
102 }
89
103
90 void DataSourceController::setDataProvider(const QUuid &dataSourceUid,
104 void DataSourceController::setDataProvider(const QUuid &dataSourceUid,
91 std::unique_ptr<IDataProvider> dataProvider) noexcept
105 std::unique_ptr<IDataProvider> dataProvider) noexcept
92 {
106 {
93 if (impl->m_DataSources.contains(dataSourceUid)) {
107 if (impl->m_DataSources.contains(dataSourceUid)) {
94 impl->m_DataProviders.insert(std::make_pair(dataSourceUid, std::move(dataProvider)));
108 impl->m_DataProviders.insert(std::make_pair(dataSourceUid, std::move(dataProvider)));
95 }
109 }
96 else {
110 else {
97 qCWarning(LOG_DataSourceController()) << tr("Can't set data provider for uid %1 : no data "
111 qCWarning(LOG_DataSourceController()) << tr("Can't set data provider for uid %1 : no data "
98 "source has been registered with the uid")
112 "source has been registered with the uid")
99 .arg(dataSourceUid.toString());
113 .arg(dataSourceUid.toString());
100 }
114 }
101 }
115 }
102
116
103 void DataSourceController::loadProductItem(const QUuid &dataSourceUid,
117 void DataSourceController::loadProductItem(const QUuid &dataSourceUid,
104 const DataSourceItem &productItem) noexcept
118 const DataSourceItem &productItem) noexcept
105 {
119 {
106 if (productItem.type() == DataSourceItemType::PRODUCT
120 if (productItem.type() == DataSourceItemType::PRODUCT
107 || productItem.type() == DataSourceItemType::COMPONENT) {
121 || productItem.type() == DataSourceItemType::COMPONENT) {
108 /// Retrieves the data provider of the data source (if any)
122 /// Retrieves the data provider of the data source (if any)
109 auto it = impl->m_DataProviders.find(dataSourceUid);
123 auto it = impl->m_DataProviders.find(dataSourceUid);
110 auto dataProvider = (it != impl->m_DataProviders.end()) ? it->second : nullptr;
124 auto dataProvider = (it != impl->m_DataProviders.end()) ? it->second : nullptr;
111
125
112 emit variableCreationRequested(productItem.name(), productItem.data(), dataProvider);
126 emit variableCreationRequested(productItem.name(), productItem.data(), dataProvider);
113 }
127 }
114 else {
128 else {
115 qCWarning(LOG_DataSourceController()) << tr("Can't load an item that is not a product");
129 qCWarning(LOG_DataSourceController()) << tr("Can't load an item that is not a product");
116 }
130 }
117 }
131 }
118
132
119 QByteArray DataSourceController::mimeDataForProductsData(const QVariantList &productsData)
133 QByteArray DataSourceController::mimeDataForProductsData(const QVariantList &productsData)
120 {
134 {
121 QByteArray encodedData;
135 QByteArray encodedData;
122 QDataStream stream{&encodedData, QIODevice::WriteOnly};
136 QDataStream stream{&encodedData, QIODevice::WriteOnly};
123
137
124 stream << productsData;
138 stream << productsData;
125
139
126 return encodedData;
140 return encodedData;
127 }
141 }
128
142
129 QVariantList DataSourceController::productsDataForMimeData(const QByteArray &mimeData)
143 QVariantList DataSourceController::productsDataForMimeData(const QByteArray &mimeData)
130 {
144 {
131 QDataStream stream{mimeData};
145 QDataStream stream{mimeData};
132
146
133 QVariantList productList;
147 QVariantList productList;
134 stream >> productList;
148 stream >> productList;
135
149
136 return productList;
150 return productList;
137 }
151 }
138
152
139 void DataSourceController::initialize()
153 void DataSourceController::initialize()
140 {
154 {
141 qCDebug(LOG_DataSourceController()) << tr("DataSourceController init")
155 qCDebug(LOG_DataSourceController()) << tr("DataSourceController init")
142 << QThread::currentThread();
156 << QThread::currentThread();
143 impl->m_WorkingMutex.lock();
157 impl->m_WorkingMutex.lock();
144 qCDebug(LOG_DataSourceController()) << tr("DataSourceController init END");
158 qCDebug(LOG_DataSourceController()) << tr("DataSourceController init END");
145 }
159 }
146
160
147 void DataSourceController::finalize()
161 void DataSourceController::finalize()
148 {
162 {
149 impl->m_WorkingMutex.unlock();
163 impl->m_WorkingMutex.unlock();
150 }
164 }
151
165
166 void DataSourceController::requestVariableFromProductIdKey(const QString &datasourceIdKey)
167 {
168 auto sourceItem = impl->findDataSourceItem(datasourceIdKey);
169
170 if (sourceItem) {
171 auto sourceName = sourceItem->rootItem().name();
172 auto sourceId = impl->m_DataSources.key(sourceName);
173 loadProductItem(sourceId, *sourceItem);
174 }
175 else {
176 qCWarning(LOG_DataSourceController()) << tr("requestVariable, product data not found");
177 }
178 }
179
152 void DataSourceController::requestVariable(const QVariantHash &productData)
180 void DataSourceController::requestVariable(const QVariantHash &productData)
153 {
181 {
154 auto sourceItem = impl->findDataSourceItem(productData);
182 auto sourceItem = impl->findDataSourceItem(productData);
155
183
156 if (sourceItem) {
184 if (sourceItem) {
157 auto sourceName = sourceItem->rootItem().name();
185 auto sourceName = sourceItem->rootItem().name();
158 auto sourceId = impl->m_DataSources.key(sourceName);
186 auto sourceId = impl->m_DataSources.key(sourceName);
159 loadProductItem(sourceId, *sourceItem);
187 loadProductItem(sourceId, *sourceItem);
160 }
188 }
161 else {
189 else {
162 qCWarning(LOG_DataSourceController()) << tr("requestVariable, product data not found");
190 qCWarning(LOG_DataSourceController()) << tr("requestVariable, product data not found");
163 }
191 }
164 }
192 }
165
193
166 void DataSourceController::waitForFinish()
194 void DataSourceController::waitForFinish()
167 {
195 {
168 QMutexLocker locker{&impl->m_WorkingMutex};
196 QMutexLocker locker{&impl->m_WorkingMutex};
169 }
197 }
@@ -1,187 +1,205
1 #include <DataSource/DataSourceItem.h>
1 #include <DataSource/DataSourceItem.h>
2 #include <DataSource/DataSourceItemAction.h>
2 #include <DataSource/DataSourceItemAction.h>
3 #include <DataSource/DataSourceItemMergeHelper.h>
3 #include <DataSource/DataSourceItemMergeHelper.h>
4
4
5 #include <QVector>
5 #include <QVector>
6
6
7 const QString DataSourceItem::NAME_DATA_KEY = QStringLiteral("name");
7 const QString DataSourceItem::NAME_DATA_KEY = QStringLiteral("name");
8 const QString DataSourceItem::PLUGIN_DATA_KEY = QStringLiteral("plugin");
8 const QString DataSourceItem::PLUGIN_DATA_KEY = QStringLiteral("plugin");
9 const QString DataSourceItem::ID_DATA_KEY = QStringLiteral("uuid");
9 const QString DataSourceItem::ID_DATA_KEY = QStringLiteral("uuid");
10
10
11 struct DataSourceItem::DataSourceItemPrivate {
11 struct DataSourceItem::DataSourceItemPrivate {
12 explicit DataSourceItemPrivate(DataSourceItemType type, QVariantHash data)
12 explicit DataSourceItemPrivate(DataSourceItemType type, QVariantHash data)
13 : m_Parent{nullptr}, m_Children{}, m_Type{type}, m_Data{std::move(data)}, m_Actions{}
13 : m_Parent{nullptr}, m_Children{}, m_Type{type}, m_Data{std::move(data)}, m_Actions{}
14 {
14 {
15 }
15 }
16
16
17 DataSourceItem *m_Parent;
17 DataSourceItem *m_Parent;
18 std::vector<std::unique_ptr<DataSourceItem> > m_Children;
18 std::vector<std::unique_ptr<DataSourceItem> > m_Children;
19 DataSourceItemType m_Type;
19 DataSourceItemType m_Type;
20 QVariantHash m_Data;
20 QVariantHash m_Data;
21 std::vector<std::unique_ptr<DataSourceItemAction> > m_Actions;
21 std::vector<std::unique_ptr<DataSourceItemAction> > m_Actions;
22 };
22 };
23
23
24 DataSourceItem::DataSourceItem(DataSourceItemType type, const QString &name)
24 DataSourceItem::DataSourceItem(DataSourceItemType type, const QString &name)
25 : DataSourceItem{type, QVariantHash{{NAME_DATA_KEY, name}}}
25 : DataSourceItem{type, QVariantHash{{NAME_DATA_KEY, name}}}
26 {
26 {
27 }
27 }
28
28
29 DataSourceItem::DataSourceItem(DataSourceItemType type, QVariantHash data)
29 DataSourceItem::DataSourceItem(DataSourceItemType type, QVariantHash data)
30 : impl{spimpl::make_unique_impl<DataSourceItemPrivate>(type, std::move(data))}
30 : impl{spimpl::make_unique_impl<DataSourceItemPrivate>(type, std::move(data))}
31 {
31 {
32 }
32 }
33
33
34 std::unique_ptr<DataSourceItem> DataSourceItem::clone() const
34 std::unique_ptr<DataSourceItem> DataSourceItem::clone() const
35 {
35 {
36 auto result = std::make_unique<DataSourceItem>(impl->m_Type, impl->m_Data);
36 auto result = std::make_unique<DataSourceItem>(impl->m_Type, impl->m_Data);
37
37
38 // Clones children
38 // Clones children
39 for (const auto &child : impl->m_Children) {
39 for (const auto &child : impl->m_Children) {
40 result->appendChild(std::move(child->clone()));
40 result->appendChild(std::move(child->clone()));
41 }
41 }
42
42
43 // Clones actions
43 // Clones actions
44 for (const auto &action : impl->m_Actions) {
44 for (const auto &action : impl->m_Actions) {
45 result->addAction(std::move(action->clone()));
45 result->addAction(std::move(action->clone()));
46 }
46 }
47
47
48 return result;
48 return result;
49 }
49 }
50
50
51 QVector<DataSourceItemAction *> DataSourceItem::actions() const noexcept
51 QVector<DataSourceItemAction *> DataSourceItem::actions() const noexcept
52 {
52 {
53 auto result = QVector<DataSourceItemAction *>{};
53 auto result = QVector<DataSourceItemAction *>{};
54
54
55 std::transform(std::cbegin(impl->m_Actions), std::cend(impl->m_Actions),
55 std::transform(std::cbegin(impl->m_Actions), std::cend(impl->m_Actions),
56 std::back_inserter(result), [](const auto &action) { return action.get(); });
56 std::back_inserter(result), [](const auto &action) { return action.get(); });
57
57
58 return result;
58 return result;
59 }
59 }
60
60
61 void DataSourceItem::addAction(std::unique_ptr<DataSourceItemAction> action) noexcept
61 void DataSourceItem::addAction(std::unique_ptr<DataSourceItemAction> action) noexcept
62 {
62 {
63 action->setDataSourceItem(this);
63 action->setDataSourceItem(this);
64 impl->m_Actions.push_back(std::move(action));
64 impl->m_Actions.push_back(std::move(action));
65 }
65 }
66
66
67 void DataSourceItem::appendChild(std::unique_ptr<DataSourceItem> child) noexcept
67 void DataSourceItem::appendChild(std::unique_ptr<DataSourceItem> child) noexcept
68 {
68 {
69 child->impl->m_Parent = this;
69 child->impl->m_Parent = this;
70 impl->m_Children.push_back(std::move(child));
70 impl->m_Children.push_back(std::move(child));
71 }
71 }
72
72
73 DataSourceItem *DataSourceItem::child(int childIndex) const noexcept
73 DataSourceItem *DataSourceItem::child(int childIndex) const noexcept
74 {
74 {
75 if (childIndex < 0 || childIndex >= childCount()) {
75 if (childIndex < 0 || childIndex >= childCount()) {
76 return nullptr;
76 return nullptr;
77 }
77 }
78 else {
78 else {
79 return impl->m_Children.at(childIndex).get();
79 return impl->m_Children.at(childIndex).get();
80 }
80 }
81 }
81 }
82
82
83 int DataSourceItem::childCount() const noexcept
83 int DataSourceItem::childCount() const noexcept
84 {
84 {
85 return impl->m_Children.size();
85 return impl->m_Children.size();
86 }
86 }
87
87
88 QVariant DataSourceItem::data(const QString &key) const noexcept
88 QVariant DataSourceItem::data(const QString &key) const noexcept
89 {
89 {
90 return impl->m_Data.value(key);
90 return impl->m_Data.value(key);
91 }
91 }
92
92
93 QVariantHash DataSourceItem::data() const noexcept
93 QVariantHash DataSourceItem::data() const noexcept
94 {
94 {
95 return impl->m_Data;
95 return impl->m_Data;
96 }
96 }
97
97
98 void DataSourceItem::merge(const DataSourceItem &item)
98 void DataSourceItem::merge(const DataSourceItem &item)
99 {
99 {
100 DataSourceItemMergeHelper::merge(item, *this);
100 DataSourceItemMergeHelper::merge(item, *this);
101 }
101 }
102
102
103 bool DataSourceItem::isRoot() const noexcept
103 bool DataSourceItem::isRoot() const noexcept
104 {
104 {
105 return impl->m_Parent == nullptr;
105 return impl->m_Parent == nullptr;
106 }
106 }
107
107
108 QString DataSourceItem::name() const noexcept
108 QString DataSourceItem::name() const noexcept
109 {
109 {
110 return data(NAME_DATA_KEY).toString();
110 return data(NAME_DATA_KEY).toString();
111 }
111 }
112
112
113 DataSourceItem *DataSourceItem::parentItem() const noexcept
113 DataSourceItem *DataSourceItem::parentItem() const noexcept
114 {
114 {
115 return impl->m_Parent;
115 return impl->m_Parent;
116 }
116 }
117
117
118 const DataSourceItem &DataSourceItem::rootItem() const noexcept
118 const DataSourceItem &DataSourceItem::rootItem() const noexcept
119 {
119 {
120 return isRoot() ? *this : parentItem()->rootItem();
120 return isRoot() ? *this : parentItem()->rootItem();
121 }
121 }
122
122
123 void DataSourceItem::setData(const QString &key, const QVariant &value, bool append) noexcept
123 void DataSourceItem::setData(const QString &key, const QVariant &value, bool append) noexcept
124 {
124 {
125 auto it = impl->m_Data.constFind(key);
125 auto it = impl->m_Data.constFind(key);
126 if (append && it != impl->m_Data.constEnd()) {
126 if (append && it != impl->m_Data.constEnd()) {
127 // Case of an existing value to which we want to add to the new value
127 // Case of an existing value to which we want to add to the new value
128 if (it->canConvert<QVariantList>()) {
128 if (it->canConvert<QVariantList>()) {
129 auto variantList = it->value<QVariantList>();
129 auto variantList = it->value<QVariantList>();
130 variantList.append(value);
130 variantList.append(value);
131
131
132 impl->m_Data.insert(key, variantList);
132 impl->m_Data.insert(key, variantList);
133 }
133 }
134 else {
134 else {
135 impl->m_Data.insert(key, QVariantList{*it, value});
135 impl->m_Data.insert(key, QVariantList{*it, value});
136 }
136 }
137 }
137 }
138 else {
138 else {
139 // Other cases :
139 // Other cases :
140 // - new value in map OR
140 // - new value in map OR
141 // - replacement of an existing value (not appending)
141 // - replacement of an existing value (not appending)
142 impl->m_Data.insert(key, value);
142 impl->m_Data.insert(key, value);
143 }
143 }
144 }
144 }
145
145
146 DataSourceItemType DataSourceItem::type() const noexcept
146 DataSourceItemType DataSourceItem::type() const noexcept
147 {
147 {
148 return impl->m_Type;
148 return impl->m_Type;
149 }
149 }
150
150
151 DataSourceItem *DataSourceItem::findItem(const QVariantHash &data, bool recursive)
151 DataSourceItem *DataSourceItem::findItem(const QVariantHash &data, bool recursive)
152 {
152 {
153 for (const auto &child : impl->m_Children) {
153 for (const auto &child : impl->m_Children) {
154 if (child->impl->m_Data == data) {
154 if (child->impl->m_Data == data) {
155 return child.get();
155 return child.get();
156 }
156 }
157
157
158 if (recursive) {
158 if (recursive) {
159 if (auto foundItem = child->findItem(data, true)) {
159 if (auto foundItem = child->findItem(data, true)) {
160 return foundItem;
160 return foundItem;
161 }
161 }
162 }
162 }
163 }
163 }
164
164
165 return nullptr;
165 return nullptr;
166 }
166 }
167
167
168 DataSourceItem *DataSourceItem::findItem(const QString &datasourceIdKey, bool recursive)
169 {
170 for (const auto &child : impl->m_Children) {
171 auto childId = child->impl->m_Data.value(ID_DATA_KEY);
172 if (childId == datasourceIdKey) {
173 return child.get();
174 }
175
176 if (recursive) {
177 if (auto foundItem = child->findItem(datasourceIdKey, true)) {
178 return foundItem;
179 }
180 }
181 }
182
183 return nullptr;
184 }
185
168 bool DataSourceItem::operator==(const DataSourceItem &other)
186 bool DataSourceItem::operator==(const DataSourceItem &other)
169 {
187 {
170 // Compares items' attributes
188 // Compares items' attributes
171 if (std::tie(impl->m_Type, impl->m_Data) == std::tie(other.impl->m_Type, other.impl->m_Data)) {
189 if (std::tie(impl->m_Type, impl->m_Data) == std::tie(other.impl->m_Type, other.impl->m_Data)) {
172 // Compares contents of items' children
190 // Compares contents of items' children
173 return std::equal(std::cbegin(impl->m_Children), std::cend(impl->m_Children),
191 return std::equal(std::cbegin(impl->m_Children), std::cend(impl->m_Children),
174 std::cbegin(other.impl->m_Children), std::cend(other.impl->m_Children),
192 std::cbegin(other.impl->m_Children), std::cend(other.impl->m_Children),
175 [](const auto &itemChild, const auto &otherChild) {
193 [](const auto &itemChild, const auto &otherChild) {
176 return *itemChild == *otherChild;
194 return *itemChild == *otherChild;
177 });
195 });
178 }
196 }
179 else {
197 else {
180 return false;
198 return false;
181 }
199 }
182 }
200 }
183
201
184 bool DataSourceItem::operator!=(const DataSourceItem &other)
202 bool DataSourceItem::operator!=(const DataSourceItem &other)
185 {
203 {
186 return !(*this == other);
204 return !(*this == other);
187 }
205 }
@@ -1,388 +1,430
1 #include "Variable/Variable.h"
1 #include "Variable/Variable.h"
2
2
3 #include <Data/IDataSeries.h>
3 #include <Data/IDataSeries.h>
4 #include <Data/SqpRange.h>
4 #include <Data/SqpRange.h>
5
5
6 #include <QMutex>
6 #include <QMutex>
7 #include <QReadWriteLock>
7 #include <QReadWriteLock>
8 #include <QThread>
8 #include <QThread>
9
9
10 Q_LOGGING_CATEGORY(LOG_Variable, "Variable")
10 Q_LOGGING_CATEGORY(LOG_Variable, "Variable")
11
11
12 namespace {
13
14 /**
15 * Searches in metadata for a value that can be converted to DataSeriesType
16 * @param metadata the metadata where to search
17 * @return the value converted to a DataSeriesType if it was found, UNKNOWN type otherwise
18 * @sa DataSeriesType
19 */
20 DataSeriesType findDataSeriesType(const QVariantHash &metadata)
21 {
22 auto dataSeriesType = DataSeriesType::UNKNOWN;
23
24 // Go through the metadata and stop at the first value that could be converted to DataSeriesType
25 for (auto it = metadata.cbegin(), end = metadata.cend();
26 it != end && dataSeriesType == DataSeriesType::UNKNOWN; ++it) {
27 dataSeriesType = DataSeriesTypeUtils::fromString(it.value().toString());
28 }
29
30 return dataSeriesType;
31 }
32
33 } // namespace
34
12 struct Variable::VariablePrivate {
35 struct Variable::VariablePrivate {
13 explicit VariablePrivate(const QString &name, const QVariantHash &metadata)
36 explicit VariablePrivate(const QString &name, const QVariantHash &metadata)
14 : m_Name{name},
37 : m_Name{name},
15 m_Range{INVALID_RANGE},
38 m_Range{INVALID_RANGE},
16 m_CacheRange{INVALID_RANGE},
39 m_CacheRange{INVALID_RANGE},
17 m_Metadata{metadata},
40 m_Metadata{metadata},
18 m_DataSeries{nullptr},
41 m_DataSeries{nullptr},
19 m_RealRange{INVALID_RANGE},
42 m_RealRange{INVALID_RANGE},
20 m_NbPoints{0}
43 m_NbPoints{0},
44 m_Type{findDataSeriesType(m_Metadata)}
21 {
45 {
22 }
46 }
23
47
24 VariablePrivate(const VariablePrivate &other)
48 VariablePrivate(const VariablePrivate &other)
25 : m_Name{other.m_Name},
49 : m_Name{other.m_Name},
26 m_Range{other.m_Range},
50 m_Range{other.m_Range},
27 m_CacheRange{other.m_CacheRange},
51 m_CacheRange{other.m_CacheRange},
28 m_Metadata{other.m_Metadata},
52 m_Metadata{other.m_Metadata},
29 m_DataSeries{other.m_DataSeries != nullptr ? other.m_DataSeries->clone() : nullptr},
53 m_DataSeries{other.m_DataSeries != nullptr ? other.m_DataSeries->clone() : nullptr},
30 m_RealRange{other.m_RealRange},
54 m_RealRange{other.m_RealRange},
31 m_NbPoints{other.m_NbPoints}
55 m_NbPoints{other.m_NbPoints},
56 m_Type{findDataSeriesType(m_Metadata)}
32 {
57 {
33 }
58 }
34
59
35 void lockRead() { m_Lock.lockForRead(); }
60 void lockRead() { m_Lock.lockForRead(); }
36 void lockWrite() { m_Lock.lockForWrite(); }
61 void lockWrite() { m_Lock.lockForWrite(); }
37 void unlock() { m_Lock.unlock(); }
62 void unlock() { m_Lock.unlock(); }
38
63
39 void purgeDataSeries()
64 void purgeDataSeries()
40 {
65 {
41 if (m_DataSeries) {
66 if (m_DataSeries) {
42 m_DataSeries->purge(m_CacheRange.m_TStart, m_CacheRange.m_TEnd);
67 m_DataSeries->purge(m_CacheRange.m_TStart, m_CacheRange.m_TEnd);
43 }
68 }
44 updateRealRange();
69 updateRealRange();
45 updateNbPoints();
70 updateNbPoints();
46 }
71 }
47
72
48 void updateNbPoints() { m_NbPoints = m_DataSeries ? m_DataSeries->nbPoints() : 0; }
73 void updateNbPoints() { m_NbPoints = m_DataSeries ? m_DataSeries->nbPoints() : 0; }
49
74
50 /// Updates real range according to current variable range and data series
75 /// Updates real range according to current variable range and data series
51 void updateRealRange()
76 void updateRealRange()
52 {
77 {
53 if (m_DataSeries) {
78 if (m_DataSeries) {
54 m_DataSeries->lockRead();
79 m_DataSeries->lockRead();
55 auto end = m_DataSeries->cend();
80 auto end = m_DataSeries->cend();
56 auto minXAxisIt = m_DataSeries->minXAxisData(m_Range.m_TStart);
81 auto minXAxisIt = m_DataSeries->minXAxisData(m_Range.m_TStart);
57 auto maxXAxisIt = m_DataSeries->maxXAxisData(m_Range.m_TEnd);
82 auto maxXAxisIt = m_DataSeries->maxXAxisData(m_Range.m_TEnd);
58
83
59 m_RealRange
84 m_RealRange
60 = (minXAxisIt != end && maxXAxisIt != end && minXAxisIt->x() <= maxXAxisIt->x())
85 = (minXAxisIt != end && maxXAxisIt != end && minXAxisIt->x() <= maxXAxisIt->x())
61 ? SqpRange{minXAxisIt->x(), maxXAxisIt->x()}
86 ? SqpRange{minXAxisIt->x(), maxXAxisIt->x()}
62 : INVALID_RANGE;
87 : INVALID_RANGE;
63 m_DataSeries->unlock();
88 m_DataSeries->unlock();
64 }
89 }
65 else {
90 else {
66 m_RealRange = INVALID_RANGE;
91 m_RealRange = INVALID_RANGE;
67 }
92 }
68 }
93 }
69
94
70 QString m_Name;
95 QString m_Name;
71
96
72 SqpRange m_Range;
97 SqpRange m_Range;
73 SqpRange m_CacheRange;
98 SqpRange m_CacheRange;
74 QVariantHash m_Metadata;
99 QVariantHash m_Metadata;
75 std::shared_ptr<IDataSeries> m_DataSeries;
100 std::shared_ptr<IDataSeries> m_DataSeries;
76 SqpRange m_RealRange;
101 SqpRange m_RealRange;
77 int m_NbPoints;
102 int m_NbPoints;
103 DataSeriesType m_Type;
78
104
79 QReadWriteLock m_Lock;
105 QReadWriteLock m_Lock;
80 };
106 };
81
107
82 Variable::Variable(const QString &name, const QVariantHash &metadata)
108 Variable::Variable(const QString &name, const QVariantHash &metadata)
83 : impl{spimpl::make_unique_impl<VariablePrivate>(name, metadata)}
109 : impl{spimpl::make_unique_impl<VariablePrivate>(name, metadata)}
84 {
110 {
85 }
111 }
86
112
87 Variable::Variable(const Variable &other)
113 Variable::Variable(const Variable &other)
88 : impl{spimpl::make_unique_impl<VariablePrivate>(*other.impl)}
114 : impl{spimpl::make_unique_impl<VariablePrivate>(*other.impl)}
89 {
115 {
90 }
116 }
91
117
92 std::shared_ptr<Variable> Variable::clone() const
118 std::shared_ptr<Variable> Variable::clone() const
93 {
119 {
94 return std::make_shared<Variable>(*this);
120 return std::make_shared<Variable>(*this);
95 }
121 }
96
122
97 QString Variable::name() const noexcept
123 QString Variable::name() const noexcept
98 {
124 {
99 impl->lockRead();
125 impl->lockRead();
100 auto name = impl->m_Name;
126 auto name = impl->m_Name;
101 impl->unlock();
127 impl->unlock();
102 return name;
128 return name;
103 }
129 }
104
130
105 void Variable::setName(const QString &name) noexcept
131 void Variable::setName(const QString &name) noexcept
106 {
132 {
107 impl->lockWrite();
133 impl->lockWrite();
108 impl->m_Name = name;
134 impl->m_Name = name;
109 impl->unlock();
135 impl->unlock();
110 }
136 }
111
137
112 SqpRange Variable::range() const noexcept
138 SqpRange Variable::range() const noexcept
113 {
139 {
114 impl->lockRead();
140 impl->lockRead();
115 auto range = impl->m_Range;
141 auto range = impl->m_Range;
116 impl->unlock();
142 impl->unlock();
117 return range;
143 return range;
118 }
144 }
119
145
120 void Variable::setRange(const SqpRange &range) noexcept
146 void Variable::setRange(const SqpRange &range) noexcept
121 {
147 {
122 impl->lockWrite();
148 impl->lockWrite();
123 impl->m_Range = range;
149 impl->m_Range = range;
124 impl->updateRealRange();
150 impl->updateRealRange();
125 impl->unlock();
151 impl->unlock();
126 }
152 }
127
153
128 SqpRange Variable::cacheRange() const noexcept
154 SqpRange Variable::cacheRange() const noexcept
129 {
155 {
130 impl->lockRead();
156 impl->lockRead();
131 auto cacheRange = impl->m_CacheRange;
157 auto cacheRange = impl->m_CacheRange;
132 impl->unlock();
158 impl->unlock();
133 return cacheRange;
159 return cacheRange;
134 }
160 }
135
161
136 void Variable::setCacheRange(const SqpRange &cacheRange) noexcept
162 void Variable::setCacheRange(const SqpRange &cacheRange) noexcept
137 {
163 {
138 impl->lockWrite();
164 impl->lockWrite();
139 if (cacheRange != impl->m_CacheRange) {
165 if (cacheRange != impl->m_CacheRange) {
140 impl->m_CacheRange = cacheRange;
166 impl->m_CacheRange = cacheRange;
141 }
167 }
142 impl->unlock();
168 impl->unlock();
143 }
169 }
144
170
145 int Variable::nbPoints() const noexcept
171 int Variable::nbPoints() const noexcept
146 {
172 {
147 return impl->m_NbPoints;
173 return impl->m_NbPoints;
148 }
174 }
149
175
150 SqpRange Variable::realRange() const noexcept
176 SqpRange Variable::realRange() const noexcept
151 {
177 {
152 return impl->m_RealRange;
178 return impl->m_RealRange;
153 }
179 }
154
180
155 void Variable::mergeDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept
181 void Variable::mergeDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept
156 {
182 {
157 qCDebug(LOG_Variable()) << "TORM Variable::mergeDataSeries"
183 qCDebug(LOG_Variable()) << "TORM Variable::mergeDataSeries"
158 << QThread::currentThread()->objectName();
184 << QThread::currentThread()->objectName();
159 if (!dataSeries) {
185 if (!dataSeries) {
160 /// @todo ALX : log
186 /// @todo ALX : log
161 return;
187 return;
162 }
188 }
163
189
190 auto dataInit = false;
191
164 // Add or merge the data
192 // Add or merge the data
165 impl->lockWrite();
193 impl->lockWrite();
166 if (!impl->m_DataSeries) {
194 if (!impl->m_DataSeries) {
167 impl->m_DataSeries = dataSeries->clone();
195 impl->m_DataSeries = dataSeries->clone();
196 dataInit = true;
168 }
197 }
169 else {
198 else {
170 impl->m_DataSeries->merge(dataSeries.get());
199 impl->m_DataSeries->merge(dataSeries.get());
171 }
200 }
172 impl->purgeDataSeries();
201 impl->purgeDataSeries();
173 impl->unlock();
202 impl->unlock();
203
204 if (dataInit) {
205 emit dataInitialized();
206 }
174 }
207 }
175
208
176
209
177 std::shared_ptr<IDataSeries> Variable::dataSeries() const noexcept
210 std::shared_ptr<IDataSeries> Variable::dataSeries() const noexcept
178 {
211 {
179 impl->lockRead();
212 impl->lockRead();
180 auto dataSeries = impl->m_DataSeries;
213 auto dataSeries = impl->m_DataSeries;
181 impl->unlock();
214 impl->unlock();
182
215
183 return dataSeries;
216 return dataSeries;
184 }
217 }
185
218
219 DataSeriesType Variable::type() const noexcept
220 {
221 impl->lockRead();
222 auto type = impl->m_Type;
223 impl->unlock();
224
225 return type;
226 }
227
186 QVariantHash Variable::metadata() const noexcept
228 QVariantHash Variable::metadata() const noexcept
187 {
229 {
188 impl->lockRead();
230 impl->lockRead();
189 auto metadata = impl->m_Metadata;
231 auto metadata = impl->m_Metadata;
190 impl->unlock();
232 impl->unlock();
191 return metadata;
233 return metadata;
192 }
234 }
193
235
194 bool Variable::contains(const SqpRange &range) const noexcept
236 bool Variable::contains(const SqpRange &range) const noexcept
195 {
237 {
196 impl->lockRead();
238 impl->lockRead();
197 auto res = impl->m_Range.contains(range);
239 auto res = impl->m_Range.contains(range);
198 impl->unlock();
240 impl->unlock();
199 return res;
241 return res;
200 }
242 }
201
243
202 bool Variable::intersect(const SqpRange &range) const noexcept
244 bool Variable::intersect(const SqpRange &range) const noexcept
203 {
245 {
204
246
205 impl->lockRead();
247 impl->lockRead();
206 auto res = impl->m_Range.intersect(range);
248 auto res = impl->m_Range.intersect(range);
207 impl->unlock();
249 impl->unlock();
208 return res;
250 return res;
209 }
251 }
210
252
211 bool Variable::isInside(const SqpRange &range) const noexcept
253 bool Variable::isInside(const SqpRange &range) const noexcept
212 {
254 {
213 impl->lockRead();
255 impl->lockRead();
214 auto res = range.contains(SqpRange{impl->m_Range.m_TStart, impl->m_Range.m_TEnd});
256 auto res = range.contains(SqpRange{impl->m_Range.m_TStart, impl->m_Range.m_TEnd});
215 impl->unlock();
257 impl->unlock();
216 return res;
258 return res;
217 }
259 }
218
260
219 bool Variable::cacheContains(const SqpRange &range) const noexcept
261 bool Variable::cacheContains(const SqpRange &range) const noexcept
220 {
262 {
221 impl->lockRead();
263 impl->lockRead();
222 auto res = impl->m_CacheRange.contains(range);
264 auto res = impl->m_CacheRange.contains(range);
223 impl->unlock();
265 impl->unlock();
224 return res;
266 return res;
225 }
267 }
226
268
227 bool Variable::cacheIntersect(const SqpRange &range) const noexcept
269 bool Variable::cacheIntersect(const SqpRange &range) const noexcept
228 {
270 {
229 impl->lockRead();
271 impl->lockRead();
230 auto res = impl->m_CacheRange.intersect(range);
272 auto res = impl->m_CacheRange.intersect(range);
231 impl->unlock();
273 impl->unlock();
232 return res;
274 return res;
233 }
275 }
234
276
235 bool Variable::cacheIsInside(const SqpRange &range) const noexcept
277 bool Variable::cacheIsInside(const SqpRange &range) const noexcept
236 {
278 {
237 impl->lockRead();
279 impl->lockRead();
238 auto res = range.contains(SqpRange{impl->m_CacheRange.m_TStart, impl->m_CacheRange.m_TEnd});
280 auto res = range.contains(SqpRange{impl->m_CacheRange.m_TStart, impl->m_CacheRange.m_TEnd});
239 impl->unlock();
281 impl->unlock();
240 return res;
282 return res;
241 }
283 }
242
284
243
285
244 QVector<SqpRange> Variable::provideNotInCacheRangeList(const SqpRange &range) const noexcept
286 QVector<SqpRange> Variable::provideNotInCacheRangeList(const SqpRange &range) const noexcept
245 {
287 {
246 // This code assume that cach in contigue. Can return 0, 1 or 2 SqpRange
288 // This code assume that cach in contigue. Can return 0, 1 or 2 SqpRange
247 auto notInCache = QVector<SqpRange>{};
289 auto notInCache = QVector<SqpRange>{};
248 if (impl->m_CacheRange != INVALID_RANGE) {
290 if (impl->m_CacheRange != INVALID_RANGE) {
249
291
250 if (!this->cacheContains(range)) {
292 if (!this->cacheContains(range)) {
251 if (range.m_TEnd <= impl->m_CacheRange.m_TStart
293 if (range.m_TEnd <= impl->m_CacheRange.m_TStart
252 || range.m_TStart >= impl->m_CacheRange.m_TEnd) {
294 || range.m_TStart >= impl->m_CacheRange.m_TEnd) {
253 notInCache << range;
295 notInCache << range;
254 }
296 }
255 else if (range.m_TStart < impl->m_CacheRange.m_TStart
297 else if (range.m_TStart < impl->m_CacheRange.m_TStart
256 && range.m_TEnd <= impl->m_CacheRange.m_TEnd) {
298 && range.m_TEnd <= impl->m_CacheRange.m_TEnd) {
257 notInCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TStart};
299 notInCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TStart};
258 }
300 }
259 else if (range.m_TStart < impl->m_CacheRange.m_TStart
301 else if (range.m_TStart < impl->m_CacheRange.m_TStart
260 && range.m_TEnd > impl->m_CacheRange.m_TEnd) {
302 && range.m_TEnd > impl->m_CacheRange.m_TEnd) {
261 notInCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TStart}
303 notInCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TStart}
262 << SqpRange{impl->m_CacheRange.m_TEnd, range.m_TEnd};
304 << SqpRange{impl->m_CacheRange.m_TEnd, range.m_TEnd};
263 }
305 }
264 else if (range.m_TStart < impl->m_CacheRange.m_TEnd) {
306 else if (range.m_TStart < impl->m_CacheRange.m_TEnd) {
265 notInCache << SqpRange{impl->m_CacheRange.m_TEnd, range.m_TEnd};
307 notInCache << SqpRange{impl->m_CacheRange.m_TEnd, range.m_TEnd};
266 }
308 }
267 else {
309 else {
268 qCCritical(LOG_Variable()) << tr("Detection of unknown case.")
310 qCCritical(LOG_Variable()) << tr("Detection of unknown case.")
269 << QThread::currentThread();
311 << QThread::currentThread();
270 }
312 }
271 }
313 }
272 }
314 }
273 else {
315 else {
274 notInCache << range;
316 notInCache << range;
275 }
317 }
276
318
277 return notInCache;
319 return notInCache;
278 }
320 }
279
321
280 QVector<SqpRange> Variable::provideInCacheRangeList(const SqpRange &range) const noexcept
322 QVector<SqpRange> Variable::provideInCacheRangeList(const SqpRange &range) const noexcept
281 {
323 {
282 // This code assume that cach in contigue. Can return 0 or 1 SqpRange
324 // This code assume that cach in contigue. Can return 0 or 1 SqpRange
283
325
284 auto inCache = QVector<SqpRange>{};
326 auto inCache = QVector<SqpRange>{};
285
327
286 if (impl->m_CacheRange != INVALID_RANGE) {
328 if (impl->m_CacheRange != INVALID_RANGE) {
287
329
288 if (this->cacheIntersect(range)) {
330 if (this->cacheIntersect(range)) {
289 if (range.m_TStart <= impl->m_CacheRange.m_TStart
331 if (range.m_TStart <= impl->m_CacheRange.m_TStart
290 && range.m_TEnd >= impl->m_CacheRange.m_TStart
332 && range.m_TEnd >= impl->m_CacheRange.m_TStart
291 && range.m_TEnd < impl->m_CacheRange.m_TEnd) {
333 && range.m_TEnd < impl->m_CacheRange.m_TEnd) {
292 inCache << SqpRange{impl->m_CacheRange.m_TStart, range.m_TEnd};
334 inCache << SqpRange{impl->m_CacheRange.m_TStart, range.m_TEnd};
293 }
335 }
294
336
295 else if (range.m_TStart >= impl->m_CacheRange.m_TStart
337 else if (range.m_TStart >= impl->m_CacheRange.m_TStart
296 && range.m_TEnd <= impl->m_CacheRange.m_TEnd) {
338 && range.m_TEnd <= impl->m_CacheRange.m_TEnd) {
297 inCache << range;
339 inCache << range;
298 }
340 }
299 else if (range.m_TStart > impl->m_CacheRange.m_TStart
341 else if (range.m_TStart > impl->m_CacheRange.m_TStart
300 && range.m_TEnd > impl->m_CacheRange.m_TEnd) {
342 && range.m_TEnd > impl->m_CacheRange.m_TEnd) {
301 inCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TEnd};
343 inCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TEnd};
302 }
344 }
303 else if (range.m_TStart <= impl->m_CacheRange.m_TStart
345 else if (range.m_TStart <= impl->m_CacheRange.m_TStart
304 && range.m_TEnd >= impl->m_CacheRange.m_TEnd) {
346 && range.m_TEnd >= impl->m_CacheRange.m_TEnd) {
305 inCache << impl->m_CacheRange;
347 inCache << impl->m_CacheRange;
306 }
348 }
307 else {
349 else {
308 qCCritical(LOG_Variable()) << tr("Detection of unknown case.")
350 qCCritical(LOG_Variable()) << tr("Detection of unknown case.")
309 << QThread::currentThread();
351 << QThread::currentThread();
310 }
352 }
311 }
353 }
312 }
354 }
313
355
314 return inCache;
356 return inCache;
315 }
357 }
316
358
317
359
318 QVector<SqpRange> Variable::provideNotInCacheRangeList(const SqpRange &oldRange,
360 QVector<SqpRange> Variable::provideNotInCacheRangeList(const SqpRange &oldRange,
319 const SqpRange &nextRange)
361 const SqpRange &nextRange)
320 {
362 {
321
363
322 // This code assume that cach in contigue. Can return 0, 1 or 2 SqpRange
364 // This code assume that cach in contigue. Can return 0, 1 or 2 SqpRange
323 auto notInCache = QVector<SqpRange>{};
365 auto notInCache = QVector<SqpRange>{};
324 if (oldRange != INVALID_RANGE) {
366 if (oldRange != INVALID_RANGE) {
325
367
326 if (!oldRange.contains(nextRange)) {
368 if (!oldRange.contains(nextRange)) {
327 if (nextRange.m_TEnd <= oldRange.m_TStart || nextRange.m_TStart >= oldRange.m_TEnd) {
369 if (nextRange.m_TEnd <= oldRange.m_TStart || nextRange.m_TStart >= oldRange.m_TEnd) {
328 notInCache << nextRange;
370 notInCache << nextRange;
329 }
371 }
330 else if (nextRange.m_TStart < oldRange.m_TStart
372 else if (nextRange.m_TStart < oldRange.m_TStart
331 && nextRange.m_TEnd <= oldRange.m_TEnd) {
373 && nextRange.m_TEnd <= oldRange.m_TEnd) {
332 notInCache << SqpRange{nextRange.m_TStart, oldRange.m_TStart};
374 notInCache << SqpRange{nextRange.m_TStart, oldRange.m_TStart};
333 }
375 }
334 else if (nextRange.m_TStart < oldRange.m_TStart && nextRange.m_TEnd > oldRange.m_TEnd) {
376 else if (nextRange.m_TStart < oldRange.m_TStart && nextRange.m_TEnd > oldRange.m_TEnd) {
335 notInCache << SqpRange{nextRange.m_TStart, oldRange.m_TStart}
377 notInCache << SqpRange{nextRange.m_TStart, oldRange.m_TStart}
336 << SqpRange{oldRange.m_TEnd, nextRange.m_TEnd};
378 << SqpRange{oldRange.m_TEnd, nextRange.m_TEnd};
337 }
379 }
338 else if (nextRange.m_TStart < oldRange.m_TEnd) {
380 else if (nextRange.m_TStart < oldRange.m_TEnd) {
339 notInCache << SqpRange{oldRange.m_TEnd, nextRange.m_TEnd};
381 notInCache << SqpRange{oldRange.m_TEnd, nextRange.m_TEnd};
340 }
382 }
341 else {
383 else {
342 qCCritical(LOG_Variable()) << tr("Detection of unknown case.")
384 qCCritical(LOG_Variable()) << tr("Detection of unknown case.")
343 << QThread::currentThread();
385 << QThread::currentThread();
344 }
386 }
345 }
387 }
346 }
388 }
347 else {
389 else {
348 notInCache << nextRange;
390 notInCache << nextRange;
349 }
391 }
350
392
351 return notInCache;
393 return notInCache;
352 }
394 }
353
395
354 QVector<SqpRange> Variable::provideInCacheRangeList(const SqpRange &oldRange,
396 QVector<SqpRange> Variable::provideInCacheRangeList(const SqpRange &oldRange,
355 const SqpRange &nextRange)
397 const SqpRange &nextRange)
356 {
398 {
357 // This code assume that cach is contigue. Can return 0 or 1 SqpRange
399 // This code assume that cach is contigue. Can return 0 or 1 SqpRange
358
400
359 auto inCache = QVector<SqpRange>{};
401 auto inCache = QVector<SqpRange>{};
360
402
361 if (oldRange != INVALID_RANGE) {
403 if (oldRange != INVALID_RANGE) {
362
404
363 if (oldRange.intersect(nextRange)) {
405 if (oldRange.intersect(nextRange)) {
364 if (nextRange.m_TStart <= oldRange.m_TStart && nextRange.m_TEnd >= oldRange.m_TStart
406 if (nextRange.m_TStart <= oldRange.m_TStart && nextRange.m_TEnd >= oldRange.m_TStart
365 && nextRange.m_TEnd < oldRange.m_TEnd) {
407 && nextRange.m_TEnd < oldRange.m_TEnd) {
366 inCache << SqpRange{oldRange.m_TStart, nextRange.m_TEnd};
408 inCache << SqpRange{oldRange.m_TStart, nextRange.m_TEnd};
367 }
409 }
368
410
369 else if (nextRange.m_TStart >= oldRange.m_TStart
411 else if (nextRange.m_TStart >= oldRange.m_TStart
370 && nextRange.m_TEnd <= oldRange.m_TEnd) {
412 && nextRange.m_TEnd <= oldRange.m_TEnd) {
371 inCache << nextRange;
413 inCache << nextRange;
372 }
414 }
373 else if (nextRange.m_TStart > oldRange.m_TStart && nextRange.m_TEnd > oldRange.m_TEnd) {
415 else if (nextRange.m_TStart > oldRange.m_TStart && nextRange.m_TEnd > oldRange.m_TEnd) {
374 inCache << SqpRange{nextRange.m_TStart, oldRange.m_TEnd};
416 inCache << SqpRange{nextRange.m_TStart, oldRange.m_TEnd};
375 }
417 }
376 else if (nextRange.m_TStart <= oldRange.m_TStart
418 else if (nextRange.m_TStart <= oldRange.m_TStart
377 && nextRange.m_TEnd >= oldRange.m_TEnd) {
419 && nextRange.m_TEnd >= oldRange.m_TEnd) {
378 inCache << oldRange;
420 inCache << oldRange;
379 }
421 }
380 else {
422 else {
381 qCCritical(LOG_Variable()) << tr("Detection of unknown case.")
423 qCCritical(LOG_Variable()) << tr("Detection of unknown case.")
382 << QThread::currentThread();
424 << QThread::currentThread();
383 }
425 }
384 }
426 }
385 }
427 }
386
428
387 return inCache;
429 return inCache;
388 }
430 }
@@ -1,1102 +1,1104
1 #include <Variable/Variable.h>
1 #include <Variable/Variable.h>
2 #include <Variable/VariableAcquisitionWorker.h>
2 #include <Variable/VariableAcquisitionWorker.h>
3 #include <Variable/VariableCacheStrategy.h>
3 #include <Variable/VariableCacheStrategy.h>
4 #include <Variable/VariableCacheStrategyFactory.h>
4 #include <Variable/VariableCacheStrategyFactory.h>
5 #include <Variable/VariableController.h>
5 #include <Variable/VariableController.h>
6 #include <Variable/VariableModel.h>
6 #include <Variable/VariableModel.h>
7 #include <Variable/VariableSynchronizationGroup.h>
7 #include <Variable/VariableSynchronizationGroup.h>
8
8
9 #include <Data/DataProviderParameters.h>
9 #include <Data/DataProviderParameters.h>
10 #include <Data/IDataProvider.h>
10 #include <Data/IDataProvider.h>
11 #include <Data/IDataSeries.h>
11 #include <Data/IDataSeries.h>
12 #include <Data/VariableRequest.h>
12 #include <Data/VariableRequest.h>
13 #include <Time/TimeController.h>
13 #include <Time/TimeController.h>
14
14
15 #include <QDataStream>
15 #include <QDataStream>
16 #include <QMutex>
16 #include <QMutex>
17 #include <QThread>
17 #include <QThread>
18 #include <QUuid>
18 #include <QUuid>
19 #include <QtCore/QItemSelectionModel>
19 #include <QtCore/QItemSelectionModel>
20
20
21 #include <deque>
21 #include <deque>
22 #include <set>
22 #include <set>
23 #include <unordered_map>
23 #include <unordered_map>
24
24
25 Q_LOGGING_CATEGORY(LOG_VariableController, "VariableController")
25 Q_LOGGING_CATEGORY(LOG_VariableController, "VariableController")
26
26
27 namespace {
27 namespace {
28
28
29 SqpRange computeSynchroRangeRequested(const SqpRange &varRange, const SqpRange &graphRange,
29 SqpRange computeSynchroRangeRequested(const SqpRange &varRange, const SqpRange &graphRange,
30 const SqpRange &oldGraphRange)
30 const SqpRange &oldGraphRange)
31 {
31 {
32 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
32 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
33
33
34 auto varRangeRequested = varRange;
34 auto varRangeRequested = varRange;
35 switch (zoomType) {
35 switch (zoomType) {
36 case AcquisitionZoomType::ZoomIn: {
36 case AcquisitionZoomType::ZoomIn: {
37 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
37 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
38 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
38 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
39 varRangeRequested.m_TStart += deltaLeft;
39 varRangeRequested.m_TStart += deltaLeft;
40 varRangeRequested.m_TEnd -= deltaRight;
40 varRangeRequested.m_TEnd -= deltaRight;
41 break;
41 break;
42 }
42 }
43
43
44 case AcquisitionZoomType::ZoomOut: {
44 case AcquisitionZoomType::ZoomOut: {
45 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
45 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
46 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
46 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
47 varRangeRequested.m_TStart -= deltaLeft;
47 varRangeRequested.m_TStart -= deltaLeft;
48 varRangeRequested.m_TEnd += deltaRight;
48 varRangeRequested.m_TEnd += deltaRight;
49 break;
49 break;
50 }
50 }
51 case AcquisitionZoomType::PanRight: {
51 case AcquisitionZoomType::PanRight: {
52 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
52 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
53 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
53 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
54 varRangeRequested.m_TStart += deltaLeft;
54 varRangeRequested.m_TStart += deltaLeft;
55 varRangeRequested.m_TEnd += deltaRight;
55 varRangeRequested.m_TEnd += deltaRight;
56 break;
56 break;
57 }
57 }
58 case AcquisitionZoomType::PanLeft: {
58 case AcquisitionZoomType::PanLeft: {
59 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
59 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
60 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
60 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
61 varRangeRequested.m_TStart -= deltaLeft;
61 varRangeRequested.m_TStart -= deltaLeft;
62 varRangeRequested.m_TEnd -= deltaRight;
62 varRangeRequested.m_TEnd -= deltaRight;
63 break;
63 break;
64 }
64 }
65 case AcquisitionZoomType::Unknown: {
65 case AcquisitionZoomType::Unknown: {
66 qCCritical(LOG_VariableController())
66 qCCritical(LOG_VariableController())
67 << VariableController::tr("Impossible to synchronize: zoom type unknown");
67 << VariableController::tr("Impossible to synchronize: zoom type unknown");
68 break;
68 break;
69 }
69 }
70 default:
70 default:
71 qCCritical(LOG_VariableController()) << VariableController::tr(
71 qCCritical(LOG_VariableController()) << VariableController::tr(
72 "Impossible to synchronize: zoom type not take into account");
72 "Impossible to synchronize: zoom type not take into account");
73 // No action
73 // No action
74 break;
74 break;
75 }
75 }
76
76
77 return varRangeRequested;
77 return varRangeRequested;
78 }
78 }
79 }
79 }
80
80
81 enum class VariableRequestHandlerState { OFF, RUNNING, PENDING };
81 enum class VariableRequestHandlerState { OFF, RUNNING, PENDING };
82
82
83 struct VariableRequestHandler {
83 struct VariableRequestHandler {
84
84
85 VariableRequestHandler()
85 VariableRequestHandler()
86 {
86 {
87 m_CanUpdate = false;
87 m_CanUpdate = false;
88 m_State = VariableRequestHandlerState::OFF;
88 m_State = VariableRequestHandlerState::OFF;
89 }
89 }
90
90
91 QUuid m_VarId;
91 QUuid m_VarId;
92 VariableRequest m_RunningVarRequest;
92 VariableRequest m_RunningVarRequest;
93 VariableRequest m_PendingVarRequest;
93 VariableRequest m_PendingVarRequest;
94 VariableRequestHandlerState m_State;
94 VariableRequestHandlerState m_State;
95 bool m_CanUpdate;
95 bool m_CanUpdate;
96 };
96 };
97
97
98 struct VariableController::VariableControllerPrivate {
98 struct VariableController::VariableControllerPrivate {
99 explicit VariableControllerPrivate(VariableController *parent)
99 explicit VariableControllerPrivate(VariableController *parent)
100 : m_WorkingMutex{},
100 : m_WorkingMutex{},
101 m_VariableModel{new VariableModel{parent}},
101 m_VariableModel{new VariableModel{parent}},
102 m_VariableSelectionModel{new QItemSelectionModel{m_VariableModel, parent}},
102 m_VariableSelectionModel{new QItemSelectionModel{m_VariableModel, parent}},
103 // m_VariableCacheStrategy{std::make_unique<VariableCacheStrategy>()},
103 // m_VariableCacheStrategy{std::make_unique<VariableCacheStrategy>()},
104 m_VariableCacheStrategy{VariableCacheStrategyFactory::createCacheStrategy(
104 m_VariableCacheStrategy{VariableCacheStrategyFactory::createCacheStrategy(
105 CacheStrategy::SingleThreshold)},
105 CacheStrategy::SingleThreshold)},
106 m_VariableAcquisitionWorker{std::make_unique<VariableAcquisitionWorker>()},
106 m_VariableAcquisitionWorker{std::make_unique<VariableAcquisitionWorker>()},
107 q{parent}
107 q{parent}
108 {
108 {
109
109
110 m_VariableAcquisitionWorker->moveToThread(&m_VariableAcquisitionWorkerThread);
110 m_VariableAcquisitionWorker->moveToThread(&m_VariableAcquisitionWorkerThread);
111 m_VariableAcquisitionWorkerThread.setObjectName("VariableAcquisitionWorkerThread");
111 m_VariableAcquisitionWorkerThread.setObjectName("VariableAcquisitionWorkerThread");
112 }
112 }
113
113
114
114
115 virtual ~VariableControllerPrivate()
115 virtual ~VariableControllerPrivate()
116 {
116 {
117 qCDebug(LOG_VariableController()) << tr("VariableControllerPrivate destruction");
117 qCDebug(LOG_VariableController()) << tr("VariableControllerPrivate destruction");
118 m_VariableAcquisitionWorkerThread.quit();
118 m_VariableAcquisitionWorkerThread.quit();
119 m_VariableAcquisitionWorkerThread.wait();
119 m_VariableAcquisitionWorkerThread.wait();
120 }
120 }
121
121
122
122
123 void processRequest(std::shared_ptr<Variable> var, const SqpRange &rangeRequested,
123 void processRequest(std::shared_ptr<Variable> var, const SqpRange &rangeRequested,
124 QUuid varRequestId);
124 QUuid varRequestId);
125
125
126 std::shared_ptr<Variable> findVariable(QUuid vIdentifier);
126 std::shared_ptr<Variable> findVariable(QUuid vIdentifier);
127 std::shared_ptr<IDataSeries>
127 std::shared_ptr<IDataSeries>
128 retrieveDataSeries(const QVector<AcquisitionDataPacket> acqDataPacketVector);
128 retrieveDataSeries(const QVector<AcquisitionDataPacket> acqDataPacketVector);
129
129
130 void registerProvider(std::shared_ptr<IDataProvider> provider);
130 void registerProvider(std::shared_ptr<IDataProvider> provider);
131
131
132 void storeVariableRequest(QUuid varId, QUuid varRequestId, const VariableRequest &varRequest);
132 void storeVariableRequest(QUuid varId, QUuid varRequestId, const VariableRequest &varRequest);
133 QUuid acceptVariableRequest(QUuid varId, std::shared_ptr<IDataSeries> dataSeries);
133 QUuid acceptVariableRequest(QUuid varId, std::shared_ptr<IDataSeries> dataSeries);
134 void updateVariables(QUuid varRequestId);
134 void updateVariables(QUuid varRequestId);
135 void updateVariableRequest(QUuid varRequestId);
135 void updateVariableRequest(QUuid varRequestId);
136 void cancelVariableRequest(QUuid varRequestId);
136 void cancelVariableRequest(QUuid varRequestId);
137 void executeVarRequest(std::shared_ptr<Variable> var, VariableRequest &varRequest);
137 void executeVarRequest(std::shared_ptr<Variable> var, VariableRequest &varRequest);
138
138
139 template <typename VariableIterator>
139 template <typename VariableIterator>
140 void desynchronize(VariableIterator variableIt, const QUuid &syncGroupId);
140 void desynchronize(VariableIterator variableIt, const QUuid &syncGroupId);
141
141
142 QMutex m_WorkingMutex;
142 QMutex m_WorkingMutex;
143 /// Variable model. The VariableController has the ownership
143 /// Variable model. The VariableController has the ownership
144 VariableModel *m_VariableModel;
144 VariableModel *m_VariableModel;
145 QItemSelectionModel *m_VariableSelectionModel;
145 QItemSelectionModel *m_VariableSelectionModel;
146
146
147
147
148 TimeController *m_TimeController{nullptr};
148 TimeController *m_TimeController{nullptr};
149 std::unique_ptr<VariableCacheStrategy> m_VariableCacheStrategy;
149 std::unique_ptr<VariableCacheStrategy> m_VariableCacheStrategy;
150 std::unique_ptr<VariableAcquisitionWorker> m_VariableAcquisitionWorker;
150 std::unique_ptr<VariableAcquisitionWorker> m_VariableAcquisitionWorker;
151 QThread m_VariableAcquisitionWorkerThread;
151 QThread m_VariableAcquisitionWorkerThread;
152
152
153 std::unordered_map<std::shared_ptr<Variable>, std::shared_ptr<IDataProvider> >
153 std::unordered_map<std::shared_ptr<Variable>, std::shared_ptr<IDataProvider> >
154 m_VariableToProviderMap;
154 m_VariableToProviderMap;
155 std::unordered_map<std::shared_ptr<Variable>, QUuid> m_VariableToIdentifierMap;
155 std::unordered_map<std::shared_ptr<Variable>, QUuid> m_VariableToIdentifierMap;
156 std::map<QUuid, std::shared_ptr<VariableSynchronizationGroup> >
156 std::map<QUuid, std::shared_ptr<VariableSynchronizationGroup> >
157 m_GroupIdToVariableSynchronizationGroupMap;
157 m_GroupIdToVariableSynchronizationGroupMap;
158 std::map<QUuid, QUuid> m_VariableIdGroupIdMap;
158 std::map<QUuid, QUuid> m_VariableIdGroupIdMap;
159 std::set<std::shared_ptr<IDataProvider> > m_ProviderSet;
159 std::set<std::shared_ptr<IDataProvider> > m_ProviderSet;
160
160
161 std::map<QUuid, std::list<QUuid> > m_VarGroupIdToVarIds;
161 std::map<QUuid, std::list<QUuid> > m_VarGroupIdToVarIds;
162 std::map<QUuid, std::unique_ptr<VariableRequestHandler> > m_VarIdToVarRequestHandler;
162 std::map<QUuid, std::unique_ptr<VariableRequestHandler> > m_VarIdToVarRequestHandler;
163
163
164 VariableController *q;
164 VariableController *q;
165 };
165 };
166
166
167
167
168 VariableController::VariableController(QObject *parent)
168 VariableController::VariableController(QObject *parent)
169 : QObject{parent}, impl{spimpl::make_unique_impl<VariableControllerPrivate>(this)}
169 : QObject{parent}, impl{spimpl::make_unique_impl<VariableControllerPrivate>(this)}
170 {
170 {
171 qCDebug(LOG_VariableController()) << tr("VariableController construction")
171 qCDebug(LOG_VariableController()) << tr("VariableController construction")
172 << QThread::currentThread();
172 << QThread::currentThread();
173
173
174 connect(impl->m_VariableModel, &VariableModel::abortProgessRequested, this,
174 connect(impl->m_VariableModel, &VariableModel::abortProgessRequested, this,
175 &VariableController::onAbortProgressRequested);
175 &VariableController::onAbortProgressRequested);
176
176
177 connect(impl->m_VariableAcquisitionWorker.get(),
177 connect(impl->m_VariableAcquisitionWorker.get(),
178 &VariableAcquisitionWorker::variableCanceledRequested, this,
178 &VariableAcquisitionWorker::variableCanceledRequested, this,
179 &VariableController::onAbortAcquisitionRequested);
179 &VariableController::onAbortAcquisitionRequested);
180
180
181 connect(impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::dataProvided, this,
181 connect(impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::dataProvided, this,
182 &VariableController::onDataProvided);
182 &VariableController::onDataProvided);
183 connect(impl->m_VariableAcquisitionWorker.get(),
183 connect(impl->m_VariableAcquisitionWorker.get(),
184 &VariableAcquisitionWorker::variableRequestInProgress, this,
184 &VariableAcquisitionWorker::variableRequestInProgress, this,
185 &VariableController::onVariableRetrieveDataInProgress);
185 &VariableController::onVariableRetrieveDataInProgress);
186
186
187
187
188 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::started,
188 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::started,
189 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::initialize);
189 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::initialize);
190 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::finished,
190 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::finished,
191 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::finalize);
191 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::finalize);
192
192
193 connect(impl->m_VariableModel, &VariableModel::requestVariableRangeUpdate, this,
193 connect(impl->m_VariableModel, &VariableModel::requestVariableRangeUpdate, this,
194 &VariableController::onUpdateDateTime);
194 &VariableController::onUpdateDateTime);
195
195
196 impl->m_VariableAcquisitionWorkerThread.start();
196 impl->m_VariableAcquisitionWorkerThread.start();
197 }
197 }
198
198
199 VariableController::~VariableController()
199 VariableController::~VariableController()
200 {
200 {
201 qCDebug(LOG_VariableController()) << tr("VariableController destruction")
201 qCDebug(LOG_VariableController()) << tr("VariableController destruction")
202 << QThread::currentThread();
202 << QThread::currentThread();
203 this->waitForFinish();
203 this->waitForFinish();
204 }
204 }
205
205
206 VariableModel *VariableController::variableModel() noexcept
206 VariableModel *VariableController::variableModel() noexcept
207 {
207 {
208 return impl->m_VariableModel;
208 return impl->m_VariableModel;
209 }
209 }
210
210
211 QItemSelectionModel *VariableController::variableSelectionModel() noexcept
211 QItemSelectionModel *VariableController::variableSelectionModel() noexcept
212 {
212 {
213 return impl->m_VariableSelectionModel;
213 return impl->m_VariableSelectionModel;
214 }
214 }
215
215
216 void VariableController::setTimeController(TimeController *timeController) noexcept
216 void VariableController::setTimeController(TimeController *timeController) noexcept
217 {
217 {
218 impl->m_TimeController = timeController;
218 impl->m_TimeController = timeController;
219 }
219 }
220
220
221 std::shared_ptr<Variable>
221 std::shared_ptr<Variable>
222 VariableController::cloneVariable(std::shared_ptr<Variable> variable) noexcept
222 VariableController::cloneVariable(std::shared_ptr<Variable> variable) noexcept
223 {
223 {
224 if (impl->m_VariableModel->containsVariable(variable)) {
224 if (impl->m_VariableModel->containsVariable(variable)) {
225 // Clones variable
225 // Clones variable
226 auto duplicate = variable->clone();
226 auto duplicate = variable->clone();
227
227
228 // Adds clone to model
228 // Adds clone to model
229 impl->m_VariableModel->addVariable(duplicate);
229 impl->m_VariableModel->addVariable(duplicate);
230
230
231 // Generates clone identifier
231 // Generates clone identifier
232 impl->m_VariableToIdentifierMap[duplicate] = QUuid::createUuid();
232 impl->m_VariableToIdentifierMap[duplicate] = QUuid::createUuid();
233
233
234 // Registers provider
234 // Registers provider
235 auto variableProvider = impl->m_VariableToProviderMap.at(variable);
235 auto variableProvider = impl->m_VariableToProviderMap.at(variable);
236 auto duplicateProvider = variableProvider != nullptr ? variableProvider->clone() : nullptr;
236 auto duplicateProvider = variableProvider != nullptr ? variableProvider->clone() : nullptr;
237
237
238 impl->m_VariableToProviderMap[duplicate] = duplicateProvider;
238 impl->m_VariableToProviderMap[duplicate] = duplicateProvider;
239 if (duplicateProvider) {
239 if (duplicateProvider) {
240 impl->registerProvider(duplicateProvider);
240 impl->registerProvider(duplicateProvider);
241 }
241 }
242
242
243 return duplicate;
243 return duplicate;
244 }
244 }
245 else {
245 else {
246 qCCritical(LOG_VariableController())
246 qCCritical(LOG_VariableController())
247 << tr("Can't create duplicate of variable %1: variable not registered in the model")
247 << tr("Can't create duplicate of variable %1: variable not registered in the model")
248 .arg(variable->name());
248 .arg(variable->name());
249 return nullptr;
249 return nullptr;
250 }
250 }
251 }
251 }
252
252
253 void VariableController::deleteVariable(std::shared_ptr<Variable> variable) noexcept
253 void VariableController::deleteVariable(std::shared_ptr<Variable> variable) noexcept
254 {
254 {
255 if (!variable) {
255 if (!variable) {
256 qCCritical(LOG_VariableController()) << "Can't delete variable: variable is null";
256 qCCritical(LOG_VariableController()) << "Can't delete variable: variable is null";
257 return;
257 return;
258 }
258 }
259
259
260 // Spreads in SciQlop that the variable will be deleted, so that potential receivers can
260 // Spreads in SciQlop that the variable will be deleted, so that potential receivers can
261 // make some treatments before the deletion
261 // make some treatments before the deletion
262 emit variableAboutToBeDeleted(variable);
262 emit variableAboutToBeDeleted(variable);
263
263
264 auto variableIt = impl->m_VariableToIdentifierMap.find(variable);
264 auto variableIt = impl->m_VariableToIdentifierMap.find(variable);
265 Q_ASSERT(variableIt != impl->m_VariableToIdentifierMap.cend());
265 Q_ASSERT(variableIt != impl->m_VariableToIdentifierMap.cend());
266
266
267 auto variableId = variableIt->second;
267 auto variableId = variableIt->second;
268
268
269 // Removes variable's handler
269 // Removes variable's handler
270 impl->m_VarIdToVarRequestHandler.erase(variableId);
270 impl->m_VarIdToVarRequestHandler.erase(variableId);
271
271
272 // Desynchronizes variable (if the variable is in a sync group)
272 // Desynchronizes variable (if the variable is in a sync group)
273 auto syncGroupIt = impl->m_VariableIdGroupIdMap.find(variableId);
273 auto syncGroupIt = impl->m_VariableIdGroupIdMap.find(variableId);
274 if (syncGroupIt != impl->m_VariableIdGroupIdMap.cend()) {
274 if (syncGroupIt != impl->m_VariableIdGroupIdMap.cend()) {
275 impl->desynchronize(variableIt, syncGroupIt->second);
275 impl->desynchronize(variableIt, syncGroupIt->second);
276 }
276 }
277
277
278 // Deletes identifier
278 // Deletes identifier
279 impl->m_VariableToIdentifierMap.erase(variableIt);
279 impl->m_VariableToIdentifierMap.erase(variableIt);
280
280
281 // Deletes provider
281 // Deletes provider
282 auto nbProvidersDeleted = impl->m_VariableToProviderMap.erase(variable);
282 auto nbProvidersDeleted = impl->m_VariableToProviderMap.erase(variable);
283 qCDebug(LOG_VariableController())
283 qCDebug(LOG_VariableController())
284 << tr("Number of providers deleted for variable %1: %2")
284 << tr("Number of providers deleted for variable %1: %2")
285 .arg(variable->name(), QString::number(nbProvidersDeleted));
285 .arg(variable->name(), QString::number(nbProvidersDeleted));
286
286
287
287
288 // Deletes from model
288 // Deletes from model
289 impl->m_VariableModel->deleteVariable(variable);
289 impl->m_VariableModel->deleteVariable(variable);
290 }
290 }
291
291
292 void VariableController::deleteVariables(
292 void VariableController::deleteVariables(
293 const QVector<std::shared_ptr<Variable> > &variables) noexcept
293 const QVector<std::shared_ptr<Variable> > &variables) noexcept
294 {
294 {
295 for (auto variable : qAsConst(variables)) {
295 for (auto variable : qAsConst(variables)) {
296 deleteVariable(variable);
296 deleteVariable(variable);
297 }
297 }
298 }
298 }
299
299
300 QByteArray
300 QByteArray
301 VariableController::mimeDataForVariables(const QList<std::shared_ptr<Variable> > &variables) const
301 VariableController::mimeDataForVariables(const QList<std::shared_ptr<Variable> > &variables) const
302 {
302 {
303 auto encodedData = QByteArray{};
303 auto encodedData = QByteArray{};
304
304
305 QVariantList ids;
305 QVariantList ids;
306 for (auto &var : variables) {
306 for (auto &var : variables) {
307 auto itVar = impl->m_VariableToIdentifierMap.find(var);
307 auto itVar = impl->m_VariableToIdentifierMap.find(var);
308 if (itVar == impl->m_VariableToIdentifierMap.cend()) {
308 if (itVar == impl->m_VariableToIdentifierMap.cend()) {
309 qCCritical(LOG_VariableController())
309 qCCritical(LOG_VariableController())
310 << tr("Impossible to find the data for an unknown variable.");
310 << tr("Impossible to find the data for an unknown variable.");
311 }
311 }
312
312
313 ids << itVar->second.toByteArray();
313 ids << itVar->second.toByteArray();
314 }
314 }
315
315
316 QDataStream stream{&encodedData, QIODevice::WriteOnly};
316 QDataStream stream{&encodedData, QIODevice::WriteOnly};
317 stream << ids;
317 stream << ids;
318
318
319 return encodedData;
319 return encodedData;
320 }
320 }
321
321
322 QList<std::shared_ptr<Variable> >
322 QList<std::shared_ptr<Variable> >
323 VariableController::variablesForMimeData(const QByteArray &mimeData) const
323 VariableController::variablesForMimeData(const QByteArray &mimeData) const
324 {
324 {
325 auto variables = QList<std::shared_ptr<Variable> >{};
325 auto variables = QList<std::shared_ptr<Variable> >{};
326 QDataStream stream{mimeData};
326 QDataStream stream{mimeData};
327
327
328 QVariantList ids;
328 QVariantList ids;
329 stream >> ids;
329 stream >> ids;
330
330
331 for (auto id : ids) {
331 for (auto id : ids) {
332 auto uuid = QUuid{id.toByteArray()};
332 auto uuid = QUuid{id.toByteArray()};
333 auto var = impl->findVariable(uuid);
333 auto var = impl->findVariable(uuid);
334 variables << var;
334 variables << var;
335 }
335 }
336
336
337 return variables;
337 return variables;
338 }
338 }
339
339
340 std::shared_ptr<Variable>
340 std::shared_ptr<Variable>
341 VariableController::createVariable(const QString &name, const QVariantHash &metadata,
341 VariableController::createVariable(const QString &name, const QVariantHash &metadata,
342 std::shared_ptr<IDataProvider> provider) noexcept
342 std::shared_ptr<IDataProvider> provider) noexcept
343 {
343 {
344 if (!impl->m_TimeController) {
344 if (!impl->m_TimeController) {
345 qCCritical(LOG_VariableController())
345 qCCritical(LOG_VariableController())
346 << tr("Impossible to create variable: The time controller is null");
346 << tr("Impossible to create variable: The time controller is null");
347 return nullptr;
347 return nullptr;
348 }
348 }
349
349
350 auto range = impl->m_TimeController->dateTime();
350 auto range = impl->m_TimeController->dateTime();
351
351
352 if (auto newVariable = impl->m_VariableModel->createVariable(name, metadata)) {
352 if (auto newVariable = impl->m_VariableModel->createVariable(name, metadata)) {
353 auto varId = QUuid::createUuid();
353 auto varId = QUuid::createUuid();
354
354
355 // Create the handler
355 // Create the handler
356 auto varRequestHandler = std::make_unique<VariableRequestHandler>();
356 auto varRequestHandler = std::make_unique<VariableRequestHandler>();
357 varRequestHandler->m_VarId = varId;
357 varRequestHandler->m_VarId = varId;
358
358
359 impl->m_VarIdToVarRequestHandler.insert(
359 impl->m_VarIdToVarRequestHandler.insert(
360 std::make_pair(varId, std::move(varRequestHandler)));
360 std::make_pair(varId, std::move(varRequestHandler)));
361
361
362 // store the provider
362 // store the provider
363 impl->registerProvider(provider);
363 impl->registerProvider(provider);
364
364
365 // Associate the provider
365 // Associate the provider
366 impl->m_VariableToProviderMap[newVariable] = provider;
366 impl->m_VariableToProviderMap[newVariable] = provider;
367 impl->m_VariableToIdentifierMap[newVariable] = varId;
367 impl->m_VariableToIdentifierMap[newVariable] = varId;
368
368
369 this->onRequestDataLoading(QVector<std::shared_ptr<Variable> >{newVariable}, range, false);
369 this->onRequestDataLoading(QVector<std::shared_ptr<Variable> >{newVariable}, range, false);
370
370
371 // auto varRequestId = QUuid::createUuid();
371 // auto varRequestId = QUuid::createUuid();
372 // qCInfo(LOG_VariableController()) << "createVariable: " << varId << varRequestId;
372 // qCInfo(LOG_VariableController()) << "createVariable: " << varId << varRequestId;
373 // impl->processRequest(newVariable, range, varRequestId);
373 // impl->processRequest(newVariable, range, varRequestId);
374 // impl->updateVariableRequest(varRequestId);
374 // impl->updateVariableRequest(varRequestId);
375
375
376 emit variableAdded(newVariable);
377
376 return newVariable;
378 return newVariable;
377 }
379 }
378
380
379 qCCritical(LOG_VariableController()) << tr("Impossible to create variable");
381 qCCritical(LOG_VariableController()) << tr("Impossible to create variable");
380 return nullptr;
382 return nullptr;
381 }
383 }
382
384
383 void VariableController::onDateTimeOnSelection(const SqpRange &dateTime)
385 void VariableController::onDateTimeOnSelection(const SqpRange &dateTime)
384 {
386 {
385 // NOTE: Even if acquisition request is aborting, the graphe range will be changed
387 // NOTE: Even if acquisition request is aborting, the graphe range will be changed
386 qCDebug(LOG_VariableController()) << "VariableController::onDateTimeOnSelection"
388 qCDebug(LOG_VariableController()) << "VariableController::onDateTimeOnSelection"
387 << QThread::currentThread()->objectName();
389 << QThread::currentThread()->objectName();
388 auto selectedRows = impl->m_VariableSelectionModel->selectedRows();
390 auto selectedRows = impl->m_VariableSelectionModel->selectedRows();
389
391
390 // NOTE we only permit the time modification for one variable
392 // NOTE we only permit the time modification for one variable
391 // DEPRECATED
393 // DEPRECATED
392 // auto variables = QVector<std::shared_ptr<Variable> >{};
394 // auto variables = QVector<std::shared_ptr<Variable> >{};
393 // for (const auto &selectedRow : qAsConst(selectedRows)) {
395 // for (const auto &selectedRow : qAsConst(selectedRows)) {
394 // if (auto selectedVariable =
396 // if (auto selectedVariable =
395 // impl->m_VariableModel->variable(selectedRow.row())) {
397 // impl->m_VariableModel->variable(selectedRow.row())) {
396 // variables << selectedVariable;
398 // variables << selectedVariable;
397
399
398 // // notify that rescale operation has to be done
400 // // notify that rescale operation has to be done
399 // emit rangeChanged(selectedVariable, dateTime);
401 // emit rangeChanged(selectedVariable, dateTime);
400 // }
402 // }
401 // }
403 // }
402 // if (!variables.isEmpty()) {
404 // if (!variables.isEmpty()) {
403 // this->onRequestDataLoading(variables, dateTime, synchro);
405 // this->onRequestDataLoading(variables, dateTime, synchro);
404 // }
406 // }
405 if (selectedRows.size() == 1) {
407 if (selectedRows.size() == 1) {
406
408
407 if (auto selectedVariable
409 if (auto selectedVariable
408 = impl->m_VariableModel->variable(qAsConst(selectedRows).first().row())) {
410 = impl->m_VariableModel->variable(qAsConst(selectedRows).first().row())) {
409
411
410 onUpdateDateTime(selectedVariable, dateTime);
412 onUpdateDateTime(selectedVariable, dateTime);
411 }
413 }
412 }
414 }
413 else if (selectedRows.size() > 1) {
415 else if (selectedRows.size() > 1) {
414 qCCritical(LOG_VariableController())
416 qCCritical(LOG_VariableController())
415 << tr("Impossible to set time for more than 1 variable in the same time");
417 << tr("Impossible to set time for more than 1 variable in the same time");
416 }
418 }
417 else {
419 else {
418 qCWarning(LOG_VariableController())
420 qCWarning(LOG_VariableController())
419 << tr("There is no variable selected to set the time one");
421 << tr("There is no variable selected to set the time one");
420 }
422 }
421 }
423 }
422
424
423 void VariableController::onUpdateDateTime(std::shared_ptr<Variable> variable,
425 void VariableController::onUpdateDateTime(std::shared_ptr<Variable> variable,
424 const SqpRange &dateTime)
426 const SqpRange &dateTime)
425 {
427 {
426 auto itVar = impl->m_VariableToIdentifierMap.find(variable);
428 auto itVar = impl->m_VariableToIdentifierMap.find(variable);
427 if (itVar == impl->m_VariableToIdentifierMap.cend()) {
429 if (itVar == impl->m_VariableToIdentifierMap.cend()) {
428 qCCritical(LOG_VariableController())
430 qCCritical(LOG_VariableController())
429 << tr("Impossible to onDateTimeOnSelection request for unknown variable");
431 << tr("Impossible to onDateTimeOnSelection request for unknown variable");
430 return;
432 return;
431 }
433 }
432
434
433 // notify that rescale operation has to be done
435 // notify that rescale operation has to be done
434 emit rangeChanged(variable, dateTime);
436 emit rangeChanged(variable, dateTime);
435
437
436 auto synchro
438 auto synchro
437 = impl->m_VariableIdGroupIdMap.find(itVar->second) != impl->m_VariableIdGroupIdMap.cend();
439 = impl->m_VariableIdGroupIdMap.find(itVar->second) != impl->m_VariableIdGroupIdMap.cend();
438
440
439 this->onRequestDataLoading(QVector<std::shared_ptr<Variable> >{variable}, dateTime, synchro);
441 this->onRequestDataLoading(QVector<std::shared_ptr<Variable> >{variable}, dateTime, synchro);
440 }
442 }
441
443
442 void VariableController::onDataProvided(QUuid vIdentifier, const SqpRange &rangeRequested,
444 void VariableController::onDataProvided(QUuid vIdentifier, const SqpRange &rangeRequested,
443 const SqpRange &cacheRangeRequested,
445 const SqpRange &cacheRangeRequested,
444 QVector<AcquisitionDataPacket> dataAcquired)
446 QVector<AcquisitionDataPacket> dataAcquired)
445 {
447 {
446 qCDebug(LOG_VariableController()) << tr("onDataProvided") << QThread::currentThread();
448 qCDebug(LOG_VariableController()) << tr("onDataProvided") << QThread::currentThread();
447 auto retrievedDataSeries = impl->retrieveDataSeries(dataAcquired);
449 auto retrievedDataSeries = impl->retrieveDataSeries(dataAcquired);
448 auto varRequestId = impl->acceptVariableRequest(vIdentifier, retrievedDataSeries);
450 auto varRequestId = impl->acceptVariableRequest(vIdentifier, retrievedDataSeries);
449 if (!varRequestId.isNull()) {
451 if (!varRequestId.isNull()) {
450 impl->updateVariables(varRequestId);
452 impl->updateVariables(varRequestId);
451 }
453 }
452 }
454 }
453
455
454 void VariableController::onVariableRetrieveDataInProgress(QUuid identifier, double progress)
456 void VariableController::onVariableRetrieveDataInProgress(QUuid identifier, double progress)
455 {
457 {
456 qCDebug(LOG_VariableController())
458 qCDebug(LOG_VariableController())
457 << "TORM: variableController::onVariableRetrieveDataInProgress"
459 << "TORM: variableController::onVariableRetrieveDataInProgress"
458 << QThread::currentThread()->objectName() << progress;
460 << QThread::currentThread()->objectName() << progress;
459 if (auto var = impl->findVariable(identifier)) {
461 if (auto var = impl->findVariable(identifier)) {
460 impl->m_VariableModel->setDataProgress(var, progress);
462 impl->m_VariableModel->setDataProgress(var, progress);
461 }
463 }
462 else {
464 else {
463 qCCritical(LOG_VariableController())
465 qCCritical(LOG_VariableController())
464 << tr("Impossible to notify progression of a null variable");
466 << tr("Impossible to notify progression of a null variable");
465 }
467 }
466 }
468 }
467
469
468 void VariableController::onAbortProgressRequested(std::shared_ptr<Variable> variable)
470 void VariableController::onAbortProgressRequested(std::shared_ptr<Variable> variable)
469 {
471 {
470 qCDebug(LOG_VariableController()) << "TORM: variableController::onAbortProgressRequested"
472 qCDebug(LOG_VariableController()) << "TORM: variableController::onAbortProgressRequested"
471 << QThread::currentThread()->objectName() << variable->name();
473 << QThread::currentThread()->objectName() << variable->name();
472
474
473 auto itVar = impl->m_VariableToIdentifierMap.find(variable);
475 auto itVar = impl->m_VariableToIdentifierMap.find(variable);
474 if (itVar == impl->m_VariableToIdentifierMap.cend()) {
476 if (itVar == impl->m_VariableToIdentifierMap.cend()) {
475 qCCritical(LOG_VariableController())
477 qCCritical(LOG_VariableController())
476 << tr("Impossible to onAbortProgressRequested request for unknown variable");
478 << tr("Impossible to onAbortProgressRequested request for unknown variable");
477 return;
479 return;
478 }
480 }
479
481
480 auto varId = itVar->second;
482 auto varId = itVar->second;
481
483
482 auto itVarHandler = impl->m_VarIdToVarRequestHandler.find(varId);
484 auto itVarHandler = impl->m_VarIdToVarRequestHandler.find(varId);
483 if (itVarHandler == impl->m_VarIdToVarRequestHandler.cend()) {
485 if (itVarHandler == impl->m_VarIdToVarRequestHandler.cend()) {
484 qCCritical(LOG_VariableController())
486 qCCritical(LOG_VariableController())
485 << tr("Impossible to onAbortProgressRequested for variable with unknown handler");
487 << tr("Impossible to onAbortProgressRequested for variable with unknown handler");
486 return;
488 return;
487 }
489 }
488
490
489 auto varHandler = itVarHandler->second.get();
491 auto varHandler = itVarHandler->second.get();
490
492
491 // case where a variable has a running request
493 // case where a variable has a running request
492 if (varHandler->m_State != VariableRequestHandlerState::OFF) {
494 if (varHandler->m_State != VariableRequestHandlerState::OFF) {
493 impl->cancelVariableRequest(varHandler->m_RunningVarRequest.m_VariableGroupId);
495 impl->cancelVariableRequest(varHandler->m_RunningVarRequest.m_VariableGroupId);
494 }
496 }
495 }
497 }
496
498
497 void VariableController::onAbortAcquisitionRequested(QUuid vIdentifier)
499 void VariableController::onAbortAcquisitionRequested(QUuid vIdentifier)
498 {
500 {
499 qCDebug(LOG_VariableController()) << "TORM: variableController::onAbortAcquisitionRequested"
501 qCDebug(LOG_VariableController()) << "TORM: variableController::onAbortAcquisitionRequested"
500 << QThread::currentThread()->objectName() << vIdentifier;
502 << QThread::currentThread()->objectName() << vIdentifier;
501
503
502 if (auto var = impl->findVariable(vIdentifier)) {
504 if (auto var = impl->findVariable(vIdentifier)) {
503 this->onAbortProgressRequested(var);
505 this->onAbortProgressRequested(var);
504 }
506 }
505 else {
507 else {
506 qCCritical(LOG_VariableController())
508 qCCritical(LOG_VariableController())
507 << tr("Impossible to abort Acquisition Requestof a null variable");
509 << tr("Impossible to abort Acquisition Requestof a null variable");
508 }
510 }
509 }
511 }
510
512
511 void VariableController::onAddSynchronizationGroupId(QUuid synchronizationGroupId)
513 void VariableController::onAddSynchronizationGroupId(QUuid synchronizationGroupId)
512 {
514 {
513 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronizationGroupId"
515 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronizationGroupId"
514 << QThread::currentThread()->objectName()
516 << QThread::currentThread()->objectName()
515 << synchronizationGroupId;
517 << synchronizationGroupId;
516 auto vSynchroGroup = std::make_shared<VariableSynchronizationGroup>();
518 auto vSynchroGroup = std::make_shared<VariableSynchronizationGroup>();
517 impl->m_GroupIdToVariableSynchronizationGroupMap.insert(
519 impl->m_GroupIdToVariableSynchronizationGroupMap.insert(
518 std::make_pair(synchronizationGroupId, vSynchroGroup));
520 std::make_pair(synchronizationGroupId, vSynchroGroup));
519 }
521 }
520
522
521 void VariableController::onRemoveSynchronizationGroupId(QUuid synchronizationGroupId)
523 void VariableController::onRemoveSynchronizationGroupId(QUuid synchronizationGroupId)
522 {
524 {
523 impl->m_GroupIdToVariableSynchronizationGroupMap.erase(synchronizationGroupId);
525 impl->m_GroupIdToVariableSynchronizationGroupMap.erase(synchronizationGroupId);
524 }
526 }
525
527
526 void VariableController::onAddSynchronized(std::shared_ptr<Variable> variable,
528 void VariableController::onAddSynchronized(std::shared_ptr<Variable> variable,
527 QUuid synchronizationGroupId)
529 QUuid synchronizationGroupId)
528
530
529 {
531 {
530 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronized"
532 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronized"
531 << synchronizationGroupId;
533 << synchronizationGroupId;
532 auto varToVarIdIt = impl->m_VariableToIdentifierMap.find(variable);
534 auto varToVarIdIt = impl->m_VariableToIdentifierMap.find(variable);
533 if (varToVarIdIt != impl->m_VariableToIdentifierMap.cend()) {
535 if (varToVarIdIt != impl->m_VariableToIdentifierMap.cend()) {
534 auto groupIdToVSGIt
536 auto groupIdToVSGIt
535 = impl->m_GroupIdToVariableSynchronizationGroupMap.find(synchronizationGroupId);
537 = impl->m_GroupIdToVariableSynchronizationGroupMap.find(synchronizationGroupId);
536 if (groupIdToVSGIt != impl->m_GroupIdToVariableSynchronizationGroupMap.cend()) {
538 if (groupIdToVSGIt != impl->m_GroupIdToVariableSynchronizationGroupMap.cend()) {
537 impl->m_VariableIdGroupIdMap.insert(
539 impl->m_VariableIdGroupIdMap.insert(
538 std::make_pair(varToVarIdIt->second, synchronizationGroupId));
540 std::make_pair(varToVarIdIt->second, synchronizationGroupId));
539 groupIdToVSGIt->second->addVariableId(varToVarIdIt->second);
541 groupIdToVSGIt->second->addVariableId(varToVarIdIt->second);
540 }
542 }
541 else {
543 else {
542 qCCritical(LOG_VariableController())
544 qCCritical(LOG_VariableController())
543 << tr("Impossible to synchronize a variable with an unknown sycnhronization group")
545 << tr("Impossible to synchronize a variable with an unknown sycnhronization group")
544 << variable->name();
546 << variable->name();
545 }
547 }
546 }
548 }
547 else {
549 else {
548 qCCritical(LOG_VariableController())
550 qCCritical(LOG_VariableController())
549 << tr("Impossible to synchronize a variable with no identifier") << variable->name();
551 << tr("Impossible to synchronize a variable with no identifier") << variable->name();
550 }
552 }
551 }
553 }
552
554
553 void VariableController::desynchronize(std::shared_ptr<Variable> variable,
555 void VariableController::desynchronize(std::shared_ptr<Variable> variable,
554 QUuid synchronizationGroupId)
556 QUuid synchronizationGroupId)
555 {
557 {
556 // Gets variable id
558 // Gets variable id
557 auto variableIt = impl->m_VariableToIdentifierMap.find(variable);
559 auto variableIt = impl->m_VariableToIdentifierMap.find(variable);
558 if (variableIt == impl->m_VariableToIdentifierMap.cend()) {
560 if (variableIt == impl->m_VariableToIdentifierMap.cend()) {
559 qCCritical(LOG_VariableController())
561 qCCritical(LOG_VariableController())
560 << tr("Can't desynchronize variable %1: variable identifier not found")
562 << tr("Can't desynchronize variable %1: variable identifier not found")
561 .arg(variable->name());
563 .arg(variable->name());
562 return;
564 return;
563 }
565 }
564
566
565 impl->desynchronize(variableIt, synchronizationGroupId);
567 impl->desynchronize(variableIt, synchronizationGroupId);
566 }
568 }
567
569
568 void VariableController::onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables,
570 void VariableController::onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables,
569 const SqpRange &range, bool synchronise)
571 const SqpRange &range, bool synchronise)
570 {
572 {
571 // variables is assumed synchronized
573 // variables is assumed synchronized
572 // TODO: Asser variables synchronization
574 // TODO: Asser variables synchronization
573 // we want to load data of the variable for the dateTime.
575 // we want to load data of the variable for the dateTime.
574 if (variables.isEmpty()) {
576 if (variables.isEmpty()) {
575 return;
577 return;
576 }
578 }
577
579
578 auto varRequestId = QUuid::createUuid();
580 auto varRequestId = QUuid::createUuid();
579 qCDebug(LOG_VariableController()) << "VariableController::onRequestDataLoading"
581 qCDebug(LOG_VariableController()) << "VariableController::onRequestDataLoading"
580 << QThread::currentThread()->objectName() << varRequestId
582 << QThread::currentThread()->objectName() << varRequestId
581 << range << synchronise;
583 << range << synchronise;
582
584
583 if (!synchronise) {
585 if (!synchronise) {
584 auto varIds = std::list<QUuid>{};
586 auto varIds = std::list<QUuid>{};
585 for (const auto &var : variables) {
587 for (const auto &var : variables) {
586 auto vId = impl->m_VariableToIdentifierMap.at(var);
588 auto vId = impl->m_VariableToIdentifierMap.at(var);
587 varIds.push_back(vId);
589 varIds.push_back(vId);
588 }
590 }
589 impl->m_VarGroupIdToVarIds.insert(std::make_pair(varRequestId, varIds));
591 impl->m_VarGroupIdToVarIds.insert(std::make_pair(varRequestId, varIds));
590 for (const auto &var : variables) {
592 for (const auto &var : variables) {
591 qCDebug(LOG_VariableController()) << "processRequest for" << var->name() << varRequestId
593 qCDebug(LOG_VariableController()) << "processRequest for" << var->name() << varRequestId
592 << varIds.size();
594 << varIds.size();
593 impl->processRequest(var, range, varRequestId);
595 impl->processRequest(var, range, varRequestId);
594 }
596 }
595 }
597 }
596 else {
598 else {
597 auto vId = impl->m_VariableToIdentifierMap.at(variables.first());
599 auto vId = impl->m_VariableToIdentifierMap.at(variables.first());
598 auto varIdToGroupIdIt = impl->m_VariableIdGroupIdMap.find(vId);
600 auto varIdToGroupIdIt = impl->m_VariableIdGroupIdMap.find(vId);
599 if (varIdToGroupIdIt != impl->m_VariableIdGroupIdMap.cend()) {
601 if (varIdToGroupIdIt != impl->m_VariableIdGroupIdMap.cend()) {
600 auto groupId = varIdToGroupIdIt->second;
602 auto groupId = varIdToGroupIdIt->second;
601
603
602 auto vSynchronizationGroup
604 auto vSynchronizationGroup
603 = impl->m_GroupIdToVariableSynchronizationGroupMap.at(groupId);
605 = impl->m_GroupIdToVariableSynchronizationGroupMap.at(groupId);
604 auto vSyncIds = vSynchronizationGroup->getIds();
606 auto vSyncIds = vSynchronizationGroup->getIds();
605
607
606 auto varIds = std::list<QUuid>{};
608 auto varIds = std::list<QUuid>{};
607 for (auto vId : vSyncIds) {
609 for (auto vId : vSyncIds) {
608 varIds.push_back(vId);
610 varIds.push_back(vId);
609 }
611 }
610 impl->m_VarGroupIdToVarIds.insert(std::make_pair(varRequestId, varIds));
612 impl->m_VarGroupIdToVarIds.insert(std::make_pair(varRequestId, varIds));
611
613
612 for (auto vId : vSyncIds) {
614 for (auto vId : vSyncIds) {
613 auto var = impl->findVariable(vId);
615 auto var = impl->findVariable(vId);
614
616
615 // Don't process already processed var
617 // Don't process already processed var
616 if (var != nullptr) {
618 if (var != nullptr) {
617 qCDebug(LOG_VariableController()) << "processRequest synchro for" << var->name()
619 qCDebug(LOG_VariableController()) << "processRequest synchro for" << var->name()
618 << varRequestId;
620 << varRequestId;
619 auto vSyncRangeRequested
621 auto vSyncRangeRequested
620 = variables.contains(var)
622 = variables.contains(var)
621 ? range
623 ? range
622 : computeSynchroRangeRequested(var->range(), range,
624 : computeSynchroRangeRequested(var->range(), range,
623 variables.first()->range());
625 variables.first()->range());
624 qCDebug(LOG_VariableController()) << "synchro RR" << vSyncRangeRequested;
626 qCDebug(LOG_VariableController()) << "synchro RR" << vSyncRangeRequested;
625 impl->processRequest(var, vSyncRangeRequested, varRequestId);
627 impl->processRequest(var, vSyncRangeRequested, varRequestId);
626 }
628 }
627 else {
629 else {
628 qCCritical(LOG_VariableController())
630 qCCritical(LOG_VariableController())
629
631
630 << tr("Impossible to synchronize a null variable");
632 << tr("Impossible to synchronize a null variable");
631 }
633 }
632 }
634 }
633 }
635 }
634 }
636 }
635
637
636 impl->updateVariables(varRequestId);
638 impl->updateVariables(varRequestId);
637 }
639 }
638
640
639
641
640 void VariableController::initialize()
642 void VariableController::initialize()
641 {
643 {
642 qCDebug(LOG_VariableController()) << tr("VariableController init") << QThread::currentThread();
644 qCDebug(LOG_VariableController()) << tr("VariableController init") << QThread::currentThread();
643 impl->m_WorkingMutex.lock();
645 impl->m_WorkingMutex.lock();
644 qCDebug(LOG_VariableController()) << tr("VariableController init END");
646 qCDebug(LOG_VariableController()) << tr("VariableController init END");
645 }
647 }
646
648
647 void VariableController::finalize()
649 void VariableController::finalize()
648 {
650 {
649 impl->m_WorkingMutex.unlock();
651 impl->m_WorkingMutex.unlock();
650 }
652 }
651
653
652 void VariableController::waitForFinish()
654 void VariableController::waitForFinish()
653 {
655 {
654 QMutexLocker locker{&impl->m_WorkingMutex};
656 QMutexLocker locker{&impl->m_WorkingMutex};
655 }
657 }
656
658
657 AcquisitionZoomType VariableController::getZoomType(const SqpRange &range, const SqpRange &oldRange)
659 AcquisitionZoomType VariableController::getZoomType(const SqpRange &range, const SqpRange &oldRange)
658 {
660 {
659 // t1.m_TStart <= t2.m_TStart && t2.m_TEnd <= t1.m_TEnd
661 // t1.m_TStart <= t2.m_TStart && t2.m_TEnd <= t1.m_TEnd
660 auto zoomType = AcquisitionZoomType::Unknown;
662 auto zoomType = AcquisitionZoomType::Unknown;
661 if (range.m_TStart <= oldRange.m_TStart && oldRange.m_TEnd <= range.m_TEnd) {
663 if (range.m_TStart <= oldRange.m_TStart && oldRange.m_TEnd <= range.m_TEnd) {
662 qCDebug(LOG_VariableController()) << "zoomtype: ZoomOut";
664 qCDebug(LOG_VariableController()) << "zoomtype: ZoomOut";
663 zoomType = AcquisitionZoomType::ZoomOut;
665 zoomType = AcquisitionZoomType::ZoomOut;
664 }
666 }
665 else if (range.m_TStart > oldRange.m_TStart && range.m_TEnd > oldRange.m_TEnd) {
667 else if (range.m_TStart > oldRange.m_TStart && range.m_TEnd > oldRange.m_TEnd) {
666 qCDebug(LOG_VariableController()) << "zoomtype: PanRight";
668 qCDebug(LOG_VariableController()) << "zoomtype: PanRight";
667 zoomType = AcquisitionZoomType::PanRight;
669 zoomType = AcquisitionZoomType::PanRight;
668 }
670 }
669 else if (range.m_TStart < oldRange.m_TStart && range.m_TEnd < oldRange.m_TEnd) {
671 else if (range.m_TStart < oldRange.m_TStart && range.m_TEnd < oldRange.m_TEnd) {
670 qCDebug(LOG_VariableController()) << "zoomtype: PanLeft";
672 qCDebug(LOG_VariableController()) << "zoomtype: PanLeft";
671 zoomType = AcquisitionZoomType::PanLeft;
673 zoomType = AcquisitionZoomType::PanLeft;
672 }
674 }
673 else if (range.m_TStart >= oldRange.m_TStart && oldRange.m_TEnd >= range.m_TEnd) {
675 else if (range.m_TStart >= oldRange.m_TStart && oldRange.m_TEnd >= range.m_TEnd) {
674 qCDebug(LOG_VariableController()) << "zoomtype: ZoomIn";
676 qCDebug(LOG_VariableController()) << "zoomtype: ZoomIn";
675 zoomType = AcquisitionZoomType::ZoomIn;
677 zoomType = AcquisitionZoomType::ZoomIn;
676 }
678 }
677 else {
679 else {
678 qCDebug(LOG_VariableController()) << "getZoomType: Unknown type detected";
680 qCDebug(LOG_VariableController()) << "getZoomType: Unknown type detected";
679 }
681 }
680 return zoomType;
682 return zoomType;
681 }
683 }
682
684
683 void VariableController::VariableControllerPrivate::processRequest(std::shared_ptr<Variable> var,
685 void VariableController::VariableControllerPrivate::processRequest(std::shared_ptr<Variable> var,
684 const SqpRange &rangeRequested,
686 const SqpRange &rangeRequested,
685 QUuid varRequestId)
687 QUuid varRequestId)
686 {
688 {
687 auto itVar = m_VariableToIdentifierMap.find(var);
689 auto itVar = m_VariableToIdentifierMap.find(var);
688 if (itVar == m_VariableToIdentifierMap.cend()) {
690 if (itVar == m_VariableToIdentifierMap.cend()) {
689 qCCritical(LOG_VariableController())
691 qCCritical(LOG_VariableController())
690 << tr("Impossible to process request for unknown variable");
692 << tr("Impossible to process request for unknown variable");
691 return;
693 return;
692 }
694 }
693
695
694 auto varId = itVar->second;
696 auto varId = itVar->second;
695
697
696 auto itVarHandler = m_VarIdToVarRequestHandler.find(varId);
698 auto itVarHandler = m_VarIdToVarRequestHandler.find(varId);
697 if (itVarHandler == m_VarIdToVarRequestHandler.cend()) {
699 if (itVarHandler == m_VarIdToVarRequestHandler.cend()) {
698 qCCritical(LOG_VariableController())
700 qCCritical(LOG_VariableController())
699 << tr("Impossible to process request for variable with unknown handler");
701 << tr("Impossible to process request for variable with unknown handler");
700 return;
702 return;
701 }
703 }
702
704
703 auto oldRange = var->range();
705 auto oldRange = var->range();
704
706
705 auto varHandler = itVarHandler->second.get();
707 auto varHandler = itVarHandler->second.get();
706
708
707 if (varHandler->m_State != VariableRequestHandlerState::OFF) {
709 if (varHandler->m_State != VariableRequestHandlerState::OFF) {
708 oldRange = varHandler->m_RunningVarRequest.m_RangeRequested;
710 oldRange = varHandler->m_RunningVarRequest.m_RangeRequested;
709 }
711 }
710
712
711 auto varRequest = VariableRequest{};
713 auto varRequest = VariableRequest{};
712 varRequest.m_VariableGroupId = varRequestId;
714 varRequest.m_VariableGroupId = varRequestId;
713 auto varStrategyRangesRequested
715 auto varStrategyRangesRequested
714 = m_VariableCacheStrategy->computeRange(oldRange, rangeRequested);
716 = m_VariableCacheStrategy->computeRange(oldRange, rangeRequested);
715 varRequest.m_RangeRequested = varStrategyRangesRequested.first;
717 varRequest.m_RangeRequested = varStrategyRangesRequested.first;
716 varRequest.m_CacheRangeRequested = varStrategyRangesRequested.second;
718 varRequest.m_CacheRangeRequested = varStrategyRangesRequested.second;
717
719
718 switch (varHandler->m_State) {
720 switch (varHandler->m_State) {
719 case VariableRequestHandlerState::OFF: {
721 case VariableRequestHandlerState::OFF: {
720 qCDebug(LOG_VariableController()) << tr("Process Request OFF")
722 qCDebug(LOG_VariableController()) << tr("Process Request OFF")
721 << varRequest.m_RangeRequested
723 << varRequest.m_RangeRequested
722 << varRequest.m_CacheRangeRequested;
724 << varRequest.m_CacheRangeRequested;
723 varHandler->m_RunningVarRequest = varRequest;
725 varHandler->m_RunningVarRequest = varRequest;
724 varHandler->m_State = VariableRequestHandlerState::RUNNING;
726 varHandler->m_State = VariableRequestHandlerState::RUNNING;
725 executeVarRequest(var, varRequest);
727 executeVarRequest(var, varRequest);
726 break;
728 break;
727 }
729 }
728 case VariableRequestHandlerState::RUNNING: {
730 case VariableRequestHandlerState::RUNNING: {
729 qCDebug(LOG_VariableController()) << tr("Process Request RUNNING")
731 qCDebug(LOG_VariableController()) << tr("Process Request RUNNING")
730 << varRequest.m_RangeRequested
732 << varRequest.m_RangeRequested
731 << varRequest.m_CacheRangeRequested;
733 << varRequest.m_CacheRangeRequested;
732 varHandler->m_State = VariableRequestHandlerState::PENDING;
734 varHandler->m_State = VariableRequestHandlerState::PENDING;
733 varHandler->m_PendingVarRequest = varRequest;
735 varHandler->m_PendingVarRequest = varRequest;
734 break;
736 break;
735 }
737 }
736 case VariableRequestHandlerState::PENDING: {
738 case VariableRequestHandlerState::PENDING: {
737 qCDebug(LOG_VariableController()) << tr("Process Request PENDING")
739 qCDebug(LOG_VariableController()) << tr("Process Request PENDING")
738 << varRequest.m_RangeRequested
740 << varRequest.m_RangeRequested
739 << varRequest.m_CacheRangeRequested;
741 << varRequest.m_CacheRangeRequested;
740 auto variableGroupIdToCancel = varHandler->m_PendingVarRequest.m_VariableGroupId;
742 auto variableGroupIdToCancel = varHandler->m_PendingVarRequest.m_VariableGroupId;
741 cancelVariableRequest(variableGroupIdToCancel);
743 cancelVariableRequest(variableGroupIdToCancel);
742 // Cancel variable can make state downgrade
744 // Cancel variable can make state downgrade
743 varHandler->m_State = VariableRequestHandlerState::PENDING;
745 varHandler->m_State = VariableRequestHandlerState::PENDING;
744 varHandler->m_PendingVarRequest = varRequest;
746 varHandler->m_PendingVarRequest = varRequest;
745
747
746 break;
748 break;
747 }
749 }
748 default:
750 default:
749 qCCritical(LOG_VariableController())
751 qCCritical(LOG_VariableController())
750 << QObject::tr("Unknown VariableRequestHandlerState");
752 << QObject::tr("Unknown VariableRequestHandlerState");
751 }
753 }
752 }
754 }
753
755
754 std::shared_ptr<Variable>
756 std::shared_ptr<Variable>
755 VariableController::VariableControllerPrivate::findVariable(QUuid vIdentifier)
757 VariableController::VariableControllerPrivate::findVariable(QUuid vIdentifier)
756 {
758 {
757 std::shared_ptr<Variable> var;
759 std::shared_ptr<Variable> var;
758 auto findReply = [vIdentifier](const auto &entry) { return vIdentifier == entry.second; };
760 auto findReply = [vIdentifier](const auto &entry) { return vIdentifier == entry.second; };
759
761
760 auto end = m_VariableToIdentifierMap.cend();
762 auto end = m_VariableToIdentifierMap.cend();
761 auto it = std::find_if(m_VariableToIdentifierMap.cbegin(), end, findReply);
763 auto it = std::find_if(m_VariableToIdentifierMap.cbegin(), end, findReply);
762 if (it != end) {
764 if (it != end) {
763 var = it->first;
765 var = it->first;
764 }
766 }
765 else {
767 else {
766 qCCritical(LOG_VariableController())
768 qCCritical(LOG_VariableController())
767 << tr("Impossible to find the variable with the identifier: ") << vIdentifier;
769 << tr("Impossible to find the variable with the identifier: ") << vIdentifier;
768 }
770 }
769
771
770 return var;
772 return var;
771 }
773 }
772
774
773 std::shared_ptr<IDataSeries> VariableController::VariableControllerPrivate::retrieveDataSeries(
775 std::shared_ptr<IDataSeries> VariableController::VariableControllerPrivate::retrieveDataSeries(
774 const QVector<AcquisitionDataPacket> acqDataPacketVector)
776 const QVector<AcquisitionDataPacket> acqDataPacketVector)
775 {
777 {
776 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size")
778 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size")
777 << acqDataPacketVector.size();
779 << acqDataPacketVector.size();
778 std::shared_ptr<IDataSeries> dataSeries;
780 std::shared_ptr<IDataSeries> dataSeries;
779 if (!acqDataPacketVector.isEmpty()) {
781 if (!acqDataPacketVector.isEmpty()) {
780 dataSeries = acqDataPacketVector[0].m_DateSeries;
782 dataSeries = acqDataPacketVector[0].m_DateSeries;
781 for (int i = 1; i < acqDataPacketVector.size(); ++i) {
783 for (int i = 1; i < acqDataPacketVector.size(); ++i) {
782 dataSeries->merge(acqDataPacketVector[i].m_DateSeries.get());
784 dataSeries->merge(acqDataPacketVector[i].m_DateSeries.get());
783 }
785 }
784 }
786 }
785 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size END")
787 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size END")
786 << acqDataPacketVector.size();
788 << acqDataPacketVector.size();
787 return dataSeries;
789 return dataSeries;
788 }
790 }
789
791
790 void VariableController::VariableControllerPrivate::registerProvider(
792 void VariableController::VariableControllerPrivate::registerProvider(
791 std::shared_ptr<IDataProvider> provider)
793 std::shared_ptr<IDataProvider> provider)
792 {
794 {
793 if (m_ProviderSet.find(provider) == m_ProviderSet.end()) {
795 if (m_ProviderSet.find(provider) == m_ProviderSet.end()) {
794 qCDebug(LOG_VariableController()) << tr("Registering of a new provider")
796 qCDebug(LOG_VariableController()) << tr("Registering of a new provider")
795 << provider->objectName();
797 << provider->objectName();
796 m_ProviderSet.insert(provider);
798 m_ProviderSet.insert(provider);
797 connect(provider.get(), &IDataProvider::dataProvided, m_VariableAcquisitionWorker.get(),
799 connect(provider.get(), &IDataProvider::dataProvided, m_VariableAcquisitionWorker.get(),
798 &VariableAcquisitionWorker::onVariableDataAcquired);
800 &VariableAcquisitionWorker::onVariableDataAcquired);
799 connect(provider.get(), &IDataProvider::dataProvidedProgress,
801 connect(provider.get(), &IDataProvider::dataProvidedProgress,
800 m_VariableAcquisitionWorker.get(),
802 m_VariableAcquisitionWorker.get(),
801 &VariableAcquisitionWorker::onVariableRetrieveDataInProgress);
803 &VariableAcquisitionWorker::onVariableRetrieveDataInProgress);
802 connect(provider.get(), &IDataProvider::dataProvidedFailed,
804 connect(provider.get(), &IDataProvider::dataProvidedFailed,
803 m_VariableAcquisitionWorker.get(),
805 m_VariableAcquisitionWorker.get(),
804 &VariableAcquisitionWorker::onVariableAcquisitionFailed);
806 &VariableAcquisitionWorker::onVariableAcquisitionFailed);
805 }
807 }
806 else {
808 else {
807 qCDebug(LOG_VariableController()) << tr("Cannot register provider, it already exists ");
809 qCDebug(LOG_VariableController()) << tr("Cannot register provider, it already exists ");
808 }
810 }
809 }
811 }
810
812
811 QUuid VariableController::VariableControllerPrivate::acceptVariableRequest(
813 QUuid VariableController::VariableControllerPrivate::acceptVariableRequest(
812 QUuid varId, std::shared_ptr<IDataSeries> dataSeries)
814 QUuid varId, std::shared_ptr<IDataSeries> dataSeries)
813 {
815 {
814 auto itVarHandler = m_VarIdToVarRequestHandler.find(varId);
816 auto itVarHandler = m_VarIdToVarRequestHandler.find(varId);
815 if (itVarHandler == m_VarIdToVarRequestHandler.cend()) {
817 if (itVarHandler == m_VarIdToVarRequestHandler.cend()) {
816 return QUuid();
818 return QUuid();
817 }
819 }
818
820
819 auto varHandler = itVarHandler->second.get();
821 auto varHandler = itVarHandler->second.get();
820 if (varHandler->m_State == VariableRequestHandlerState::OFF) {
822 if (varHandler->m_State == VariableRequestHandlerState::OFF) {
821 qCCritical(LOG_VariableController())
823 qCCritical(LOG_VariableController())
822 << tr("acceptVariableRequest impossible on a variable with OFF state");
824 << tr("acceptVariableRequest impossible on a variable with OFF state");
823 }
825 }
824
826
825 varHandler->m_RunningVarRequest.m_DataSeries = dataSeries;
827 varHandler->m_RunningVarRequest.m_DataSeries = dataSeries;
826 varHandler->m_CanUpdate = true;
828 varHandler->m_CanUpdate = true;
827
829
828 // Element traité, on a déjà toutes les données necessaires
830 // Element traité, on a déjà toutes les données necessaires
829 auto varGroupId = varHandler->m_RunningVarRequest.m_VariableGroupId;
831 auto varGroupId = varHandler->m_RunningVarRequest.m_VariableGroupId;
830 qCDebug(LOG_VariableController()) << "Variable::acceptVariableRequest" << varGroupId
832 qCDebug(LOG_VariableController()) << "Variable::acceptVariableRequest" << varGroupId
831 << m_VarGroupIdToVarIds.size();
833 << m_VarGroupIdToVarIds.size();
832
834
833 return varHandler->m_RunningVarRequest.m_VariableGroupId;
835 return varHandler->m_RunningVarRequest.m_VariableGroupId;
834 }
836 }
835
837
836 void VariableController::VariableControllerPrivate::updateVariables(QUuid varRequestId)
838 void VariableController::VariableControllerPrivate::updateVariables(QUuid varRequestId)
837 {
839 {
838 qCDebug(LOG_VariableController()) << "VariableControllerPrivate::updateVariables"
840 qCDebug(LOG_VariableController()) << "VariableControllerPrivate::updateVariables"
839 << QThread::currentThread()->objectName() << varRequestId;
841 << QThread::currentThread()->objectName() << varRequestId;
840
842
841 auto varGroupIdToVarIdsIt = m_VarGroupIdToVarIds.find(varRequestId);
843 auto varGroupIdToVarIdsIt = m_VarGroupIdToVarIds.find(varRequestId);
842 if (varGroupIdToVarIdsIt == m_VarGroupIdToVarIds.end()) {
844 if (varGroupIdToVarIdsIt == m_VarGroupIdToVarIds.end()) {
843 qCWarning(LOG_VariableController())
845 qCWarning(LOG_VariableController())
844 << tr("Impossible to updateVariables of unknown variables") << varRequestId;
846 << tr("Impossible to updateVariables of unknown variables") << varRequestId;
845 return;
847 return;
846 }
848 }
847
849
848 auto &varIds = varGroupIdToVarIdsIt->second;
850 auto &varIds = varGroupIdToVarIdsIt->second;
849 auto varIdsEnd = varIds.end();
851 auto varIdsEnd = varIds.end();
850 bool processVariableUpdate = true;
852 bool processVariableUpdate = true;
851 qCDebug(LOG_VariableController()) << "VariableControllerPrivate::updateVariables"
853 qCDebug(LOG_VariableController()) << "VariableControllerPrivate::updateVariables"
852 << varRequestId << varIds.size();
854 << varRequestId << varIds.size();
853 for (auto varIdsIt = varIds.begin(); (varIdsIt != varIdsEnd) && processVariableUpdate;
855 for (auto varIdsIt = varIds.begin(); (varIdsIt != varIdsEnd) && processVariableUpdate;
854 ++varIdsIt) {
856 ++varIdsIt) {
855 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
857 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
856 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
858 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
857 processVariableUpdate &= itVarHandler->second->m_CanUpdate;
859 processVariableUpdate &= itVarHandler->second->m_CanUpdate;
858 }
860 }
859 }
861 }
860
862
861 if (processVariableUpdate) {
863 if (processVariableUpdate) {
862 qCDebug(LOG_VariableController()) << "Final update OK for the var request" << varIds.size();
864 qCDebug(LOG_VariableController()) << "Final update OK for the var request" << varIds.size();
863 for (auto varIdsIt = varIds.begin(); varIdsIt != varIdsEnd; ++varIdsIt) {
865 for (auto varIdsIt = varIds.begin(); varIdsIt != varIdsEnd; ++varIdsIt) {
864 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
866 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
865 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
867 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
866 if (auto var = findVariable(*varIdsIt)) {
868 if (auto var = findVariable(*varIdsIt)) {
867 auto &varRequest = itVarHandler->second->m_RunningVarRequest;
869 auto &varRequest = itVarHandler->second->m_RunningVarRequest;
868 var->setRange(varRequest.m_RangeRequested);
870 var->setRange(varRequest.m_RangeRequested);
869 var->setCacheRange(varRequest.m_CacheRangeRequested);
871 var->setCacheRange(varRequest.m_CacheRangeRequested);
870 qCDebug(LOG_VariableController()) << tr("1: onDataProvided")
872 qCDebug(LOG_VariableController()) << tr("1: onDataProvided")
871 << varRequest.m_RangeRequested
873 << varRequest.m_RangeRequested
872 << varRequest.m_CacheRangeRequested;
874 << varRequest.m_CacheRangeRequested;
873 qCDebug(LOG_VariableController()) << tr("2: onDataProvided var points before")
875 qCDebug(LOG_VariableController()) << tr("2: onDataProvided var points before")
874 << var->nbPoints()
876 << var->nbPoints()
875 << varRequest.m_DataSeries->nbPoints();
877 << varRequest.m_DataSeries->nbPoints();
876 var->mergeDataSeries(varRequest.m_DataSeries);
878 var->mergeDataSeries(varRequest.m_DataSeries);
877 qCDebug(LOG_VariableController()) << tr("3: onDataProvided var points after")
879 qCDebug(LOG_VariableController()) << tr("3: onDataProvided var points after")
878 << var->nbPoints();
880 << var->nbPoints();
879
881
880 emit var->updated();
882 emit var->updated();
881 qCDebug(LOG_VariableController()) << tr("Update OK");
883 qCDebug(LOG_VariableController()) << tr("Update OK");
882 }
884 }
883 else {
885 else {
884 qCCritical(LOG_VariableController())
886 qCCritical(LOG_VariableController())
885 << tr("Impossible to update data to a null variable");
887 << tr("Impossible to update data to a null variable");
886 }
888 }
887 }
889 }
888 }
890 }
889 updateVariableRequest(varRequestId);
891 updateVariableRequest(varRequestId);
890
892
891 // cleaning varRequestId
893 // cleaning varRequestId
892 qCDebug(LOG_VariableController()) << tr("m_VarGroupIdToVarIds erase") << varRequestId;
894 qCDebug(LOG_VariableController()) << tr("m_VarGroupIdToVarIds erase") << varRequestId;
893 m_VarGroupIdToVarIds.erase(varRequestId);
895 m_VarGroupIdToVarIds.erase(varRequestId);
894 if (m_VarGroupIdToVarIds.empty()) {
896 if (m_VarGroupIdToVarIds.empty()) {
895 emit q->acquisitionFinished();
897 emit q->acquisitionFinished();
896 }
898 }
897 }
899 }
898 }
900 }
899
901
900
902
901 void VariableController::VariableControllerPrivate::updateVariableRequest(QUuid varRequestId)
903 void VariableController::VariableControllerPrivate::updateVariableRequest(QUuid varRequestId)
902 {
904 {
903 auto varGroupIdToVarIdsIt = m_VarGroupIdToVarIds.find(varRequestId);
905 auto varGroupIdToVarIdsIt = m_VarGroupIdToVarIds.find(varRequestId);
904 if (varGroupIdToVarIdsIt == m_VarGroupIdToVarIds.end()) {
906 if (varGroupIdToVarIdsIt == m_VarGroupIdToVarIds.end()) {
905 qCCritical(LOG_VariableController()) << QObject::tr(
907 qCCritical(LOG_VariableController()) << QObject::tr(
906 "Impossible to updateVariableRequest since varGroupdId isn't here anymore");
908 "Impossible to updateVariableRequest since varGroupdId isn't here anymore");
907
909
908 return;
910 return;
909 }
911 }
910
912
911 auto &varIds = varGroupIdToVarIdsIt->second;
913 auto &varIds = varGroupIdToVarIdsIt->second;
912 auto varIdsEnd = varIds.end();
914 auto varIdsEnd = varIds.end();
913 for (auto varIdsIt = varIds.begin(); (varIdsIt != varIdsEnd); ++varIdsIt) {
915 for (auto varIdsIt = varIds.begin(); (varIdsIt != varIdsEnd); ++varIdsIt) {
914 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
916 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
915 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
917 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
916
918
917 auto varHandler = itVarHandler->second.get();
919 auto varHandler = itVarHandler->second.get();
918 varHandler->m_CanUpdate = false;
920 varHandler->m_CanUpdate = false;
919
921
920
922
921 switch (varHandler->m_State) {
923 switch (varHandler->m_State) {
922 case VariableRequestHandlerState::OFF: {
924 case VariableRequestHandlerState::OFF: {
923 qCCritical(LOG_VariableController())
925 qCCritical(LOG_VariableController())
924 << QObject::tr("Impossible to update a variable with handler in OFF state");
926 << QObject::tr("Impossible to update a variable with handler in OFF state");
925 } break;
927 } break;
926 case VariableRequestHandlerState::RUNNING: {
928 case VariableRequestHandlerState::RUNNING: {
927 varHandler->m_State = VariableRequestHandlerState::OFF;
929 varHandler->m_State = VariableRequestHandlerState::OFF;
928 varHandler->m_RunningVarRequest = VariableRequest{};
930 varHandler->m_RunningVarRequest = VariableRequest{};
929 break;
931 break;
930 }
932 }
931 case VariableRequestHandlerState::PENDING: {
933 case VariableRequestHandlerState::PENDING: {
932 varHandler->m_State = VariableRequestHandlerState::RUNNING;
934 varHandler->m_State = VariableRequestHandlerState::RUNNING;
933 varHandler->m_RunningVarRequest = varHandler->m_PendingVarRequest;
935 varHandler->m_RunningVarRequest = varHandler->m_PendingVarRequest;
934 varHandler->m_PendingVarRequest = VariableRequest{};
936 varHandler->m_PendingVarRequest = VariableRequest{};
935 auto var = findVariable(itVarHandler->first);
937 auto var = findVariable(itVarHandler->first);
936 executeVarRequest(var, varHandler->m_RunningVarRequest);
938 executeVarRequest(var, varHandler->m_RunningVarRequest);
937 updateVariables(varHandler->m_RunningVarRequest.m_VariableGroupId);
939 updateVariables(varHandler->m_RunningVarRequest.m_VariableGroupId);
938 break;
940 break;
939 }
941 }
940 default:
942 default:
941 qCCritical(LOG_VariableController())
943 qCCritical(LOG_VariableController())
942 << QObject::tr("Unknown VariableRequestHandlerState");
944 << QObject::tr("Unknown VariableRequestHandlerState");
943 }
945 }
944 }
946 }
945 }
947 }
946 }
948 }
947
949
948
950
949 void VariableController::VariableControllerPrivate::cancelVariableRequest(QUuid varRequestId)
951 void VariableController::VariableControllerPrivate::cancelVariableRequest(QUuid varRequestId)
950 {
952 {
951 qCDebug(LOG_VariableController()) << tr("cancelVariableRequest") << varRequestId;
953 qCDebug(LOG_VariableController()) << tr("cancelVariableRequest") << varRequestId;
952
954
953 auto varGroupIdToVarIdsIt = m_VarGroupIdToVarIds.find(varRequestId);
955 auto varGroupIdToVarIdsIt = m_VarGroupIdToVarIds.find(varRequestId);
954 if (varGroupIdToVarIdsIt == m_VarGroupIdToVarIds.end()) {
956 if (varGroupIdToVarIdsIt == m_VarGroupIdToVarIds.end()) {
955 qCCritical(LOG_VariableController())
957 qCCritical(LOG_VariableController())
956 << tr("Impossible to cancelVariableRequest for unknown varGroupdId") << varRequestId;
958 << tr("Impossible to cancelVariableRequest for unknown varGroupdId") << varRequestId;
957 return;
959 return;
958 }
960 }
959
961
960 auto &varIds = varGroupIdToVarIdsIt->second;
962 auto &varIds = varGroupIdToVarIdsIt->second;
961 auto varIdsEnd = varIds.end();
963 auto varIdsEnd = varIds.end();
962 for (auto varIdsIt = varIds.begin(); (varIdsIt != varIdsEnd); ++varIdsIt) {
964 for (auto varIdsIt = varIds.begin(); (varIdsIt != varIdsEnd); ++varIdsIt) {
963 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
965 auto itVarHandler = m_VarIdToVarRequestHandler.find(*varIdsIt);
964 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
966 if (itVarHandler != m_VarIdToVarRequestHandler.cend()) {
965
967
966 auto varHandler = itVarHandler->second.get();
968 auto varHandler = itVarHandler->second.get();
967 varHandler->m_VarId = QUuid{};
969 varHandler->m_VarId = QUuid{};
968 switch (varHandler->m_State) {
970 switch (varHandler->m_State) {
969 case VariableRequestHandlerState::OFF: {
971 case VariableRequestHandlerState::OFF: {
970 qCWarning(LOG_VariableController())
972 qCWarning(LOG_VariableController())
971 << QObject::tr("Impossible to cancel a variable with no running request");
973 << QObject::tr("Impossible to cancel a variable with no running request");
972 break;
974 break;
973 }
975 }
974 case VariableRequestHandlerState::RUNNING: {
976 case VariableRequestHandlerState::RUNNING: {
975
977
976 if (varHandler->m_RunningVarRequest.m_VariableGroupId == varRequestId) {
978 if (varHandler->m_RunningVarRequest.m_VariableGroupId == varRequestId) {
977 auto var = findVariable(itVarHandler->first);
979 auto var = findVariable(itVarHandler->first);
978 auto varProvider = m_VariableToProviderMap.at(var);
980 auto varProvider = m_VariableToProviderMap.at(var);
979 if (varProvider != nullptr) {
981 if (varProvider != nullptr) {
980 m_VariableAcquisitionWorker->abortProgressRequested(
982 m_VariableAcquisitionWorker->abortProgressRequested(
981 itVarHandler->first);
983 itVarHandler->first);
982 }
984 }
983 m_VariableModel->setDataProgress(var, 0.0);
985 m_VariableModel->setDataProgress(var, 0.0);
984 varHandler->m_CanUpdate = false;
986 varHandler->m_CanUpdate = false;
985 varHandler->m_State = VariableRequestHandlerState::OFF;
987 varHandler->m_State = VariableRequestHandlerState::OFF;
986 varHandler->m_RunningVarRequest = VariableRequest{};
988 varHandler->m_RunningVarRequest = VariableRequest{};
987 }
989 }
988 else {
990 else {
989 // TODO: log Impossible to cancel the running variable request beacause its
991 // TODO: log Impossible to cancel the running variable request beacause its
990 // varRequestId isn't not the canceled one
992 // varRequestId isn't not the canceled one
991 }
993 }
992 break;
994 break;
993 }
995 }
994 case VariableRequestHandlerState::PENDING: {
996 case VariableRequestHandlerState::PENDING: {
995 if (varHandler->m_RunningVarRequest.m_VariableGroupId == varRequestId) {
997 if (varHandler->m_RunningVarRequest.m_VariableGroupId == varRequestId) {
996 auto var = findVariable(itVarHandler->first);
998 auto var = findVariable(itVarHandler->first);
997 auto varProvider = m_VariableToProviderMap.at(var);
999 auto varProvider = m_VariableToProviderMap.at(var);
998 if (varProvider != nullptr) {
1000 if (varProvider != nullptr) {
999 m_VariableAcquisitionWorker->abortProgressRequested(
1001 m_VariableAcquisitionWorker->abortProgressRequested(
1000 itVarHandler->first);
1002 itVarHandler->first);
1001 }
1003 }
1002 m_VariableModel->setDataProgress(var, 0.0);
1004 m_VariableModel->setDataProgress(var, 0.0);
1003 varHandler->m_CanUpdate = false;
1005 varHandler->m_CanUpdate = false;
1004 varHandler->m_State = VariableRequestHandlerState::RUNNING;
1006 varHandler->m_State = VariableRequestHandlerState::RUNNING;
1005 varHandler->m_RunningVarRequest = varHandler->m_PendingVarRequest;
1007 varHandler->m_RunningVarRequest = varHandler->m_PendingVarRequest;
1006 varHandler->m_PendingVarRequest = VariableRequest{};
1008 varHandler->m_PendingVarRequest = VariableRequest{};
1007 executeVarRequest(var, varHandler->m_RunningVarRequest);
1009 executeVarRequest(var, varHandler->m_RunningVarRequest);
1008 }
1010 }
1009 else if (varHandler->m_PendingVarRequest.m_VariableGroupId == varRequestId) {
1011 else if (varHandler->m_PendingVarRequest.m_VariableGroupId == varRequestId) {
1010 varHandler->m_State = VariableRequestHandlerState::RUNNING;
1012 varHandler->m_State = VariableRequestHandlerState::RUNNING;
1011 varHandler->m_PendingVarRequest = VariableRequest{};
1013 varHandler->m_PendingVarRequest = VariableRequest{};
1012 }
1014 }
1013 else {
1015 else {
1014 // TODO: log Impossible to cancel the variable request beacause its
1016 // TODO: log Impossible to cancel the variable request beacause its
1015 // varRequestId isn't not the canceled one
1017 // varRequestId isn't not the canceled one
1016 }
1018 }
1017 break;
1019 break;
1018 }
1020 }
1019 default:
1021 default:
1020 qCCritical(LOG_VariableController())
1022 qCCritical(LOG_VariableController())
1021 << QObject::tr("Unknown VariableRequestHandlerState");
1023 << QObject::tr("Unknown VariableRequestHandlerState");
1022 }
1024 }
1023 }
1025 }
1024 }
1026 }
1025 qCDebug(LOG_VariableController()) << tr("cancelVariableRequest: erase") << varRequestId;
1027 qCDebug(LOG_VariableController()) << tr("cancelVariableRequest: erase") << varRequestId;
1026 m_VarGroupIdToVarIds.erase(varRequestId);
1028 m_VarGroupIdToVarIds.erase(varRequestId);
1027 if (m_VarGroupIdToVarIds.empty()) {
1029 if (m_VarGroupIdToVarIds.empty()) {
1028 emit q->acquisitionFinished();
1030 emit q->acquisitionFinished();
1029 }
1031 }
1030 }
1032 }
1031
1033
1032 void VariableController::VariableControllerPrivate::executeVarRequest(std::shared_ptr<Variable> var,
1034 void VariableController::VariableControllerPrivate::executeVarRequest(std::shared_ptr<Variable> var,
1033 VariableRequest &varRequest)
1035 VariableRequest &varRequest)
1034 {
1036 {
1035 qCDebug(LOG_VariableController()) << tr("TORM: executeVarRequest");
1037 qCDebug(LOG_VariableController()) << tr("TORM: executeVarRequest");
1036
1038
1037 auto varIdIt = m_VariableToIdentifierMap.find(var);
1039 auto varIdIt = m_VariableToIdentifierMap.find(var);
1038 if (varIdIt == m_VariableToIdentifierMap.cend()) {
1040 if (varIdIt == m_VariableToIdentifierMap.cend()) {
1039 qCWarning(LOG_VariableController()) << tr(
1041 qCWarning(LOG_VariableController()) << tr(
1040 "Can't execute request of a variable that is not registered (may has been deleted)");
1042 "Can't execute request of a variable that is not registered (may has been deleted)");
1041 return;
1043 return;
1042 }
1044 }
1043
1045
1044 auto varId = varIdIt->second;
1046 auto varId = varIdIt->second;
1045
1047
1046 auto varCacheRange = var->cacheRange();
1048 auto varCacheRange = var->cacheRange();
1047 auto varCacheRangeRequested = varRequest.m_CacheRangeRequested;
1049 auto varCacheRangeRequested = varRequest.m_CacheRangeRequested;
1048 auto notInCacheRangeList
1050 auto notInCacheRangeList
1049 = Variable::provideNotInCacheRangeList(varCacheRange, varCacheRangeRequested);
1051 = Variable::provideNotInCacheRangeList(varCacheRange, varCacheRangeRequested);
1050 auto inCacheRangeList
1052 auto inCacheRangeList
1051 = Variable::provideInCacheRangeList(varCacheRange, varCacheRangeRequested);
1053 = Variable::provideInCacheRangeList(varCacheRange, varCacheRangeRequested);
1052
1054
1053 if (!notInCacheRangeList.empty()) {
1055 if (!notInCacheRangeList.empty()) {
1054
1056
1055 auto varProvider = m_VariableToProviderMap.at(var);
1057 auto varProvider = m_VariableToProviderMap.at(var);
1056 if (varProvider != nullptr) {
1058 if (varProvider != nullptr) {
1057 qCDebug(LOG_VariableController()) << "executeVarRequest " << varRequest.m_RangeRequested
1059 qCDebug(LOG_VariableController()) << "executeVarRequest " << varRequest.m_RangeRequested
1058 << varRequest.m_CacheRangeRequested;
1060 << varRequest.m_CacheRangeRequested;
1059 m_VariableAcquisitionWorker->pushVariableRequest(
1061 m_VariableAcquisitionWorker->pushVariableRequest(
1060 varRequest.m_VariableGroupId, varId, varRequest.m_RangeRequested,
1062 varRequest.m_VariableGroupId, varId, varRequest.m_RangeRequested,
1061 varRequest.m_CacheRangeRequested,
1063 varRequest.m_CacheRangeRequested,
1062 DataProviderParameters{std::move(notInCacheRangeList), var->metadata()},
1064 DataProviderParameters{std::move(notInCacheRangeList), var->metadata()},
1063 varProvider);
1065 varProvider);
1064 }
1066 }
1065 else {
1067 else {
1066 qCCritical(LOG_VariableController())
1068 qCCritical(LOG_VariableController())
1067 << "Impossible to provide data with a null provider";
1069 << "Impossible to provide data with a null provider";
1068 }
1070 }
1069
1071
1070 if (!inCacheRangeList.empty()) {
1072 if (!inCacheRangeList.empty()) {
1071 emit q->updateVarDisplaying(var, inCacheRangeList.first());
1073 emit q->updateVarDisplaying(var, inCacheRangeList.first());
1072 }
1074 }
1073 }
1075 }
1074 else {
1076 else {
1075 acceptVariableRequest(varId,
1077 acceptVariableRequest(varId,
1076 var->dataSeries()->subDataSeries(varRequest.m_CacheRangeRequested));
1078 var->dataSeries()->subDataSeries(varRequest.m_CacheRangeRequested));
1077 }
1079 }
1078 }
1080 }
1079
1081
1080 template <typename VariableIterator>
1082 template <typename VariableIterator>
1081 void VariableController::VariableControllerPrivate::desynchronize(VariableIterator variableIt,
1083 void VariableController::VariableControllerPrivate::desynchronize(VariableIterator variableIt,
1082 const QUuid &syncGroupId)
1084 const QUuid &syncGroupId)
1083 {
1085 {
1084 const auto &variable = variableIt->first;
1086 const auto &variable = variableIt->first;
1085 const auto &variableId = variableIt->second;
1087 const auto &variableId = variableIt->second;
1086
1088
1087 // Gets synchronization group
1089 // Gets synchronization group
1088 auto groupIt = m_GroupIdToVariableSynchronizationGroupMap.find(syncGroupId);
1090 auto groupIt = m_GroupIdToVariableSynchronizationGroupMap.find(syncGroupId);
1089 if (groupIt == m_GroupIdToVariableSynchronizationGroupMap.cend()) {
1091 if (groupIt == m_GroupIdToVariableSynchronizationGroupMap.cend()) {
1090 qCCritical(LOG_VariableController())
1092 qCCritical(LOG_VariableController())
1091 << tr("Can't desynchronize variable %1: unknown synchronization group")
1093 << tr("Can't desynchronize variable %1: unknown synchronization group")
1092 .arg(variable->name());
1094 .arg(variable->name());
1093 return;
1095 return;
1094 }
1096 }
1095
1097
1096 // Removes variable from synchronization group
1098 // Removes variable from synchronization group
1097 auto synchronizationGroup = groupIt->second;
1099 auto synchronizationGroup = groupIt->second;
1098 synchronizationGroup->removeVariableId(variableId);
1100 synchronizationGroup->removeVariableId(variableId);
1099
1101
1100 // Removes link between variable and synchronization group
1102 // Removes link between variable and synchronization group
1101 m_VariableIdGroupIdMap.erase(variableId);
1103 m_VariableIdGroupIdMap.erase(variableId);
1102 }
1104 }
@@ -1,58 +1,64
1 #ifndef SCIQLOP_CATALOGUEEVENTSWIDGET_H
1 #ifndef SCIQLOP_CATALOGUEEVENTSWIDGET_H
2 #define SCIQLOP_CATALOGUEEVENTSWIDGET_H
2 #define SCIQLOP_CATALOGUEEVENTSWIDGET_H
3
3
4 #include <Common/spimpl.h>
4 #include <Common/spimpl.h>
5 #include <QLoggingCategory>
5 #include <QLoggingCategory>
6 #include <QWidget>
6 #include <QWidget>
7
7
8 class DBCatalogue;
8 class DBCatalogue;
9 class DBEvent;
9 class DBEvent;
10 class DBEventProduct;
10 class DBEventProduct;
11 class VisualizationWidget;
11 class VisualizationWidget;
12 class VisualizationSelectionZoneItem;
12
13
13 namespace Ui {
14 namespace Ui {
14 class CatalogueEventsWidget;
15 class CatalogueEventsWidget;
15 }
16 }
16
17
17 Q_DECLARE_LOGGING_CATEGORY(LOG_CatalogueEventsWidget)
18 Q_DECLARE_LOGGING_CATEGORY(LOG_CatalogueEventsWidget)
18
19
19 class CatalogueEventsWidget : public QWidget {
20 class CatalogueEventsWidget : public QWidget {
20 Q_OBJECT
21 Q_OBJECT
21
22
22 signals:
23 signals:
23 void eventsSelected(const QVector<std::shared_ptr<DBEvent> > &event);
24 void eventsSelected(const QVector<std::shared_ptr<DBEvent> > &event);
25 void eventsRemoved(const QVector<std::shared_ptr<DBEvent> > &event);
24 void eventProductsSelected(
26 void eventProductsSelected(
25 const QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > >
27 const QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > >
26 &eventproducts);
28 &eventproducts);
27 void selectionCleared();
29 void selectionCleared();
30 void selectionZoneAdded(const std::shared_ptr<DBEvent> &event, const QString &productId,
31 VisualizationSelectionZoneItem *selectionZone);
28
32
29 public:
33 public:
30 explicit CatalogueEventsWidget(QWidget *parent = 0);
34 explicit CatalogueEventsWidget(QWidget *parent = 0);
31 virtual ~CatalogueEventsWidget();
35 virtual ~CatalogueEventsWidget();
32
36
33 void setVisualizationWidget(VisualizationWidget *visualization);
37 void setVisualizationWidget(VisualizationWidget *visualization);
34
38
35 void addEvent(const std::shared_ptr<DBEvent> &event);
39 void addEvent(const std::shared_ptr<DBEvent> &event);
36 void setEventChanges(const std::shared_ptr<DBEvent> &event, bool hasChanges);
40 void setEventChanges(const std::shared_ptr<DBEvent> &event, bool hasChanges);
37
41
38 QVector<std::shared_ptr<DBCatalogue> > displayedCatalogues() const;
42 QVector<std::shared_ptr<DBCatalogue> > displayedCatalogues() const;
39 bool isAllEventsDisplayed() const;
43 bool isAllEventsDisplayed() const;
40 bool isEventDisplayed(const std::shared_ptr<DBEvent> &event) const;
44 bool isEventDisplayed(const std::shared_ptr<DBEvent> &event) const;
41
45
46 void refreshEvent(const std::shared_ptr<DBEvent> &event);
47
42 public slots:
48 public slots:
43 void populateWithCatalogues(const QVector<std::shared_ptr<DBCatalogue> > &catalogues);
49 void populateWithCatalogues(const QVector<std::shared_ptr<DBCatalogue> > &catalogues);
44 void populateWithAllEvents();
50 void populateWithAllEvents();
45 void clear();
51 void clear();
46 void refresh();
52 void refresh();
47
53
48 private:
54 private:
49 Ui::CatalogueEventsWidget *ui;
55 Ui::CatalogueEventsWidget *ui;
50
56
51 class CatalogueEventsWidgetPrivate;
57 class CatalogueEventsWidgetPrivate;
52 spimpl::unique_impl_ptr<CatalogueEventsWidgetPrivate> impl;
58 spimpl::unique_impl_ptr<CatalogueEventsWidgetPrivate> impl;
53
59
54 private slots:
60 private slots:
55 void emitSelection();
61 void emitSelection();
56 };
62 };
57
63
58 #endif // SCIQLOP_CATALOGUEEVENTSWIDGET_H
64 #endif // SCIQLOP_CATALOGUEEVENTSWIDGET_H
@@ -1,35 +1,43
1 #ifndef SCIQLOP_CATALOGUEEXPLORER_H
1 #ifndef SCIQLOP_CATALOGUEEXPLORER_H
2 #define SCIQLOP_CATALOGUEEXPLORER_H
2 #define SCIQLOP_CATALOGUEEXPLORER_H
3
3
4 #include <Common/spimpl.h>
4 #include <Common/spimpl.h>
5 #include <QDialog>
5 #include <QDialog>
6
6
7 namespace Ui {
7 namespace Ui {
8 class CatalogueExplorer;
8 class CatalogueExplorer;
9 }
9 }
10
10
11 class CatalogueEventsWidget;
11 class CatalogueEventsWidget;
12 class CatalogueSideBarWidget;
12 class CatalogueSideBarWidget;
13
13
14 class VisualizationWidget;
14 class VisualizationWidget;
15 class VisualizationSelectionZoneItem;
16
17 class DBEvent;
18
15
19
16 class CatalogueExplorer : public QDialog {
20 class CatalogueExplorer : public QDialog {
17 Q_OBJECT
21 Q_OBJECT
18
22
19 public:
23 public:
20 explicit CatalogueExplorer(QWidget *parent = 0);
24 explicit CatalogueExplorer(QWidget *parent = 0);
21 virtual ~CatalogueExplorer();
25 virtual ~CatalogueExplorer();
22
26
23 void setVisualizationWidget(VisualizationWidget *visualization);
27 void setVisualizationWidget(VisualizationWidget *visualization);
24
28
25 CatalogueEventsWidget &eventsWidget() const;
29 CatalogueEventsWidget &eventsWidget() const;
26 CatalogueSideBarWidget &sideBarWidget() const;
30 CatalogueSideBarWidget &sideBarWidget() const;
27
31
32 void clearSelectionZones();
33 void addSelectionZoneItem(const std::shared_ptr<DBEvent> &event, const QString &productId,
34 VisualizationSelectionZoneItem *selectionZone);
35
28 private:
36 private:
29 Ui::CatalogueExplorer *ui;
37 Ui::CatalogueExplorer *ui;
30
38
31 class CatalogueExplorerPrivate;
39 class CatalogueExplorerPrivate;
32 spimpl::unique_impl_ptr<CatalogueExplorerPrivate> impl;
40 spimpl::unique_impl_ptr<CatalogueExplorerPrivate> impl;
33 };
41 };
34
42
35 #endif // SCIQLOP_CATALOGUEEXPLORER_H
43 #endif // SCIQLOP_CATALOGUEEXPLORER_H
@@ -1,49 +1,51
1 #ifndef SCIQLOP_CATALOGUEINSPECTORWIDGET_H
1 #ifndef SCIQLOP_CATALOGUEINSPECTORWIDGET_H
2 #define SCIQLOP_CATALOGUEINSPECTORWIDGET_H
2 #define SCIQLOP_CATALOGUEINSPECTORWIDGET_H
3
3
4 #include <Common/spimpl.h>
4 #include <Common/spimpl.h>
5 #include <QWidget>
5 #include <QWidget>
6 #include <memory>
6 #include <memory>
7
7
8 namespace Ui {
8 namespace Ui {
9 class CatalogueInspectorWidget;
9 class CatalogueInspectorWidget;
10 }
10 }
11
11
12 class DBCatalogue;
12 class DBCatalogue;
13 class DBEvent;
13 class DBEvent;
14 class DBEventProduct;
14 class DBEventProduct;
15
15
16 class CatalogueInspectorWidget : public QWidget {
16 class CatalogueInspectorWidget : public QWidget {
17 Q_OBJECT
17 Q_OBJECT
18
18
19 signals:
19 signals:
20 void catalogueUpdated(const std::shared_ptr<DBCatalogue> &catalogue);
20 void catalogueUpdated(const std::shared_ptr<DBCatalogue> &catalogue);
21 void eventUpdated(const std::shared_ptr<DBEvent> &event);
21 void eventUpdated(const std::shared_ptr<DBEvent> &event);
22 void eventProductUpdated(const std::shared_ptr<DBEvent> &event,
22 void eventProductUpdated(const std::shared_ptr<DBEvent> &event,
23 const std::shared_ptr<DBEventProduct> &eventProduct);
23 const std::shared_ptr<DBEventProduct> &eventProduct);
24
24
25 public:
25 public:
26 explicit CatalogueInspectorWidget(QWidget *parent = 0);
26 explicit CatalogueInspectorWidget(QWidget *parent = 0);
27 virtual ~CatalogueInspectorWidget();
27 virtual ~CatalogueInspectorWidget();
28
28
29 /// Enum matching the pages inside the stacked widget
29 /// Enum matching the pages inside the stacked widget
30 enum class Page { Empty, CatalogueProperties, EventProperties };
30 enum class Page { Empty, CatalogueProperties, EventProperties };
31
31
32 Page currentPage() const;
32 Page currentPage() const;
33
33
34 void setEvent(const std::shared_ptr<DBEvent> &event);
34 void setEvent(const std::shared_ptr<DBEvent> &event);
35 void setEventProduct(const std::shared_ptr<DBEvent> &event,
35 void setEventProduct(const std::shared_ptr<DBEvent> &event,
36 const std::shared_ptr<DBEventProduct> &eventProduct);
36 const std::shared_ptr<DBEventProduct> &eventProduct);
37 void setCatalogue(const std::shared_ptr<DBCatalogue> &catalogue);
37 void setCatalogue(const std::shared_ptr<DBCatalogue> &catalogue);
38
38
39 void refresh();
40
39 public slots:
41 public slots:
40 void showPage(Page page);
42 void showPage(Page page);
41
43
42 private:
44 private:
43 Ui::CatalogueInspectorWidget *ui;
45 Ui::CatalogueInspectorWidget *ui;
44
46
45 class CatalogueInspectorWidgetPrivate;
47 class CatalogueInspectorWidgetPrivate;
46 spimpl::unique_impl_ptr<CatalogueInspectorWidgetPrivate> impl;
48 spimpl::unique_impl_ptr<CatalogueInspectorWidgetPrivate> impl;
47 };
49 };
48
50
49 #endif // SCIQLOP_CATALOGUEINSPECTORWIDGET_H
51 #endif // SCIQLOP_CATALOGUEINSPECTORWIDGET_H
@@ -1,37 +1,44
1 #ifndef SCIQLOP_AXISRENDERINGUTILS_H
1 #ifndef SCIQLOP_AXISRENDERINGUTILS_H
2 #define SCIQLOP_AXISRENDERINGUTILS_H
2 #define SCIQLOP_AXISRENDERINGUTILS_H
3
3
4 #include <memory>
4 #include <memory>
5
5
6 #include <QtCore/QLoggingCategory>
6 #include <QtCore/QLoggingCategory>
7 #include <QtCore/QString>
7 #include <QtCore/QString>
8
8
9 Q_DECLARE_LOGGING_CATEGORY(LOG_AxisRenderingUtils)
9 Q_DECLARE_LOGGING_CATEGORY(LOG_AxisRenderingUtils)
10
10
11 class IDataSeries;
11 class IDataSeries;
12 class QCPAxis;
12 class QCPAxis;
13 class QCustomPlot;
13 class QCustomPlot;
14 class SqpColorScale;
14 class SqpColorScale;
15 class Variable;
15
16
16 /// Formats a data value according to the axis on which it is present
17 /// Formats a data value according to the axis on which it is present
17 QString formatValue(double value, const QCPAxis &axis);
18 QString formatValue(double value, const QCPAxis &axis);
18
19
19 /**
20 /**
20 * Helper used to handle axes rendering
21 * Helper used to handle axes rendering
21 */
22 */
22 struct IAxisHelper {
23 struct IAxisHelper {
23 virtual ~IAxisHelper() noexcept = default;
24 virtual ~IAxisHelper() noexcept = default;
24
25
25 /// Set properties of the plot's axes and the color scale associated to plot passed as
26 /// Set properties of the plot's axes and the color scale associated to plot passed as
26 /// parameters
27 /// parameters
27 /// @param plot the plot for which to set axe properties
28 /// @param plot the plot for which to set axe properties
28 /// @param colorScale the color scale for which to set properties
29 /// @param colorScale the color scale for which to set properties
29 virtual void setProperties(QCustomPlot &plot, SqpColorScale &colorScale) = 0;
30 virtual void setProperties(QCustomPlot &plot, SqpColorScale &colorScale) = 0;
31
32 /// Set the units of the plot's axes and the color scale associated to plot passed as
33 /// parameters
34 /// @param plot the plot for which to set axe units
35 /// @param colorScale the color scale for which to set unit
36 virtual void setUnits(QCustomPlot &plot, SqpColorScale &colorScale) = 0;
30 };
37 };
31
38
32 struct IAxisHelperFactory {
39 struct IAxisHelperFactory {
33 /// Creates IAxisHelper according to a data series
40 /// Creates IPlottablesHelper according to the type of data series a variable holds
34 static std::unique_ptr<IAxisHelper> create(std::shared_ptr<IDataSeries> dataSeries) noexcept;
41 static std::unique_ptr<IAxisHelper> create(const Variable &variable) noexcept;
35 };
42 };
36
43
37 #endif // SCIQLOP_AXISRENDERINGUTILS_H
44 #endif // SCIQLOP_AXISRENDERINGUTILS_H
@@ -1,33 +1,34
1 #ifndef SCIQLOP_PLOTTABLESRENDERINGUTILS_H
1 #ifndef SCIQLOP_PLOTTABLESRENDERINGUTILS_H
2 #define SCIQLOP_PLOTTABLESRENDERINGUTILS_H
2 #define SCIQLOP_PLOTTABLESRENDERINGUTILS_H
3
3
4 #include <Data/DataSeriesType.h>
5
4 #include <Visualization/VisualizationDefs.h>
6 #include <Visualization/VisualizationDefs.h>
5
7
6 #include <memory>
8 #include <memory>
7
9
8 #include <QtCore/QLoggingCategory>
10 #include <QtCore/QLoggingCategory>
9
11
10 Q_DECLARE_LOGGING_CATEGORY(LOG_PlottablesRenderingUtils)
12 Q_DECLARE_LOGGING_CATEGORY(LOG_PlottablesRenderingUtils)
11
13
12 class IDataSeries;
13 class QCPColorScale;
14 class QCPColorScale;
14 class QCustomPlot;
15 class QCustomPlot;
16 class Variable;
15
17
16 /**
18 /**
17 * Helper used to handle plottables rendering
19 * Helper used to handle plottables rendering
18 */
20 */
19 struct IPlottablesHelper {
21 struct IPlottablesHelper {
20 virtual ~IPlottablesHelper() noexcept = default;
22 virtual ~IPlottablesHelper() noexcept = default;
21
23
22 /// Set properties of the plottables passed as parameter
24 /// Set properties of the plottables passed as parameter
23 /// @param plottables the plottables for which to set properties
25 /// @param plottables the plottables for which to set properties
24 virtual void setProperties(PlottablesMap &plottables) = 0;
26 virtual void setProperties(PlottablesMap &plottables) = 0;
25 };
27 };
26
28
27 struct IPlottablesHelperFactory {
29 struct IPlottablesHelperFactory {
28 /// Creates IPlottablesHelper according to a data series
30 /// Creates IPlottablesHelper according to the type of data series a variable holds
29 static std::unique_ptr<IPlottablesHelper>
31 static std::unique_ptr<IPlottablesHelper> create(const Variable &variable) noexcept;
30 create(std::shared_ptr<IDataSeries> dataSeries) noexcept;
31 };
32 };
32
33
33 #endif // SCIQLOP_PLOTTABLESRENDERINGUTILS_H
34 #endif // SCIQLOP_PLOTTABLESRENDERINGUTILS_H
@@ -1,41 +1,41
1 #ifndef SCIQLOP_VISUALIZATIONGRAPHHELPER_H
1 #ifndef SCIQLOP_VISUALIZATIONGRAPHHELPER_H
2 #define SCIQLOP_VISUALIZATIONGRAPHHELPER_H
2 #define SCIQLOP_VISUALIZATIONGRAPHHELPER_H
3
3
4 #include "Visualization/VisualizationDefs.h"
4 #include "Visualization/VisualizationDefs.h"
5
5
6 #include <Data/SqpRange.h>
6 #include <Data/SqpRange.h>
7
7
8 #include <QLoggingCategory>
8 #include <QLoggingCategory>
9 #include <QVector>
9 #include <QVector>
10
10
11 #include <memory>
11 #include <memory>
12
12
13 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationGraphHelper)
13 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationGraphHelper)
14
14
15 class IDataSeries;
15 class IDataSeries;
16 class QCPAbstractPlottable;
16 class QCPAbstractPlottable;
17 class QCustomPlot;
17 class QCustomPlot;
18 class Variable;
18 class Variable;
19
19
20 /**
20 /**
21 * @brief The VisualizationGraphHelper class aims to create the QCustomPlot components relative to a
21 * @brief The VisualizationGraphHelper class aims to create the QCustomPlot components relative to a
22 * variable, depending on the data series of this variable
22 * variable, depending on the data series of this variable
23 */
23 */
24 struct VisualizationGraphHelper {
24 struct VisualizationGraphHelper {
25 /**
25 /**
26 * Creates (if possible) the QCustomPlot components relative to the variable passed in
26 * Creates (if possible) the QCustomPlot components relative to the variable passed in
27 * parameter, and adds these to the plot passed in parameter.
27 * parameter, and adds these to the plot passed in parameter.
28 * @param variable the variable for which to create the components
28 * @param variable the variable for which to create the components
29 * @param plot the plot in which to add the created components. It takes ownership of these
29 * @param plot the plot in which to add the created components. It takes ownership of these
30 * components.
30 * components.
31 * @return the list of the components created
31 * @return the list of the components created
32 */
32 */
33 static PlottablesMap create(std::shared_ptr<Variable> variable, QCustomPlot &plot) noexcept;
33 static PlottablesMap create(std::shared_ptr<Variable> variable, QCustomPlot &plot) noexcept;
34
34
35 static void updateData(PlottablesMap &plottables, std::shared_ptr<IDataSeries> dataSeries,
35 static void updateData(PlottablesMap &plottables, std::shared_ptr<Variable> variable,
36 const SqpRange &dateTime);
36 const SqpRange &dateTime);
37
37
38 static void setYAxisRange(std::shared_ptr<Variable> variable, QCustomPlot &plot) noexcept;
38 static void setYAxisRange(std::shared_ptr<Variable> variable, QCustomPlot &plot) noexcept;
39 };
39 };
40
40
41 #endif // SCIQLOP_VISUALIZATIONGRAPHHELPER_H
41 #endif // SCIQLOP_VISUALIZATIONGRAPHHELPER_H
@@ -1,42 +1,44
1 #ifndef SCIQLOP_VISUALIZATIONGRAPHRENDERINGDELEGATE_H
1 #ifndef SCIQLOP_VISUALIZATIONGRAPHRENDERINGDELEGATE_H
2 #define SCIQLOP_VISUALIZATIONGRAPHRENDERINGDELEGATE_H
2 #define SCIQLOP_VISUALIZATIONGRAPHRENDERINGDELEGATE_H
3
3
4 #include <Common/spimpl.h>
4 #include <Common/spimpl.h>
5
5
6 #include <Visualization/VisualizationDefs.h>
6 #include <Visualization/VisualizationDefs.h>
7
7
8 class IDataSeries;
8 class IDataSeries;
9 class QCustomPlot;
9 class QCustomPlot;
10 class QMouseEvent;
10 class QMouseEvent;
11 class Unit;
11 class Unit;
12 class Variable;
12 class VisualizationGraphWidget;
13 class VisualizationGraphWidget;
13
14
14 class VisualizationGraphRenderingDelegate {
15 class VisualizationGraphRenderingDelegate {
15 public:
16 public:
16 /// Ctor
17 /// Ctor
17 /// @param graphWidget the graph widget to which the delegate is associated
18 /// @param graphWidget the graph widget to which the delegate is associated
18 /// @remarks the graph widget must exist throughout the life cycle of the delegate
19 /// @remarks the graph widget must exist throughout the life cycle of the delegate
19 explicit VisualizationGraphRenderingDelegate(VisualizationGraphWidget &graphWidget);
20 explicit VisualizationGraphRenderingDelegate(VisualizationGraphWidget &graphWidget);
20
21
21 void onMouseDoubleClick(QMouseEvent *event) noexcept;
22 void onMouseDoubleClick(QMouseEvent *event) noexcept;
22 void onMouseMove(QMouseEvent *event) noexcept;
23 void onMouseMove(QMouseEvent *event) noexcept;
23 /// Updates rendering when data of plot changed
24 /// Updates rendering when data of plot changed
24 void onPlotUpdated() noexcept;
25 void onPlotUpdated() noexcept;
25
26
26 /// Sets properties of the plot's axes from the data series passed as parameter
27 /// Sets units of the plot's axes according to the properties of the variable passed as
27 void setAxesProperties(std::shared_ptr<IDataSeries> dataSeries) noexcept;
28 /// parameter
29 void setAxesUnits(const Variable &variable) noexcept;
28
30
29 /// Sets rendering properties of the plottables passed as parameter, from the data series that
31 /// Sets graph properties of the plottables passed as parameter, from the variable that
30 /// generated these
32 /// generated these
31 void setPlottablesProperties(std::shared_ptr<IDataSeries> dataSeries,
33 void setGraphProperties(const Variable &variable, PlottablesMap &plottables) noexcept;
32 PlottablesMap &plottables) noexcept;
34
33
35
34 /// Shows or hides graph overlay (name, close button, etc.)
36 /// Shows or hides graph overlay (name, close button, etc.)
35 void showGraphOverlay(bool show) noexcept;
37 void showGraphOverlay(bool show) noexcept;
36
38
37 private:
39 private:
38 class VisualizationGraphRenderingDelegatePrivate;
40 class VisualizationGraphRenderingDelegatePrivate;
39 spimpl::unique_impl_ptr<VisualizationGraphRenderingDelegatePrivate> impl;
41 spimpl::unique_impl_ptr<VisualizationGraphRenderingDelegatePrivate> impl;
40 };
42 };
41
43
42 #endif // SCIQLOP_VISUALIZATIONGRAPHRENDERINGDELEGATE_H
44 #endif // SCIQLOP_VISUALIZATIONGRAPHRENDERINGDELEGATE_H
@@ -1,155 +1,158
1 #ifndef SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
1 #ifndef SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
2 #define SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
2 #define SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
3
3
4 #include "Visualization/IVisualizationWidget.h"
4 #include "Visualization/IVisualizationWidget.h"
5 #include "Visualization/VisualizationDragWidget.h"
5 #include "Visualization/VisualizationDragWidget.h"
6
6
7 #include <QLoggingCategory>
7 #include <QLoggingCategory>
8 #include <QWidget>
8 #include <QWidget>
9
9
10 #include <memory>
10 #include <memory>
11
11
12 #include <Common/spimpl.h>
12 #include <Common/spimpl.h>
13
13
14 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationGraphWidget)
14 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationGraphWidget)
15
15
16 class QCPRange;
16 class QCPRange;
17 class QCustomPlot;
17 class QCustomPlot;
18 class SqpRange;
18 class SqpRange;
19 class Variable;
19 class Variable;
20 class VisualizationWidget;
20 class VisualizationWidget;
21 class VisualizationZoneWidget;
21 class VisualizationZoneWidget;
22 class VisualizationSelectionZoneItem;
22 class VisualizationSelectionZoneItem;
23
23
24 namespace Ui {
24 namespace Ui {
25 class VisualizationGraphWidget;
25 class VisualizationGraphWidget;
26 } // namespace Ui
26 } // namespace Ui
27
27
28 /// Defines options that can be associated with the graph
28 /// Defines options that can be associated with the graph
29 enum GraphFlag {
29 enum GraphFlag {
30 DisableAll = 0x0, ///< Disables acquisition and synchronization
30 DisableAll = 0x0, ///< Disables acquisition and synchronization
31 EnableAcquisition = 0x1, ///< When this flag is set, the change of the graph's range leads to
31 EnableAcquisition = 0x1, ///< When this flag is set, the change of the graph's range leads to
32 /// the acquisition of data
32 /// the acquisition of data
33 EnableSynchronization = 0x2, ///< When this flag is set, the change of the graph's range causes
33 EnableSynchronization = 0x2, ///< When this flag is set, the change of the graph's range causes
34 /// the call to the synchronization of the graphs contained in the
34 /// the call to the synchronization of the graphs contained in the
35 /// same zone of this graph
35 /// same zone of this graph
36 EnableAll = ~DisableAll ///< Enables acquisition and synchronization
36 EnableAll = ~DisableAll ///< Enables acquisition and synchronization
37 };
37 };
38
38
39 Q_DECLARE_FLAGS(GraphFlags, GraphFlag)
39 Q_DECLARE_FLAGS(GraphFlags, GraphFlag)
40 Q_DECLARE_OPERATORS_FOR_FLAGS(GraphFlags)
40 Q_DECLARE_OPERATORS_FOR_FLAGS(GraphFlags)
41
41
42 class VisualizationGraphWidget : public VisualizationDragWidget, public IVisualizationWidget {
42 class VisualizationGraphWidget : public VisualizationDragWidget, public IVisualizationWidget {
43 Q_OBJECT
43 Q_OBJECT
44
44
45 friend class QCustomPlotSynchronizer;
45 friend class QCustomPlotSynchronizer;
46 friend class VisualizationGraphRenderingDelegate;
46 friend class VisualizationGraphRenderingDelegate;
47
47
48 public:
48 public:
49 explicit VisualizationGraphWidget(const QString &name = {}, QWidget *parent = 0);
49 explicit VisualizationGraphWidget(const QString &name = {}, QWidget *parent = 0);
50 virtual ~VisualizationGraphWidget();
50 virtual ~VisualizationGraphWidget();
51
51
52 /// Returns the VisualizationZoneWidget which contains the graph or nullptr
52 /// Returns the VisualizationZoneWidget which contains the graph or nullptr
53 VisualizationZoneWidget *parentZoneWidget() const noexcept;
53 VisualizationZoneWidget *parentZoneWidget() const noexcept;
54
54
55 /// Returns the main VisualizationWidget which contains the graph or nullptr
55 /// Returns the main VisualizationWidget which contains the graph or nullptr
56 VisualizationWidget *parentVisualizationWidget() const;
56 VisualizationWidget *parentVisualizationWidget() const;
57
57
58 /// Sets graph options
58 /// Sets graph options
59 void setFlags(GraphFlags flags);
59 void setFlags(GraphFlags flags);
60
60
61 void addVariable(std::shared_ptr<Variable> variable, SqpRange range);
61 void addVariable(std::shared_ptr<Variable> variable, SqpRange range);
62
62
63 /// Removes a variable from the graph
63 /// Removes a variable from the graph
64 void removeVariable(std::shared_ptr<Variable> variable) noexcept;
64 void removeVariable(std::shared_ptr<Variable> variable) noexcept;
65
65
66 /// Returns the list of all variables used in the graph
66 /// Returns the list of all variables used in the graph
67 QList<std::shared_ptr<Variable> > variables() const;
67 QList<std::shared_ptr<Variable> > variables() const;
68
68
69 /// Sets the y-axis range based on the data of a variable
69 /// Sets the y-axis range based on the data of a variable
70 void setYRange(std::shared_ptr<Variable> variable);
70 void setYRange(std::shared_ptr<Variable> variable);
71 SqpRange graphRange() const noexcept;
71 SqpRange graphRange() const noexcept;
72 void setGraphRange(const SqpRange &range);
72 void setGraphRange(const SqpRange &range, bool calibration = false);
73 void setAutoRangeOnVariableInitialization(bool value);
73
74
74 // Zones
75 // Zones
75 /// Returns the ranges of all the selection zones on the graph
76 /// Returns the ranges of all the selection zones on the graph
76 QVector<SqpRange> selectionZoneRanges() const;
77 QVector<SqpRange> selectionZoneRanges() const;
77 /// Adds new selection zones in the graph
78 /// Adds new selection zones in the graph
78 void addSelectionZones(const QVector<SqpRange> &ranges);
79 void addSelectionZones(const QVector<SqpRange> &ranges);
80 /// Adds a new selection zone in the graph
81 VisualizationSelectionZoneItem *addSelectionZone(const QString &name, const SqpRange &range);
79 /// Removes the specified selection zone
82 /// Removes the specified selection zone
80 void removeSelectionZone(VisualizationSelectionZoneItem *selectionZone);
83 void removeSelectionZone(VisualizationSelectionZoneItem *selectionZone);
81
84
82 /// Undo the last zoom done with a zoom box
85 /// Undo the last zoom done with a zoom box
83 void undoZoom();
86 void undoZoom();
84
87
85 // IVisualizationWidget interface
88 // IVisualizationWidget interface
86 void accept(IVisualizationWidgetVisitor *visitor) override;
89 void accept(IVisualizationWidgetVisitor *visitor) override;
87 bool canDrop(const Variable &variable) const override;
90 bool canDrop(const Variable &variable) const override;
88 bool contains(const Variable &variable) const override;
91 bool contains(const Variable &variable) const override;
89 QString name() const override;
92 QString name() const override;
90
93
91 // VisualisationDragWidget
94 // VisualisationDragWidget
92 QMimeData *mimeData(const QPoint &position) const override;
95 QMimeData *mimeData(const QPoint &position) const override;
93 QPixmap customDragPixmap(const QPoint &dragPosition) override;
96 QPixmap customDragPixmap(const QPoint &dragPosition) override;
94 bool isDragAllowed() const override;
97 bool isDragAllowed() const override;
95 void highlightForMerge(bool highlighted) override;
98 void highlightForMerge(bool highlighted) override;
96
99
97 // Cursors
100 // Cursors
98 /// Adds or moves the vertical cursor at the specified value on the x-axis
101 /// Adds or moves the vertical cursor at the specified value on the x-axis
99 void addVerticalCursor(double time);
102 void addVerticalCursor(double time);
100 /// Adds or moves the vertical cursor at the specified value on the x-axis
103 /// Adds or moves the vertical cursor at the specified value on the x-axis
101 void addVerticalCursorAtViewportPosition(double position);
104 void addVerticalCursorAtViewportPosition(double position);
102 void removeVerticalCursor();
105 void removeVerticalCursor();
103 /// Adds or moves the vertical cursor at the specified value on the y-axis
106 /// Adds or moves the vertical cursor at the specified value on the y-axis
104 void addHorizontalCursor(double value);
107 void addHorizontalCursor(double value);
105 /// Adds or moves the vertical cursor at the specified value on the y-axis
108 /// Adds or moves the vertical cursor at the specified value on the y-axis
106 void addHorizontalCursorAtViewportPosition(double position);
109 void addHorizontalCursorAtViewportPosition(double position);
107 void removeHorizontalCursor();
110 void removeHorizontalCursor();
108
111
109 signals:
112 signals:
110 void synchronize(const SqpRange &range, const SqpRange &oldRange);
113 void synchronize(const SqpRange &range, const SqpRange &oldRange);
111 void requestDataLoading(QVector<std::shared_ptr<Variable> > variable, const SqpRange &range,
114 void requestDataLoading(QVector<std::shared_ptr<Variable> > variable, const SqpRange &range,
112 bool synchronise);
115 bool synchronise);
113
116
114 /// Signal emitted when the variable is about to be removed from the graph
117 /// Signal emitted when the variable is about to be removed from the graph
115 void variableAboutToBeRemoved(std::shared_ptr<Variable> var);
118 void variableAboutToBeRemoved(std::shared_ptr<Variable> var);
116 /// Signal emitted when the variable has been added to the graph
119 /// Signal emitted when the variable has been added to the graph
117 void variableAdded(std::shared_ptr<Variable> var);
120 void variableAdded(std::shared_ptr<Variable> var);
118
121
119 protected:
122 protected:
120 void closeEvent(QCloseEvent *event) override;
123 void closeEvent(QCloseEvent *event) override;
121 void enterEvent(QEvent *event) override;
124 void enterEvent(QEvent *event) override;
122 void leaveEvent(QEvent *event) override;
125 void leaveEvent(QEvent *event) override;
123
126
124 QCustomPlot &plot() const noexcept;
127 QCustomPlot &plot() const noexcept;
125
128
126 private:
129 private:
127 Ui::VisualizationGraphWidget *ui;
130 Ui::VisualizationGraphWidget *ui;
128
131
129 class VisualizationGraphWidgetPrivate;
132 class VisualizationGraphWidgetPrivate;
130 spimpl::unique_impl_ptr<VisualizationGraphWidgetPrivate> impl;
133 spimpl::unique_impl_ptr<VisualizationGraphWidgetPrivate> impl;
131
134
132 private slots:
135 private slots:
133 /// Slot called when right clicking on the graph (displays a menu)
136 /// Slot called when right clicking on the graph (displays a menu)
134 void onGraphMenuRequested(const QPoint &pos) noexcept;
137 void onGraphMenuRequested(const QPoint &pos) noexcept;
135
138
136 /// Rescale the X axe to range parameter
139 /// Rescale the X axe to range parameter
137 void onRangeChanged(const QCPRange &t1, const QCPRange &t2);
140 void onRangeChanged(const QCPRange &t1, const QCPRange &t2);
138
141
139 /// Slot called when a mouse double click was made
142 /// Slot called when a mouse double click was made
140 void onMouseDoubleClick(QMouseEvent *event) noexcept;
143 void onMouseDoubleClick(QMouseEvent *event) noexcept;
141 /// Slot called when a mouse move was made
144 /// Slot called when a mouse move was made
142 void onMouseMove(QMouseEvent *event) noexcept;
145 void onMouseMove(QMouseEvent *event) noexcept;
143 /// Slot called when a mouse wheel was made, to perform some processing before the zoom is done
146 /// Slot called when a mouse wheel was made, to perform some processing before the zoom is done
144 void onMouseWheel(QWheelEvent *event) noexcept;
147 void onMouseWheel(QWheelEvent *event) noexcept;
145 /// Slot called when a mouse press was made, to activate the calibration of a graph
148 /// Slot called when a mouse press was made, to activate the calibration of a graph
146 void onMousePress(QMouseEvent *event) noexcept;
149 void onMousePress(QMouseEvent *event) noexcept;
147 /// Slot called when a mouse release was made, to deactivate the calibration of a graph
150 /// Slot called when a mouse release was made, to deactivate the calibration of a graph
148 void onMouseRelease(QMouseEvent *event) noexcept;
151 void onMouseRelease(QMouseEvent *event) noexcept;
149
152
150 void onDataCacheVariableUpdated();
153 void onDataCacheVariableUpdated();
151
154
152 void onUpdateVarDisplaying(std::shared_ptr<Variable> variable, const SqpRange &range);
155 void onUpdateVarDisplaying(std::shared_ptr<Variable> variable, const SqpRange &range);
153 };
156 };
154
157
155 #endif // SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
158 #endif // SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
@@ -1,68 +1,73
1 #ifndef SCIQLOP_VISUALIZATIONSELECTIONZONEITEM_H
1 #ifndef SCIQLOP_VISUALIZATIONSELECTIONZONEITEM_H
2 #define SCIQLOP_VISUALIZATIONSELECTIONZONEITEM_H
2 #define SCIQLOP_VISUALIZATIONSELECTIONZONEITEM_H
3
3
4 #include <Common/spimpl.h>
4 #include <Common/spimpl.h>
5 #include <Data/SqpRange.h>
5 #include <Data/SqpRange.h>
6 #include <Visualization/qcustomplot.h>
6 #include <Visualization/qcustomplot.h>
7
7
8 class VisualizationGraphWidget;
8 class VisualizationGraphWidget;
9
9
10 class VisualizationSelectionZoneItem : public QCPItemRect {
10 class VisualizationSelectionZoneItem : public QCPItemRect {
11 Q_OBJECT
12
13 signals:
14 /// Signal emitted when the zone range is edited manually
15 void rangeEdited(const SqpRange &range);
11
16
12 public:
17 public:
13 VisualizationSelectionZoneItem(QCustomPlot *plot);
18 VisualizationSelectionZoneItem(QCustomPlot *plot);
14 virtual ~VisualizationSelectionZoneItem();
19 virtual ~VisualizationSelectionZoneItem();
15
20
16 VisualizationGraphWidget *parentGraphWidget() const noexcept;
21 VisualizationGraphWidget *parentGraphWidget() const noexcept;
17
22
18 void setName(const QString &name);
23 void setName(const QString &name);
19 QString name() const;
24 QString name() const;
20
25
21 SqpRange range() const;
26 SqpRange range() const;
22 void setRange(double tstart, double tend);
27 void setRange(double tstart, double tend);
23 void setStart(double tstart);
28 void setStart(double tstart);
24 void setEnd(double tend);
29 void setEnd(double tend);
25
30
26 void setColor(const QColor &color);
31 void setColor(const QColor &color);
27
32
28 void setEditionEnabled(bool value);
33 void setEditionEnabled(bool value);
29 bool isEditionEnabled() const;
34 bool isEditionEnabled() const;
30
35
31 /// Moves the item at the top of its QCPLayer. It will then receive the mouse events if multiple
36 /// Moves the item at the top of its QCPLayer. It will then receive the mouse events if multiple
32 /// items are stacked on top of each others.
37 /// items are stacked on top of each others.
33 void moveToTop();
38 void moveToTop();
34
39
35 Qt::CursorShape curshorShapeForPosition(const QPoint &position) const;
40 Qt::CursorShape curshorShapeForPosition(const QPoint &position) const;
36 void setHovered(bool value);
41 void setHovered(bool value);
37
42
38 /// Sets the zones which should be moved or reisized together with this zone
43 /// Sets the zones which should be moved or reisized together with this zone
39 void setAssociatedEditedZones(const QVector<VisualizationSelectionZoneItem *> &associatedZones);
44 void setAssociatedEditedZones(const QVector<VisualizationSelectionZoneItem *> &associatedZones);
40
45
41 /// Align the specified zones with this one, vertically with the left border
46 /// Align the specified zones with this one, vertically with the left border
42 bool alignZonesVerticallyOnLeft(const QVector<VisualizationSelectionZoneItem *> &zonesToAlign,
47 bool alignZonesVerticallyOnLeft(const QVector<VisualizationSelectionZoneItem *> &zonesToAlign,
43 bool allowResize);
48 bool allowResize);
44 /// Align the specified zones with this one, vertically with the right border
49 /// Align the specified zones with this one, vertically with the right border
45 bool alignZonesVerticallyOnRight(const QVector<VisualizationSelectionZoneItem *> &zonesToAlign,
50 bool alignZonesVerticallyOnRight(const QVector<VisualizationSelectionZoneItem *> &zonesToAlign,
46 bool allowResize);
51 bool allowResize);
47 /// Align the specified zones with this one, temporally with the left border
52 /// Align the specified zones with this one, temporally with the left border
48 bool alignZonesTemporallyOnLeft(const QVector<VisualizationSelectionZoneItem *> &zonesToAlign,
53 bool alignZonesTemporallyOnLeft(const QVector<VisualizationSelectionZoneItem *> &zonesToAlign,
49 bool allowResize);
54 bool allowResize);
50 /// Align the specified zones with this one, temporally with the right border
55 /// Align the specified zones with this one, temporally with the right border
51 bool alignZonesTemporallyOnRight(const QVector<VisualizationSelectionZoneItem *> &zonesToAlign,
56 bool alignZonesTemporallyOnRight(const QVector<VisualizationSelectionZoneItem *> &zonesToAlign,
52 bool allowResize);
57 bool allowResize);
53
58
54 protected:
59 protected:
55 void mousePressEvent(QMouseEvent *event, const QVariant &details) override;
60 void mousePressEvent(QMouseEvent *event, const QVariant &details) override;
56 void mouseMoveEvent(QMouseEvent *event, const QPointF &startPos) override;
61 void mouseMoveEvent(QMouseEvent *event, const QPointF &startPos) override;
57 void mouseReleaseEvent(QMouseEvent *event, const QPointF &startPos) override;
62 void mouseReleaseEvent(QMouseEvent *event, const QPointF &startPos) override;
58
63
59 void resizeLeft(double pixelDiff);
64 void resizeLeft(double pixelDiff);
60 void resizeRight(double pixelDiff);
65 void resizeRight(double pixelDiff);
61 void move(double pixelDiff);
66 void move(double pixelDiff);
62
67
63 private:
68 private:
64 class VisualizationSelectionZoneItemPrivate;
69 class VisualizationSelectionZoneItemPrivate;
65 spimpl::unique_impl_ptr<VisualizationSelectionZoneItemPrivate> impl;
70 spimpl::unique_impl_ptr<VisualizationSelectionZoneItemPrivate> impl;
66 };
71 };
67
72
68 #endif // SCIQLOP_VISUALIZATIONSELECTIONZONEITEM_H
73 #endif // SCIQLOP_VISUALIZATIONSELECTIONZONEITEM_H
@@ -1,147 +1,148
1 qxorm_dep = dependency('QxOrm', required : true, fallback:['QxOrm','qxorm_dep'])
1 qxorm_dep = dependency('QxOrm', required : true, fallback:['QxOrm','qxorm_dep'])
2 catalogueapi_dep = dependency('CatalogueAPI', required : true, fallback:['CatalogueAPI','CatalogueAPI_dep'])
2 catalogueapi_dep = dependency('CatalogueAPI', required : true, fallback:['CatalogueAPI','CatalogueAPI_dep'])
3
3
4 gui_moc_headers = [
4 gui_moc_headers = [
5 'include/DataSource/DataSourceWidget.h',
5 'include/DataSource/DataSourceWidget.h',
6 'include/Settings/SqpSettingsDialog.h',
6 'include/Settings/SqpSettingsDialog.h',
7 'include/Settings/SqpSettingsGeneralWidget.h',
7 'include/Settings/SqpSettingsGeneralWidget.h',
8 'include/SidePane/SqpSidePane.h',
8 'include/SidePane/SqpSidePane.h',
9 'include/SqpApplication.h',
9 'include/SqpApplication.h',
10 'include/DragAndDrop/DragDropScroller.h',
10 'include/DragAndDrop/DragDropScroller.h',
11 'include/DragAndDrop/DragDropTabSwitcher.h',
11 'include/DragAndDrop/DragDropTabSwitcher.h',
12 'include/TimeWidget/TimeWidget.h',
12 'include/TimeWidget/TimeWidget.h',
13 'include/Variable/VariableInspectorWidget.h',
13 'include/Variable/VariableInspectorWidget.h',
14 'include/Variable/RenameVariableDialog.h',
14 'include/Variable/RenameVariableDialog.h',
15 'include/Visualization/qcustomplot.h',
15 'include/Visualization/qcustomplot.h',
16 'include/Visualization/VisualizationGraphWidget.h',
16 'include/Visualization/VisualizationGraphWidget.h',
17 'include/Visualization/VisualizationTabWidget.h',
17 'include/Visualization/VisualizationTabWidget.h',
18 'include/Visualization/VisualizationWidget.h',
18 'include/Visualization/VisualizationWidget.h',
19 'include/Visualization/VisualizationZoneWidget.h',
19 'include/Visualization/VisualizationZoneWidget.h',
20 'include/Visualization/VisualizationDragDropContainer.h',
20 'include/Visualization/VisualizationDragDropContainer.h',
21 'include/Visualization/VisualizationDragWidget.h',
21 'include/Visualization/VisualizationDragWidget.h',
22 'include/Visualization/ColorScaleEditor.h',
22 'include/Visualization/ColorScaleEditor.h',
23 'include/Visualization/VisualizationSelectionZoneItem.h',
23 'include/Actions/SelectionZoneAction.h',
24 'include/Actions/SelectionZoneAction.h',
24 'include/Visualization/VisualizationMultiZoneSelectionDialog.h',
25 'include/Visualization/VisualizationMultiZoneSelectionDialog.h',
25 'include/Catalogue/CatalogueExplorer.h',
26 'include/Catalogue/CatalogueExplorer.h',
26 'include/Catalogue/CatalogueEventsWidget.h',
27 'include/Catalogue/CatalogueEventsWidget.h',
27 'include/Catalogue/CatalogueSideBarWidget.h',
28 'include/Catalogue/CatalogueSideBarWidget.h',
28 'include/Catalogue/CatalogueInspectorWidget.h',
29 'include/Catalogue/CatalogueInspectorWidget.h',
29 'include/Catalogue/CatalogueEventsModel.h',
30 'include/Catalogue/CatalogueEventsModel.h',
30 'include/Catalogue/CreateEventDialog.h',
31 'include/Catalogue/CreateEventDialog.h',
31 'include/Catalogue/CatalogueTreeModel.h'
32 'include/Catalogue/CatalogueTreeModel.h'
32 ]
33 ]
33
34
34 gui_ui_files = [
35 gui_ui_files = [
35 'ui/DataSource/DataSourceWidget.ui',
36 'ui/DataSource/DataSourceWidget.ui',
36 'ui/Settings/SqpSettingsDialog.ui',
37 'ui/Settings/SqpSettingsDialog.ui',
37 'ui/Settings/SqpSettingsGeneralWidget.ui',
38 'ui/Settings/SqpSettingsGeneralWidget.ui',
38 'ui/SidePane/SqpSidePane.ui',
39 'ui/SidePane/SqpSidePane.ui',
39 'ui/TimeWidget/TimeWidget.ui',
40 'ui/TimeWidget/TimeWidget.ui',
40 'ui/Variable/VariableInspectorWidget.ui',
41 'ui/Variable/VariableInspectorWidget.ui',
41 'ui/Variable/RenameVariableDialog.ui',
42 'ui/Variable/RenameVariableDialog.ui',
42 'ui/Variable/VariableMenuHeaderWidget.ui',
43 'ui/Variable/VariableMenuHeaderWidget.ui',
43 'ui/Visualization/VisualizationGraphWidget.ui',
44 'ui/Visualization/VisualizationGraphWidget.ui',
44 'ui/Visualization/VisualizationTabWidget.ui',
45 'ui/Visualization/VisualizationTabWidget.ui',
45 'ui/Visualization/VisualizationWidget.ui',
46 'ui/Visualization/VisualizationWidget.ui',
46 'ui/Visualization/VisualizationZoneWidget.ui',
47 'ui/Visualization/VisualizationZoneWidget.ui',
47 'ui/Visualization/ColorScaleEditor.ui',
48 'ui/Visualization/ColorScaleEditor.ui',
48 'ui/Visualization/VisualizationMultiZoneSelectionDialog.ui',
49 'ui/Visualization/VisualizationMultiZoneSelectionDialog.ui',
49 'ui/Catalogue/CatalogueExplorer.ui',
50 'ui/Catalogue/CatalogueExplorer.ui',
50 'ui/Catalogue/CatalogueEventsWidget.ui',
51 'ui/Catalogue/CatalogueEventsWidget.ui',
51 'ui/Catalogue/CatalogueSideBarWidget.ui',
52 'ui/Catalogue/CatalogueSideBarWidget.ui',
52 'ui/Catalogue/CatalogueInspectorWidget.ui',
53 'ui/Catalogue/CatalogueInspectorWidget.ui',
53 'ui/Catalogue/CreateEventDialog.ui'
54 'ui/Catalogue/CreateEventDialog.ui'
54 ]
55 ]
55
56
56 gui_qresources = ['resources/sqpguiresources.qrc']
57 gui_qresources = ['resources/sqpguiresources.qrc']
57
58
58 rcc_gen = generator(rcc,
59 rcc_gen = generator(rcc,
59 output : 'qrc_@BASENAME@.cpp',
60 output : 'qrc_@BASENAME@.cpp',
60 arguments : [
61 arguments : [
61 '--output',
62 '--output',
62 '@OUTPUT@',
63 '@OUTPUT@',
63 '@INPUT@',
64 '@INPUT@',
64 '@EXTRA_ARGS@'])
65 '@EXTRA_ARGS@'])
65
66
66 rcc_files = rcc_gen.process(gui_qresources, extra_args : ['-name', 'sqpguiresources'])
67 rcc_files = rcc_gen.process(gui_qresources, extra_args : ['-name', 'sqpguiresources'])
67
68
68 gui_moc_files = qt5.preprocess(moc_headers : gui_moc_headers,
69 gui_moc_files = qt5.preprocess(moc_headers : gui_moc_headers,
69 ui_files : gui_ui_files)
70 ui_files : gui_ui_files)
70
71
71 gui_sources = [
72 gui_sources = [
72 'src/SqpApplication.cpp',
73 'src/SqpApplication.cpp',
73 'src/DragAndDrop/DragDropGuiController.cpp',
74 'src/DragAndDrop/DragDropGuiController.cpp',
74 'src/DragAndDrop/DragDropScroller.cpp',
75 'src/DragAndDrop/DragDropScroller.cpp',
75 'src/DragAndDrop/DragDropTabSwitcher.cpp',
76 'src/DragAndDrop/DragDropTabSwitcher.cpp',
76 'src/Common/ColorUtils.cpp',
77 'src/Common/ColorUtils.cpp',
77 'src/Common/VisualizationDef.cpp',
78 'src/Common/VisualizationDef.cpp',
78 'src/DataSource/DataSourceTreeWidgetItem.cpp',
79 'src/DataSource/DataSourceTreeWidgetItem.cpp',
79 'src/DataSource/DataSourceTreeWidgetHelper.cpp',
80 'src/DataSource/DataSourceTreeWidgetHelper.cpp',
80 'src/DataSource/DataSourceWidget.cpp',
81 'src/DataSource/DataSourceWidget.cpp',
81 'src/DataSource/DataSourceTreeWidget.cpp',
82 'src/DataSource/DataSourceTreeWidget.cpp',
82 'src/Settings/SqpSettingsDialog.cpp',
83 'src/Settings/SqpSettingsDialog.cpp',
83 'src/Settings/SqpSettingsGeneralWidget.cpp',
84 'src/Settings/SqpSettingsGeneralWidget.cpp',
84 'src/SidePane/SqpSidePane.cpp',
85 'src/SidePane/SqpSidePane.cpp',
85 'src/TimeWidget/TimeWidget.cpp',
86 'src/TimeWidget/TimeWidget.cpp',
86 'src/Variable/VariableInspectorWidget.cpp',
87 'src/Variable/VariableInspectorWidget.cpp',
87 'src/Variable/VariableInspectorTableView.cpp',
88 'src/Variable/VariableInspectorTableView.cpp',
88 'src/Variable/VariableMenuHeaderWidget.cpp',
89 'src/Variable/VariableMenuHeaderWidget.cpp',
89 'src/Variable/RenameVariableDialog.cpp',
90 'src/Variable/RenameVariableDialog.cpp',
90 'src/Visualization/VisualizationGraphHelper.cpp',
91 'src/Visualization/VisualizationGraphHelper.cpp',
91 'src/Visualization/VisualizationGraphRenderingDelegate.cpp',
92 'src/Visualization/VisualizationGraphRenderingDelegate.cpp',
92 'src/Visualization/VisualizationGraphWidget.cpp',
93 'src/Visualization/VisualizationGraphWidget.cpp',
93 'src/Visualization/VisualizationTabWidget.cpp',
94 'src/Visualization/VisualizationTabWidget.cpp',
94 'src/Visualization/VisualizationWidget.cpp',
95 'src/Visualization/VisualizationWidget.cpp',
95 'src/Visualization/VisualizationZoneWidget.cpp',
96 'src/Visualization/VisualizationZoneWidget.cpp',
96 'src/Visualization/qcustomplot.cpp',
97 'src/Visualization/qcustomplot.cpp',
97 'src/Visualization/QCustomPlotSynchronizer.cpp',
98 'src/Visualization/QCustomPlotSynchronizer.cpp',
98 'src/Visualization/operations/FindVariableOperation.cpp',
99 'src/Visualization/operations/FindVariableOperation.cpp',
99 'src/Visualization/operations/GenerateVariableMenuOperation.cpp',
100 'src/Visualization/operations/GenerateVariableMenuOperation.cpp',
100 'src/Visualization/operations/MenuBuilder.cpp',
101 'src/Visualization/operations/MenuBuilder.cpp',
101 'src/Visualization/operations/RemoveVariableOperation.cpp',
102 'src/Visualization/operations/RemoveVariableOperation.cpp',
102 'src/Visualization/operations/RescaleAxeOperation.cpp',
103 'src/Visualization/operations/RescaleAxeOperation.cpp',
103 'src/Visualization/VisualizationDragDropContainer.cpp',
104 'src/Visualization/VisualizationDragDropContainer.cpp',
104 'src/Visualization/VisualizationDragWidget.cpp',
105 'src/Visualization/VisualizationDragWidget.cpp',
105 'src/Visualization/AxisRenderingUtils.cpp',
106 'src/Visualization/AxisRenderingUtils.cpp',
106 'src/Visualization/PlottablesRenderingUtils.cpp',
107 'src/Visualization/PlottablesRenderingUtils.cpp',
107 'src/Visualization/MacScrollBarStyle.cpp',
108 'src/Visualization/MacScrollBarStyle.cpp',
108 'src/Visualization/VisualizationCursorItem.cpp',
109 'src/Visualization/VisualizationCursorItem.cpp',
109 'src/Visualization/ColorScaleEditor.cpp',
110 'src/Visualization/ColorScaleEditor.cpp',
110 'src/Visualization/SqpColorScale.cpp',
111 'src/Visualization/SqpColorScale.cpp',
111 'src/Visualization/QCPColorMapIterator.cpp',
112 'src/Visualization/QCPColorMapIterator.cpp',
112 'src/Visualization/VisualizationSelectionZoneItem.cpp',
113 'src/Visualization/VisualizationSelectionZoneItem.cpp',
113 'src/Visualization/VisualizationSelectionZoneManager.cpp',
114 'src/Visualization/VisualizationSelectionZoneManager.cpp',
114 'src/Actions/SelectionZoneAction.cpp',
115 'src/Actions/SelectionZoneAction.cpp',
115 'src/Actions/ActionsGuiController.cpp',
116 'src/Actions/ActionsGuiController.cpp',
116 'src/Visualization/VisualizationActionManager.cpp',
117 'src/Visualization/VisualizationActionManager.cpp',
117 'src/Visualization/VisualizationMultiZoneSelectionDialog.cpp',
118 'src/Visualization/VisualizationMultiZoneSelectionDialog.cpp',
118 'src/Catalogue/CatalogueExplorer.cpp',
119 'src/Catalogue/CatalogueExplorer.cpp',
119 'src/Catalogue/CatalogueEventsWidget.cpp',
120 'src/Catalogue/CatalogueEventsWidget.cpp',
120 'src/Catalogue/CatalogueSideBarWidget.cpp',
121 'src/Catalogue/CatalogueSideBarWidget.cpp',
121 'src/Catalogue/CatalogueInspectorWidget.cpp',
122 'src/Catalogue/CatalogueInspectorWidget.cpp',
122 'src/Catalogue/CatalogueTreeItems/CatalogueAbstractTreeItem.cpp',
123 'src/Catalogue/CatalogueTreeItems/CatalogueAbstractTreeItem.cpp',
123 'src/Catalogue/CatalogueTreeItems/CatalogueTreeItem.cpp',
124 'src/Catalogue/CatalogueTreeItems/CatalogueTreeItem.cpp',
124 'src/Catalogue/CatalogueTreeItems/CatalogueTextTreeItem.cpp',
125 'src/Catalogue/CatalogueTreeItems/CatalogueTextTreeItem.cpp',
125 'src/Catalogue/CatalogueEventsModel.cpp',
126 'src/Catalogue/CatalogueEventsModel.cpp',
126 'src/Catalogue/CatalogueExplorerHelper.cpp',
127 'src/Catalogue/CatalogueExplorerHelper.cpp',
127 'src/Catalogue/CatalogueActionManager.cpp',
128 'src/Catalogue/CatalogueActionManager.cpp',
128 'src/Catalogue/CreateEventDialog.cpp',
129 'src/Catalogue/CreateEventDialog.cpp',
129 'src/Catalogue/CatalogueTreeModel.cpp'
130 'src/Catalogue/CatalogueTreeModel.cpp'
130 ]
131 ]
131
132
132 gui_inc = include_directories(['include'])
133 gui_inc = include_directories(['include'])
133
134
134 sciqlop_gui_lib = library('sciqlopgui',
135 sciqlop_gui_lib = library('sciqlopgui',
135 gui_sources,
136 gui_sources,
136 gui_moc_files,
137 gui_moc_files,
137 rcc_files,
138 rcc_files,
138 include_directories : [gui_inc],
139 include_directories : [gui_inc],
139 dependencies : [ qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core, catalogueapi_dep],
140 dependencies : [ qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core, catalogueapi_dep],
140 install : true
141 install : true
141 )
142 )
142
143
143 sciqlop_gui = declare_dependency(link_with : sciqlop_gui_lib,
144 sciqlop_gui = declare_dependency(link_with : sciqlop_gui_lib,
144 include_directories : gui_inc,
145 include_directories : gui_inc,
145 dependencies : [qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core, catalogueapi_dep])
146 dependencies : [qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core, catalogueapi_dep])
146
147
147
148
@@ -1,143 +1,147
1 #include "Catalogue/CatalogueActionManager.h"
1 #include "Catalogue/CatalogueActionManager.h"
2
2
3 #include <Actions/ActionsGuiController.h>
3 #include <Actions/ActionsGuiController.h>
4 #include <Catalogue/CatalogueController.h>
4 #include <Catalogue/CatalogueController.h>
5 #include <DataSource/DataSourceItem.h>
5 #include <DataSource/DataSourceItem.h>
6 #include <SqpApplication.h>
6 #include <SqpApplication.h>
7 #include <Variable/Variable.h>
7 #include <Variable/Variable.h>
8 #include <Visualization/VisualizationGraphWidget.h>
8 #include <Visualization/VisualizationGraphWidget.h>
9 #include <Visualization/VisualizationSelectionZoneItem.h>
9 #include <Visualization/VisualizationSelectionZoneItem.h>
10
10
11 #include <Catalogue/CatalogueEventsWidget.h>
11 #include <Catalogue/CatalogueEventsWidget.h>
12 #include <Catalogue/CatalogueExplorer.h>
12 #include <Catalogue/CatalogueExplorer.h>
13 #include <Catalogue/CatalogueSideBarWidget.h>
13 #include <Catalogue/CatalogueSideBarWidget.h>
14 #include <Catalogue/CreateEventDialog.h>
14 #include <Catalogue/CreateEventDialog.h>
15
15
16 #include <CatalogueDao.h>
16 #include <CatalogueDao.h>
17 #include <DBCatalogue.h>
17 #include <DBCatalogue.h>
18 #include <DBEvent.h>
18 #include <DBEvent.h>
19 #include <DBEventProduct.h>
19 #include <DBEventProduct.h>
20
20
21 #include <QBoxLayout>
21 #include <QBoxLayout>
22 #include <QComboBox>
22 #include <QComboBox>
23 #include <QDialog>
23 #include <QDialog>
24 #include <QDialogButtonBox>
24 #include <QDialogButtonBox>
25 #include <QLineEdit>
25 #include <QLineEdit>
26 #include <memory>
26 #include <memory>
27
27
28 struct CatalogueActionManager::CatalogueActionManagerPrivate {
28 struct CatalogueActionManager::CatalogueActionManagerPrivate {
29
29
30 CatalogueExplorer *m_CatalogueExplorer = nullptr;
30 CatalogueExplorer *m_CatalogueExplorer = nullptr;
31
31
32 CatalogueActionManagerPrivate(CatalogueExplorer *catalogueExplorer)
32 CatalogueActionManagerPrivate(CatalogueExplorer *catalogueExplorer)
33 : m_CatalogueExplorer(catalogueExplorer)
33 : m_CatalogueExplorer(catalogueExplorer)
34 {
34 {
35 }
35 }
36
36
37 void createEventFromZones(const QString &eventName,
37 void createEventFromZones(const QString &eventName,
38 const QVector<VisualizationSelectionZoneItem *> &zones,
38 const QVector<VisualizationSelectionZoneItem *> &zones,
39 const std::shared_ptr<DBCatalogue> &catalogue = nullptr)
39 const std::shared_ptr<DBCatalogue> &catalogue = nullptr)
40 {
40 {
41 auto event = std::make_shared<DBEvent>();
41 auto event = std::make_shared<DBEvent>();
42 event->setName(eventName);
42 event->setName(eventName);
43
43
44 std::list<DBEventProduct> productList;
44 std::list<DBEventProduct> productList;
45 for (auto zone : zones) {
45 for (auto zone : zones) {
46 auto graph = zone->parentGraphWidget();
46 auto graph = zone->parentGraphWidget();
47 for (auto var : graph->variables()) {
47 for (auto var : graph->variables()) {
48 auto eventProduct = std::make_shared<DBEventProduct>();
48 auto eventProduct = std::make_shared<DBEventProduct>();
49 eventProduct->setEvent(*event);
49 eventProduct->setEvent(*event);
50
50
51 auto productId
52 = var->metadata().value(DataSourceItem::ID_DATA_KEY, "UnknownID").toString();
53
51 auto zoneRange = zone->range();
54 auto zoneRange = zone->range();
52 eventProduct->setTStart(zoneRange.m_TStart);
55 eventProduct->setTStart(zoneRange.m_TStart);
53 eventProduct->setTEnd(zoneRange.m_TEnd);
56 eventProduct->setTEnd(zoneRange.m_TEnd);
54
57
55 eventProduct->setProductId(
58 eventProduct->setProductId(productId);
56 var->metadata().value(DataSourceItem::ID_DATA_KEY, "UnknownID").toString());
57
59
58 productList.push_back(*eventProduct);
60 productList.push_back(*eventProduct);
61
62 m_CatalogueExplorer->addSelectionZoneItem(event, productId, zone);
59 }
63 }
60 }
64 }
61
65
62 event->setEventProducts(productList);
66 event->setEventProducts(productList);
63
67
64 sqpApp->catalogueController().addEvent(event);
68 sqpApp->catalogueController().addEvent(event);
65
69
66
70
67 if (catalogue) {
71 if (catalogue) {
68 // TODO
72 // TODO
69 // catalogue->addEvent(event);
73 // catalogue->addEvent(event);
70 m_CatalogueExplorer->sideBarWidget().setCatalogueChanges(catalogue, true);
74 m_CatalogueExplorer->sideBarWidget().setCatalogueChanges(catalogue, true);
71 if (m_CatalogueExplorer->eventsWidget().displayedCatalogues().contains(catalogue)) {
75 if (m_CatalogueExplorer->eventsWidget().displayedCatalogues().contains(catalogue)) {
72 m_CatalogueExplorer->eventsWidget().addEvent(event);
76 m_CatalogueExplorer->eventsWidget().addEvent(event);
73 m_CatalogueExplorer->eventsWidget().setEventChanges(event, true);
77 m_CatalogueExplorer->eventsWidget().setEventChanges(event, true);
74 }
78 }
75 }
79 }
76 else if (m_CatalogueExplorer->eventsWidget().isAllEventsDisplayed()) {
80 else if (m_CatalogueExplorer->eventsWidget().isAllEventsDisplayed()) {
77 m_CatalogueExplorer->eventsWidget().addEvent(event);
81 m_CatalogueExplorer->eventsWidget().addEvent(event);
78 m_CatalogueExplorer->eventsWidget().setEventChanges(event, true);
82 m_CatalogueExplorer->eventsWidget().setEventChanges(event, true);
79 }
83 }
80 }
84 }
81 };
85 };
82
86
83 CatalogueActionManager::CatalogueActionManager(CatalogueExplorer *catalogueExplorer)
87 CatalogueActionManager::CatalogueActionManager(CatalogueExplorer *catalogueExplorer)
84 : impl{spimpl::make_unique_impl<CatalogueActionManagerPrivate>(catalogueExplorer)}
88 : impl{spimpl::make_unique_impl<CatalogueActionManagerPrivate>(catalogueExplorer)}
85 {
89 {
86 }
90 }
87
91
88 void CatalogueActionManager::installSelectionZoneActions()
92 void CatalogueActionManager::installSelectionZoneActions()
89 {
93 {
90 auto &actionController = sqpApp->actionsGuiController();
94 auto &actionController = sqpApp->actionsGuiController();
91
95
92 auto createEventEnableFuntion = [](auto zones) {
96 auto createEventEnableFuntion = [](auto zones) {
93
97
94 // Checks that all variables in the zones doesn't refer to the same product
98 // Checks that all variables in the zones doesn't refer to the same product
95 QSet<QString> usedDatasource;
99 QSet<QString> usedDatasource;
96 for (auto zone : zones) {
100 for (auto zone : zones) {
97 auto graph = zone->parentGraphWidget();
101 auto graph = zone->parentGraphWidget();
98 auto variables = graph->variables();
102 auto variables = graph->variables();
99
103
100 for (auto var : variables) {
104 for (auto var : variables) {
101 auto datasourceId = var->metadata().value(DataSourceItem::ID_DATA_KEY).toString();
105 auto datasourceId = var->metadata().value(DataSourceItem::ID_DATA_KEY).toString();
102 if (!usedDatasource.contains(datasourceId)) {
106 if (!usedDatasource.contains(datasourceId)) {
103 usedDatasource.insert(datasourceId);
107 usedDatasource.insert(datasourceId);
104 }
108 }
105 else {
109 else {
106 return false;
110 return false;
107 }
111 }
108 }
112 }
109 }
113 }
110
114
111 return true;
115 return true;
112 };
116 };
113
117
114 auto createEventAction = actionController.addSectionZoneAction(
118 auto createEventAction = actionController.addSectionZoneAction(
115 {QObject::tr("Catalogues")}, QObject::tr("New Event..."), [this](auto zones) {
119 {QObject::tr("Catalogues")}, QObject::tr("New Event..."), [this](auto zones) {
116 CreateEventDialog dialog(
120 CreateEventDialog dialog(
117 impl->m_CatalogueExplorer->sideBarWidget().getCatalogues(REPOSITORY_DEFAULT));
121 impl->m_CatalogueExplorer->sideBarWidget().getCatalogues(REPOSITORY_DEFAULT));
118 dialog.hideCatalogueChoice();
122 dialog.hideCatalogueChoice();
119 if (dialog.exec() == QDialog::Accepted) {
123 if (dialog.exec() == QDialog::Accepted) {
120 impl->createEventFromZones(dialog.eventName(), zones);
124 impl->createEventFromZones(dialog.eventName(), zones);
121 }
125 }
122 });
126 });
123 createEventAction->setEnableFunction(createEventEnableFuntion);
127 createEventAction->setEnableFunction(createEventEnableFuntion);
124
128
125 auto createEventInCatalogueAction = actionController.addSectionZoneAction(
129 auto createEventInCatalogueAction = actionController.addSectionZoneAction(
126 {QObject::tr("Catalogues")}, QObject::tr("New Event in Catalogue..."), [this](auto zones) {
130 {QObject::tr("Catalogues")}, QObject::tr("New Event in Catalogue..."), [this](auto zones) {
127 CreateEventDialog dialog(
131 CreateEventDialog dialog(
128 impl->m_CatalogueExplorer->sideBarWidget().getCatalogues(REPOSITORY_DEFAULT));
132 impl->m_CatalogueExplorer->sideBarWidget().getCatalogues(REPOSITORY_DEFAULT));
129 if (dialog.exec() == QDialog::Accepted) {
133 if (dialog.exec() == QDialog::Accepted) {
130 auto selectedCatalogue = dialog.selectedCatalogue();
134 auto selectedCatalogue = dialog.selectedCatalogue();
131 if (!selectedCatalogue) {
135 if (!selectedCatalogue) {
132 selectedCatalogue = std::make_shared<DBCatalogue>();
136 selectedCatalogue = std::make_shared<DBCatalogue>();
133 selectedCatalogue->setName(dialog.catalogueName());
137 selectedCatalogue->setName(dialog.catalogueName());
134 // sqpApp->catalogueController().addCatalogue(selectedCatalogue); TODO
138 // sqpApp->catalogueController().addCatalogue(selectedCatalogue); TODO
135 impl->m_CatalogueExplorer->sideBarWidget().addCatalogue(selectedCatalogue,
139 impl->m_CatalogueExplorer->sideBarWidget().addCatalogue(selectedCatalogue,
136 REPOSITORY_DEFAULT);
140 REPOSITORY_DEFAULT);
137 }
141 }
138
142
139 impl->createEventFromZones(dialog.eventName(), zones, selectedCatalogue);
143 impl->createEventFromZones(dialog.eventName(), zones, selectedCatalogue);
140 }
144 }
141 });
145 });
142 createEventInCatalogueAction->setEnableFunction(createEventEnableFuntion);
146 createEventInCatalogueAction->setEnableFunction(createEventEnableFuntion);
143 }
147 }
@@ -1,470 +1,590
1 #include "Catalogue/CatalogueEventsWidget.h"
1 #include "Catalogue/CatalogueEventsWidget.h"
2 #include "ui_CatalogueEventsWidget.h"
2 #include "ui_CatalogueEventsWidget.h"
3
3
4 #include <Catalogue/CatalogueController.h>
4 #include <Catalogue/CatalogueController.h>
5 #include <Catalogue/CatalogueEventsModel.h>
5 #include <Catalogue/CatalogueEventsModel.h>
6 #include <Catalogue/CatalogueExplorerHelper.h>
6 #include <Catalogue/CatalogueExplorerHelper.h>
7 #include <CatalogueDao.h>
7 #include <CatalogueDao.h>
8 #include <DBCatalogue.h>
8 #include <DBCatalogue.h>
9 #include <DBEventProduct.h>
10 #include <DataSource/DataSourceController.h>
11 #include <DataSource/DataSourceItem.h>
9 #include <SqpApplication.h>
12 #include <SqpApplication.h>
13 #include <Variable/Variable.h>
14 #include <Variable/VariableController.h>
15 #include <Visualization/VisualizationGraphWidget.h>
10 #include <Visualization/VisualizationTabWidget.h>
16 #include <Visualization/VisualizationTabWidget.h>
11 #include <Visualization/VisualizationWidget.h>
17 #include <Visualization/VisualizationWidget.h>
12 #include <Visualization/VisualizationZoneWidget.h>
18 #include <Visualization/VisualizationZoneWidget.h>
13
19
14 #include <QDialog>
20 #include <QDialog>
15 #include <QDialogButtonBox>
21 #include <QDialogButtonBox>
16 #include <QListWidget>
22 #include <QListWidget>
17 #include <QMessageBox>
23 #include <QMessageBox>
18
24
19 Q_LOGGING_CATEGORY(LOG_CatalogueEventsWidget, "CatalogueEventsWidget")
25 Q_LOGGING_CATEGORY(LOG_CatalogueEventsWidget, "CatalogueEventsWidget")
20
26
21 /// Fixed size of the validation column
27 /// Fixed size of the validation column
22 const auto VALIDATION_COLUMN_SIZE = 35;
28 const auto VALIDATION_COLUMN_SIZE = 35;
23
29
30 /// Percentage added to the range of a event when it is displayed
31 const auto EVENT_RANGE_MARGE = 30; // in %
32
24 struct CatalogueEventsWidget::CatalogueEventsWidgetPrivate {
33 struct CatalogueEventsWidget::CatalogueEventsWidgetPrivate {
25
34
26 CatalogueEventsModel *m_Model = nullptr;
35 CatalogueEventsModel *m_Model = nullptr;
27 QStringList m_ZonesForTimeMode;
36 QStringList m_ZonesForTimeMode;
28 QString m_ZoneForGraphMode;
37 QString m_ZoneForGraphMode;
29 QVector<std::shared_ptr<DBCatalogue> > m_DisplayedCatalogues;
38 QVector<std::shared_ptr<DBCatalogue> > m_DisplayedCatalogues;
30 bool m_AllEventDisplayed = false;
39 bool m_AllEventDisplayed = false;
40 QVector<VisualizationGraphWidget *> m_CustomGraphs;
31
41
32 VisualizationWidget *m_VisualizationWidget = nullptr;
42 VisualizationWidget *m_VisualizationWidget = nullptr;
33
43
34 void setEvents(const QVector<std::shared_ptr<DBEvent> > &events, CatalogueEventsWidget *widget)
44 void setEvents(const QVector<std::shared_ptr<DBEvent> > &events, CatalogueEventsWidget *widget)
35 {
45 {
36 widget->ui->treeView->setSortingEnabled(false);
46 widget->ui->treeView->setSortingEnabled(false);
37 m_Model->setEvents(events);
47 m_Model->setEvents(events);
38 widget->ui->treeView->setSortingEnabled(true);
48 widget->ui->treeView->setSortingEnabled(true);
39
49
40 for (auto event : events) {
50 for (auto event : events) {
41 if (sqpApp->catalogueController().eventHasChanges(event)) {
51 if (sqpApp->catalogueController().eventHasChanges(event)) {
42 auto index = m_Model->indexOf(event);
52 auto index = m_Model->indexOf(event);
43 widget->setEventChanges(event, true);
53 widget->setEventChanges(event, true);
44 }
54 }
45 }
55 }
46 }
56 }
47
57
48 void addEvent(const std::shared_ptr<DBEvent> &event, QTreeView *treeView)
58 void addEvent(const std::shared_ptr<DBEvent> &event, QTreeView *treeView)
49 {
59 {
50 treeView->setSortingEnabled(false);
60 treeView->setSortingEnabled(false);
51 m_Model->addEvent(event);
61 m_Model->addEvent(event);
52 treeView->setSortingEnabled(true);
62 treeView->setSortingEnabled(true);
53 }
63 }
54
64
55 void removeEvent(const std::shared_ptr<DBEvent> &event, QTreeView *treeView)
65 void removeEvent(const std::shared_ptr<DBEvent> &event, QTreeView *treeView)
56 {
66 {
57 treeView->setSortingEnabled(false);
67 treeView->setSortingEnabled(false);
58 m_Model->removeEvent(event);
68 m_Model->removeEvent(event);
59 treeView->setSortingEnabled(true);
69 treeView->setSortingEnabled(true);
60 }
70 }
61
71
62 QStringList getAvailableVisualizationZoneList() const
72 QStringList getAvailableVisualizationZoneList() const
63 {
73 {
64 if (m_VisualizationWidget) {
74 if (m_VisualizationWidget) {
65 if (auto tab = m_VisualizationWidget->currentTabWidget()) {
75 if (auto tab = m_VisualizationWidget->currentTabWidget()) {
66 return tab->availableZoneWidgets();
76 return tab->availableZoneWidgets();
67 }
77 }
68 }
78 }
69
79
70 return QStringList{};
80 return QStringList{};
71 }
81 }
72
82
73 QStringList selectZone(QWidget *parent, const QStringList &selectedZones,
83 QStringList selectZone(QWidget *parent, const QStringList &selectedZones,
74 bool allowMultiSelection, const QPoint &location)
84 bool allowMultiSelection, const QPoint &location)
75 {
85 {
76 auto availableZones = getAvailableVisualizationZoneList();
86 auto availableZones = getAvailableVisualizationZoneList();
77 if (availableZones.isEmpty()) {
87 if (availableZones.isEmpty()) {
78 return QStringList{};
88 return QStringList{};
79 }
89 }
80
90
81 QDialog d(parent, Qt::Tool);
91 QDialog d(parent, Qt::Tool);
82 d.setWindowTitle("Choose a zone");
92 d.setWindowTitle("Choose a zone");
83 auto layout = new QVBoxLayout{&d};
93 auto layout = new QVBoxLayout{&d};
84 layout->setContentsMargins(0, 0, 0, 0);
94 layout->setContentsMargins(0, 0, 0, 0);
85 auto listWidget = new QListWidget{&d};
95 auto listWidget = new QListWidget{&d};
86 layout->addWidget(listWidget);
96 layout->addWidget(listWidget);
87
97
88 QSet<QListWidgetItem *> checkedItems;
98 QSet<QListWidgetItem *> checkedItems;
89 for (auto zone : availableZones) {
99 for (auto zone : availableZones) {
90 auto item = new QListWidgetItem{zone};
100 auto item = new QListWidgetItem{zone};
91 item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsUserCheckable);
101 item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsUserCheckable);
92 if (selectedZones.contains(zone)) {
102 if (selectedZones.contains(zone)) {
93 item->setCheckState(Qt::Checked);
103 item->setCheckState(Qt::Checked);
94 checkedItems << item;
104 checkedItems << item;
95 }
105 }
96 else {
106 else {
97 item->setCheckState(Qt::Unchecked);
107 item->setCheckState(Qt::Unchecked);
98 }
108 }
99
109
100 listWidget->addItem(item);
110 listWidget->addItem(item);
101 }
111 }
102
112
103 auto buttonBox = new QDialogButtonBox{QDialogButtonBox::Ok, &d};
113 auto buttonBox = new QDialogButtonBox{QDialogButtonBox::Ok, &d};
104 layout->addWidget(buttonBox);
114 layout->addWidget(buttonBox);
105
115
106 QObject::connect(buttonBox, &QDialogButtonBox::accepted, &d, &QDialog::accept);
116 QObject::connect(buttonBox, &QDialogButtonBox::accepted, &d, &QDialog::accept);
107 QObject::connect(buttonBox, &QDialogButtonBox::rejected, &d, &QDialog::reject);
117 QObject::connect(buttonBox, &QDialogButtonBox::rejected, &d, &QDialog::reject);
108
118
109 QObject::connect(listWidget, &QListWidget::itemChanged,
119 QObject::connect(listWidget, &QListWidget::itemChanged,
110 [&checkedItems, allowMultiSelection, listWidget](auto item) {
120 [&checkedItems, allowMultiSelection, listWidget](auto item) {
111 if (item->checkState() == Qt::Checked) {
121 if (item->checkState() == Qt::Checked) {
112 if (!allowMultiSelection) {
122 if (!allowMultiSelection) {
113 for (auto checkedItem : checkedItems) {
123 for (auto checkedItem : checkedItems) {
114 listWidget->blockSignals(true);
124 listWidget->blockSignals(true);
115 checkedItem->setCheckState(Qt::Unchecked);
125 checkedItem->setCheckState(Qt::Unchecked);
116 listWidget->blockSignals(false);
126 listWidget->blockSignals(false);
117 }
127 }
118
128
119 checkedItems.clear();
129 checkedItems.clear();
120 }
130 }
121 checkedItems << item;
131 checkedItems << item;
122 }
132 }
123 else {
133 else {
124 checkedItems.remove(item);
134 checkedItems.remove(item);
125 }
135 }
126 });
136 });
127
137
128 QStringList result;
138 QStringList result;
129
139
130 d.setMinimumWidth(120);
140 d.setMinimumWidth(120);
131 d.resize(d.minimumSizeHint());
141 d.resize(d.minimumSizeHint());
132 d.move(location);
142 d.move(location);
133 if (d.exec() == QDialog::Accepted) {
143 if (d.exec() == QDialog::Accepted) {
134 for (auto item : checkedItems) {
144 for (auto item : checkedItems) {
135 result += item->text();
145 result += item->text();
136 }
146 }
137 }
147 }
138 else {
148 else {
139 result = selectedZones;
149 result = selectedZones;
140 }
150 }
141
151
142 return result;
152 return result;
143 }
153 }
144
154
145 void updateForTimeMode(QTreeView *treeView)
155 void updateForTimeMode(QTreeView *treeView)
146 {
156 {
147 auto selectedRows = treeView->selectionModel()->selectedRows();
157 auto selectedRows = treeView->selectionModel()->selectedRows();
148
158
149 if (selectedRows.count() == 1) {
159 if (selectedRows.count() == 1) {
150 auto event = m_Model->getEvent(selectedRows.first());
160 auto event = m_Model->getEvent(selectedRows.first());
151 if (event) {
161 if (event) {
152 if (m_VisualizationWidget) {
162 if (m_VisualizationWidget) {
153 if (auto tab = m_VisualizationWidget->currentTabWidget()) {
163 if (auto tab = m_VisualizationWidget->currentTabWidget()) {
154
164
155 for (auto zoneName : m_ZonesForTimeMode) {
165 for (auto zoneName : m_ZonesForTimeMode) {
156 if (auto zone = tab->getZoneWithName(zoneName)) {
166 if (auto zone = tab->getZoneWithName(zoneName)) {
157 SqpRange eventRange;
167 SqpRange eventRange;
158 eventRange.m_TStart = event->getTStart();
168 eventRange.m_TStart = event->getTStart();
159 eventRange.m_TEnd = event->getTEnd();
169 eventRange.m_TEnd = event->getTEnd();
160 zone->setZoneRange(eventRange);
170 zone->setZoneRange(eventRange);
161 }
171 }
162 }
172 }
163 }
173 }
164 else {
174 else {
165 qCWarning(LOG_CatalogueEventsWidget())
175 qCWarning(LOG_CatalogueEventsWidget())
166 << "updateTimeZone: no tab found in the visualization";
176 << "updateTimeZone: no tab found in the visualization";
167 }
177 }
168 }
178 }
169 else {
179 else {
170 qCWarning(LOG_CatalogueEventsWidget())
180 qCWarning(LOG_CatalogueEventsWidget())
171 << "updateTimeZone: visualization widget not found";
181 << "updateTimeZone: visualization widget not found";
172 }
182 }
173 }
183 }
174 }
184 }
175 else {
185 else {
176 qCWarning(LOG_CatalogueEventsWidget())
186 qCWarning(LOG_CatalogueEventsWidget())
177 << "updateTimeZone: not compatible with multiple events selected";
187 << "updateTimeZone: not compatible with multiple events selected";
178 }
188 }
179 }
189 }
180
190
181 void updateForGraphMode(QTreeView *treeView)
191 QVector<SqpRange> getGraphRanges(const std::shared_ptr<DBEvent> &event)
182 {
192 {
183 auto selectedRows = treeView->selectionModel()->selectedRows();
193 // Retrieves the range of each product and the maximum size
184
194 QVector<SqpRange> graphRanges;
185 if (selectedRows.count() == 1) {
195 double maxDt = 0;
186 auto event = m_Model->getEvent(selectedRows.first());
196 for (auto eventProduct : event->getEventProducts()) {
187 if (m_VisualizationWidget) {
197 SqpRange eventRange;
188 if (auto tab = m_VisualizationWidget->currentTabWidget()) {
198 eventRange.m_TStart = eventProduct.getTStart();
189 if (auto zone = tab->getZoneWithName(m_ZoneForGraphMode)) {
199 eventRange.m_TEnd = eventProduct.getTEnd();
190 // TODO
200 graphRanges << eventRange;
191 }
201
192 }
202 auto dt = eventRange.m_TEnd - eventRange.m_TStart;
193 else {
203 if (dt > maxDt) {
194 qCWarning(LOG_CatalogueEventsWidget())
204 maxDt = dt;
195 << "updateGraphMode: no tab found in the visualization";
196 }
197 }
198 else {
199 qCWarning(LOG_CatalogueEventsWidget())
200 << "updateGraphMode: visualization widget not found";
201 }
205 }
202 }
206 }
203 else {
207
208 // Adds the marge
209 maxDt *= (100.0 + EVENT_RANGE_MARGE) / 100.0;
210
211 // Corrects the graph ranges so that they all have the same size
212 QVector<SqpRange> correctedGraphRanges;
213 for (auto range : graphRanges) {
214 auto dt = range.m_TEnd - range.m_TStart;
215 auto diff = qAbs((maxDt - dt) / 2.0);
216
217 SqpRange correctedRange;
218 correctedRange.m_TStart = range.m_TStart - diff;
219 correctedRange.m_TEnd = range.m_TEnd + diff;
220
221 correctedGraphRanges << correctedRange;
222 }
223
224 return correctedGraphRanges;
225 }
226
227 void updateForGraphMode(CatalogueEventsWidget *catalogueEventWidget)
228 {
229 auto selectedRows = catalogueEventWidget->ui->treeView->selectionModel()->selectedRows();
230 if (selectedRows.count() != 1) {
204 qCWarning(LOG_CatalogueEventsWidget())
231 qCWarning(LOG_CatalogueEventsWidget())
205 << "updateGraphMode: not compatible with multiple events selected";
232 << "updateGraphMode: not compatible with multiple events selected";
233 return;
234 }
235
236 if (!m_VisualizationWidget) {
237 qCWarning(LOG_CatalogueEventsWidget())
238 << "updateGraphMode: visualization widget not found";
239 return;
240 }
241
242 auto event = m_Model->getEvent(selectedRows.first());
243 if (!event) {
244 // A event product is probably selected
245 qCInfo(LOG_CatalogueEventsWidget()) << "updateGraphMode: no events are selected";
246 return;
247 }
248
249 auto tab = m_VisualizationWidget->currentTabWidget();
250 if (!tab) {
251 qCWarning(LOG_CatalogueEventsWidget())
252 << "updateGraphMode: no tab found in the visualization";
253 return;
254 }
255
256 auto zone = tab->getZoneWithName(m_ZoneForGraphMode);
257 if (!zone) {
258 qCWarning(LOG_CatalogueEventsWidget()) << "updateGraphMode: zone not found";
259 return;
260 }
261
262 // Close the previous graph and delete the asociated variables
263 for (auto graph : m_CustomGraphs) {
264 graph->close();
265 auto variables = graph->variables().toVector();
266
267 QMetaObject::invokeMethod(&sqpApp->variableController(), "deleteVariables",
268 Qt::QueuedConnection,
269 Q_ARG(QVector<std::shared_ptr<Variable> >, variables));
270 }
271 m_CustomGraphs.clear();
272
273 // Calculates the range of each graph which will be created
274 auto graphRange = getGraphRanges(event);
275
276 // Loops through the event products and create the graph
277 auto itRange = graphRange.cbegin();
278 for (auto eventProduct : event->getEventProducts()) {
279 auto productId = eventProduct.getProductId();
280
281 auto range = *itRange;
282 ++itRange;
283
284 SqpRange productRange;
285 productRange.m_TStart = eventProduct.getTStart();
286 productRange.m_TEnd = eventProduct.getTEnd();
287
288 auto context = new QObject{catalogueEventWidget};
289 QObject::connect(
290 &sqpApp->variableController(), &VariableController::variableAdded, context,
291 [this, catalogueEventWidget, zone, context, event, range, productRange,
292 productId](auto variable) {
293
294 if (variable->metadata().value(DataSourceItem::ID_DATA_KEY).toString()
295 == productId) {
296 auto graph = zone->createGraph(variable);
297 graph->setAutoRangeOnVariableInitialization(false);
298
299 auto selectionZone
300 = graph->addSelectionZone(event->getName(), productRange);
301 emit catalogueEventWidget->selectionZoneAdded(event, productId,
302 selectionZone);
303 m_CustomGraphs << graph;
304
305 graph->setGraphRange(range, true);
306
307 // Removes the graph from the graph list if it is closed manually
308 QObject::connect(graph, &VisualizationGraphWidget::destroyed,
309 [this, graph]() { m_CustomGraphs.removeAll(graph); });
310
311 delete context; // removes the connection
312 }
313 },
314 Qt::QueuedConnection);
315
316 QMetaObject::invokeMethod(&sqpApp->dataSourceController(),
317 "requestVariableFromProductIdKey", Qt::QueuedConnection,
318 Q_ARG(QString, productId));
206 }
319 }
207 }
320 }
208
321
209 void getSelectedItems(
322 void getSelectedItems(
210 QTreeView *treeView, QVector<std::shared_ptr<DBEvent> > &events,
323 QTreeView *treeView, QVector<std::shared_ptr<DBEvent> > &events,
211 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > &eventProducts)
324 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > &eventProducts)
212 {
325 {
213 for (auto rowIndex : treeView->selectionModel()->selectedRows()) {
326 for (auto rowIndex : treeView->selectionModel()->selectedRows()) {
214 auto itemType = m_Model->itemTypeOf(rowIndex);
327 auto itemType = m_Model->itemTypeOf(rowIndex);
215 if (itemType == CatalogueEventsModel::ItemType::Event) {
328 if (itemType == CatalogueEventsModel::ItemType::Event) {
216 events << m_Model->getEvent(rowIndex);
329 events << m_Model->getEvent(rowIndex);
217 }
330 }
218 else if (itemType == CatalogueEventsModel::ItemType::EventProduct) {
331 else if (itemType == CatalogueEventsModel::ItemType::EventProduct) {
219 eventProducts << qMakePair(m_Model->getParentEvent(rowIndex),
332 eventProducts << qMakePair(m_Model->getParentEvent(rowIndex),
220 m_Model->getEventProduct(rowIndex));
333 m_Model->getEventProduct(rowIndex));
221 }
334 }
222 }
335 }
223 }
336 }
224 };
337 };
225
338
226 CatalogueEventsWidget::CatalogueEventsWidget(QWidget *parent)
339 CatalogueEventsWidget::CatalogueEventsWidget(QWidget *parent)
227 : QWidget(parent),
340 : QWidget(parent),
228 ui(new Ui::CatalogueEventsWidget),
341 ui(new Ui::CatalogueEventsWidget),
229 impl{spimpl::make_unique_impl<CatalogueEventsWidgetPrivate>()}
342 impl{spimpl::make_unique_impl<CatalogueEventsWidgetPrivate>()}
230 {
343 {
231 ui->setupUi(this);
344 ui->setupUi(this);
232
345
233 impl->m_Model = new CatalogueEventsModel{this};
346 impl->m_Model = new CatalogueEventsModel{this};
234 ui->treeView->setModel(impl->m_Model);
347 ui->treeView->setModel(impl->m_Model);
235
348
236 ui->treeView->setSortingEnabled(true);
349 ui->treeView->setSortingEnabled(true);
237 ui->treeView->setDragDropMode(QAbstractItemView::DragDrop);
350 ui->treeView->setDragDropMode(QAbstractItemView::DragDrop);
238 ui->treeView->setDragEnabled(true);
351 ui->treeView->setDragEnabled(true);
239
352
240 connect(ui->btnTime, &QToolButton::clicked, [this](auto checked) {
353 connect(ui->btnTime, &QToolButton::clicked, [this](auto checked) {
241 if (checked) {
354 if (checked) {
242 ui->btnChart->setChecked(false);
355 ui->btnChart->setChecked(false);
243 impl->m_ZonesForTimeMode
356 impl->m_ZonesForTimeMode
244 = impl->selectZone(this, impl->m_ZonesForTimeMode, true,
357 = impl->selectZone(this, impl->m_ZonesForTimeMode, true,
245 this->mapToGlobal(ui->btnTime->frameGeometry().center()));
358 this->mapToGlobal(ui->btnTime->frameGeometry().center()));
246
359
247 impl->updateForTimeMode(ui->treeView);
360 impl->updateForTimeMode(ui->treeView);
248 }
361 }
249 });
362 });
250
363
251 connect(ui->btnChart, &QToolButton::clicked, [this](auto checked) {
364 connect(ui->btnChart, &QToolButton::clicked, [this](auto checked) {
252 if (checked) {
365 if (checked) {
253 ui->btnTime->setChecked(false);
366 ui->btnTime->setChecked(false);
254 impl->m_ZoneForGraphMode
367 impl->m_ZoneForGraphMode
255 = impl->selectZone(this, {impl->m_ZoneForGraphMode}, false,
368 = impl->selectZone(this, {impl->m_ZoneForGraphMode}, false,
256 this->mapToGlobal(ui->btnChart->frameGeometry().center()))
369 this->mapToGlobal(ui->btnChart->frameGeometry().center()))
257 .value(0);
370 .value(0);
258
371
259 impl->updateForGraphMode(ui->treeView);
372 impl->updateForGraphMode(this);
260 }
373 }
261 });
374 });
262
375
263 connect(ui->btnRemove, &QToolButton::clicked, [this]() {
376 connect(ui->btnRemove, &QToolButton::clicked, [this]() {
264 QVector<std::shared_ptr<DBEvent> > events;
377 QVector<std::shared_ptr<DBEvent> > events;
265 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > eventProducts;
378 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > eventProducts;
266 impl->getSelectedItems(ui->treeView, events, eventProducts);
379 impl->getSelectedItems(ui->treeView, events, eventProducts);
267
380
268 if (!events.isEmpty() && eventProducts.isEmpty()) {
381 if (!events.isEmpty() && eventProducts.isEmpty()) {
269
382
270 if (QMessageBox::warning(this, tr("Remove Event(s)"),
383 if (QMessageBox::warning(this, tr("Remove Event(s)"),
271 tr("The selected event(s) will be completly removed "
384 tr("The selected event(s) will be permanently removed "
272 "from the repository!\nAre you sure you want to continue?"),
385 "from the repository!\nAre you sure you want to continue?"),
273 QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
386 QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
274 == QMessageBox::Yes) {
387 == QMessageBox::Yes) {
275
388
276 for (auto event : events) {
389 for (auto event : events) {
277 sqpApp->catalogueController().removeEvent(event);
390 sqpApp->catalogueController().removeEvent(event);
278 impl->removeEvent(event, ui->treeView);
391 impl->removeEvent(event, ui->treeView);
279 }
392 }
393
394 emit this->eventsRemoved(events);
280 }
395 }
281 }
396 }
282 });
397 });
283
398
284 connect(ui->treeView, &QTreeView::clicked, this, &CatalogueEventsWidget::emitSelection);
399 connect(ui->treeView, &QTreeView::clicked, this, &CatalogueEventsWidget::emitSelection);
285 connect(ui->treeView->selectionModel(), &QItemSelectionModel::selectionChanged, this,
400 connect(ui->treeView->selectionModel(), &QItemSelectionModel::selectionChanged, this,
286 &CatalogueEventsWidget::emitSelection);
401 &CatalogueEventsWidget::emitSelection);
287
402
288 ui->btnRemove->setEnabled(false); // Disabled by default when nothing is selected
403 ui->btnRemove->setEnabled(false); // Disabled by default when nothing is selected
289 connect(ui->treeView->selectionModel(), &QItemSelectionModel::selectionChanged, [this]() {
404 connect(ui->treeView->selectionModel(), &QItemSelectionModel::selectionChanged, [this]() {
290 auto isNotMultiSelection = ui->treeView->selectionModel()->selectedRows().count() <= 1;
405 auto isNotMultiSelection = ui->treeView->selectionModel()->selectedRows().count() <= 1;
291 ui->btnChart->setEnabled(isNotMultiSelection);
406 ui->btnChart->setEnabled(isNotMultiSelection);
292 ui->btnTime->setEnabled(isNotMultiSelection);
407 ui->btnTime->setEnabled(isNotMultiSelection);
293
408
294 if (isNotMultiSelection && ui->btnTime->isChecked()) {
409 if (isNotMultiSelection && ui->btnTime->isChecked()) {
295 impl->updateForTimeMode(ui->treeView);
410 impl->updateForTimeMode(ui->treeView);
296 }
411 }
297 else if (isNotMultiSelection && ui->btnChart->isChecked()) {
412 else if (isNotMultiSelection && ui->btnChart->isChecked()) {
298 impl->updateForGraphMode(ui->treeView);
413 impl->updateForGraphMode(this);
299 }
414 }
300
415
301 QVector<std::shared_ptr<DBEvent> > events;
416 QVector<std::shared_ptr<DBEvent> > events;
302 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > eventProducts;
417 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > eventProducts;
303 impl->getSelectedItems(ui->treeView, events, eventProducts);
418 impl->getSelectedItems(ui->treeView, events, eventProducts);
304 ui->btnRemove->setEnabled(!events.isEmpty() && eventProducts.isEmpty());
419 ui->btnRemove->setEnabled(!events.isEmpty() && eventProducts.isEmpty());
305 });
420 });
306
421
307 ui->treeView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
422 ui->treeView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
308 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::Tags,
423 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::Tags,
309 QHeaderView::Stretch);
424 QHeaderView::Stretch);
310 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::Validation,
425 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::Validation,
311 QHeaderView::Fixed);
426 QHeaderView::Fixed);
312 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::Name,
427 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::Name,
313 QHeaderView::Interactive);
428 QHeaderView::Interactive);
314 ui->treeView->header()->resizeSection((int)CatalogueEventsModel::Column::Validation,
429 ui->treeView->header()->resizeSection((int)CatalogueEventsModel::Column::Validation,
315 VALIDATION_COLUMN_SIZE);
430 VALIDATION_COLUMN_SIZE);
316 ui->treeView->header()->setSortIndicatorShown(true);
431 ui->treeView->header()->setSortIndicatorShown(true);
317
432
318 connect(impl->m_Model, &CatalogueEventsModel::modelSorted, [this]() {
433 connect(impl->m_Model, &CatalogueEventsModel::modelSorted, [this]() {
319 auto allEvents = impl->m_Model->events();
434 auto allEvents = impl->m_Model->events();
320 for (auto event : allEvents) {
435 for (auto event : allEvents) {
321 setEventChanges(event, sqpApp->catalogueController().eventHasChanges(event));
436 setEventChanges(event, sqpApp->catalogueController().eventHasChanges(event));
322 }
437 }
323 });
438 });
324
439
325 populateWithAllEvents();
440 populateWithAllEvents();
326 }
441 }
327
442
328 CatalogueEventsWidget::~CatalogueEventsWidget()
443 CatalogueEventsWidget::~CatalogueEventsWidget()
329 {
444 {
330 delete ui;
445 delete ui;
331 }
446 }
332
447
333 void CatalogueEventsWidget::setVisualizationWidget(VisualizationWidget *visualization)
448 void CatalogueEventsWidget::setVisualizationWidget(VisualizationWidget *visualization)
334 {
449 {
335 impl->m_VisualizationWidget = visualization;
450 impl->m_VisualizationWidget = visualization;
336 }
451 }
337
452
338 void CatalogueEventsWidget::addEvent(const std::shared_ptr<DBEvent> &event)
453 void CatalogueEventsWidget::addEvent(const std::shared_ptr<DBEvent> &event)
339 {
454 {
340 impl->addEvent(event, ui->treeView);
455 impl->addEvent(event, ui->treeView);
341 }
456 }
342
457
343 void CatalogueEventsWidget::setEventChanges(const std::shared_ptr<DBEvent> &event, bool hasChanges)
458 void CatalogueEventsWidget::setEventChanges(const std::shared_ptr<DBEvent> &event, bool hasChanges)
344 {
459 {
345 impl->m_Model->refreshEvent(event);
460 impl->m_Model->refreshEvent(event);
346
461
347 auto eventIndex = impl->m_Model->indexOf(event);
462 auto eventIndex = impl->m_Model->indexOf(event);
348 auto validationIndex
463 auto validationIndex
349 = eventIndex.sibling(eventIndex.row(), (int)CatalogueEventsModel::Column::Validation);
464 = eventIndex.sibling(eventIndex.row(), (int)CatalogueEventsModel::Column::Validation);
350
465
351 if (validationIndex.isValid()) {
466 if (validationIndex.isValid()) {
352 if (hasChanges) {
467 if (hasChanges) {
353 if (ui->treeView->indexWidget(validationIndex) == nullptr) {
468 if (ui->treeView->indexWidget(validationIndex) == nullptr) {
354 auto widget = CatalogueExplorerHelper::buildValidationWidget(
469 auto widget = CatalogueExplorerHelper::buildValidationWidget(
355 ui->treeView,
470 ui->treeView,
356 [this, event]() {
471 [this, event]() {
357 sqpApp->catalogueController().saveEvent(event);
472 sqpApp->catalogueController().saveEvent(event);
358 setEventChanges(event, false);
473 setEventChanges(event, false);
359 },
474 },
360 [this, event]() {
475 [this, event]() {
361 bool removed = false;
476 bool removed = false;
362 sqpApp->catalogueController().discardEvent(event, removed);
477 sqpApp->catalogueController().discardEvent(event, removed);
363 if (removed) {
478 if (removed) {
364 impl->m_Model->removeEvent(event);
479 impl->m_Model->removeEvent(event);
365 }
480 }
366 else {
481 else {
367 setEventChanges(event, false);
482 setEventChanges(event, false);
368 impl->m_Model->refreshEvent(event, true);
483 impl->m_Model->refreshEvent(event, true);
369 }
484 }
370 emitSelection();
485 emitSelection();
371 });
486 });
372 ui->treeView->setIndexWidget(validationIndex, widget);
487 ui->treeView->setIndexWidget(validationIndex, widget);
373 }
488 }
374 }
489 }
375 else {
490 else {
376 // Note: the widget is destroyed
491 // Note: the widget is destroyed
377 ui->treeView->setIndexWidget(validationIndex, nullptr);
492 ui->treeView->setIndexWidget(validationIndex, nullptr);
378 }
493 }
379 }
494 }
380 else {
495 else {
381 qCWarning(LOG_CatalogueEventsWidget())
496 qCWarning(LOG_CatalogueEventsWidget())
382 << "setEventChanges: the event is not displayed in the model.";
497 << "setEventChanges: the event is not displayed in the model.";
383 }
498 }
384 }
499 }
385
500
386 QVector<std::shared_ptr<DBCatalogue> > CatalogueEventsWidget::displayedCatalogues() const
501 QVector<std::shared_ptr<DBCatalogue> > CatalogueEventsWidget::displayedCatalogues() const
387 {
502 {
388 return impl->m_DisplayedCatalogues;
503 return impl->m_DisplayedCatalogues;
389 }
504 }
390
505
391 bool CatalogueEventsWidget::isAllEventsDisplayed() const
506 bool CatalogueEventsWidget::isAllEventsDisplayed() const
392 {
507 {
393 return impl->m_AllEventDisplayed;
508 return impl->m_AllEventDisplayed;
394 }
509 }
395
510
396 bool CatalogueEventsWidget::isEventDisplayed(const std::shared_ptr<DBEvent> &event) const
511 bool CatalogueEventsWidget::isEventDisplayed(const std::shared_ptr<DBEvent> &event) const
397 {
512 {
398 return impl->m_Model->indexOf(event).isValid();
513 return impl->m_Model->indexOf(event).isValid();
399 }
514 }
400
515
516 void CatalogueEventsWidget::refreshEvent(const std::shared_ptr<DBEvent> &event)
517 {
518 impl->m_Model->refreshEvent(event, true);
519 }
520
401 void CatalogueEventsWidget::populateWithCatalogues(
521 void CatalogueEventsWidget::populateWithCatalogues(
402 const QVector<std::shared_ptr<DBCatalogue> > &catalogues)
522 const QVector<std::shared_ptr<DBCatalogue> > &catalogues)
403 {
523 {
404 impl->m_DisplayedCatalogues = catalogues;
524 impl->m_DisplayedCatalogues = catalogues;
405 impl->m_AllEventDisplayed = false;
525 impl->m_AllEventDisplayed = false;
406
526
407 QSet<QUuid> eventIds;
527 QSet<QUuid> eventIds;
408 QVector<std::shared_ptr<DBEvent> > events;
528 QVector<std::shared_ptr<DBEvent> > events;
409
529
410 for (auto catalogue : catalogues) {
530 for (auto catalogue : catalogues) {
411 auto catalogueEvents = sqpApp->catalogueController().retrieveEventsFromCatalogue(catalogue);
531 auto catalogueEvents = sqpApp->catalogueController().retrieveEventsFromCatalogue(catalogue);
412 for (auto event : catalogueEvents) {
532 for (auto event : catalogueEvents) {
413 if (!eventIds.contains(event->getUniqId())) {
533 if (!eventIds.contains(event->getUniqId())) {
414 events << event;
534 events << event;
415 eventIds.insert(event->getUniqId());
535 eventIds.insert(event->getUniqId());
416 }
536 }
417 }
537 }
418 }
538 }
419
539
420 impl->setEvents(events, this);
540 impl->setEvents(events, this);
421 }
541 }
422
542
423 void CatalogueEventsWidget::populateWithAllEvents()
543 void CatalogueEventsWidget::populateWithAllEvents()
424 {
544 {
425 impl->m_DisplayedCatalogues.clear();
545 impl->m_DisplayedCatalogues.clear();
426 impl->m_AllEventDisplayed = true;
546 impl->m_AllEventDisplayed = true;
427
547
428 auto allEvents = sqpApp->catalogueController().retrieveAllEvents();
548 auto allEvents = sqpApp->catalogueController().retrieveAllEvents();
429
549
430 QVector<std::shared_ptr<DBEvent> > events;
550 QVector<std::shared_ptr<DBEvent> > events;
431 for (auto event : allEvents) {
551 for (auto event : allEvents) {
432 events << event;
552 events << event;
433 }
553 }
434
554
435 impl->setEvents(events, this);
555 impl->setEvents(events, this);
436 }
556 }
437
557
438 void CatalogueEventsWidget::clear()
558 void CatalogueEventsWidget::clear()
439 {
559 {
440 impl->m_DisplayedCatalogues.clear();
560 impl->m_DisplayedCatalogues.clear();
441 impl->m_AllEventDisplayed = false;
561 impl->m_AllEventDisplayed = false;
442 impl->setEvents({}, this);
562 impl->setEvents({}, this);
443 }
563 }
444
564
445 void CatalogueEventsWidget::refresh()
565 void CatalogueEventsWidget::refresh()
446 {
566 {
447 if (isAllEventsDisplayed()) {
567 if (isAllEventsDisplayed()) {
448 populateWithAllEvents();
568 populateWithAllEvents();
449 }
569 }
450 else if (!impl->m_DisplayedCatalogues.isEmpty()) {
570 else if (!impl->m_DisplayedCatalogues.isEmpty()) {
451 populateWithCatalogues(impl->m_DisplayedCatalogues);
571 populateWithCatalogues(impl->m_DisplayedCatalogues);
452 }
572 }
453 }
573 }
454
574
455 void CatalogueEventsWidget::emitSelection()
575 void CatalogueEventsWidget::emitSelection()
456 {
576 {
457 QVector<std::shared_ptr<DBEvent> > events;
577 QVector<std::shared_ptr<DBEvent> > events;
458 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > eventProducts;
578 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > eventProducts;
459 impl->getSelectedItems(ui->treeView, events, eventProducts);
579 impl->getSelectedItems(ui->treeView, events, eventProducts);
460
580
461 if (!events.isEmpty() && eventProducts.isEmpty()) {
581 if (!events.isEmpty() && eventProducts.isEmpty()) {
462 emit eventsSelected(events);
582 emit eventsSelected(events);
463 }
583 }
464 else if (events.isEmpty() && !eventProducts.isEmpty()) {
584 else if (events.isEmpty() && !eventProducts.isEmpty()) {
465 emit eventProductsSelected(eventProducts);
585 emit eventProductsSelected(eventProducts);
466 }
586 }
467 else {
587 else {
468 emit selectionCleared();
588 emit selectionCleared();
469 }
589 }
470 }
590 }
@@ -1,126 +1,193
1 #include "Catalogue/CatalogueExplorer.h"
1 #include "Catalogue/CatalogueExplorer.h"
2 #include "ui_CatalogueExplorer.h"
2 #include "ui_CatalogueExplorer.h"
3
3
4 #include <Catalogue/CatalogueActionManager.h>
4 #include <Catalogue/CatalogueActionManager.h>
5 #include <Catalogue/CatalogueController.h>
5 #include <Catalogue/CatalogueController.h>
6 #include <SqpApplication.h>
6 #include <SqpApplication.h>
7 #include <Visualization/VisualizationGraphWidget.h>
8 #include <Visualization/VisualizationSelectionZoneItem.h>
7 #include <Visualization/VisualizationWidget.h>
9 #include <Visualization/VisualizationWidget.h>
8
10
9 #include <DBCatalogue.h>
11 #include <DBCatalogue.h>
10 #include <DBEvent.h>
12 #include <DBEvent.h>
13 #include <DBEventProduct.h>
14
15 #include <unordered_map>
11
16
12 struct CatalogueExplorer::CatalogueExplorerPrivate {
17 struct CatalogueExplorer::CatalogueExplorerPrivate {
13 CatalogueActionManager m_ActionManager;
18 CatalogueActionManager m_ActionManager;
19 std::unordered_map<std::shared_ptr<DBEvent>, QVector<VisualizationSelectionZoneItem *> >
20 m_SelectionZonesPerEvents;
21
22 QMetaObject::Connection m_Conn;
14
23
15 CatalogueExplorerPrivate(CatalogueExplorer *catalogueExplorer)
24 CatalogueExplorerPrivate(CatalogueExplorer *catalogueExplorer)
16 : m_ActionManager(catalogueExplorer)
25 : m_ActionManager(catalogueExplorer)
17 {
26 {
18 }
27 }
19 };
28 };
20
29
21 CatalogueExplorer::CatalogueExplorer(QWidget *parent)
30 CatalogueExplorer::CatalogueExplorer(QWidget *parent)
22 : QDialog(parent, Qt::Dialog | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint),
31 : QDialog(parent, Qt::Dialog | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint),
23 ui(new Ui::CatalogueExplorer),
32 ui(new Ui::CatalogueExplorer),
24 impl{spimpl::make_unique_impl<CatalogueExplorerPrivate>(this)}
33 impl{spimpl::make_unique_impl<CatalogueExplorerPrivate>(this)}
25 {
34 {
26 ui->setupUi(this);
35 ui->setupUi(this);
27
36
28 impl->m_ActionManager.installSelectionZoneActions();
37 impl->m_ActionManager.installSelectionZoneActions();
29
38
39 // Updates events and inspector when something is selected in the catalogue widget
30 connect(ui->catalogues, &CatalogueSideBarWidget::catalogueSelected, [this](auto catalogues) {
40 connect(ui->catalogues, &CatalogueSideBarWidget::catalogueSelected, [this](auto catalogues) {
31 if (catalogues.count() == 1) {
41 if (catalogues.count() == 1) {
32 ui->inspector->setCatalogue(catalogues.first());
42 ui->inspector->setCatalogue(catalogues.first());
33 }
43 }
34 else {
44 else {
35 ui->inspector->showPage(CatalogueInspectorWidget::Page::Empty);
45 ui->inspector->showPage(CatalogueInspectorWidget::Page::Empty);
36 }
46 }
37
47
38 ui->events->populateWithCatalogues(catalogues);
48 ui->events->populateWithCatalogues(catalogues);
39 });
49 });
40
50
41 connect(ui->catalogues, &CatalogueSideBarWidget::databaseSelected, [this](auto databases) {
51 connect(ui->catalogues, &CatalogueSideBarWidget::databaseSelected, [this](auto databases) {
42 ui->inspector->showPage(CatalogueInspectorWidget::Page::Empty);
52 ui->inspector->showPage(CatalogueInspectorWidget::Page::Empty);
43 });
53 });
44
54
45 connect(ui->catalogues, &CatalogueSideBarWidget::trashSelected, [this]() {
55 connect(ui->catalogues, &CatalogueSideBarWidget::trashSelected, [this]() {
46 ui->inspector->showPage(CatalogueInspectorWidget::Page::Empty);
56 ui->inspector->showPage(CatalogueInspectorWidget::Page::Empty);
47 ui->events->clear();
57 ui->events->clear();
48 });
58 });
49
59
50 connect(ui->catalogues, &CatalogueSideBarWidget::allEventsSelected, [this]() {
60 connect(ui->catalogues, &CatalogueSideBarWidget::allEventsSelected, [this]() {
51 ui->inspector->showPage(CatalogueInspectorWidget::Page::Empty);
61 ui->inspector->showPage(CatalogueInspectorWidget::Page::Empty);
52 ui->events->populateWithAllEvents();
62 ui->events->populateWithAllEvents();
53 });
63 });
54
64
55 connect(ui->catalogues, &CatalogueSideBarWidget::databaseSelected, [this](auto databaseList) {
65 connect(ui->catalogues, &CatalogueSideBarWidget::databaseSelected, [this](auto databaseList) {
56 QVector<std::shared_ptr<DBCatalogue> > catalogueList;
66 QVector<std::shared_ptr<DBCatalogue> > catalogueList;
57 for (auto database : databaseList) {
67 for (auto database : databaseList) {
58 catalogueList.append(ui->catalogues->getCatalogues(database));
68 catalogueList.append(ui->catalogues->getCatalogues(database));
59 }
69 }
60 ui->events->populateWithCatalogues(catalogueList);
70 ui->events->populateWithCatalogues(catalogueList);
61 ui->inspector->showPage(CatalogueInspectorWidget::Page::Empty);
71 ui->inspector->showPage(CatalogueInspectorWidget::Page::Empty);
62 });
72 });
63
73
64 connect(ui->catalogues, &CatalogueSideBarWidget::selectionCleared, [this]() {
74 connect(ui->catalogues, &CatalogueSideBarWidget::selectionCleared, [this]() {
65 ui->inspector->showPage(CatalogueInspectorWidget::Page::Empty);
75 ui->inspector->showPage(CatalogueInspectorWidget::Page::Empty);
66 ui->events->clear();
76 ui->events->clear();
67 });
77 });
68
78
79 // Updates the inspectot when something is selected in the events
69 connect(ui->events, &CatalogueEventsWidget::eventsSelected, [this](auto events) {
80 connect(ui->events, &CatalogueEventsWidget::eventsSelected, [this](auto events) {
70 if (events.count() == 1) {
81 if (events.count() == 1) {
71 ui->inspector->setEvent(events.first());
82 ui->inspector->setEvent(events.first());
72 }
83 }
73 else {
84 else {
74 ui->inspector->showPage(CatalogueInspectorWidget::Page::Empty);
85 ui->inspector->showPage(CatalogueInspectorWidget::Page::Empty);
75 }
86 }
76 });
87 });
77
88
78 connect(ui->events, &CatalogueEventsWidget::eventProductsSelected, [this](auto eventProducts) {
89 connect(ui->events, &CatalogueEventsWidget::eventProductsSelected, [this](auto eventProducts) {
79 if (eventProducts.count() == 1) {
90 if (eventProducts.count() == 1) {
80 ui->inspector->setEventProduct(eventProducts.first().first,
91 ui->inspector->setEventProduct(eventProducts.first().first,
81 eventProducts.first().second);
92 eventProducts.first().second);
82 }
93 }
83 else {
94 else {
84 ui->inspector->showPage(CatalogueInspectorWidget::Page::Empty);
95 ui->inspector->showPage(CatalogueInspectorWidget::Page::Empty);
85 }
96 }
86 });
97 });
87
98
88 connect(ui->events, &CatalogueEventsWidget::selectionCleared,
99 connect(ui->events, &CatalogueEventsWidget::selectionCleared,
89 [this]() { ui->inspector->showPage(CatalogueInspectorWidget::Page::Empty); });
100 [this]() { ui->inspector->showPage(CatalogueInspectorWidget::Page::Empty); });
90
101
102 // Manage Selection Zones associated to events
103 connect(ui->events, &CatalogueEventsWidget::selectionZoneAdded,
104 [this](auto event, auto productId, auto zone) {
105 this->addSelectionZoneItem(event, productId, zone);
106 });
107
108 connect(ui->events, &CatalogueEventsWidget::eventsRemoved, [this](auto events) {
109 for (auto event : events) {
110 auto associatedSelectionZonesIt = impl->m_SelectionZonesPerEvents.find(event);
111 if (associatedSelectionZonesIt != impl->m_SelectionZonesPerEvents.cend()) {
112 for (auto selectionZone : associatedSelectionZonesIt->second) {
113 auto parentGraph = selectionZone->parentGraphWidget();
114 parentGraph->removeSelectionZone(selectionZone);
115 }
116
117 impl->m_SelectionZonesPerEvents.erase(event);
118 }
119 }
120 });
121
122 // Updates changes from the inspector
91 connect(ui->inspector, &CatalogueInspectorWidget::catalogueUpdated, [this](auto catalogue) {
123 connect(ui->inspector, &CatalogueInspectorWidget::catalogueUpdated, [this](auto catalogue) {
92 sqpApp->catalogueController().updateCatalogue(catalogue);
124 sqpApp->catalogueController().updateCatalogue(catalogue);
93 ui->catalogues->setCatalogueChanges(catalogue, true);
125 ui->catalogues->setCatalogueChanges(catalogue, true);
94 });
126 });
95
127
96 connect(ui->inspector, &CatalogueInspectorWidget::eventUpdated, [this](auto event) {
128 connect(ui->inspector, &CatalogueInspectorWidget::eventUpdated, [this](auto event) {
97 sqpApp->catalogueController().updateEvent(event);
129 sqpApp->catalogueController().updateEvent(event);
98 ui->events->setEventChanges(event, true);
130 ui->events->setEventChanges(event, true);
99 });
131 });
100
132
101 connect(ui->inspector, &CatalogueInspectorWidget::eventProductUpdated,
133 connect(ui->inspector, &CatalogueInspectorWidget::eventProductUpdated,
102 [this](auto event, auto eventProduct) {
134 [this](auto event, auto eventProduct) {
103 sqpApp->catalogueController().updateEventProduct(eventProduct);
135 sqpApp->catalogueController().updateEventProduct(eventProduct);
104 ui->events->setEventChanges(event, true);
136 ui->events->setEventChanges(event, true);
105 });
137 });
106 }
138 }
107
139
108 CatalogueExplorer::~CatalogueExplorer()
140 CatalogueExplorer::~CatalogueExplorer()
109 {
141 {
142 disconnect(impl->m_Conn);
110 delete ui;
143 delete ui;
111 }
144 }
112
145
113 void CatalogueExplorer::setVisualizationWidget(VisualizationWidget *visualization)
146 void CatalogueExplorer::setVisualizationWidget(VisualizationWidget *visualization)
114 {
147 {
115 ui->events->setVisualizationWidget(visualization);
148 ui->events->setVisualizationWidget(visualization);
116 }
149 }
117
150
118 CatalogueEventsWidget &CatalogueExplorer::eventsWidget() const
151 CatalogueEventsWidget &CatalogueExplorer::eventsWidget() const
119 {
152 {
120 return *ui->events;
153 return *ui->events;
121 }
154 }
122
155
123 CatalogueSideBarWidget &CatalogueExplorer::sideBarWidget() const
156 CatalogueSideBarWidget &CatalogueExplorer::sideBarWidget() const
124 {
157 {
125 return *ui->catalogues;
158 return *ui->catalogues;
126 }
159 }
160
161 void CatalogueExplorer::clearSelectionZones()
162 {
163 impl->m_SelectionZonesPerEvents.clear();
164 }
165
166 void CatalogueExplorer::addSelectionZoneItem(const std::shared_ptr<DBEvent> &event,
167 const QString &productId,
168 VisualizationSelectionZoneItem *selectionZone)
169 {
170 impl->m_SelectionZonesPerEvents[event] << selectionZone;
171 connect(selectionZone, &VisualizationSelectionZoneItem::rangeEdited,
172 [event, productId, this](auto range) {
173 auto productList = event->getEventProducts();
174 for (auto &product : productList) {
175 if (product.getProductId() == productId) {
176 product.setTStart(range.m_TStart);
177 product.setTEnd(range.m_TEnd);
178 }
179 }
180 event->setEventProducts(productList);
181 sqpApp->catalogueController().updateEvent(event);
182 ui->events->refreshEvent(event);
183 ui->events->setEventChanges(event, true);
184 ui->inspector->refresh();
185 });
186
187 impl->m_Conn = connect(selectionZone, &VisualizationSelectionZoneItem::destroyed,
188 [event, selectionZone, this]() {
189 if (!impl->m_SelectionZonesPerEvents.empty()) {
190 impl->m_SelectionZonesPerEvents[event].removeAll(selectionZone);
191 }
192 });
193 }
@@ -1,211 +1,227
1 #include "Catalogue/CatalogueInspectorWidget.h"
1 #include "Catalogue/CatalogueInspectorWidget.h"
2 #include "ui_CatalogueInspectorWidget.h"
2 #include "ui_CatalogueInspectorWidget.h"
3
3
4 #include <Common/DateUtils.h>
4 #include <Common/DateUtils.h>
5 #include <DBCatalogue.h>
5 #include <DBCatalogue.h>
6 #include <DBEvent.h>
6 #include <DBEvent.h>
7 #include <DBEventProduct.h>
7 #include <DBEventProduct.h>
8 #include <DBTag.h>
8 #include <DBTag.h>
9
9
10 struct CatalogueInspectorWidget::CatalogueInspectorWidgetPrivate {
10 struct CatalogueInspectorWidget::CatalogueInspectorWidgetPrivate {
11 std::shared_ptr<DBCatalogue> m_DisplayedCatalogue = nullptr;
11 std::shared_ptr<DBCatalogue> m_DisplayedCatalogue = nullptr;
12 std::shared_ptr<DBEvent> m_DisplayedEvent = nullptr;
12 std::shared_ptr<DBEvent> m_DisplayedEvent = nullptr;
13 std::shared_ptr<DBEventProduct> m_DisplayedEventProduct = nullptr;
13 std::shared_ptr<DBEventProduct> m_DisplayedEventProduct = nullptr;
14
14
15 void connectCatalogueUpdateSignals(CatalogueInspectorWidget *inspector,
15 void connectCatalogueUpdateSignals(CatalogueInspectorWidget *inspector,
16 Ui::CatalogueInspectorWidget *ui);
16 Ui::CatalogueInspectorWidget *ui);
17 void connectEventUpdateSignals(CatalogueInspectorWidget *inspector,
17 void connectEventUpdateSignals(CatalogueInspectorWidget *inspector,
18 Ui::CatalogueInspectorWidget *ui);
18 Ui::CatalogueInspectorWidget *ui);
19 };
19 };
20
20
21 CatalogueInspectorWidget::CatalogueInspectorWidget(QWidget *parent)
21 CatalogueInspectorWidget::CatalogueInspectorWidget(QWidget *parent)
22 : QWidget(parent),
22 : QWidget(parent),
23 ui(new Ui::CatalogueInspectorWidget),
23 ui(new Ui::CatalogueInspectorWidget),
24 impl{spimpl::make_unique_impl<CatalogueInspectorWidgetPrivate>()}
24 impl{spimpl::make_unique_impl<CatalogueInspectorWidgetPrivate>()}
25 {
25 {
26 ui->setupUi(this);
26 ui->setupUi(this);
27 showPage(Page::Empty);
27 showPage(Page::Empty);
28
28
29 impl->connectCatalogueUpdateSignals(this, ui);
29 impl->connectCatalogueUpdateSignals(this, ui);
30 impl->connectEventUpdateSignals(this, ui);
30 impl->connectEventUpdateSignals(this, ui);
31 }
31 }
32
32
33 CatalogueInspectorWidget::~CatalogueInspectorWidget()
33 CatalogueInspectorWidget::~CatalogueInspectorWidget()
34 {
34 {
35 delete ui;
35 delete ui;
36 }
36 }
37
37
38 void CatalogueInspectorWidget::CatalogueInspectorWidgetPrivate::connectCatalogueUpdateSignals(
38 void CatalogueInspectorWidget::CatalogueInspectorWidgetPrivate::connectCatalogueUpdateSignals(
39 CatalogueInspectorWidget *inspector, Ui::CatalogueInspectorWidget *ui)
39 CatalogueInspectorWidget *inspector, Ui::CatalogueInspectorWidget *ui)
40 {
40 {
41 connect(ui->leCatalogueName, &QLineEdit::editingFinished, [ui, inspector, this]() {
41 connect(ui->leCatalogueName, &QLineEdit::editingFinished, [ui, inspector, this]() {
42 if (ui->leCatalogueName->text() != m_DisplayedCatalogue->getName()) {
42 if (ui->leCatalogueName->text() != m_DisplayedCatalogue->getName()) {
43 m_DisplayedCatalogue->setName(ui->leCatalogueName->text());
43 m_DisplayedCatalogue->setName(ui->leCatalogueName->text());
44 emit inspector->catalogueUpdated(m_DisplayedCatalogue);
44 emit inspector->catalogueUpdated(m_DisplayedCatalogue);
45 }
45 }
46 });
46 });
47
47
48 connect(ui->leCatalogueAuthor, &QLineEdit::editingFinished, [ui, inspector, this]() {
48 connect(ui->leCatalogueAuthor, &QLineEdit::editingFinished, [ui, inspector, this]() {
49 if (ui->leCatalogueAuthor->text() != m_DisplayedCatalogue->getAuthor()) {
49 if (ui->leCatalogueAuthor->text() != m_DisplayedCatalogue->getAuthor()) {
50 m_DisplayedCatalogue->setAuthor(ui->leCatalogueAuthor->text());
50 m_DisplayedCatalogue->setAuthor(ui->leCatalogueAuthor->text());
51 emit inspector->catalogueUpdated(m_DisplayedCatalogue);
51 emit inspector->catalogueUpdated(m_DisplayedCatalogue);
52 }
52 }
53 });
53 });
54 }
54 }
55
55
56 void CatalogueInspectorWidget::CatalogueInspectorWidgetPrivate::connectEventUpdateSignals(
56 void CatalogueInspectorWidget::CatalogueInspectorWidgetPrivate::connectEventUpdateSignals(
57 CatalogueInspectorWidget *inspector, Ui::CatalogueInspectorWidget *ui)
57 CatalogueInspectorWidget *inspector, Ui::CatalogueInspectorWidget *ui)
58 {
58 {
59 connect(ui->leEventName, &QLineEdit::editingFinished, [ui, inspector, this]() {
59 connect(ui->leEventName, &QLineEdit::editingFinished, [ui, inspector, this]() {
60 if (ui->leEventName->text() != m_DisplayedEvent->getName()) {
60 if (ui->leEventName->text() != m_DisplayedEvent->getName()) {
61 m_DisplayedEvent->setName(ui->leEventName->text());
61 m_DisplayedEvent->setName(ui->leEventName->text());
62 emit inspector->eventUpdated(m_DisplayedEvent);
62 emit inspector->eventUpdated(m_DisplayedEvent);
63 }
63 }
64 });
64 });
65
65
66 connect(ui->leEventTags, &QLineEdit::editingFinished, [ui, inspector, this]() {
66 connect(ui->leEventTags, &QLineEdit::editingFinished, [ui, inspector, this]() {
67 auto tags = ui->leEventTags->text().split(QRegExp("\\s+"), QString::SkipEmptyParts);
67 auto tags = ui->leEventTags->text().split(QRegExp("\\s+"), QString::SkipEmptyParts);
68 std::list<QString> tagNames;
68 std::list<QString> tagNames;
69 for (auto tag : tags) {
69 for (auto tag : tags) {
70 tagNames.push_back(tag);
70 tagNames.push_back(tag);
71 }
71 }
72
72
73 if (m_DisplayedEvent->getTagsNames() != tagNames) {
73 if (m_DisplayedEvent->getTagsNames() != tagNames) {
74 m_DisplayedEvent->setTagsNames(tagNames);
74 m_DisplayedEvent->setTagsNames(tagNames);
75 emit inspector->eventUpdated(m_DisplayedEvent);
75 emit inspector->eventUpdated(m_DisplayedEvent);
76 }
76 }
77 });
77 });
78
78
79 connect(ui->leEventProduct, &QLineEdit::editingFinished, [ui, inspector, this]() {
79 connect(ui->leEventProduct, &QLineEdit::editingFinished, [ui, inspector, this]() {
80 if (ui->leEventProduct->text() != m_DisplayedEventProduct->getProductId()) {
80 if (ui->leEventProduct->text() != m_DisplayedEventProduct->getProductId()) {
81 auto oldProductId = m_DisplayedEventProduct->getProductId();
81 auto oldProductId = m_DisplayedEventProduct->getProductId();
82 m_DisplayedEventProduct->setProductId(ui->leEventProduct->text());
82 m_DisplayedEventProduct->setProductId(ui->leEventProduct->text());
83
83
84 auto eventProducts = m_DisplayedEvent->getEventProducts();
84 auto eventProducts = m_DisplayedEvent->getEventProducts();
85 for (auto &eventProduct : eventProducts) {
85 for (auto &eventProduct : eventProducts) {
86 if (eventProduct.getProductId() == oldProductId) {
86 if (eventProduct.getProductId() == oldProductId) {
87 eventProduct.setProductId(m_DisplayedEventProduct->getProductId());
87 eventProduct.setProductId(m_DisplayedEventProduct->getProductId());
88 }
88 }
89 }
89 }
90 m_DisplayedEvent->setEventProducts(eventProducts);
90 m_DisplayedEvent->setEventProducts(eventProducts);
91
91
92 emit inspector->eventUpdated(m_DisplayedEvent);
92 emit inspector->eventUpdated(m_DisplayedEvent);
93 }
93 }
94 });
94 });
95
95
96 connect(ui->dateTimeEventTStart, &QDateTimeEdit::editingFinished, [ui, inspector, this]() {
96 connect(ui->dateTimeEventTStart, &QDateTimeEdit::editingFinished, [ui, inspector, this]() {
97 auto time = DateUtils::secondsSinceEpoch(ui->dateTimeEventTStart->dateTime());
97 auto time = DateUtils::secondsSinceEpoch(ui->dateTimeEventTStart->dateTime());
98 if (time != m_DisplayedEventProduct->getTStart()) {
98 if (time != m_DisplayedEventProduct->getTStart()) {
99 m_DisplayedEventProduct->setTStart(time);
99 m_DisplayedEventProduct->setTStart(time);
100
100
101 auto eventProducts = m_DisplayedEvent->getEventProducts();
101 auto eventProducts = m_DisplayedEvent->getEventProducts();
102 for (auto &eventProduct : eventProducts) {
102 for (auto &eventProduct : eventProducts) {
103 if (eventProduct.getProductId() == m_DisplayedEventProduct->getProductId()) {
103 if (eventProduct.getProductId() == m_DisplayedEventProduct->getProductId()) {
104 eventProduct.setTStart(m_DisplayedEventProduct->getTStart());
104 eventProduct.setTStart(m_DisplayedEventProduct->getTStart());
105 }
105 }
106 }
106 }
107 m_DisplayedEvent->setEventProducts(eventProducts);
107 m_DisplayedEvent->setEventProducts(eventProducts);
108
108
109 emit inspector->eventUpdated(m_DisplayedEvent);
109 emit inspector->eventUpdated(m_DisplayedEvent);
110 }
110 }
111 });
111 });
112
112
113 connect(ui->dateTimeEventTEnd, &QDateTimeEdit::editingFinished, [ui, inspector, this]() {
113 connect(ui->dateTimeEventTEnd, &QDateTimeEdit::editingFinished, [ui, inspector, this]() {
114 auto time = DateUtils::secondsSinceEpoch(ui->dateTimeEventTEnd->dateTime());
114 auto time = DateUtils::secondsSinceEpoch(ui->dateTimeEventTEnd->dateTime());
115 if (time != m_DisplayedEventProduct->getTEnd()) {
115 if (time != m_DisplayedEventProduct->getTEnd()) {
116 m_DisplayedEventProduct->setTEnd(time);
116 m_DisplayedEventProduct->setTEnd(time);
117
117
118 auto eventProducts = m_DisplayedEvent->getEventProducts();
118 auto eventProducts = m_DisplayedEvent->getEventProducts();
119 for (auto &eventProduct : eventProducts) {
119 for (auto &eventProduct : eventProducts) {
120 if (eventProduct.getProductId() == m_DisplayedEventProduct->getProductId()) {
120 if (eventProduct.getProductId() == m_DisplayedEventProduct->getProductId()) {
121 eventProduct.setTEnd(m_DisplayedEventProduct->getTEnd());
121 eventProduct.setTEnd(m_DisplayedEventProduct->getTEnd());
122 }
122 }
123 }
123 }
124 m_DisplayedEvent->setEventProducts(eventProducts);
124 m_DisplayedEvent->setEventProducts(eventProducts);
125
125
126 emit inspector->eventUpdated(m_DisplayedEvent);
126 emit inspector->eventUpdated(m_DisplayedEvent);
127 }
127 }
128 });
128 });
129 }
129 }
130
130
131 void CatalogueInspectorWidget::showPage(CatalogueInspectorWidget::Page page)
131 void CatalogueInspectorWidget::showPage(CatalogueInspectorWidget::Page page)
132 {
132 {
133 ui->stackedWidget->setCurrentIndex(static_cast<int>(page));
133 ui->stackedWidget->setCurrentIndex(static_cast<int>(page));
134 }
134 }
135
135
136 CatalogueInspectorWidget::Page CatalogueInspectorWidget::currentPage() const
136 CatalogueInspectorWidget::Page CatalogueInspectorWidget::currentPage() const
137 {
137 {
138 return static_cast<Page>(ui->stackedWidget->currentIndex());
138 return static_cast<Page>(ui->stackedWidget->currentIndex());
139 }
139 }
140
140
141 void CatalogueInspectorWidget::setEvent(const std::shared_ptr<DBEvent> &event)
141 void CatalogueInspectorWidget::setEvent(const std::shared_ptr<DBEvent> &event)
142 {
142 {
143 impl->m_DisplayedEvent = event;
143 impl->m_DisplayedEvent = event;
144
144
145 blockSignals(true);
145 blockSignals(true);
146
146
147 showPage(Page::EventProperties);
147 showPage(Page::EventProperties);
148 ui->leEventName->setEnabled(true);
148 ui->leEventName->setEnabled(true);
149 ui->leEventName->setText(event->getName());
149 ui->leEventName->setText(event->getName());
150 ui->leEventProduct->setEnabled(false);
150 ui->leEventProduct->setEnabled(false);
151 ui->leEventProduct->setText(
151 ui->leEventProduct->setText(
152 QString::number(event->getEventProducts().size()).append(" product(s)"));
152 QString::number(event->getEventProducts().size()).append(" product(s)"));
153
153
154 QString tagList;
154 QString tagList;
155 auto tags = event->getTagsNames();
155 auto tags = event->getTagsNames();
156 for (auto tag : tags) {
156 for (auto tag : tags) {
157 tagList += tag;
157 tagList += tag;
158 tagList += ' ';
158 tagList += ' ';
159 }
159 }
160
160
161 ui->leEventTags->setEnabled(true);
161 ui->leEventTags->setEnabled(true);
162 ui->leEventTags->setText(tagList);
162 ui->leEventTags->setText(tagList);
163
163
164 ui->dateTimeEventTStart->setEnabled(false);
164 ui->dateTimeEventTStart->setEnabled(false);
165 ui->dateTimeEventTEnd->setEnabled(false);
165 ui->dateTimeEventTEnd->setEnabled(false);
166
166
167 ui->dateTimeEventTStart->setDateTime(DateUtils::dateTime(event->getTStart()));
167 ui->dateTimeEventTStart->setDateTime(DateUtils::dateTime(event->getTStart()));
168 ui->dateTimeEventTEnd->setDateTime(DateUtils::dateTime(event->getTEnd()));
168 ui->dateTimeEventTEnd->setDateTime(DateUtils::dateTime(event->getTEnd()));
169
169
170 blockSignals(false);
170 blockSignals(false);
171 }
171 }
172
172
173 void CatalogueInspectorWidget::setEventProduct(const std::shared_ptr<DBEvent> &event,
173 void CatalogueInspectorWidget::setEventProduct(const std::shared_ptr<DBEvent> &event,
174 const std::shared_ptr<DBEventProduct> &eventProduct)
174 const std::shared_ptr<DBEventProduct> &eventProduct)
175 {
175 {
176
176
177 impl->m_DisplayedEvent = event;
177 impl->m_DisplayedEvent = event;
178 impl->m_DisplayedEventProduct = eventProduct;
178 impl->m_DisplayedEventProduct = eventProduct;
179
179
180 blockSignals(true);
180 blockSignals(true);
181
181
182 showPage(Page::EventProperties);
182 showPage(Page::EventProperties);
183 ui->leEventName->setEnabled(false);
183 ui->leEventName->setEnabled(false);
184 ui->leEventName->setText(event->getName());
184 ui->leEventName->setText(event->getName());
185 ui->leEventProduct->setEnabled(false);
185 ui->leEventProduct->setEnabled(false);
186 ui->leEventProduct->setText(eventProduct->getProductId());
186 ui->leEventProduct->setText(eventProduct->getProductId());
187
187
188 ui->leEventTags->setEnabled(false);
188 ui->leEventTags->setEnabled(false);
189 ui->leEventTags->clear();
189 ui->leEventTags->clear();
190
190
191 ui->dateTimeEventTStart->setEnabled(true);
191 ui->dateTimeEventTStart->setEnabled(true);
192 ui->dateTimeEventTEnd->setEnabled(true);
192 ui->dateTimeEventTEnd->setEnabled(true);
193
193
194 ui->dateTimeEventTStart->setDateTime(DateUtils::dateTime(eventProduct->getTStart()));
194 ui->dateTimeEventTStart->setDateTime(DateUtils::dateTime(eventProduct->getTStart()));
195 ui->dateTimeEventTEnd->setDateTime(DateUtils::dateTime(eventProduct->getTEnd()));
195 ui->dateTimeEventTEnd->setDateTime(DateUtils::dateTime(eventProduct->getTEnd()));
196
196
197 blockSignals(false);
197 blockSignals(false);
198 }
198 }
199
199
200 void CatalogueInspectorWidget::setCatalogue(const std::shared_ptr<DBCatalogue> &catalogue)
200 void CatalogueInspectorWidget::setCatalogue(const std::shared_ptr<DBCatalogue> &catalogue)
201 {
201 {
202 impl->m_DisplayedCatalogue = catalogue;
202 impl->m_DisplayedCatalogue = catalogue;
203
203
204 blockSignals(true);
204 blockSignals(true);
205
205
206 showPage(Page::CatalogueProperties);
206 showPage(Page::CatalogueProperties);
207 ui->leCatalogueName->setText(catalogue->getName());
207 ui->leCatalogueName->setText(catalogue->getName());
208 ui->leCatalogueAuthor->setText(catalogue->getAuthor());
208 ui->leCatalogueAuthor->setText(catalogue->getAuthor());
209
209
210 blockSignals(false);
210 blockSignals(false);
211 }
211 }
212
213 void CatalogueInspectorWidget::refresh()
214 {
215 switch (static_cast<Page>(ui->stackedWidget->currentIndex())) {
216 case Page::CatalogueProperties:
217 setCatalogue(impl->m_DisplayedCatalogue);
218 break;
219 case Page::EventProperties: {
220 auto isEventShowed = ui->leEventName->isEnabled();
221 setEvent(impl->m_DisplayedEvent);
222 if (!isEventShowed && impl->m_DisplayedEvent) {
223 setEventProduct(impl->m_DisplayedEvent, impl->m_DisplayedEventProduct);
224 }
225 }
226 }
227 }
@@ -1,296 +1,308
1 #include "DragAndDrop/DragDropGuiController.h"
1 #include "DragAndDrop/DragDropGuiController.h"
2 #include "DragAndDrop/DragDropScroller.h"
2 #include "DragAndDrop/DragDropScroller.h"
3 #include "DragAndDrop/DragDropTabSwitcher.h"
3 #include "DragAndDrop/DragDropTabSwitcher.h"
4 #include "SqpApplication.h"
4 #include "SqpApplication.h"
5 #include "Visualization/VisualizationDragDropContainer.h"
5 #include "Visualization/VisualizationDragDropContainer.h"
6 #include "Visualization/VisualizationDragWidget.h"
6 #include "Visualization/VisualizationDragWidget.h"
7 #include "Visualization/VisualizationWidget.h"
7 #include "Visualization/VisualizationWidget.h"
8 #include "Visualization/operations/FindVariableOperation.h"
8 #include "Visualization/operations/FindVariableOperation.h"
9
9
10 #include "DataSource/DataSourceController.h"
10 #include "Variable/Variable.h"
11 #include "Variable/Variable.h"
11 #include "Variable/VariableController.h"
12 #include "Variable/VariableController.h"
12
13
13 #include "Common/MimeTypesDef.h"
14 #include "Common/MimeTypesDef.h"
14 #include "Common/VisualizationDef.h"
15 #include "Common/VisualizationDef.h"
15
16
16 #include <QDir>
17 #include <QDir>
17 #include <QLabel>
18 #include <QLabel>
18 #include <QUrl>
19 #include <QUrl>
19 #include <QVBoxLayout>
20 #include <QVBoxLayout>
20
21
21
22
22 Q_LOGGING_CATEGORY(LOG_DragDropGuiController, "DragDropGuiController")
23 Q_LOGGING_CATEGORY(LOG_DragDropGuiController, "DragDropGuiController")
23
24
24
25
25 struct DragDropGuiController::DragDropGuiControllerPrivate {
26 struct DragDropGuiController::DragDropGuiControllerPrivate {
26
27
27 VisualizationDragWidget *m_CurrentDragWidget = nullptr;
28 VisualizationDragWidget *m_CurrentDragWidget = nullptr;
28 std::unique_ptr<QWidget> m_PlaceHolder = nullptr;
29 std::unique_ptr<QWidget> m_PlaceHolder = nullptr;
29 QLabel *m_PlaceHolderLabel;
30 QLabel *m_PlaceHolderLabel;
30 QWidget *m_PlaceBackground;
31 QWidget *m_PlaceBackground;
31 std::unique_ptr<DragDropScroller> m_DragDropScroller = nullptr;
32 std::unique_ptr<DragDropScroller> m_DragDropScroller = nullptr;
32 std::unique_ptr<DragDropTabSwitcher> m_DragDropTabSwitcher = nullptr;
33 std::unique_ptr<DragDropTabSwitcher> m_DragDropTabSwitcher = nullptr;
33 QString m_ImageTempUrl; // Temporary file for image url generated by the drag & drop. Not using
34 QString m_ImageTempUrl; // Temporary file for image url generated by the drag & drop. Not using
34 // QTemporaryFile to have a name which is not generated.
35 // QTemporaryFile to have a name which is not generated.
35
36
36 VisualizationDragWidget *m_HighlightedDragWidget = nullptr;
37 VisualizationDragWidget *m_HighlightedDragWidget = nullptr;
37
38
38 QMetaObject::Connection m_DragWidgetDestroyedConnection;
39 QMetaObject::Connection m_DragWidgetDestroyedConnection;
39 QMetaObject::Connection m_HighlightedWidgetDestroyedConnection;
40 QMetaObject::Connection m_HighlightedWidgetDestroyedConnection;
40
41
41 QList<QWidget *> m_WidgetToClose;
42 QList<QWidget *> m_WidgetToClose;
42
43
43 explicit DragDropGuiControllerPrivate()
44 explicit DragDropGuiControllerPrivate()
44 : m_PlaceHolder{std::make_unique<QWidget>()},
45 : m_PlaceHolder{std::make_unique<QWidget>()},
45 m_DragDropScroller{std::make_unique<DragDropScroller>()},
46 m_DragDropScroller{std::make_unique<DragDropScroller>()},
46 m_DragDropTabSwitcher{std::make_unique<DragDropTabSwitcher>()}
47 m_DragDropTabSwitcher{std::make_unique<DragDropTabSwitcher>()}
47 {
48 {
48
49
49 auto layout = new QVBoxLayout{m_PlaceHolder.get()};
50 auto layout = new QVBoxLayout{m_PlaceHolder.get()};
50 layout->setSpacing(0);
51 layout->setSpacing(0);
51 layout->setContentsMargins(0, 0, 0, 0);
52 layout->setContentsMargins(0, 0, 0, 0);
52
53
53 m_PlaceHolderLabel = new QLabel{"", m_PlaceHolder.get()};
54 m_PlaceHolderLabel = new QLabel{"", m_PlaceHolder.get()};
54 m_PlaceHolderLabel->setMinimumHeight(25);
55 m_PlaceHolderLabel->setMinimumHeight(25);
55 layout->addWidget(m_PlaceHolderLabel);
56 layout->addWidget(m_PlaceHolderLabel);
56
57
57 m_PlaceBackground = new QWidget{m_PlaceHolder.get()};
58 m_PlaceBackground = new QWidget{m_PlaceHolder.get()};
58 m_PlaceBackground->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
59 m_PlaceBackground->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
59 layout->addWidget(m_PlaceBackground);
60 layout->addWidget(m_PlaceBackground);
60
61
61 sqpApp->installEventFilter(m_DragDropScroller.get());
62 sqpApp->installEventFilter(m_DragDropScroller.get());
62 sqpApp->installEventFilter(m_DragDropTabSwitcher.get());
63 sqpApp->installEventFilter(m_DragDropTabSwitcher.get());
63
64
64 m_ImageTempUrl = QDir::temp().absoluteFilePath("Sciqlop_graph.png");
65 m_ImageTempUrl = QDir::temp().absoluteFilePath("Sciqlop_graph.png");
65 }
66 }
66
67
67 void preparePlaceHolder(DragDropGuiController::PlaceHolderType type,
68 void preparePlaceHolder(DragDropGuiController::PlaceHolderType type,
68 const QString &topLabelText) const
69 const QString &topLabelText) const
69 {
70 {
70 if (m_CurrentDragWidget) {
71 if (m_CurrentDragWidget) {
71 m_PlaceHolder->setMinimumSize(m_CurrentDragWidget->size());
72 m_PlaceHolder->setMinimumSize(m_CurrentDragWidget->size());
72 m_PlaceHolder->setSizePolicy(m_CurrentDragWidget->sizePolicy());
73 m_PlaceHolder->setSizePolicy(m_CurrentDragWidget->sizePolicy());
73 }
74 }
74 else {
75 else {
75 // Configuration of the placeHolder when there is no dragWidget
76 // Configuration of the placeHolder when there is no dragWidget
76 // (for instance with a drag from a variable)
77 // (for instance with a drag from a variable)
77
78
78 m_PlaceHolder->setMinimumSize(0, GRAPH_MINIMUM_HEIGHT);
79 m_PlaceHolder->setMinimumSize(0, GRAPH_MINIMUM_HEIGHT);
79 m_PlaceHolder->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
80 m_PlaceHolder->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
80 }
81 }
81
82
82 switch (type) {
83 switch (type) {
83 case DragDropGuiController::PlaceHolderType::Graph:
84 case DragDropGuiController::PlaceHolderType::Graph:
84 m_PlaceBackground->setStyleSheet(
85 m_PlaceBackground->setStyleSheet(
85 "background-color: #BBD5EE; border: 1px solid #2A7FD4");
86 "background-color: #BBD5EE; border: 1px solid #2A7FD4");
86 break;
87 break;
87 case DragDropGuiController::PlaceHolderType::Zone:
88 case DragDropGuiController::PlaceHolderType::Zone:
88 case DragDropGuiController::PlaceHolderType::Default:
89 case DragDropGuiController::PlaceHolderType::Default:
89 m_PlaceBackground->setStyleSheet(
90 m_PlaceBackground->setStyleSheet(
90 "background-color: #BBD5EE; border: 2px solid #2A7FD4");
91 "background-color: #BBD5EE; border: 2px solid #2A7FD4");
91 m_PlaceHolderLabel->setStyleSheet("color: #2A7FD4");
92 m_PlaceHolderLabel->setStyleSheet("color: #2A7FD4");
92 break;
93 break;
93 }
94 }
94
95
95 m_PlaceHolderLabel->setText(topLabelText);
96 m_PlaceHolderLabel->setText(topLabelText);
96 m_PlaceHolderLabel->setVisible(!topLabelText.isEmpty());
97 m_PlaceHolderLabel->setVisible(!topLabelText.isEmpty());
97 }
98 }
98 };
99 };
99
100
100
101
101 DragDropGuiController::DragDropGuiController()
102 DragDropGuiController::DragDropGuiController()
102 : impl{spimpl::make_unique_impl<DragDropGuiControllerPrivate>()}
103 : impl{spimpl::make_unique_impl<DragDropGuiControllerPrivate>()}
103 {
104 {
104 }
105 }
105
106
106 DragDropGuiController::~DragDropGuiController()
107 DragDropGuiController::~DragDropGuiController()
107 {
108 {
108 QFile::remove(impl->m_ImageTempUrl);
109 QFile::remove(impl->m_ImageTempUrl);
109 }
110 }
110
111
111 void DragDropGuiController::resetDragAndDrop()
112 void DragDropGuiController::resetDragAndDrop()
112 {
113 {
113 setCurrentDragWidget(nullptr);
114 setCurrentDragWidget(nullptr);
114 impl->m_HighlightedDragWidget = nullptr;
115 impl->m_HighlightedDragWidget = nullptr;
115 }
116 }
116
117
117 void DragDropGuiController::setCurrentDragWidget(VisualizationDragWidget *dragWidget)
118 void DragDropGuiController::setCurrentDragWidget(VisualizationDragWidget *dragWidget)
118 {
119 {
119 if (impl->m_CurrentDragWidget) {
120 if (impl->m_CurrentDragWidget) {
120
121
121 QObject::disconnect(impl->m_DragWidgetDestroyedConnection);
122 QObject::disconnect(impl->m_DragWidgetDestroyedConnection);
122 }
123 }
123
124
124 if (dragWidget) {
125 if (dragWidget) {
125 // ensures the impl->m_CurrentDragWidget is reset when the widget is destroyed
126 // ensures the impl->m_CurrentDragWidget is reset when the widget is destroyed
126 impl->m_DragWidgetDestroyedConnection
127 impl->m_DragWidgetDestroyedConnection
127 = QObject::connect(dragWidget, &VisualizationDragWidget::destroyed,
128 = QObject::connect(dragWidget, &VisualizationDragWidget::destroyed,
128 [this]() { impl->m_CurrentDragWidget = nullptr; });
129 [this]() { impl->m_CurrentDragWidget = nullptr; });
129 }
130 }
130
131
131 impl->m_CurrentDragWidget = dragWidget;
132 impl->m_CurrentDragWidget = dragWidget;
132 }
133 }
133
134
134 VisualizationDragWidget *DragDropGuiController::getCurrentDragWidget() const
135 VisualizationDragWidget *DragDropGuiController::getCurrentDragWidget() const
135 {
136 {
136 return impl->m_CurrentDragWidget;
137 return impl->m_CurrentDragWidget;
137 }
138 }
138
139
139 QWidget &DragDropGuiController::placeHolder() const
140 QWidget &DragDropGuiController::placeHolder() const
140 {
141 {
141 return *impl->m_PlaceHolder;
142 return *impl->m_PlaceHolder;
142 }
143 }
143
144
144 void DragDropGuiController::insertPlaceHolder(QVBoxLayout *layout, int index, PlaceHolderType type,
145 void DragDropGuiController::insertPlaceHolder(QVBoxLayout *layout, int index, PlaceHolderType type,
145 const QString &topLabelText)
146 const QString &topLabelText)
146 {
147 {
147 removePlaceHolder();
148 removePlaceHolder();
148 impl->preparePlaceHolder(type, topLabelText);
149 impl->preparePlaceHolder(type, topLabelText);
149 layout->insertWidget(index, impl->m_PlaceHolder.get());
150 layout->insertWidget(index, impl->m_PlaceHolder.get());
150 impl->m_PlaceHolder->show();
151 impl->m_PlaceHolder->show();
151 }
152 }
152
153
153 void DragDropGuiController::removePlaceHolder()
154 void DragDropGuiController::removePlaceHolder()
154 {
155 {
155 auto parentWidget = impl->m_PlaceHolder->parentWidget();
156 auto parentWidget = impl->m_PlaceHolder->parentWidget();
156 if (parentWidget) {
157 if (parentWidget) {
157 parentWidget->layout()->removeWidget(impl->m_PlaceHolder.get());
158 parentWidget->layout()->removeWidget(impl->m_PlaceHolder.get());
158 impl->m_PlaceHolder->setParent(nullptr);
159 impl->m_PlaceHolder->setParent(nullptr);
159 impl->m_PlaceHolder->hide();
160 impl->m_PlaceHolder->hide();
160 }
161 }
161 }
162 }
162
163
163 bool DragDropGuiController::isPlaceHolderSet() const
164 bool DragDropGuiController::isPlaceHolderSet() const
164 {
165 {
165 return impl->m_PlaceHolder->parentWidget();
166 return impl->m_PlaceHolder->parentWidget();
166 }
167 }
167
168
168 void DragDropGuiController::addDragDropScrollArea(QScrollArea *scrollArea)
169 void DragDropGuiController::addDragDropScrollArea(QScrollArea *scrollArea)
169 {
170 {
170 impl->m_DragDropScroller->addScrollArea(scrollArea);
171 impl->m_DragDropScroller->addScrollArea(scrollArea);
171 }
172 }
172
173
173 void DragDropGuiController::removeDragDropScrollArea(QScrollArea *scrollArea)
174 void DragDropGuiController::removeDragDropScrollArea(QScrollArea *scrollArea)
174 {
175 {
175 impl->m_DragDropScroller->removeScrollArea(scrollArea);
176 impl->m_DragDropScroller->removeScrollArea(scrollArea);
176 }
177 }
177
178
178 void DragDropGuiController::addDragDropTabBar(QTabBar *tabBar)
179 void DragDropGuiController::addDragDropTabBar(QTabBar *tabBar)
179 {
180 {
180 impl->m_DragDropTabSwitcher->addTabBar(tabBar);
181 impl->m_DragDropTabSwitcher->addTabBar(tabBar);
181 }
182 }
182
183
183 void DragDropGuiController::removeDragDropTabBar(QTabBar *tabBar)
184 void DragDropGuiController::removeDragDropTabBar(QTabBar *tabBar)
184 {
185 {
185 impl->m_DragDropTabSwitcher->removeTabBar(tabBar);
186 impl->m_DragDropTabSwitcher->removeTabBar(tabBar);
186 }
187 }
187
188
188 QUrl DragDropGuiController::imageTemporaryUrl(const QImage &image) const
189 QUrl DragDropGuiController::imageTemporaryUrl(const QImage &image) const
189 {
190 {
190 image.save(impl->m_ImageTempUrl);
191 image.save(impl->m_ImageTempUrl);
191 return QUrl::fromLocalFile(impl->m_ImageTempUrl);
192 return QUrl::fromLocalFile(impl->m_ImageTempUrl);
192 }
193 }
193
194
194 void DragDropGuiController::setHightlightedDragWidget(VisualizationDragWidget *dragWidget)
195 void DragDropGuiController::setHightlightedDragWidget(VisualizationDragWidget *dragWidget)
195 {
196 {
196 if (impl->m_HighlightedDragWidget) {
197 if (impl->m_HighlightedDragWidget) {
197 impl->m_HighlightedDragWidget->highlightForMerge(false);
198 impl->m_HighlightedDragWidget->highlightForMerge(false);
198 QObject::disconnect(impl->m_HighlightedWidgetDestroyedConnection);
199 QObject::disconnect(impl->m_HighlightedWidgetDestroyedConnection);
199 }
200 }
200
201
201 if (dragWidget) {
202 if (dragWidget) {
202 dragWidget->highlightForMerge(true);
203 dragWidget->highlightForMerge(true);
203
204
204 // ensures the impl->m_HighlightedDragWidget is reset when the widget is destroyed
205 // ensures the impl->m_HighlightedDragWidget is reset when the widget is destroyed
205 impl->m_DragWidgetDestroyedConnection
206 impl->m_DragWidgetDestroyedConnection
206 = QObject::connect(dragWidget, &VisualizationDragWidget::destroyed,
207 = QObject::connect(dragWidget, &VisualizationDragWidget::destroyed,
207 [this]() { impl->m_HighlightedDragWidget = nullptr; });
208 [this]() { impl->m_HighlightedDragWidget = nullptr; });
208 }
209 }
209
210
210 impl->m_HighlightedDragWidget = dragWidget;
211 impl->m_HighlightedDragWidget = dragWidget;
211 }
212 }
212
213
213 VisualizationDragWidget *DragDropGuiController::getHightlightedDragWidget() const
214 VisualizationDragWidget *DragDropGuiController::getHightlightedDragWidget() const
214 {
215 {
215 return impl->m_HighlightedDragWidget;
216 return impl->m_HighlightedDragWidget;
216 }
217 }
217
218
218 void DragDropGuiController::delayedCloseWidget(QWidget *widget)
219 void DragDropGuiController::delayedCloseWidget(QWidget *widget)
219 {
220 {
220 widget->hide();
221 widget->hide();
221 impl->m_WidgetToClose << widget;
222 impl->m_WidgetToClose << widget;
222 }
223 }
223
224
224 void DragDropGuiController::doCloseWidgets()
225 void DragDropGuiController::doCloseWidgets()
225 {
226 {
226 for (auto widget : impl->m_WidgetToClose) {
227 for (auto widget : impl->m_WidgetToClose) {
227 widget->close();
228 widget->close();
228 }
229 }
229
230
230 impl->m_WidgetToClose.clear();
231 impl->m_WidgetToClose.clear();
231 }
232 }
232
233
233 bool DragDropGuiController::checkMimeDataForVisualization(
234 bool DragDropGuiController::checkMimeDataForVisualization(
234 const QMimeData *mimeData, VisualizationDragDropContainer *dropContainer)
235 const QMimeData *mimeData, VisualizationDragDropContainer *dropContainer)
235 {
236 {
236 if (!mimeData || !dropContainer) {
237 if (!mimeData || !dropContainer) {
237 qCWarning(LOG_DragDropGuiController()) << QObject::tr(
238 qCWarning(LOG_DragDropGuiController()) << QObject::tr(
238 "DragDropGuiController::checkMimeDataForVisualization, invalid input parameters.");
239 "DragDropGuiController::checkMimeDataForVisualization, invalid input parameters.");
239 Q_ASSERT(false);
240 Q_ASSERT(false);
240 return false;
241 return false;
241 }
242 }
242
243
243 auto result = false;
244 auto result = false;
244
245
245 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
246 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
246 auto variables = sqpApp->variableController().variablesForMimeData(
247 auto variables = sqpApp->variableController().variablesForMimeData(
247 mimeData->data(MIME_TYPE_VARIABLE_LIST));
248 mimeData->data(MIME_TYPE_VARIABLE_LIST));
248
249
249 if (variables.count() == 1) {
250 if (variables.count() == 1) {
250
251
251 auto variable = variables.first();
252 auto variable = variables.first();
252 if (variable->dataSeries() != nullptr) {
253 if (variable->dataSeries() != nullptr) {
253
254
254 // Check that the variable is not already in a graph
255 // Check that the variable is not already in a graph
255
256
256 auto parent = dropContainer->parentWidget();
257 auto parent = dropContainer->parentWidget();
257 while (parent && qobject_cast<VisualizationWidget *>(parent) == nullptr) {
258 while (parent && qobject_cast<VisualizationWidget *>(parent) == nullptr) {
258 parent = parent->parentWidget(); // Search for the top level VisualizationWidget
259 parent = parent->parentWidget(); // Search for the top level VisualizationWidget
259 }
260 }
260
261
261 if (parent) {
262 if (parent) {
262 auto visualizationWidget = static_cast<VisualizationWidget *>(parent);
263 auto visualizationWidget = static_cast<VisualizationWidget *>(parent);
263
264
264 FindVariableOperation findVariableOperation{variable};
265 FindVariableOperation findVariableOperation{variable};
265 visualizationWidget->accept(&findVariableOperation);
266 visualizationWidget->accept(&findVariableOperation);
266 auto variableContainers = findVariableOperation.result();
267 auto variableContainers = findVariableOperation.result();
267 if (variableContainers.empty()) {
268 if (variableContainers.empty()) {
268 result = true;
269 result = true;
269 }
270 }
270 else {
271 else {
271 // result = false: the variable already exist in the visualisation
272 // result = false: the variable already exist in the visualisation
272 }
273 }
273 }
274 }
274 else {
275 else {
275 qCWarning(LOG_DragDropGuiController()) << QObject::tr(
276 qCWarning(LOG_DragDropGuiController()) << QObject::tr(
276 "DragDropGuiController::checkMimeDataForVisualization, the parent "
277 "DragDropGuiController::checkMimeDataForVisualization, the parent "
277 "VisualizationWidget cannot be found. Cannot check if the variable is "
278 "VisualizationWidget cannot be found. Cannot check if the variable is "
278 "already used or not.");
279 "already used or not.");
279 }
280 }
280 }
281 }
281 else {
282 else {
282 // result = false: the variable is not fully loaded
283 // result = false: the variable is not fully loaded
283 }
284 }
284 }
285 }
285 else {
286 else {
286 // result = false: cannot drop multiple variables in the visualisation
287 // result = false: cannot drop multiple variables in the visualisation
287 }
288 }
288 }
289 }
290 else if (mimeData->hasFormat(MIME_TYPE_PRODUCT_LIST)) {
291 auto productDataList = sqpApp->dataSourceController().productsDataForMimeData(
292 mimeData->data(MIME_TYPE_PRODUCT_LIST));
293 if (productDataList.count() == 1) {
294 result = true;
295 }
296 else {
297 // result = false: cannot drop multiple products in the visualisation
298 }
299 }
289 else {
300 else {
290 // Other MIME data
301 // Other MIME data
291 // no special rules, accepted by default
302 // no special rules, accepted by default
292 result = true;
303 result = true;
293 }
304 }
294
305
306
295 return result;
307 return result;
296 }
308 }
@@ -1,177 +1,207
1 #include "Visualization/AxisRenderingUtils.h"
1 #include "Visualization/AxisRenderingUtils.h"
2
2
3 #include <Data/ScalarSeries.h>
3 #include <Data/ScalarSeries.h>
4 #include <Data/SpectrogramSeries.h>
4 #include <Data/SpectrogramSeries.h>
5 #include <Data/VectorSeries.h>
5 #include <Data/VectorSeries.h>
6
6
7 #include <Variable/Variable.h>
8
7 #include <Visualization/SqpColorScale.h>
9 #include <Visualization/SqpColorScale.h>
8 #include <Visualization/qcustomplot.h>
10 #include <Visualization/qcustomplot.h>
9
11
10 Q_LOGGING_CATEGORY(LOG_AxisRenderingUtils, "AxisRenderingUtils")
12 Q_LOGGING_CATEGORY(LOG_AxisRenderingUtils, "AxisRenderingUtils")
11
13
12 namespace {
14 namespace {
13
15
14 const auto DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd hh:mm:ss:zzz");
16 const auto DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd hh:mm:ss:zzz");
15
17
16 /// Format for datetimes on a axis
18 /// Format for datetimes on a axis
17 const auto DATETIME_TICKER_FORMAT = QStringLiteral("yyyy/MM/dd \nhh:mm:ss");
19 const auto DATETIME_TICKER_FORMAT = QStringLiteral("yyyy/MM/dd \nhh:mm:ss");
18
20
19 const auto NUMBER_FORMAT = 'g';
21 const auto NUMBER_FORMAT = 'g';
20 const auto NUMBER_PRECISION = 9;
22 const auto NUMBER_PRECISION = 9;
21
23
22 /// Generates the appropriate ticker for an axis, depending on whether the axis displays time or
24 /// Generates the appropriate ticker for an axis, depending on whether the axis displays time or
23 /// non-time data
25 /// non-time data
24 QSharedPointer<QCPAxisTicker> axisTicker(bool isTimeAxis, QCPAxis::ScaleType scaleType)
26 QSharedPointer<QCPAxisTicker> axisTicker(bool isTimeAxis, QCPAxis::ScaleType scaleType)
25 {
27 {
26 if (isTimeAxis) {
28 if (isTimeAxis) {
27 auto dateTicker = QSharedPointer<QCPAxisTickerDateTime>::create();
29 auto dateTicker = QSharedPointer<QCPAxisTickerDateTime>::create();
28 dateTicker->setDateTimeFormat(DATETIME_TICKER_FORMAT);
30 dateTicker->setDateTimeFormat(DATETIME_TICKER_FORMAT);
29 dateTicker->setDateTimeSpec(Qt::UTC);
31 dateTicker->setDateTimeSpec(Qt::UTC);
30
32
31 return dateTicker;
33 return dateTicker;
32 }
34 }
33 else if (scaleType == QCPAxis::stLogarithmic) {
35 else if (scaleType == QCPAxis::stLogarithmic) {
34 return QSharedPointer<QCPAxisTickerLog>::create();
36 return QSharedPointer<QCPAxisTickerLog>::create();
35 }
37 }
36 else {
38 else {
37 // default ticker
39 // default ticker
38 return QSharedPointer<QCPAxisTicker>::create();
40 return QSharedPointer<QCPAxisTicker>::create();
39 }
41 }
40 }
42 }
41
43
42 /**
44 /**
43 * Sets properties of the axis passed as parameter
45 * Sets properties of the axis passed as parameter
44 * @param axis the axis to set
46 * @param axis the axis to set
45 * @param unit the unit to set for the axis
47 * @param unit the unit to set for the axis
46 * @param scaleType the scale type to set for the axis
48 * @param scaleType the scale type to set for the axis
47 */
49 */
48 void setAxisProperties(QCPAxis &axis, const Unit &unit,
50 void setAxisProperties(QCPAxis &axis, const Unit &unit,
49 QCPAxis::ScaleType scaleType = QCPAxis::stLinear)
51 QCPAxis::ScaleType scaleType = QCPAxis::stLinear)
50 {
52 {
51 // label (unit name)
53 // label (unit name)
52 axis.setLabel(unit.m_Name);
54 axis.setLabel(unit.m_Name);
53
55
54 // scale type
56 // scale type
55 axis.setScaleType(scaleType);
57 axis.setScaleType(scaleType);
56 if (scaleType == QCPAxis::stLogarithmic) {
58 if (scaleType == QCPAxis::stLogarithmic) {
57 // Scientific notation
59 // Scientific notation
58 axis.setNumberPrecision(0);
60 axis.setNumberPrecision(0);
59 axis.setNumberFormat("eb");
61 axis.setNumberFormat("eb");
60 }
62 }
61
63
62 // ticker (depending on the type of unit)
64 // ticker (depending on the type of unit)
63 axis.setTicker(axisTicker(unit.m_TimeUnit, scaleType));
65 axis.setTicker(axisTicker(unit.m_TimeUnit, scaleType));
64 }
66 }
65
67
66 /**
68 /**
67 * Delegate used to set axes properties
69 * Delegate used to set axes properties
68 */
70 */
69 template <typename T, typename Enabled = void>
71 template <typename T, typename Enabled = void>
70 struct AxisSetter {
72 struct AxisSetter {
71 static void setProperties(T &, QCustomPlot &, SqpColorScale &)
73 static void setProperties(QCustomPlot &, SqpColorScale &)
72 {
74 {
73 // Default implementation does nothing
75 // Default implementation does nothing
74 qCCritical(LOG_AxisRenderingUtils()) << "Can't set axis properties: unmanaged type of data";
76 qCCritical(LOG_AxisRenderingUtils()) << "Can't set axis properties: unmanaged type of data";
75 }
77 }
78
79 static void setUnits(T &, QCustomPlot &, SqpColorScale &)
80 {
81 // Default implementation does nothing
82 qCCritical(LOG_AxisRenderingUtils()) << "Can't set axis units: unmanaged type of data";
83 }
76 };
84 };
77
85
78 /**
86 /**
79 * Specialization of AxisSetter for scalars and vectors
87 * Specialization of AxisSetter for scalars and vectors
80 * @sa ScalarSeries
88 * @sa ScalarSeries
81 * @sa VectorSeries
89 * @sa VectorSeries
82 */
90 */
83 template <typename T>
91 template <typename T>
84 struct AxisSetter<T, typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
92 struct AxisSetter<T, typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
85 or std::is_base_of<VectorSeries, T>::value> > {
93 or std::is_base_of<VectorSeries, T>::value> > {
86 static void setProperties(T &dataSeries, QCustomPlot &plot, SqpColorScale &)
94 static void setProperties(QCustomPlot &, SqpColorScale &)
95 {
96 // Nothing to do
97 }
98
99 static void setUnits(T &dataSeries, QCustomPlot &plot, SqpColorScale &)
87 {
100 {
88 dataSeries.lockRead();
101 dataSeries.lockRead();
89 auto xAxisUnit = dataSeries.xAxisUnit();
102 auto xAxisUnit = dataSeries.xAxisUnit();
90 auto valuesUnit = dataSeries.valuesUnit();
103 auto valuesUnit = dataSeries.valuesUnit();
91 dataSeries.unlock();
104 dataSeries.unlock();
92
105
93 setAxisProperties(*plot.xAxis, xAxisUnit);
106 setAxisProperties(*plot.xAxis, xAxisUnit);
94 setAxisProperties(*plot.yAxis, valuesUnit);
107 setAxisProperties(*plot.yAxis, valuesUnit);
95 }
108 }
96 };
109 };
97
110
98 /**
111 /**
99 * Specialization of AxisSetter for spectrograms
112 * Specialization of AxisSetter for spectrograms
100 * @sa SpectrogramSeries
113 * @sa SpectrogramSeries
101 */
114 */
102 template <typename T>
115 template <typename T>
103 struct AxisSetter<T, typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
116 struct AxisSetter<T, typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
104 static void setProperties(T &dataSeries, QCustomPlot &plot, SqpColorScale &colorScale)
117 static void setProperties(QCustomPlot &plot, SqpColorScale &colorScale)
105 {
118 {
106 dataSeries.lockRead();
107 auto xAxisUnit = dataSeries.xAxisUnit();
108 auto yAxisUnit = dataSeries.yAxisUnit();
109 auto valuesUnit = dataSeries.valuesUnit();
110 dataSeries.unlock();
111
112 setAxisProperties(*plot.xAxis, xAxisUnit);
113 setAxisProperties(*plot.yAxis, yAxisUnit, QCPAxis::stLogarithmic);
114
115 // Displays color scale in plot
119 // Displays color scale in plot
116 plot.plotLayout()->insertRow(0);
120 plot.plotLayout()->insertRow(0);
117 plot.plotLayout()->addElement(0, 0, colorScale.m_Scale);
121 plot.plotLayout()->addElement(0, 0, colorScale.m_Scale);
118 colorScale.m_Scale->setType(QCPAxis::atTop);
122 colorScale.m_Scale->setType(QCPAxis::atTop);
119 colorScale.m_Scale->setMinimumMargins(QMargins{0, 0, 0, 0});
123 colorScale.m_Scale->setMinimumMargins(QMargins{0, 0, 0, 0});
120
124
121 // Aligns color scale with axes
125 // Aligns color scale with axes
122 auto marginGroups = plot.axisRect()->marginGroups();
126 auto marginGroups = plot.axisRect()->marginGroups();
123 for (auto it = marginGroups.begin(), end = marginGroups.end(); it != end; ++it) {
127 for (auto it = marginGroups.begin(), end = marginGroups.end(); it != end; ++it) {
124 colorScale.m_Scale->setMarginGroup(it.key(), it.value());
128 colorScale.m_Scale->setMarginGroup(it.key(), it.value());
125 }
129 }
126
130
127 // Set color scale properties
131 // Set color scale properties
128 setAxisProperties(*colorScale.m_Scale->axis(), valuesUnit, QCPAxis::stLogarithmic);
129 colorScale.m_AutomaticThreshold = true;
132 colorScale.m_AutomaticThreshold = true;
130 }
133 }
134
135 static void setUnits(T &dataSeries, QCustomPlot &plot, SqpColorScale &colorScale)
136 {
137 dataSeries.lockRead();
138 auto xAxisUnit = dataSeries.xAxisUnit();
139 auto yAxisUnit = dataSeries.yAxisUnit();
140 auto valuesUnit = dataSeries.valuesUnit();
141 dataSeries.unlock();
142
143 setAxisProperties(*plot.xAxis, xAxisUnit);
144 setAxisProperties(*plot.yAxis, yAxisUnit, QCPAxis::stLogarithmic);
145 setAxisProperties(*colorScale.m_Scale->axis(), valuesUnit, QCPAxis::stLogarithmic);
146 }
131 };
147 };
132
148
133 /**
149 /**
134 * Default implementation of IAxisHelper, which takes data series to set axes properties
150 * Default implementation of IAxisHelper, which takes data series to set axes properties
135 * @tparam T the data series' type
151 * @tparam T the data series' type
136 */
152 */
137 template <typename T>
153 template <typename T>
138 struct AxisHelper : public IAxisHelper {
154 struct AxisHelper : public IAxisHelper {
139 explicit AxisHelper(T &dataSeries) : m_DataSeries{dataSeries} {}
155 explicit AxisHelper(std::shared_ptr<T> dataSeries) : m_DataSeries{dataSeries} {}
140
156
141 void setProperties(QCustomPlot &plot, SqpColorScale &colorScale) override
157 void setProperties(QCustomPlot &plot, SqpColorScale &colorScale) override
142 {
158 {
143 AxisSetter<T>::setProperties(m_DataSeries, plot, colorScale);
159 AxisSetter<T>::setProperties(plot, colorScale);
144 }
160 }
145
161
146 T &m_DataSeries;
162 void setUnits(QCustomPlot &plot, SqpColorScale &colorScale) override
163 {
164 if (m_DataSeries) {
165 AxisSetter<T>::setUnits(*m_DataSeries, plot, colorScale);
166 }
167 else {
168 qCCritical(LOG_AxisRenderingUtils()) << "Can't set units: inconsistency between the "
169 "type of data series and the type supposed";
170 }
171 }
172
173 std::shared_ptr<T> m_DataSeries;
147 };
174 };
148
175
149 } // namespace
176 } // namespace
150
177
151 QString formatValue(double value, const QCPAxis &axis)
178 QString formatValue(double value, const QCPAxis &axis)
152 {
179 {
153 // If the axis is a time axis, formats the value as a date
180 // If the axis is a time axis, formats the value as a date
154 if (auto axisTicker = qSharedPointerDynamicCast<QCPAxisTickerDateTime>(axis.ticker())) {
181 if (auto axisTicker = qSharedPointerDynamicCast<QCPAxisTickerDateTime>(axis.ticker())) {
155 return DateUtils::dateTime(value, axisTicker->dateTimeSpec()).toString(DATETIME_FORMAT);
182 return DateUtils::dateTime(value, axisTicker->dateTimeSpec()).toString(DATETIME_FORMAT);
156 }
183 }
157 else {
184 else {
158 return QString::number(value, NUMBER_FORMAT, NUMBER_PRECISION);
185 return QString::number(value, NUMBER_FORMAT, NUMBER_PRECISION);
159 }
186 }
160 }
187 }
161
188
162 std::unique_ptr<IAxisHelper>
189 std::unique_ptr<IAxisHelper> IAxisHelperFactory::create(const Variable &variable) noexcept
163 IAxisHelperFactory::create(std::shared_ptr<IDataSeries> dataSeries) noexcept
164 {
190 {
165 if (auto scalarSeries = std::dynamic_pointer_cast<ScalarSeries>(dataSeries)) {
191 switch (variable.type()) {
166 return std::make_unique<AxisHelper<ScalarSeries> >(*scalarSeries);
192 case DataSeriesType::SCALAR:
167 }
193 return std::make_unique<AxisHelper<ScalarSeries> >(
168 else if (auto spectrogramSeries = std::dynamic_pointer_cast<SpectrogramSeries>(dataSeries)) {
194 std::dynamic_pointer_cast<ScalarSeries>(variable.dataSeries()));
169 return std::make_unique<AxisHelper<SpectrogramSeries> >(*spectrogramSeries);
195 case DataSeriesType::SPECTROGRAM:
170 }
196 return std::make_unique<AxisHelper<SpectrogramSeries> >(
171 else if (auto vectorSeries = std::dynamic_pointer_cast<VectorSeries>(dataSeries)) {
197 std::dynamic_pointer_cast<SpectrogramSeries>(variable.dataSeries()));
172 return std::make_unique<AxisHelper<VectorSeries> >(*vectorSeries);
198 case DataSeriesType::VECTOR:
173 }
199 return std::make_unique<AxisHelper<VectorSeries> >(
174 else {
200 std::dynamic_pointer_cast<VectorSeries>(variable.dataSeries()));
175 return std::make_unique<AxisHelper<IDataSeries> >(*dataSeries);
201 default:
202 // Creates default helper
203 break;
176 }
204 }
205
206 return std::make_unique<AxisHelper<IDataSeries> >(nullptr);
177 }
207 }
@@ -1,122 +1,126
1 #include "Visualization/PlottablesRenderingUtils.h"
1 #include "Visualization/PlottablesRenderingUtils.h"
2
2
3 #include <Common/ColorUtils.h>
3 #include <Common/ColorUtils.h>
4
4
5 #include <Data/ScalarSeries.h>
5 #include <Data/ScalarSeries.h>
6 #include <Data/SpectrogramSeries.h>
6 #include <Data/SpectrogramSeries.h>
7 #include <Data/VectorSeries.h>
7 #include <Data/VectorSeries.h>
8
8
9 #include <Variable/Variable.h>
10
9 #include <Visualization/qcustomplot.h>
11 #include <Visualization/qcustomplot.h>
10
12
11 Q_LOGGING_CATEGORY(LOG_PlottablesRenderingUtils, "PlottablesRenderingUtils")
13 Q_LOGGING_CATEGORY(LOG_PlottablesRenderingUtils, "PlottablesRenderingUtils")
12
14
13 namespace {
15 namespace {
14
16
15 /**
17 /**
16 * Delegate used to set plottables properties
18 * Delegate used to set plottables properties
17 */
19 */
18 template <typename T, typename Enabled = void>
20 template <typename T, typename Enabled = void>
19 struct PlottablesSetter {
21 struct PlottablesSetter {
20 static void setProperties(T &, PlottablesMap &)
22 static void setProperties(PlottablesMap &)
21 {
23 {
22 // Default implementation does nothing
24 // Default implementation does nothing
23 qCCritical(LOG_PlottablesRenderingUtils())
25 qCCritical(LOG_PlottablesRenderingUtils())
24 << "Can't set plottables properties: unmanaged type of data";
26 << "Can't set plottables properties: unmanaged type of data";
25 }
27 }
26 };
28 };
27
29
28 /**
30 /**
29 * Specialization of PlottablesSetter for scalars and vectors
31 * Specialization of PlottablesSetter for scalars and vectors
30 * @sa ScalarSeries
32 * @sa ScalarSeries
31 * @sa VectorSeries
33 * @sa VectorSeries
32 */
34 */
33 template <typename T>
35 template <typename T>
34 struct PlottablesSetter<T, typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
36 struct PlottablesSetter<T, typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
35 or std::is_base_of<VectorSeries, T>::value> > {
37 or std::is_base_of<VectorSeries, T>::value> > {
36 static void setProperties(T &dataSeries, PlottablesMap &plottables)
38 static void setProperties(PlottablesMap &plottables)
37 {
39 {
38 // Gets the number of components of the data series
40 // Finds the plottable with the highest index to determine the number of colors to generate
39 dataSeries.lockRead();
41 auto end = plottables.cend();
40 auto componentCount = dataSeries.valuesData()->componentCount();
42 auto maxPlottableIndexIt
41 dataSeries.unlock();
43 = std::max_element(plottables.cbegin(), end, [](const auto &it1, const auto &it2) {
44 return it1.first < it2.first;
45 });
46 auto componentCount = maxPlottableIndexIt != end ? maxPlottableIndexIt->first + 1 : 0;
42
47
43 // Generates colors for each component
48 // Generates colors for each component
44 auto colors = ColorUtils::colors(Qt::blue, Qt::red, componentCount);
49 auto colors = ColorUtils::colors(Qt::blue, Qt::red, componentCount);
45
50
46 // For each component of the data series, creates a QCPGraph to add to the plot
51 // For each component of the data series, creates a QCPGraph to add to the plot
47 for (auto i = 0; i < componentCount; ++i) {
52 for (auto i = 0; i < componentCount; ++i) {
48 auto graph = plottables.at(i);
53 auto graphIt = plottables.find(i);
49 graph->setPen(QPen{colors.at(i)});
54 if (graphIt != end) {
55 graphIt->second->setPen(QPen{colors.at(i)});
56 }
50 }
57 }
51 }
58 }
52 };
59 };
53
60
54 /**
61 /**
55 * Specialization of PlottablesSetter for spectrograms
62 * Specialization of PlottablesSetter for spectrograms
56 * @sa SpectrogramSeries
63 * @sa SpectrogramSeries
57 */
64 */
58 template <typename T>
65 template <typename T>
59 struct PlottablesSetter<T,
66 struct PlottablesSetter<T,
60 typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
67 typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
61 static void setProperties(T &, PlottablesMap &plottables)
68 static void setProperties(PlottablesMap &plottables)
62 {
69 {
63 // Checks that for a spectrogram there is only one plottable, that is a colormap
70 // Checks that for a spectrogram there is only one plottable, that is a colormap
64 if (plottables.size() != 1) {
71 if (plottables.size() != 1) {
65 return;
72 return;
66 }
73 }
67
74
68 if (auto colormap = dynamic_cast<QCPColorMap *>(plottables.begin()->second)) {
75 if (auto colormap = dynamic_cast<QCPColorMap *>(plottables.begin()->second)) {
69 colormap->setInterpolate(false); // No value interpolation
76 colormap->setInterpolate(false); // No value interpolation
70 colormap->setTightBoundary(true);
77 colormap->setTightBoundary(true);
71
78
72 // Finds color scale in the colormap's plot to associate with it
79 // Finds color scale in the colormap's plot to associate with it
73 auto plot = colormap->parentPlot();
80 auto plot = colormap->parentPlot();
74 auto plotElements = plot->plotLayout()->elements(false);
81 auto plotElements = plot->plotLayout()->elements(false);
75 for (auto plotElement : plotElements) {
82 for (auto plotElement : plotElements) {
76 if (auto colorScale = dynamic_cast<QCPColorScale *>(plotElement)) {
83 if (auto colorScale = dynamic_cast<QCPColorScale *>(plotElement)) {
77 colormap->setColorScale(colorScale);
84 colormap->setColorScale(colorScale);
78 }
85 }
79 }
86 }
80
87
81 colormap->rescaleDataRange();
88 colormap->rescaleDataRange();
82 }
89 }
83 else {
90 else {
84 qCCritical(LOG_PlottablesRenderingUtils()) << "Can't get colormap of the spectrogram";
91 qCCritical(LOG_PlottablesRenderingUtils()) << "Can't get colormap of the spectrogram";
85 }
92 }
86 }
93 }
87 };
94 };
88
95
89 /**
96 /**
90 * Default implementation of IPlottablesHelper, which takes data series to set plottables properties
97 * Default implementation of IPlottablesHelper, which takes data series to set plottables properties
91 * @tparam T the data series' type
98 * @tparam T the data series' type
92 */
99 */
93 template <typename T>
100 template <typename T>
94 struct PlottablesHelper : public IPlottablesHelper {
101 struct PlottablesHelper : public IPlottablesHelper {
95 explicit PlottablesHelper(T &dataSeries) : m_DataSeries{dataSeries} {}
96
97 void setProperties(PlottablesMap &plottables) override
102 void setProperties(PlottablesMap &plottables) override
98 {
103 {
99 PlottablesSetter<T>::setProperties(m_DataSeries, plottables);
104 PlottablesSetter<T>::setProperties(plottables);
100 }
105 }
101
102 T &m_DataSeries;
103 };
106 };
104
107
105 } // namespace
108 } // namespace
106
109
107 std::unique_ptr<IPlottablesHelper>
110 std::unique_ptr<IPlottablesHelper>
108 IPlottablesHelperFactory::create(std::shared_ptr<IDataSeries> dataSeries) noexcept
111 IPlottablesHelperFactory::create(const Variable &variable) noexcept
109 {
112 {
110 if (auto scalarSeries = std::dynamic_pointer_cast<ScalarSeries>(dataSeries)) {
113 switch (variable.type()) {
111 return std::make_unique<PlottablesHelper<ScalarSeries> >(*scalarSeries);
114 case DataSeriesType::SCALAR:
112 }
115 return std::make_unique<PlottablesHelper<ScalarSeries> >();
113 else if (auto spectrogramSeries = std::dynamic_pointer_cast<SpectrogramSeries>(dataSeries)) {
116 case DataSeriesType::SPECTROGRAM:
114 return std::make_unique<PlottablesHelper<SpectrogramSeries> >(*spectrogramSeries);
117 return std::make_unique<PlottablesHelper<SpectrogramSeries> >();
115 }
118 case DataSeriesType::VECTOR:
116 else if (auto vectorSeries = std::dynamic_pointer_cast<VectorSeries>(dataSeries)) {
119 return std::make_unique<PlottablesHelper<VectorSeries> >();
117 return std::make_unique<PlottablesHelper<VectorSeries> >(*vectorSeries);
120 default:
118 }
121 // Returns default helper
119 else {
122 break;
120 return std::make_unique<PlottablesHelper<IDataSeries> >(*dataSeries);
121 }
123 }
124
125 return std::make_unique<PlottablesHelper<IDataSeries> >();
122 }
126 }
@@ -1,340 +1,361
1 #include "Visualization/VisualizationGraphHelper.h"
1 #include "Visualization/VisualizationGraphHelper.h"
2 #include "Visualization/qcustomplot.h"
2 #include "Visualization/qcustomplot.h"
3
3
4 #include <Data/DataSeriesUtils.h>
4 #include <Data/DataSeriesUtils.h>
5 #include <Data/ScalarSeries.h>
5 #include <Data/ScalarSeries.h>
6 #include <Data/SpectrogramSeries.h>
6 #include <Data/SpectrogramSeries.h>
7 #include <Data/VectorSeries.h>
7 #include <Data/VectorSeries.h>
8
8
9 #include <Variable/Variable.h>
9 #include <Variable/Variable.h>
10
10
11 Q_LOGGING_CATEGORY(LOG_VisualizationGraphHelper, "VisualizationGraphHelper")
11 Q_LOGGING_CATEGORY(LOG_VisualizationGraphHelper, "VisualizationGraphHelper")
12
12
13 namespace {
13 namespace {
14
14
15 class SqpDataContainer : public QCPGraphDataContainer {
15 class SqpDataContainer : public QCPGraphDataContainer {
16 public:
16 public:
17 void appendGraphData(const QCPGraphData &data) { mData.append(data); }
17 void appendGraphData(const QCPGraphData &data) { mData.append(data); }
18 };
18 };
19
19
20 /**
20 /**
21 * Struct used to create plottables, depending on the type of the data series from which to create
21 * Struct used to create plottables, depending on the type of the data series from which to create
22 * them
22 * them
23 * @tparam T the data series' type
23 * @tparam T the data series' type
24 * @remarks Default implementation can't create plottables
24 * @remarks Default implementation can't create plottables
25 */
25 */
26 template <typename T, typename Enabled = void>
26 template <typename T, typename Enabled = void>
27 struct PlottablesCreator {
27 struct PlottablesCreator {
28 static PlottablesMap createPlottables(T &, QCustomPlot &)
28 static PlottablesMap createPlottables(QCustomPlot &)
29 {
29 {
30 qCCritical(LOG_DataSeries())
30 qCCritical(LOG_DataSeries())
31 << QObject::tr("Can't create plottables: unmanaged data series type");
31 << QObject::tr("Can't create plottables: unmanaged data series type");
32 return {};
32 return {};
33 }
33 }
34 };
34 };
35
35
36 PlottablesMap createGraphs(QCustomPlot &plot, int nbGraphs)
37 {
38 PlottablesMap result{};
39
40 // Creates {nbGraphs} QCPGraph to add to the plot
41 for (auto i = 0; i < nbGraphs; ++i) {
42 auto graph = plot.addGraph();
43 result.insert({i, graph});
44 }
45
46 plot.replot();
47
48 return result;
49 }
50
36 /**
51 /**
37 * Specialization of PlottablesCreator for scalars and vectors
52 * Specialization of PlottablesCreator for scalars
38 * @sa ScalarSeries
53 * @sa ScalarSeries
39 * @sa VectorSeries
40 */
54 */
41 template <typename T>
55 template <typename T>
42 struct PlottablesCreator<T,
56 struct PlottablesCreator<T, typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value> > {
43 typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
57 static PlottablesMap createPlottables(QCustomPlot &plot) { return createGraphs(plot, 1); }
44 or std::is_base_of<VectorSeries, T>::value> > {
58 };
45 static PlottablesMap createPlottables(T &dataSeries, QCustomPlot &plot)
46 {
47 PlottablesMap result{};
48
49 // Gets the number of components of the data series
50 dataSeries.lockRead();
51 auto componentCount = dataSeries.valuesData()->componentCount();
52 dataSeries.unlock();
53
54 // For each component of the data series, creates a QCPGraph to add to the plot
55 for (auto i = 0; i < componentCount; ++i) {
56 auto graph = plot.addGraph();
57 result.insert({i, graph});
58 }
59
60 plot.replot();
61
59
62 return result;
60 /**
63 }
61 * Specialization of PlottablesCreator for vectors
62 * @sa VectorSeries
63 */
64 template <typename T>
65 struct PlottablesCreator<T, typename std::enable_if_t<std::is_base_of<VectorSeries, T>::value> > {
66 static PlottablesMap createPlottables(QCustomPlot &plot) { return createGraphs(plot, 3); }
64 };
67 };
65
68
66 /**
69 /**
67 * Specialization of PlottablesCreator for spectrograms
70 * Specialization of PlottablesCreator for spectrograms
68 * @sa SpectrogramSeries
71 * @sa SpectrogramSeries
69 */
72 */
70 template <typename T>
73 template <typename T>
71 struct PlottablesCreator<T,
74 struct PlottablesCreator<T,
72 typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
75 typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
73 static PlottablesMap createPlottables(T &dataSeries, QCustomPlot &plot)
76 static PlottablesMap createPlottables(QCustomPlot &plot)
74 {
77 {
75 PlottablesMap result{};
78 PlottablesMap result{};
76 result.insert({0, new QCPColorMap{plot.xAxis, plot.yAxis}});
79 result.insert({0, new QCPColorMap{plot.xAxis, plot.yAxis}});
77
80
78 plot.replot();
81 plot.replot();
79
82
80 return result;
83 return result;
81 }
84 }
82 };
85 };
83
86
84 /**
87 /**
85 * Struct used to update plottables, depending on the type of the data series from which to update
88 * Struct used to update plottables, depending on the type of the data series from which to update
86 * them
89 * them
87 * @tparam T the data series' type
90 * @tparam T the data series' type
88 * @remarks Default implementation can't update plottables
91 * @remarks Default implementation can't update plottables
89 */
92 */
90 template <typename T, typename Enabled = void>
93 template <typename T, typename Enabled = void>
91 struct PlottablesUpdater {
94 struct PlottablesUpdater {
92 static void setPlotYAxisRange(T &, const SqpRange &, QCustomPlot &)
95 static void setPlotYAxisRange(T &, const SqpRange &, QCustomPlot &)
93 {
96 {
94 qCCritical(LOG_VisualizationGraphHelper())
97 qCCritical(LOG_VisualizationGraphHelper())
95 << QObject::tr("Can't set plot y-axis range: unmanaged data series type");
98 << QObject::tr("Can't set plot y-axis range: unmanaged data series type");
96 }
99 }
97
100
98 static void updatePlottables(T &, PlottablesMap &, const SqpRange &, bool)
101 static void updatePlottables(T &, PlottablesMap &, const SqpRange &, bool)
99 {
102 {
100 qCCritical(LOG_VisualizationGraphHelper())
103 qCCritical(LOG_VisualizationGraphHelper())
101 << QObject::tr("Can't update plottables: unmanaged data series type");
104 << QObject::tr("Can't update plottables: unmanaged data series type");
102 }
105 }
103 };
106 };
104
107
105 /**
108 /**
106 * Specialization of PlottablesUpdater for scalars and vectors
109 * Specialization of PlottablesUpdater for scalars and vectors
107 * @sa ScalarSeries
110 * @sa ScalarSeries
108 * @sa VectorSeries
111 * @sa VectorSeries
109 */
112 */
110 template <typename T>
113 template <typename T>
111 struct PlottablesUpdater<T,
114 struct PlottablesUpdater<T,
112 typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
115 typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
113 or std::is_base_of<VectorSeries, T>::value> > {
116 or std::is_base_of<VectorSeries, T>::value> > {
114 static void setPlotYAxisRange(T &dataSeries, const SqpRange &xAxisRange, QCustomPlot &plot)
117 static void setPlotYAxisRange(T &dataSeries, const SqpRange &xAxisRange, QCustomPlot &plot)
115 {
118 {
116 auto minValue = 0., maxValue = 0.;
119 auto minValue = 0., maxValue = 0.;
117
120
118 dataSeries.lockRead();
121 dataSeries.lockRead();
119 auto valuesBounds = dataSeries.valuesBounds(xAxisRange.m_TStart, xAxisRange.m_TEnd);
122 auto valuesBounds = dataSeries.valuesBounds(xAxisRange.m_TStart, xAxisRange.m_TEnd);
120 auto end = dataSeries.cend();
123 auto end = dataSeries.cend();
121 if (valuesBounds.first != end && valuesBounds.second != end) {
124 if (valuesBounds.first != end && valuesBounds.second != end) {
122 auto rangeValue = [](const auto &value) { return std::isnan(value) ? 0. : value; };
125 auto rangeValue = [](const auto &value) { return std::isnan(value) ? 0. : value; };
123
126
124 minValue = rangeValue(valuesBounds.first->minValue());
127 minValue = rangeValue(valuesBounds.first->minValue());
125 maxValue = rangeValue(valuesBounds.second->maxValue());
128 maxValue = rangeValue(valuesBounds.second->maxValue());
126 }
129 }
127 dataSeries.unlock();
130 dataSeries.unlock();
128
131
129 plot.yAxis->setRange(QCPRange{minValue, maxValue});
132 plot.yAxis->setRange(QCPRange{minValue, maxValue});
130 }
133 }
131
134
132 static void updatePlottables(T &dataSeries, PlottablesMap &plottables, const SqpRange &range,
135 static void updatePlottables(T &dataSeries, PlottablesMap &plottables, const SqpRange &range,
133 bool rescaleAxes)
136 bool rescaleAxes)
134 {
137 {
135
138
136 // For each plottable to update, resets its data
139 // For each plottable to update, resets its data
137 std::map<int, QSharedPointer<SqpDataContainer> > dataContainers{};
140 std::map<int, QSharedPointer<SqpDataContainer> > dataContainers{};
138 for (const auto &plottable : plottables) {
141 for (const auto &plottable : plottables) {
139 if (auto graph = dynamic_cast<QCPGraph *>(plottable.second)) {
142 if (auto graph = dynamic_cast<QCPGraph *>(plottable.second)) {
140 auto dataContainer = QSharedPointer<SqpDataContainer>::create();
143 auto dataContainer = QSharedPointer<SqpDataContainer>::create();
141 graph->setData(dataContainer);
144 graph->setData(dataContainer);
142
145
143 dataContainers.insert({plottable.first, dataContainer});
146 dataContainers.insert({plottable.first, dataContainer});
144 }
147 }
145 }
148 }
146 dataSeries.lockRead();
149 dataSeries.lockRead();
147
150
148 // - Gets the data of the series included in the current range
151 // - Gets the data of the series included in the current range
149 // - Updates each plottable by adding, for each data item, a point that takes x-axis data
152 // - Updates each plottable by adding, for each data item, a point that takes x-axis data
150 // and value data. The correct value is retrieved according to the index of the component
153 // and value data. The correct value is retrieved according to the index of the component
151 auto subDataIts = dataSeries.xAxisRange(range.m_TStart, range.m_TEnd);
154 auto subDataIts = dataSeries.xAxisRange(range.m_TStart, range.m_TEnd);
152 for (auto it = subDataIts.first; it != subDataIts.second; ++it) {
155 for (auto it = subDataIts.first; it != subDataIts.second; ++it) {
153 for (const auto &dataContainer : dataContainers) {
156 for (const auto &dataContainer : dataContainers) {
154 auto componentIndex = dataContainer.first;
157 auto componentIndex = dataContainer.first;
155 dataContainer.second->appendGraphData(
158 dataContainer.second->appendGraphData(
156 QCPGraphData(it->x(), it->value(componentIndex)));
159 QCPGraphData(it->x(), it->value(componentIndex)));
157 }
160 }
158 }
161 }
159
162
160 dataSeries.unlock();
163 dataSeries.unlock();
161
164
162 if (!plottables.empty()) {
165 if (!plottables.empty()) {
163 auto plot = plottables.begin()->second->parentPlot();
166 auto plot = plottables.begin()->second->parentPlot();
164
167
165 if (rescaleAxes) {
168 if (rescaleAxes) {
166 plot->rescaleAxes();
169 plot->rescaleAxes();
167 }
170 }
168 }
171 }
169 }
172 }
170 };
173 };
171
174
172 /**
175 /**
173 * Specialization of PlottablesUpdater for spectrograms
176 * Specialization of PlottablesUpdater for spectrograms
174 * @sa SpectrogramSeries
177 * @sa SpectrogramSeries
175 */
178 */
176 template <typename T>
179 template <typename T>
177 struct PlottablesUpdater<T,
180 struct PlottablesUpdater<T,
178 typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
181 typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
179 static void setPlotYAxisRange(T &dataSeries, const SqpRange &xAxisRange, QCustomPlot &plot)
182 static void setPlotYAxisRange(T &dataSeries, const SqpRange &xAxisRange, QCustomPlot &plot)
180 {
183 {
181 double min, max;
184 double min, max;
182 std::tie(min, max) = dataSeries.yBounds();
185 std::tie(min, max) = dataSeries.yBounds();
183
186
184 if (!std::isnan(min) && !std::isnan(max)) {
187 if (!std::isnan(min) && !std::isnan(max)) {
185 plot.yAxis->setRange(QCPRange{min, max});
188 plot.yAxis->setRange(QCPRange{min, max});
186 }
189 }
187 }
190 }
188
191
189 static void updatePlottables(T &dataSeries, PlottablesMap &plottables, const SqpRange &range,
192 static void updatePlottables(T &dataSeries, PlottablesMap &plottables, const SqpRange &range,
190 bool rescaleAxes)
193 bool rescaleAxes)
191 {
194 {
192 if (plottables.empty()) {
195 if (plottables.empty()) {
193 qCDebug(LOG_VisualizationGraphHelper())
196 qCDebug(LOG_VisualizationGraphHelper())
194 << QObject::tr("Can't update spectrogram: no colormap has been associated");
197 << QObject::tr("Can't update spectrogram: no colormap has been associated");
195 return;
198 return;
196 }
199 }
197
200
198 // Gets the colormap to update (normally there is only one colormap)
201 // Gets the colormap to update (normally there is only one colormap)
199 Q_ASSERT(plottables.size() == 1);
202 Q_ASSERT(plottables.size() == 1);
200 auto colormap = dynamic_cast<QCPColorMap *>(plottables.at(0));
203 auto colormap = dynamic_cast<QCPColorMap *>(plottables.at(0));
201 Q_ASSERT(colormap != nullptr);
204 Q_ASSERT(colormap != nullptr);
202
205
203 dataSeries.lockRead();
206 dataSeries.lockRead();
204
207
205 // Processing spectrogram data for display in QCustomPlot
208 // Processing spectrogram data for display in QCustomPlot
206 auto its = dataSeries.xAxisRange(range.m_TStart, range.m_TEnd);
209 auto its = dataSeries.xAxisRange(range.m_TStart, range.m_TEnd);
207
210
208 // Computes logarithmic y-axis resolution for the spectrogram
211 // Computes logarithmic y-axis resolution for the spectrogram
209 auto yData = its.first->y();
212 auto yData = its.first->y();
210 auto yResolution = DataSeriesUtils::resolution(yData.begin(), yData.end(), true);
213 auto yResolution = DataSeriesUtils::resolution(yData.begin(), yData.end(), true);
211
214
212 // Generates mesh for colormap
215 // Generates mesh for colormap
213 auto mesh = DataSeriesUtils::regularMesh(
216 auto mesh = DataSeriesUtils::regularMesh(
214 its.first, its.second, DataSeriesUtils::Resolution{dataSeries.xResolution()},
217 its.first, its.second, DataSeriesUtils::Resolution{dataSeries.xResolution()},
215 yResolution);
218 yResolution);
216
219
217 dataSeries.unlock();
220 dataSeries.unlock();
218
221
219 colormap->data()->setSize(mesh.m_NbX, mesh.m_NbY);
222 colormap->data()->setSize(mesh.m_NbX, mesh.m_NbY);
220 if (!mesh.isEmpty()) {
223 if (!mesh.isEmpty()) {
221 colormap->data()->setRange(
224 colormap->data()->setRange(
222 QCPRange{mesh.m_XMin, mesh.xMax()},
225 QCPRange{mesh.m_XMin, mesh.xMax()},
223 // y-axis range is converted to linear values
226 // y-axis range is converted to linear values
224 QCPRange{std::pow(10, mesh.m_YMin), std::pow(10, mesh.yMax())});
227 QCPRange{std::pow(10, mesh.m_YMin), std::pow(10, mesh.yMax())});
225
228
226 // Sets values
229 // Sets values
227 auto index = 0;
230 auto index = 0;
228 for (auto it = mesh.m_Data.begin(), end = mesh.m_Data.end(); it != end; ++it, ++index) {
231 for (auto it = mesh.m_Data.begin(), end = mesh.m_Data.end(); it != end; ++it, ++index) {
229 auto xIndex = index % mesh.m_NbX;
232 auto xIndex = index % mesh.m_NbX;
230 auto yIndex = index / mesh.m_NbX;
233 auto yIndex = index / mesh.m_NbX;
231
234
232 colormap->data()->setCell(xIndex, yIndex, *it);
235 colormap->data()->setCell(xIndex, yIndex, *it);
233
236
234 // Makes the NaN values to be transparent in the colormap
237 // Makes the NaN values to be transparent in the colormap
235 if (std::isnan(*it)) {
238 if (std::isnan(*it)) {
236 colormap->data()->setAlpha(xIndex, yIndex, 0);
239 colormap->data()->setAlpha(xIndex, yIndex, 0);
237 }
240 }
238 }
241 }
239 }
242 }
240
243
241 // Rescales axes
244 // Rescales axes
242 auto plot = colormap->parentPlot();
245 auto plot = colormap->parentPlot();
243
246
244 if (rescaleAxes) {
247 if (rescaleAxes) {
245 plot->rescaleAxes();
248 plot->rescaleAxes();
246 }
249 }
247 }
250 }
248 };
251 };
249
252
250 /**
253 /**
251 * Helper used to create/update plottables
254 * Helper used to create/update plottables
252 */
255 */
253 struct IPlottablesHelper {
256 struct IPlottablesHelper {
254 virtual ~IPlottablesHelper() noexcept = default;
257 virtual ~IPlottablesHelper() noexcept = default;
255 virtual PlottablesMap create(QCustomPlot &plot) const = 0;
258 virtual PlottablesMap create(QCustomPlot &plot) const = 0;
256 virtual void setYAxisRange(const SqpRange &xAxisRange, QCustomPlot &plot) const = 0;
259 virtual void setYAxisRange(const SqpRange &xAxisRange, QCustomPlot &plot) const = 0;
257 virtual void update(PlottablesMap &plottables, const SqpRange &range,
260 virtual void update(PlottablesMap &plottables, const SqpRange &range,
258 bool rescaleAxes = false) const = 0;
261 bool rescaleAxes = false) const = 0;
259 };
262 };
260
263
261 /**
264 /**
262 * Default implementation of IPlottablesHelper, which takes data series to create/update plottables
265 * Default implementation of IPlottablesHelper, which takes data series to create/update plottables
263 * @tparam T the data series' type
266 * @tparam T the data series' type
264 */
267 */
265 template <typename T>
268 template <typename T>
266 struct PlottablesHelper : public IPlottablesHelper {
269 struct PlottablesHelper : public IPlottablesHelper {
267 explicit PlottablesHelper(T &dataSeries) : m_DataSeries{dataSeries} {}
270 explicit PlottablesHelper(std::shared_ptr<T> dataSeries) : m_DataSeries{dataSeries} {}
268
271
269 PlottablesMap create(QCustomPlot &plot) const override
272 PlottablesMap create(QCustomPlot &plot) const override
270 {
273 {
271 return PlottablesCreator<T>::createPlottables(m_DataSeries, plot);
274 return PlottablesCreator<T>::createPlottables(plot);
272 }
275 }
273
276
274 void update(PlottablesMap &plottables, const SqpRange &range, bool rescaleAxes) const override
277 void update(PlottablesMap &plottables, const SqpRange &range, bool rescaleAxes) const override
275 {
278 {
276 PlottablesUpdater<T>::updatePlottables(m_DataSeries, plottables, range, rescaleAxes);
279 if (m_DataSeries) {
280 PlottablesUpdater<T>::updatePlottables(*m_DataSeries, plottables, range, rescaleAxes);
281 }
282 else {
283 qCCritical(LOG_VisualizationGraphHelper()) << "Can't update plottables: inconsistency "
284 "between the type of data series and the "
285 "type supposed";
286 }
277 }
287 }
278
288
279 void setYAxisRange(const SqpRange &xAxisRange, QCustomPlot &plot) const override
289 void setYAxisRange(const SqpRange &xAxisRange, QCustomPlot &plot) const override
280 {
290 {
281 return PlottablesUpdater<T>::setPlotYAxisRange(m_DataSeries, xAxisRange, plot);
291 if (m_DataSeries) {
292 PlottablesUpdater<T>::setPlotYAxisRange(*m_DataSeries, xAxisRange, plot);
293 }
294 else {
295 qCCritical(LOG_VisualizationGraphHelper()) << "Can't update plottables: inconsistency "
296 "between the type of data series and the "
297 "type supposed";
298 }
282 }
299 }
283
300
284 T &m_DataSeries;
301 std::shared_ptr<T> m_DataSeries;
285 };
302 };
286
303
287 /// Creates IPlottablesHelper according to a data series
304 /// Creates IPlottablesHelper according to the type of data series a variable holds
288 std::unique_ptr<IPlottablesHelper> createHelper(std::shared_ptr<IDataSeries> dataSeries) noexcept
305 std::unique_ptr<IPlottablesHelper> createHelper(std::shared_ptr<Variable> variable) noexcept
289 {
306 {
290 if (auto scalarSeries = std::dynamic_pointer_cast<ScalarSeries>(dataSeries)) {
307 switch (variable->type()) {
291 return std::make_unique<PlottablesHelper<ScalarSeries> >(*scalarSeries);
308 case DataSeriesType::SCALAR:
292 }
309 return std::make_unique<PlottablesHelper<ScalarSeries> >(
293 else if (auto spectrogramSeries = std::dynamic_pointer_cast<SpectrogramSeries>(dataSeries)) {
310 std::dynamic_pointer_cast<ScalarSeries>(variable->dataSeries()));
294 return std::make_unique<PlottablesHelper<SpectrogramSeries> >(*spectrogramSeries);
311 case DataSeriesType::SPECTROGRAM:
295 }
312 return std::make_unique<PlottablesHelper<SpectrogramSeries> >(
296 else if (auto vectorSeries = std::dynamic_pointer_cast<VectorSeries>(dataSeries)) {
313 std::dynamic_pointer_cast<SpectrogramSeries>(variable->dataSeries()));
297 return std::make_unique<PlottablesHelper<VectorSeries> >(*vectorSeries);
314 case DataSeriesType::VECTOR:
298 }
315 return std::make_unique<PlottablesHelper<VectorSeries> >(
299 else {
316 std::dynamic_pointer_cast<VectorSeries>(variable->dataSeries()));
300 return std::make_unique<PlottablesHelper<IDataSeries> >(*dataSeries);
317 default:
318 // Creates default helper
319 break;
301 }
320 }
321
322 return std::make_unique<PlottablesHelper<IDataSeries> >(nullptr);
302 }
323 }
303
324
304 } // namespace
325 } // namespace
305
326
306 PlottablesMap VisualizationGraphHelper::create(std::shared_ptr<Variable> variable,
327 PlottablesMap VisualizationGraphHelper::create(std::shared_ptr<Variable> variable,
307 QCustomPlot &plot) noexcept
328 QCustomPlot &plot) noexcept
308 {
329 {
309 if (variable) {
330 if (variable) {
310 auto helper = createHelper(variable->dataSeries());
331 auto helper = createHelper(variable);
311 auto plottables = helper->create(plot);
332 auto plottables = helper->create(plot);
312 return plottables;
333 return plottables;
313 }
334 }
314 else {
335 else {
315 qCDebug(LOG_VisualizationGraphHelper())
336 qCDebug(LOG_VisualizationGraphHelper())
316 << QObject::tr("Can't create graph plottables : the variable is null");
337 << QObject::tr("Can't create graph plottables : the variable is null");
317 return PlottablesMap{};
338 return PlottablesMap{};
318 }
339 }
319 }
340 }
320
341
321 void VisualizationGraphHelper::setYAxisRange(std::shared_ptr<Variable> variable,
342 void VisualizationGraphHelper::setYAxisRange(std::shared_ptr<Variable> variable,
322 QCustomPlot &plot) noexcept
343 QCustomPlot &plot) noexcept
323 {
344 {
324 if (variable) {
345 if (variable) {
325 auto helper = createHelper(variable->dataSeries());
346 auto helper = createHelper(variable);
326 helper->setYAxisRange(variable->range(), plot);
347 helper->setYAxisRange(variable->range(), plot);
327 }
348 }
328 else {
349 else {
329 qCDebug(LOG_VisualizationGraphHelper())
350 qCDebug(LOG_VisualizationGraphHelper())
330 << QObject::tr("Can't set y-axis range of plot: the variable is null");
351 << QObject::tr("Can't set y-axis range of plot: the variable is null");
331 }
352 }
332 }
353 }
333
354
334 void VisualizationGraphHelper::updateData(PlottablesMap &plottables,
355 void VisualizationGraphHelper::updateData(PlottablesMap &plottables,
335 std::shared_ptr<IDataSeries> dataSeries,
356 std::shared_ptr<Variable> variable,
336 const SqpRange &dateTime)
357 const SqpRange &dateTime)
337 {
358 {
338 auto helper = createHelper(dataSeries);
359 auto helper = createHelper(variable);
339 helper->update(plottables, dateTime);
360 helper->update(plottables, dateTime);
340 }
361 }
@@ -1,332 +1,338
1 #include "Visualization/VisualizationGraphRenderingDelegate.h"
1 #include "Visualization/VisualizationGraphRenderingDelegate.h"
2 #include "Visualization/AxisRenderingUtils.h"
2 #include "Visualization/AxisRenderingUtils.h"
3 #include "Visualization/ColorScaleEditor.h"
3 #include "Visualization/ColorScaleEditor.h"
4 #include "Visualization/PlottablesRenderingUtils.h"
4 #include "Visualization/PlottablesRenderingUtils.h"
5 #include "Visualization/SqpColorScale.h"
5 #include "Visualization/SqpColorScale.h"
6 #include "Visualization/VisualizationGraphWidget.h"
6 #include "Visualization/VisualizationGraphWidget.h"
7 #include "Visualization/qcustomplot.h"
7 #include "Visualization/qcustomplot.h"
8
8
9 #include <Common/DateUtils.h>
9 #include <Common/DateUtils.h>
10
10
11 #include <Data/IDataSeries.h>
11 #include <Data/IDataSeries.h>
12 #include <Variable/Variable.h>
12
13
13 #include <SqpApplication.h>
14 #include <SqpApplication.h>
14
15
15 namespace {
16 namespace {
16
17
17 /// Name of the axes layer in QCustomPlot
18 /// Name of the axes layer in QCustomPlot
18 const auto AXES_LAYER = QStringLiteral("axes");
19 const auto AXES_LAYER = QStringLiteral("axes");
19
20
20 /// Icon used to show x-axis properties
21 /// Icon used to show x-axis properties
21 const auto HIDE_AXIS_ICON_PATH = QStringLiteral(":/icones/down.png");
22 const auto HIDE_AXIS_ICON_PATH = QStringLiteral(":/icones/down.png");
22
23
23 /// Name of the overlay layer in QCustomPlot
24 /// Name of the overlay layer in QCustomPlot
24 const auto OVERLAY_LAYER = QStringLiteral("overlay");
25 const auto OVERLAY_LAYER = QStringLiteral("overlay");
25
26
26 /// Pixmap used to show x-axis properties
27 /// Pixmap used to show x-axis properties
27 const auto SHOW_AXIS_ICON_PATH = QStringLiteral(":/icones/up.png");
28 const auto SHOW_AXIS_ICON_PATH = QStringLiteral(":/icones/up.png");
28
29
29 /// Tooltip format for graphs
30 /// Tooltip format for graphs
30 const auto GRAPH_TOOLTIP_FORMAT = QStringLiteral("key: %1\nvalue: %2");
31 const auto GRAPH_TOOLTIP_FORMAT = QStringLiteral("key: %1\nvalue: %2");
31
32
32 /// Tooltip format for colormaps
33 /// Tooltip format for colormaps
33 const auto COLORMAP_TOOLTIP_FORMAT = QStringLiteral("x: %1\ny: %2\nvalue: %3");
34 const auto COLORMAP_TOOLTIP_FORMAT = QStringLiteral("x: %1\ny: %2\nvalue: %3");
34
35
35 /// Offset used to shift the tooltip of the mouse
36 /// Offset used to shift the tooltip of the mouse
36 const auto TOOLTIP_OFFSET = QPoint{20, 20};
37 const auto TOOLTIP_OFFSET = QPoint{20, 20};
37
38
38 /// Tooltip display rectangle (the tooltip is hidden when the mouse leaves this rectangle)
39 /// Tooltip display rectangle (the tooltip is hidden when the mouse leaves this rectangle)
39 const auto TOOLTIP_RECT = QRect{10, 10, 10, 10};
40 const auto TOOLTIP_RECT = QRect{10, 10, 10, 10};
40
41
41 /// Timeout after which the tooltip is displayed
42 /// Timeout after which the tooltip is displayed
42 const auto TOOLTIP_TIMEOUT = 500;
43 const auto TOOLTIP_TIMEOUT = 500;
43
44
44 void initPointTracerStyle(QCPItemTracer &tracer) noexcept
45 void initPointTracerStyle(QCPItemTracer &tracer) noexcept
45 {
46 {
46 tracer.setInterpolating(false);
47 tracer.setInterpolating(false);
47 tracer.setStyle(QCPItemTracer::tsCircle);
48 tracer.setStyle(QCPItemTracer::tsCircle);
48 tracer.setSize(3);
49 tracer.setSize(3);
49 tracer.setPen(QPen(Qt::black));
50 tracer.setPen(QPen(Qt::black));
50 tracer.setBrush(Qt::black);
51 tracer.setBrush(Qt::black);
51 tracer.setSelectable(false);
52 tracer.setSelectable(false);
52 }
53 }
53
54
54 QPixmap pixmap(const QString &iconPath) noexcept
55 QPixmap pixmap(const QString &iconPath) noexcept
55 {
56 {
56 return QIcon{iconPath}.pixmap(QSize{16, 16});
57 return QIcon{iconPath}.pixmap(QSize{16, 16});
57 }
58 }
58
59
59 void initClosePixmapStyle(QCPItemPixmap &pixmap) noexcept
60 void initClosePixmapStyle(QCPItemPixmap &pixmap) noexcept
60 {
61 {
61 // Icon
62 // Icon
62 pixmap.setPixmap(
63 pixmap.setPixmap(
63 sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton).pixmap(QSize{16, 16}));
64 sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton).pixmap(QSize{16, 16}));
64
65
65 // Position
66 // Position
66 pixmap.topLeft->setType(QCPItemPosition::ptAxisRectRatio);
67 pixmap.topLeft->setType(QCPItemPosition::ptAxisRectRatio);
67 pixmap.topLeft->setCoords(1, 0);
68 pixmap.topLeft->setCoords(1, 0);
68 pixmap.setClipToAxisRect(false);
69 pixmap.setClipToAxisRect(false);
69
70
70 // Can be selected
71 // Can be selected
71 pixmap.setSelectable(true);
72 pixmap.setSelectable(true);
72 }
73 }
73
74
74 void initXAxisPixmapStyle(QCPItemPixmap &itemPixmap) noexcept
75 void initXAxisPixmapStyle(QCPItemPixmap &itemPixmap) noexcept
75 {
76 {
76 // Icon
77 // Icon
77 itemPixmap.setPixmap(pixmap(HIDE_AXIS_ICON_PATH));
78 itemPixmap.setPixmap(pixmap(HIDE_AXIS_ICON_PATH));
78
79
79 // Position
80 // Position
80 itemPixmap.topLeft->setType(QCPItemPosition::ptAxisRectRatio);
81 itemPixmap.topLeft->setType(QCPItemPosition::ptAxisRectRatio);
81 itemPixmap.topLeft->setCoords(0, 1);
82 itemPixmap.topLeft->setCoords(0, 1);
82 itemPixmap.setClipToAxisRect(false);
83 itemPixmap.setClipToAxisRect(false);
83
84
84 // Can be selected
85 // Can be selected
85 itemPixmap.setSelectable(true);
86 itemPixmap.setSelectable(true);
86 }
87 }
87
88
88 void initTitleTextStyle(QCPItemText &text) noexcept
89 void initTitleTextStyle(QCPItemText &text) noexcept
89 {
90 {
90 // Font and background styles
91 // Font and background styles
91 text.setColor(Qt::gray);
92 text.setColor(Qt::gray);
92 text.setBrush(Qt::white);
93 text.setBrush(Qt::white);
93
94
94 // Position
95 // Position
95 text.setPositionAlignment(Qt::AlignTop | Qt::AlignLeft);
96 text.setPositionAlignment(Qt::AlignTop | Qt::AlignLeft);
96 text.position->setType(QCPItemPosition::ptAxisRectRatio);
97 text.position->setType(QCPItemPosition::ptAxisRectRatio);
97 text.position->setCoords(0.5, 0);
98 text.position->setCoords(0.5, 0);
98 text.setSelectable(false);
99 text.setSelectable(false);
99 }
100 }
100
101
101 /**
102 /**
102 * Returns the cell index (x or y) of a colormap according to the coordinate passed in parameter.
103 * Returns the cell index (x or y) of a colormap according to the coordinate passed in parameter.
103 * This method handles the fact that a colormap axis can be logarithmic or linear.
104 * This method handles the fact that a colormap axis can be logarithmic or linear.
104 * @param colormap the colormap for which to calculate the index
105 * @param colormap the colormap for which to calculate the index
105 * @param coord the coord to convert to cell index
106 * @param coord the coord to convert to cell index
106 * @param xCoord calculates the x index if true, calculates y index if false
107 * @param xCoord calculates the x index if true, calculates y index if false
107 * @return the cell index
108 * @return the cell index
108 */
109 */
109 int colorMapCellIndex(const QCPColorMap &colormap, double coord, bool xCoord)
110 int colorMapCellIndex(const QCPColorMap &colormap, double coord, bool xCoord)
110 {
111 {
111 // Determines the axis of the colormap according to xCoord, and whether it is logarithmic or not
112 // Determines the axis of the colormap according to xCoord, and whether it is logarithmic or not
112 auto isLogarithmic = (xCoord ? colormap.keyAxis() : colormap.valueAxis())->scaleType()
113 auto isLogarithmic = (xCoord ? colormap.keyAxis() : colormap.valueAxis())->scaleType()
113 == QCPAxis::stLogarithmic;
114 == QCPAxis::stLogarithmic;
114
115
115 if (isLogarithmic) {
116 if (isLogarithmic) {
116 // For a logarithmic axis we can't use the conversion method of colormap, so we calculate
117 // For a logarithmic axis we can't use the conversion method of colormap, so we calculate
117 // the index manually based on the position of the coordinate on the axis
118 // the index manually based on the position of the coordinate on the axis
118
119
119 // Gets the axis range and the number of values between range bounds to calculate the step
120 // Gets the axis range and the number of values between range bounds to calculate the step
120 // between each value of the range
121 // between each value of the range
121 auto range = xCoord ? colormap.data()->keyRange() : colormap.data()->valueRange();
122 auto range = xCoord ? colormap.data()->keyRange() : colormap.data()->valueRange();
122 auto nbValues = (xCoord ? colormap.data()->keySize() : colormap.data()->valueSize()) - 1;
123 auto nbValues = (xCoord ? colormap.data()->keySize() : colormap.data()->valueSize()) - 1;
123 auto valueStep
124 auto valueStep
124 = (std::log10(range.upper) - std::log10(range.lower)) / static_cast<double>(nbValues);
125 = (std::log10(range.upper) - std::log10(range.lower)) / static_cast<double>(nbValues);
125
126
126 // According to the coord position, calculates the closest index in the range
127 // According to the coord position, calculates the closest index in the range
127 return std::round((std::log10(coord) - std::log10(range.lower)) / valueStep);
128 return std::round((std::log10(coord) - std::log10(range.lower)) / valueStep);
128 }
129 }
129 else {
130 else {
130 // For a linear axis, we use the conversion method of colormap
131 // For a linear axis, we use the conversion method of colormap
131 int index;
132 int index;
132 if (xCoord) {
133 if (xCoord) {
133 colormap.data()->coordToCell(coord, 0., &index, nullptr);
134 colormap.data()->coordToCell(coord, 0., &index, nullptr);
134 }
135 }
135 else {
136 else {
136 colormap.data()->coordToCell(0., coord, nullptr, &index);
137 colormap.data()->coordToCell(0., coord, nullptr, &index);
137 }
138 }
138
139
139 return index;
140 return index;
140 }
141 }
141 }
142 }
142
143
143 } // namespace
144 } // namespace
144
145
145 struct VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegatePrivate {
146 struct VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegatePrivate {
146 explicit VisualizationGraphRenderingDelegatePrivate(VisualizationGraphWidget &graphWidget)
147 explicit VisualizationGraphRenderingDelegatePrivate(VisualizationGraphWidget &graphWidget)
147 : m_Plot{graphWidget.plot()},
148 : m_Plot{graphWidget.plot()},
148 m_PointTracer{new QCPItemTracer{&m_Plot}},
149 m_PointTracer{new QCPItemTracer{&m_Plot}},
149 m_TracerTimer{},
150 m_TracerTimer{},
150 m_ClosePixmap{new QCPItemPixmap{&m_Plot}},
151 m_ClosePixmap{new QCPItemPixmap{&m_Plot}},
151 m_TitleText{new QCPItemText{&m_Plot}},
152 m_TitleText{new QCPItemText{&m_Plot}},
152 m_XAxisPixmap{new QCPItemPixmap{&m_Plot}},
153 m_XAxisPixmap{new QCPItemPixmap{&m_Plot}},
153 m_ShowXAxis{true},
154 m_ShowXAxis{true},
154 m_XAxisLabel{},
155 m_XAxisLabel{},
155 m_ColorScale{SqpColorScale{m_Plot}}
156 m_ColorScale{SqpColorScale{m_Plot}}
156 {
157 {
157 initPointTracerStyle(*m_PointTracer);
158 initPointTracerStyle(*m_PointTracer);
158
159
159 m_TracerTimer.setInterval(TOOLTIP_TIMEOUT);
160 m_TracerTimer.setInterval(TOOLTIP_TIMEOUT);
160 m_TracerTimer.setSingleShot(true);
161 m_TracerTimer.setSingleShot(true);
161
162
162 // Inits "close button" in plot overlay
163 // Inits "close button" in plot overlay
163 m_ClosePixmap->setLayer(OVERLAY_LAYER);
164 m_ClosePixmap->setLayer(OVERLAY_LAYER);
164 initClosePixmapStyle(*m_ClosePixmap);
165 initClosePixmapStyle(*m_ClosePixmap);
165
166
166 // Connects pixmap selection to graph widget closing
167 // Connects pixmap selection to graph widget closing
167 QObject::connect(&m_Plot, &QCustomPlot::itemClick,
168 QObject::connect(&m_Plot, &QCustomPlot::itemClick,
168 [&graphWidget, this](auto item, auto mouseEvent) {
169 [&graphWidget, this](auto item, auto mouseEvent) {
169 if (item == m_ClosePixmap) {
170 if (item == m_ClosePixmap) {
170 graphWidget.close();
171 graphWidget.close();
171 }
172 }
172 });
173 });
173
174
174 // Inits graph name in plot overlay
175 // Inits graph name in plot overlay
175 m_TitleText->setLayer(OVERLAY_LAYER);
176 m_TitleText->setLayer(OVERLAY_LAYER);
176 m_TitleText->setText(graphWidget.name());
177 m_TitleText->setText(graphWidget.name());
177 initTitleTextStyle(*m_TitleText);
178 initTitleTextStyle(*m_TitleText);
178
179
179 // Inits "show x-axis button" in plot overlay
180 // Inits "show x-axis button" in plot overlay
180 m_XAxisPixmap->setLayer(OVERLAY_LAYER);
181 m_XAxisPixmap->setLayer(OVERLAY_LAYER);
181 initXAxisPixmapStyle(*m_XAxisPixmap);
182 initXAxisPixmapStyle(*m_XAxisPixmap);
182
183
183 // Connects pixmap selection to graph x-axis showing/hiding
184 // Connects pixmap selection to graph x-axis showing/hiding
184 QObject::connect(&m_Plot, &QCustomPlot::itemClick, [this](auto item, auto mouseEvent) {
185 QObject::connect(&m_Plot, &QCustomPlot::itemClick, [this](auto item, auto mouseEvent) {
185 if (m_XAxisPixmap == item) {
186 if (m_XAxisPixmap == item) {
186 // Changes the selection state and refreshes the x-axis
187 // Changes the selection state and refreshes the x-axis
187 m_ShowXAxis = !m_ShowXAxis;
188 m_ShowXAxis = !m_ShowXAxis;
188 this->updateXAxisState();
189 this->updateXAxisState();
189 m_Plot.layer(AXES_LAYER)->replot();
190 m_Plot.layer(AXES_LAYER)->replot();
190
191
191 // Deselects the x-axis pixmap and updates icon
192 // Deselects the x-axis pixmap and updates icon
192 m_XAxisPixmap->setPixmap(
193 m_XAxisPixmap->setPixmap(
193 pixmap(m_ShowXAxis ? HIDE_AXIS_ICON_PATH : SHOW_AXIS_ICON_PATH));
194 pixmap(m_ShowXAxis ? HIDE_AXIS_ICON_PATH : SHOW_AXIS_ICON_PATH));
194 m_Plot.layer(OVERLAY_LAYER)->replot();
195 m_Plot.layer(OVERLAY_LAYER)->replot();
195 }
196 }
196 });
197 });
197 }
198 }
198
199
199 /// Updates state of x-axis according to the current selection of x-axis pixmap
200 /// Updates state of x-axis according to the current selection of x-axis pixmap
200 /// @remarks the method doesn't call plot refresh
201 /// @remarks the method doesn't call plot refresh
201 void updateXAxisState() noexcept
202 void updateXAxisState() noexcept
202 {
203 {
203 m_Plot.xAxis->setTickLabels(m_ShowXAxis);
204 m_Plot.xAxis->setTickLabels(m_ShowXAxis);
204 m_Plot.xAxis->setLabel(m_ShowXAxis ? m_XAxisLabel : QString{});
205 m_Plot.xAxis->setLabel(m_ShowXAxis ? m_XAxisLabel : QString{});
205 }
206 }
206
207
207 QCustomPlot &m_Plot;
208 QCustomPlot &m_Plot;
208 QCPItemTracer *m_PointTracer;
209 QCPItemTracer *m_PointTracer;
209 QTimer m_TracerTimer;
210 QTimer m_TracerTimer;
210 QCPItemPixmap *m_ClosePixmap; /// Graph's close button
211 QCPItemPixmap *m_ClosePixmap; /// Graph's close button
211 QCPItemText *m_TitleText; /// Graph's title
212 QCPItemText *m_TitleText; /// Graph's title
212 QCPItemPixmap *m_XAxisPixmap;
213 QCPItemPixmap *m_XAxisPixmap;
213 bool m_ShowXAxis; /// X-axis properties are shown or hidden
214 bool m_ShowXAxis; /// X-axis properties are shown or hidden
214 QString m_XAxisLabel;
215 QString m_XAxisLabel;
215 SqpColorScale m_ColorScale; /// Color scale used for some types of graphs (as spectrograms)
216 SqpColorScale m_ColorScale; /// Color scale used for some types of graphs (as spectrograms)
216 };
217 };
217
218
218 VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegate(
219 VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegate(
219 VisualizationGraphWidget &graphWidget)
220 VisualizationGraphWidget &graphWidget)
220 : impl{spimpl::make_unique_impl<VisualizationGraphRenderingDelegatePrivate>(graphWidget)}
221 : impl{spimpl::make_unique_impl<VisualizationGraphRenderingDelegatePrivate>(graphWidget)}
221 {
222 {
222 }
223 }
223
224
224 void VisualizationGraphRenderingDelegate::onMouseDoubleClick(QMouseEvent *event) noexcept
225 void VisualizationGraphRenderingDelegate::onMouseDoubleClick(QMouseEvent *event) noexcept
225 {
226 {
226 // Opens color scale editor if color scale is double clicked
227 // Opens color scale editor if color scale is double clicked
227 auto colorScale = static_cast<QCPColorScale *>(impl->m_Plot.layoutElementAt(event->pos()));
228 auto colorScale = static_cast<QCPColorScale *>(impl->m_Plot.layoutElementAt(event->pos()));
228 if (impl->m_ColorScale.m_Scale == colorScale) {
229 if (impl->m_ColorScale.m_Scale == colorScale) {
229 if (ColorScaleEditor{impl->m_ColorScale}.exec() == QDialog::Accepted) {
230 if (ColorScaleEditor{impl->m_ColorScale}.exec() == QDialog::Accepted) {
230 impl->m_Plot.replot();
231 impl->m_Plot.replot();
231 }
232 }
232 }
233 }
233 }
234 }
234
235
235 void VisualizationGraphRenderingDelegate::onMouseMove(QMouseEvent *event) noexcept
236 void VisualizationGraphRenderingDelegate::onMouseMove(QMouseEvent *event) noexcept
236 {
237 {
237 // Cancels pending refresh
238 // Cancels pending refresh
238 impl->m_TracerTimer.disconnect();
239 impl->m_TracerTimer.disconnect();
239
240
240 // Reinits tracers
241 // Reinits tracers
241 impl->m_PointTracer->setGraph(nullptr);
242 impl->m_PointTracer->setGraph(nullptr);
242 impl->m_PointTracer->setVisible(false);
243 impl->m_PointTracer->setVisible(false);
243 impl->m_Plot.replot();
244 impl->m_Plot.replot();
244
245
245 QString tooltip{};
246 QString tooltip{};
246
247
247 // Gets the graph under the mouse position
248 // Gets the graph under the mouse position
248 auto eventPos = event->pos();
249 auto eventPos = event->pos();
249 if (auto graph = qobject_cast<QCPGraph *>(impl->m_Plot.plottableAt(eventPos))) {
250 if (auto graph = qobject_cast<QCPGraph *>(impl->m_Plot.plottableAt(eventPos))) {
250 auto mouseKey = graph->keyAxis()->pixelToCoord(eventPos.x());
251 auto mouseKey = graph->keyAxis()->pixelToCoord(eventPos.x());
251 auto graphData = graph->data();
252 auto graphData = graph->data();
252
253
253 // Gets the closest data point to the mouse
254 // Gets the closest data point to the mouse
254 auto graphDataIt = graphData->findBegin(mouseKey);
255 auto graphDataIt = graphData->findBegin(mouseKey);
255 if (graphDataIt != graphData->constEnd()) {
256 if (graphDataIt != graphData->constEnd()) {
256 // Sets tooltip
257 // Sets tooltip
257 auto key = formatValue(graphDataIt->key, *graph->keyAxis());
258 auto key = formatValue(graphDataIt->key, *graph->keyAxis());
258 auto value = formatValue(graphDataIt->value, *graph->valueAxis());
259 auto value = formatValue(graphDataIt->value, *graph->valueAxis());
259 tooltip = GRAPH_TOOLTIP_FORMAT.arg(key, value);
260 tooltip = GRAPH_TOOLTIP_FORMAT.arg(key, value);
260
261
261 // Displays point tracer
262 // Displays point tracer
262 impl->m_PointTracer->setGraph(graph);
263 impl->m_PointTracer->setGraph(graph);
263 impl->m_PointTracer->setGraphKey(graphDataIt->key);
264 impl->m_PointTracer->setGraphKey(graphDataIt->key);
264 impl->m_PointTracer->setLayer(
265 impl->m_PointTracer->setLayer(
265 impl->m_Plot.layer("main")); // Tracer is set on top of the plot's main layer
266 impl->m_Plot.layer("main")); // Tracer is set on top of the plot's main layer
266 impl->m_PointTracer->setVisible(true);
267 impl->m_PointTracer->setVisible(true);
267 impl->m_Plot.replot();
268 impl->m_Plot.replot();
268 }
269 }
269 }
270 }
270 else if (auto colorMap = qobject_cast<QCPColorMap *>(impl->m_Plot.plottableAt(eventPos))) {
271 else if (auto colorMap = qobject_cast<QCPColorMap *>(impl->m_Plot.plottableAt(eventPos))) {
271 // Gets x and y coords
272 // Gets x and y coords
272 auto x = colorMap->keyAxis()->pixelToCoord(eventPos.x());
273 auto x = colorMap->keyAxis()->pixelToCoord(eventPos.x());
273 auto y = colorMap->valueAxis()->pixelToCoord(eventPos.y());
274 auto y = colorMap->valueAxis()->pixelToCoord(eventPos.y());
274
275
275 // Calculates x and y cell indexes, and retrieves the underlying value
276 // Calculates x and y cell indexes, and retrieves the underlying value
276 auto xCellIndex = colorMapCellIndex(*colorMap, x, true);
277 auto xCellIndex = colorMapCellIndex(*colorMap, x, true);
277 auto yCellIndex = colorMapCellIndex(*colorMap, y, false);
278 auto yCellIndex = colorMapCellIndex(*colorMap, y, false);
278 auto value = colorMap->data()->cell(xCellIndex, yCellIndex);
279 auto value = colorMap->data()->cell(xCellIndex, yCellIndex);
279
280
280 // Sets tooltips
281 // Sets tooltips
281 tooltip = COLORMAP_TOOLTIP_FORMAT.arg(formatValue(x, *colorMap->keyAxis()),
282 tooltip = COLORMAP_TOOLTIP_FORMAT.arg(formatValue(x, *colorMap->keyAxis()),
282 formatValue(y, *colorMap->valueAxis()),
283 formatValue(y, *colorMap->valueAxis()),
283 formatValue(value, *colorMap->colorScale()->axis()));
284 formatValue(value, *colorMap->colorScale()->axis()));
284 }
285 }
285
286
286 if (!tooltip.isEmpty()) {
287 if (!tooltip.isEmpty()) {
287 // Starts timer to show tooltip after timeout
288 // Starts timer to show tooltip after timeout
288 auto showTooltip = [tooltip, eventPos, this]() {
289 auto showTooltip = [tooltip, eventPos, this]() {
289 QToolTip::showText(impl->m_Plot.mapToGlobal(eventPos) + TOOLTIP_OFFSET, tooltip,
290 QToolTip::showText(impl->m_Plot.mapToGlobal(eventPos) + TOOLTIP_OFFSET, tooltip,
290 &impl->m_Plot, TOOLTIP_RECT);
291 &impl->m_Plot, TOOLTIP_RECT);
291 };
292 };
292
293
293 QObject::connect(&impl->m_TracerTimer, &QTimer::timeout, showTooltip);
294 QObject::connect(&impl->m_TracerTimer, &QTimer::timeout, showTooltip);
294 impl->m_TracerTimer.start();
295 impl->m_TracerTimer.start();
295 }
296 }
296 }
297 }
297
298
298 void VisualizationGraphRenderingDelegate::onPlotUpdated() noexcept
299 void VisualizationGraphRenderingDelegate::onPlotUpdated() noexcept
299 {
300 {
300 // Updates color scale bounds
301 // Updates color scale bounds
301 impl->m_ColorScale.updateDataRange();
302 impl->m_ColorScale.updateDataRange();
302 impl->m_Plot.replot();
303 impl->m_Plot.replot();
303 }
304 }
304
305
305 void VisualizationGraphRenderingDelegate::setAxesProperties(
306 void VisualizationGraphRenderingDelegate::setAxesUnits(const Variable &variable) noexcept
306 std::shared_ptr<IDataSeries> dataSeries) noexcept
307 {
307 {
308 // Stores x-axis label to be able to retrieve it when x-axis pixmap is unselected
309 impl->m_XAxisLabel = dataSeries->xAxisUnit().m_Name;
310
308
311 auto axisHelper = IAxisHelperFactory::create(dataSeries);
309 auto axisHelper = IAxisHelperFactory::create(variable);
312 axisHelper->setProperties(impl->m_Plot, impl->m_ColorScale);
310 axisHelper->setUnits(impl->m_Plot, impl->m_ColorScale);
311
312 // Stores x-axis label to be able to retrieve it when x-axis pixmap is unselected
313 impl->m_XAxisLabel = impl->m_Plot.xAxis->label();
313
314
314 // Updates x-axis state
315 // Updates x-axis state
315 impl->updateXAxisState();
316 impl->updateXAxisState();
316
317
317 impl->m_Plot.layer(AXES_LAYER)->replot();
318 impl->m_Plot.layer(AXES_LAYER)->replot();
318 }
319 }
319
320
320 void VisualizationGraphRenderingDelegate::setPlottablesProperties(
321 void VisualizationGraphRenderingDelegate::setGraphProperties(const Variable &variable,
321 std::shared_ptr<IDataSeries> dataSeries, PlottablesMap &plottables) noexcept
322 PlottablesMap &plottables) noexcept
322 {
323 {
323 auto plottablesHelper = IPlottablesHelperFactory::create(dataSeries);
324 // Axes' properties
325 auto axisHelper = IAxisHelperFactory::create(variable);
326 axisHelper->setProperties(impl->m_Plot, impl->m_ColorScale);
327
328 // Plottables' properties
329 auto plottablesHelper = IPlottablesHelperFactory::create(variable);
324 plottablesHelper->setProperties(plottables);
330 plottablesHelper->setProperties(plottables);
325 }
331 }
326
332
327 void VisualizationGraphRenderingDelegate::showGraphOverlay(bool show) noexcept
333 void VisualizationGraphRenderingDelegate::showGraphOverlay(bool show) noexcept
328 {
334 {
329 auto overlay = impl->m_Plot.layer(OVERLAY_LAYER);
335 auto overlay = impl->m_Plot.layer(OVERLAY_LAYER);
330 overlay->setVisible(show);
336 overlay->setVisible(show);
331 overlay->replot();
337 overlay->replot();
332 }
338 }
@@ -1,1004 +1,1055
1 #include "Visualization/VisualizationGraphWidget.h"
1 #include "Visualization/VisualizationGraphWidget.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 #include "Visualization/VisualizationCursorItem.h"
3 #include "Visualization/VisualizationCursorItem.h"
4 #include "Visualization/VisualizationDefs.h"
4 #include "Visualization/VisualizationDefs.h"
5 #include "Visualization/VisualizationGraphHelper.h"
5 #include "Visualization/VisualizationGraphHelper.h"
6 #include "Visualization/VisualizationGraphRenderingDelegate.h"
6 #include "Visualization/VisualizationGraphRenderingDelegate.h"
7 #include "Visualization/VisualizationMultiZoneSelectionDialog.h"
7 #include "Visualization/VisualizationMultiZoneSelectionDialog.h"
8 #include "Visualization/VisualizationSelectionZoneItem.h"
8 #include "Visualization/VisualizationSelectionZoneItem.h"
9 #include "Visualization/VisualizationSelectionZoneManager.h"
9 #include "Visualization/VisualizationSelectionZoneManager.h"
10 #include "Visualization/VisualizationWidget.h"
10 #include "Visualization/VisualizationWidget.h"
11 #include "Visualization/VisualizationZoneWidget.h"
11 #include "Visualization/VisualizationZoneWidget.h"
12 #include "ui_VisualizationGraphWidget.h"
12 #include "ui_VisualizationGraphWidget.h"
13
13
14 #include <Actions/ActionsGuiController.h>
14 #include <Actions/ActionsGuiController.h>
15 #include <Common/MimeTypesDef.h>
15 #include <Common/MimeTypesDef.h>
16 #include <Data/ArrayData.h>
16 #include <Data/ArrayData.h>
17 #include <Data/IDataSeries.h>
17 #include <Data/IDataSeries.h>
18 #include <Data/SpectrogramSeries.h>
18 #include <Data/SpectrogramSeries.h>
19 #include <DragAndDrop/DragDropGuiController.h>
19 #include <DragAndDrop/DragDropGuiController.h>
20 #include <Settings/SqpSettingsDefs.h>
20 #include <Settings/SqpSettingsDefs.h>
21 #include <SqpApplication.h>
21 #include <SqpApplication.h>
22 #include <Time/TimeController.h>
22 #include <Time/TimeController.h>
23 #include <Variable/Variable.h>
23 #include <Variable/Variable.h>
24 #include <Variable/VariableController.h>
24 #include <Variable/VariableController.h>
25
25
26 #include <unordered_map>
26 #include <unordered_map>
27
27
28 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
28 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
29
29
30 namespace {
30 namespace {
31
31
32 /// Key pressed to enable drag&drop in all modes
32 /// Key pressed to enable drag&drop in all modes
33 const auto DRAG_DROP_MODIFIER = Qt::AltModifier;
33 const auto DRAG_DROP_MODIFIER = Qt::AltModifier;
34
34
35 /// Key pressed to enable zoom on horizontal axis
35 /// Key pressed to enable zoom on horizontal axis
36 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::ControlModifier;
36 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::ControlModifier;
37
37
38 /// Key pressed to enable zoom on vertical axis
38 /// Key pressed to enable zoom on vertical axis
39 const auto VERTICAL_ZOOM_MODIFIER = Qt::ShiftModifier;
39 const auto VERTICAL_ZOOM_MODIFIER = Qt::ShiftModifier;
40
40
41 /// Speed of a step of a wheel event for a pan, in percentage of the axis range
41 /// Speed of a step of a wheel event for a pan, in percentage of the axis range
42 const auto PAN_SPEED = 5;
42 const auto PAN_SPEED = 5;
43
43
44 /// Key pressed to enable a calibration pan
44 /// Key pressed to enable a calibration pan
45 const auto VERTICAL_PAN_MODIFIER = Qt::AltModifier;
45 const auto VERTICAL_PAN_MODIFIER = Qt::AltModifier;
46
46
47 /// Key pressed to enable multi selection of selection zones
47 /// Key pressed to enable multi selection of selection zones
48 const auto MULTI_ZONE_SELECTION_MODIFIER = Qt::ControlModifier;
48 const auto MULTI_ZONE_SELECTION_MODIFIER = Qt::ControlModifier;
49
49
50 /// Minimum size for the zoom box, in percentage of the axis range
50 /// Minimum size for the zoom box, in percentage of the axis range
51 const auto ZOOM_BOX_MIN_SIZE = 0.8;
51 const auto ZOOM_BOX_MIN_SIZE = 0.8;
52
52
53 /// Format of the dates appearing in the label of a cursor
53 /// Format of the dates appearing in the label of a cursor
54 const auto CURSOR_LABELS_DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd\nhh:mm:ss:zzz");
54 const auto CURSOR_LABELS_DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd\nhh:mm:ss:zzz");
55
55
56 } // namespace
56 } // namespace
57
57
58 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
58 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
59
59
60 explicit VisualizationGraphWidgetPrivate(const QString &name)
60 explicit VisualizationGraphWidgetPrivate(const QString &name)
61 : m_Name{name},
61 : m_Name{name},
62 m_Flags{GraphFlag::EnableAll},
62 m_Flags{GraphFlag::EnableAll},
63 m_IsCalibration{false},
63 m_IsCalibration{false},
64 m_RenderingDelegate{nullptr}
64 m_RenderingDelegate{nullptr}
65 {
65 {
66 }
66 }
67
67
68 void updateData(PlottablesMap &plottables, std::shared_ptr<IDataSeries> dataSeries,
68 void updateData(PlottablesMap &plottables, std::shared_ptr<Variable> variable,
69 const SqpRange &range)
69 const SqpRange &range)
70 {
70 {
71 VisualizationGraphHelper::updateData(plottables, dataSeries, range);
71 VisualizationGraphHelper::updateData(plottables, variable, range);
72
72
73 // Prevents that data has changed to update rendering
73 // Prevents that data has changed to update rendering
74 m_RenderingDelegate->onPlotUpdated();
74 m_RenderingDelegate->onPlotUpdated();
75 }
75 }
76
76
77 QString m_Name;
77 QString m_Name;
78 // 1 variable -> n qcpplot
78 // 1 variable -> n qcpplot
79 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
79 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
80 GraphFlags m_Flags;
80 GraphFlags m_Flags;
81 bool m_IsCalibration;
81 bool m_IsCalibration;
82 /// Delegate used to attach rendering features to the plot
82 /// Delegate used to attach rendering features to the plot
83 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
83 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
84
84
85 QCPItemRect *m_DrawingZoomRect = nullptr;
85 QCPItemRect *m_DrawingZoomRect = nullptr;
86 QStack<QPair<QCPRange, QCPRange> > m_ZoomStack;
86 QStack<QPair<QCPRange, QCPRange> > m_ZoomStack;
87
87
88 std::unique_ptr<VisualizationCursorItem> m_HorizontalCursor = nullptr;
88 std::unique_ptr<VisualizationCursorItem> m_HorizontalCursor = nullptr;
89 std::unique_ptr<VisualizationCursorItem> m_VerticalCursor = nullptr;
89 std::unique_ptr<VisualizationCursorItem> m_VerticalCursor = nullptr;
90
90
91 VisualizationSelectionZoneItem *m_DrawingZone = nullptr;
91 VisualizationSelectionZoneItem *m_DrawingZone = nullptr;
92 VisualizationSelectionZoneItem *m_HoveredZone = nullptr;
92 VisualizationSelectionZoneItem *m_HoveredZone = nullptr;
93 QVector<VisualizationSelectionZoneItem *> m_SelectionZones;
93 QVector<VisualizationSelectionZoneItem *> m_SelectionZones;
94
94
95 bool m_HasMovedMouse = false; // Indicates if the mouse moved in a releaseMouse even
95 bool m_HasMovedMouse = false; // Indicates if the mouse moved in a releaseMouse even
96
96
97 bool m_VariableAutoRangeOnInit = true;
98
97 void startDrawingRect(const QPoint &pos, QCustomPlot &plot)
99 void startDrawingRect(const QPoint &pos, QCustomPlot &plot)
98 {
100 {
99 removeDrawingRect(plot);
101 removeDrawingRect(plot);
100
102
101 auto axisPos = posToAxisPos(pos, plot);
103 auto axisPos = posToAxisPos(pos, plot);
102
104
103 m_DrawingZoomRect = new QCPItemRect{&plot};
105 m_DrawingZoomRect = new QCPItemRect{&plot};
104 QPen p;
106 QPen p;
105 p.setWidth(2);
107 p.setWidth(2);
106 m_DrawingZoomRect->setPen(p);
108 m_DrawingZoomRect->setPen(p);
107
109
108 m_DrawingZoomRect->topLeft->setCoords(axisPos);
110 m_DrawingZoomRect->topLeft->setCoords(axisPos);
109 m_DrawingZoomRect->bottomRight->setCoords(axisPos);
111 m_DrawingZoomRect->bottomRight->setCoords(axisPos);
110 }
112 }
111
113
112 void removeDrawingRect(QCustomPlot &plot)
114 void removeDrawingRect(QCustomPlot &plot)
113 {
115 {
114 if (m_DrawingZoomRect) {
116 if (m_DrawingZoomRect) {
115 plot.removeItem(m_DrawingZoomRect); // the item is deleted by QCustomPlot
117 plot.removeItem(m_DrawingZoomRect); // the item is deleted by QCustomPlot
116 m_DrawingZoomRect = nullptr;
118 m_DrawingZoomRect = nullptr;
117 plot.replot(QCustomPlot::rpQueuedReplot);
119 plot.replot(QCustomPlot::rpQueuedReplot);
118 }
120 }
119 }
121 }
120
122
121 void startDrawingZone(const QPoint &pos, VisualizationGraphWidget *graph)
123 void startDrawingZone(const QPoint &pos, VisualizationGraphWidget *graph)
122 {
124 {
123 endDrawingZone(graph);
125 endDrawingZone(graph);
124
126
125 auto axisPos = posToAxisPos(pos, graph->plot());
127 auto axisPos = posToAxisPos(pos, graph->plot());
126
128
127 m_DrawingZone = new VisualizationSelectionZoneItem{&graph->plot()};
129 m_DrawingZone = new VisualizationSelectionZoneItem{&graph->plot()};
128 m_DrawingZone->setRange(axisPos.x(), axisPos.x());
130 m_DrawingZone->setRange(axisPos.x(), axisPos.x());
129 m_DrawingZone->setEditionEnabled(false);
131 m_DrawingZone->setEditionEnabled(false);
130 }
132 }
131
133
132 void endDrawingZone(VisualizationGraphWidget *graph)
134 void endDrawingZone(VisualizationGraphWidget *graph)
133 {
135 {
134 if (m_DrawingZone) {
136 if (m_DrawingZone) {
135 auto drawingZoneRange = m_DrawingZone->range();
137 auto drawingZoneRange = m_DrawingZone->range();
136 if (qAbs(drawingZoneRange.m_TEnd - drawingZoneRange.m_TStart) > 0) {
138 if (qAbs(drawingZoneRange.m_TEnd - drawingZoneRange.m_TStart) > 0) {
137 m_DrawingZone->setEditionEnabled(true);
139 m_DrawingZone->setEditionEnabled(true);
138 addSelectionZone(m_DrawingZone);
140 addSelectionZone(m_DrawingZone);
139 }
141 }
140 else {
142 else {
141 graph->plot().removeItem(m_DrawingZone); // the item is deleted by QCustomPlot
143 graph->plot().removeItem(m_DrawingZone); // the item is deleted by QCustomPlot
142 }
144 }
143
145
144 graph->plot().replot(QCustomPlot::rpQueuedReplot);
146 graph->plot().replot(QCustomPlot::rpQueuedReplot);
145 m_DrawingZone = nullptr;
147 m_DrawingZone = nullptr;
146 }
148 }
147 }
149 }
148
150
149 void setSelectionZonesEditionEnabled(bool value)
151 void setSelectionZonesEditionEnabled(bool value)
150 {
152 {
151 for (auto s : m_SelectionZones) {
153 for (auto s : m_SelectionZones) {
152 s->setEditionEnabled(value);
154 s->setEditionEnabled(value);
153 }
155 }
154 }
156 }
155
157
156 void addSelectionZone(VisualizationSelectionZoneItem *zone) { m_SelectionZones << zone; }
158 void addSelectionZone(VisualizationSelectionZoneItem *zone) { m_SelectionZones << zone; }
157
159
158 VisualizationSelectionZoneItem *selectionZoneAt(const QPoint &pos,
160 VisualizationSelectionZoneItem *selectionZoneAt(const QPoint &pos,
159 const QCustomPlot &plot) const
161 const QCustomPlot &plot) const
160 {
162 {
161 VisualizationSelectionZoneItem *selectionZoneItemUnderCursor = nullptr;
163 VisualizationSelectionZoneItem *selectionZoneItemUnderCursor = nullptr;
162 auto minDistanceToZone = -1;
164 auto minDistanceToZone = -1;
163 for (auto zone : m_SelectionZones) {
165 for (auto zone : m_SelectionZones) {
164 auto distanceToZone = zone->selectTest(pos, false);
166 auto distanceToZone = zone->selectTest(pos, false);
165 if ((minDistanceToZone < 0 || distanceToZone <= minDistanceToZone)
167 if ((minDistanceToZone < 0 || distanceToZone <= minDistanceToZone)
166 && distanceToZone >= 0 && distanceToZone < plot.selectionTolerance()) {
168 && distanceToZone >= 0 && distanceToZone < plot.selectionTolerance()) {
167 selectionZoneItemUnderCursor = zone;
169 selectionZoneItemUnderCursor = zone;
168 }
170 }
169 }
171 }
170
172
171 return selectionZoneItemUnderCursor;
173 return selectionZoneItemUnderCursor;
172 }
174 }
173
175
174 QVector<VisualizationSelectionZoneItem *> selectionZonesAt(const QPoint &pos,
176 QVector<VisualizationSelectionZoneItem *> selectionZonesAt(const QPoint &pos,
175 const QCustomPlot &plot) const
177 const QCustomPlot &plot) const
176 {
178 {
177 QVector<VisualizationSelectionZoneItem *> zones;
179 QVector<VisualizationSelectionZoneItem *> zones;
178 for (auto zone : m_SelectionZones) {
180 for (auto zone : m_SelectionZones) {
179 auto distanceToZone = zone->selectTest(pos, false);
181 auto distanceToZone = zone->selectTest(pos, false);
180 if (distanceToZone >= 0 && distanceToZone < plot.selectionTolerance()) {
182 if (distanceToZone >= 0 && distanceToZone < plot.selectionTolerance()) {
181 zones << zone;
183 zones << zone;
182 }
184 }
183 }
185 }
184
186
185 return zones;
187 return zones;
186 }
188 }
187
189
188 void moveSelectionZoneOnTop(VisualizationSelectionZoneItem *zone, QCustomPlot &plot)
190 void moveSelectionZoneOnTop(VisualizationSelectionZoneItem *zone, QCustomPlot &plot)
189 {
191 {
190 if (!m_SelectionZones.isEmpty() && m_SelectionZones.last() != zone) {
192 if (!m_SelectionZones.isEmpty() && m_SelectionZones.last() != zone) {
191 zone->moveToTop();
193 zone->moveToTop();
192 m_SelectionZones.removeAll(zone);
194 m_SelectionZones.removeAll(zone);
193 m_SelectionZones.append(zone);
195 m_SelectionZones.append(zone);
194 }
196 }
195 }
197 }
196
198
197 QPointF posToAxisPos(const QPoint &pos, QCustomPlot &plot) const
199 QPointF posToAxisPos(const QPoint &pos, QCustomPlot &plot) const
198 {
200 {
199 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
201 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
200 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
202 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
201 return QPointF{axisX->pixelToCoord(pos.x()), axisY->pixelToCoord(pos.y())};
203 return QPointF{axisX->pixelToCoord(pos.x()), axisY->pixelToCoord(pos.y())};
202 }
204 }
203
205
204 bool pointIsInAxisRect(const QPointF &axisPoint, QCustomPlot &plot) const
206 bool pointIsInAxisRect(const QPointF &axisPoint, QCustomPlot &plot) const
205 {
207 {
206 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
208 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
207 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
209 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
208 return axisX->range().contains(axisPoint.x()) && axisY->range().contains(axisPoint.y());
210 return axisX->range().contains(axisPoint.x()) && axisY->range().contains(axisPoint.y());
209 }
211 }
210 };
212 };
211
213
212 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
214 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
213 : VisualizationDragWidget{parent},
215 : VisualizationDragWidget{parent},
214 ui{new Ui::VisualizationGraphWidget},
216 ui{new Ui::VisualizationGraphWidget},
215 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
217 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
216 {
218 {
217 ui->setupUi(this);
219 ui->setupUi(this);
218
220
219 // 'Close' options : widget is deleted when closed
221 // 'Close' options : widget is deleted when closed
220 setAttribute(Qt::WA_DeleteOnClose);
222 setAttribute(Qt::WA_DeleteOnClose);
221
223
222 // Set qcpplot properties :
224 // Set qcpplot properties :
223 // - zoom is enabled
225 // - zoom is enabled
224 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
226 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
225 ui->widget->setInteractions(QCP::iRangeZoom);
227 ui->widget->setInteractions(QCP::iRangeZoom);
226 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal | Qt::Vertical);
228 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal | Qt::Vertical);
227
229
228 // The delegate must be initialized after the ui as it uses the plot
230 // The delegate must be initialized after the ui as it uses the plot
229 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
231 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
230
232
231 // Init the cursors
233 // Init the cursors
232 impl->m_HorizontalCursor = std::make_unique<VisualizationCursorItem>(&plot());
234 impl->m_HorizontalCursor = std::make_unique<VisualizationCursorItem>(&plot());
233 impl->m_HorizontalCursor->setOrientation(Qt::Horizontal);
235 impl->m_HorizontalCursor->setOrientation(Qt::Horizontal);
234 impl->m_VerticalCursor = std::make_unique<VisualizationCursorItem>(&plot());
236 impl->m_VerticalCursor = std::make_unique<VisualizationCursorItem>(&plot());
235 impl->m_VerticalCursor->setOrientation(Qt::Vertical);
237 impl->m_VerticalCursor->setOrientation(Qt::Vertical);
236
238
237 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
239 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
238 connect(ui->widget, &QCustomPlot::mouseRelease, this,
240 connect(ui->widget, &QCustomPlot::mouseRelease, this,
239 &VisualizationGraphWidget::onMouseRelease);
241 &VisualizationGraphWidget::onMouseRelease);
240 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
242 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
241 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
243 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
242 connect(ui->widget, &QCustomPlot::mouseDoubleClick, this,
244 connect(ui->widget, &QCustomPlot::mouseDoubleClick, this,
243 &VisualizationGraphWidget::onMouseDoubleClick);
245 &VisualizationGraphWidget::onMouseDoubleClick);
244 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
246 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
245 &QCPAxis::rangeChanged),
247 &QCPAxis::rangeChanged),
246 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
248 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
247
249
248 // Activates menu when right clicking on the graph
250 // Activates menu when right clicking on the graph
249 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
251 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
250 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
252 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
251 &VisualizationGraphWidget::onGraphMenuRequested);
253 &VisualizationGraphWidget::onGraphMenuRequested);
252
254
253 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
255 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
254 &VariableController::onRequestDataLoading);
256 &VariableController::onRequestDataLoading);
255
257
256 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
258 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
257 &VisualizationGraphWidget::onUpdateVarDisplaying);
259 &VisualizationGraphWidget::onUpdateVarDisplaying);
258
260
259 #ifdef Q_OS_MAC
261 #ifdef Q_OS_MAC
260 plot().setPlottingHint(QCP::phFastPolylines, true);
262 plot().setPlottingHint(QCP::phFastPolylines, true);
261 #endif
263 #endif
262 }
264 }
263
265
264
266
265 VisualizationGraphWidget::~VisualizationGraphWidget()
267 VisualizationGraphWidget::~VisualizationGraphWidget()
266 {
268 {
267 delete ui;
269 delete ui;
268 }
270 }
269
271
270 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
272 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
271 {
273 {
272 auto parent = parentWidget();
274 auto parent = parentWidget();
273 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
275 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
274 parent = parent->parentWidget();
276 parent = parent->parentWidget();
275 }
277 }
276
278
277 return qobject_cast<VisualizationZoneWidget *>(parent);
279 return qobject_cast<VisualizationZoneWidget *>(parent);
278 }
280 }
279
281
280 VisualizationWidget *VisualizationGraphWidget::parentVisualizationWidget() const
282 VisualizationWidget *VisualizationGraphWidget::parentVisualizationWidget() const
281 {
283 {
282 auto parent = parentWidget();
284 auto parent = parentWidget();
283 while (parent != nullptr && !qobject_cast<VisualizationWidget *>(parent)) {
285 while (parent != nullptr && !qobject_cast<VisualizationWidget *>(parent)) {
284 parent = parent->parentWidget();
286 parent = parent->parentWidget();
285 }
287 }
286
288
287 return qobject_cast<VisualizationWidget *>(parent);
289 return qobject_cast<VisualizationWidget *>(parent);
288 }
290 }
289
291
290 void VisualizationGraphWidget::setFlags(GraphFlags flags)
292 void VisualizationGraphWidget::setFlags(GraphFlags flags)
291 {
293 {
292 impl->m_Flags = std::move(flags);
294 impl->m_Flags = std::move(flags);
293 }
295 }
294
296
295 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
297 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
296 {
298 {
297 // Uses delegate to create the qcpplot components according to the variable
299 /// Lambda used to set graph's units and range according to the variable passed in parameter
298 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
300 auto loadRange = [this](std::shared_ptr<Variable> variable, const SqpRange &range) {
299
301 impl->m_RenderingDelegate->setAxesUnits(*variable);
300 if (auto dataSeries = variable->dataSeries()) {
301 // Set axes properties according to the units of the data series
302 impl->m_RenderingDelegate->setAxesProperties(dataSeries);
303
302
304 // Sets rendering properties for the new plottables
303 this->setFlags(GraphFlag::DisableAll);
305 // Warning: this method must be called after setAxesProperties(), as it can access to some
304 setGraphRange(range);
306 // axes properties that have to be initialized
305 this->setFlags(GraphFlag::EnableAll);
307 impl->m_RenderingDelegate->setPlottablesProperties(dataSeries, createdPlottables);
308 }
309
306
310 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
307 emit requestDataLoading({variable}, range, false);
308 };
311
309
312 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
310 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
313
311
314 this->setFlags(GraphFlag::DisableAll);
312 // Calls update of graph's range and units when the data of the variable have been initialized.
315 this->setGraphRange(range);
313 // Note: we use QueuedConnection here as the update event must be called in the UI thread
316 this->setFlags(GraphFlag::EnableAll);
314 connect(variable.get(), &Variable::dataInitialized, this,
315 [ varW = std::weak_ptr<Variable>{variable}, range, loadRange, this ]() {
316 if (auto var = varW.lock()) {
317 // If the variable is the first added in the graph, we load its range
318 auto firstVariableInGraph = range == INVALID_RANGE;
319 auto loadedRange = graphRange();
320 if (impl->m_VariableAutoRangeOnInit) {
321 loadedRange = firstVariableInGraph ? var->range() : range;
322 }
323 loadRange(var, loadedRange);
324 setYRange(var);
325 }
326 },
327 Qt::QueuedConnection);
328
329 // Uses delegate to create the qcpplot components according to the variable
330 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
331
332 // Sets graph properties
333 impl->m_RenderingDelegate->setGraphProperties(*variable, createdPlottables);
334
335 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
317
336
318 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable, range, false);
337 // If the variable already has its data loaded, load its units and its range in the graph
338 if (variable->dataSeries() != nullptr) {
339 loadRange(variable, range);
340 }
319
341
320 emit variableAdded(variable);
342 emit variableAdded(variable);
321 }
343 }
322
344
323 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
345 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
324 {
346 {
325 // Each component associated to the variable :
347 // Each component associated to the variable :
326 // - is removed from qcpplot (which deletes it)
348 // - is removed from qcpplot (which deletes it)
327 // - is no longer referenced in the map
349 // - is no longer referenced in the map
328 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
350 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
329 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
351 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
330 emit variableAboutToBeRemoved(variable);
352 emit variableAboutToBeRemoved(variable);
331
353
332 auto &plottablesMap = variableIt->second;
354 auto &plottablesMap = variableIt->second;
333
355
334 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
356 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
335 plottableIt != plottableEnd;) {
357 plottableIt != plottableEnd;) {
336 ui->widget->removePlottable(plottableIt->second);
358 ui->widget->removePlottable(plottableIt->second);
337 plottableIt = plottablesMap.erase(plottableIt);
359 plottableIt = plottablesMap.erase(plottableIt);
338 }
360 }
339
361
340 impl->m_VariableToPlotMultiMap.erase(variableIt);
362 impl->m_VariableToPlotMultiMap.erase(variableIt);
341 }
363 }
342
364
343 // Updates graph
365 // Updates graph
344 ui->widget->replot();
366 ui->widget->replot();
345 }
367 }
346
368
347 QList<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
369 QList<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
348 {
370 {
349 auto variables = QList<std::shared_ptr<Variable> >{};
371 auto variables = QList<std::shared_ptr<Variable> >{};
350 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
372 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
351 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
373 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
352 variables << it->first;
374 variables << it->first;
353 }
375 }
354
376
355 return variables;
377 return variables;
356 }
378 }
357
379
358 void VisualizationGraphWidget::setYRange(std::shared_ptr<Variable> variable)
380 void VisualizationGraphWidget::setYRange(std::shared_ptr<Variable> variable)
359 {
381 {
360 if (!variable) {
382 if (!variable) {
361 qCCritical(LOG_VisualizationGraphWidget()) << "Can't set y-axis range: variable is null";
383 qCCritical(LOG_VisualizationGraphWidget()) << "Can't set y-axis range: variable is null";
362 return;
384 return;
363 }
385 }
364
386
365 VisualizationGraphHelper::setYAxisRange(variable, *ui->widget);
387 VisualizationGraphHelper::setYAxisRange(variable, *ui->widget);
366 }
388 }
367
389
368 SqpRange VisualizationGraphWidget::graphRange() const noexcept
390 SqpRange VisualizationGraphWidget::graphRange() const noexcept
369 {
391 {
370 auto graphRange = ui->widget->xAxis->range();
392 auto graphRange = ui->widget->xAxis->range();
371 return SqpRange{graphRange.lower, graphRange.upper};
393 return SqpRange{graphRange.lower, graphRange.upper};
372 }
394 }
373
395
374 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
396 void VisualizationGraphWidget::setGraphRange(const SqpRange &range, bool calibration)
375 {
397 {
376 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
398 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
399
400 if (calibration) {
401 impl->m_IsCalibration = true;
402 }
403
377 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
404 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
378 ui->widget->replot();
405 ui->widget->replot();
406
407 if (calibration) {
408 impl->m_IsCalibration = false;
409 }
410
379 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
411 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
380 }
412 }
381
413
414 void VisualizationGraphWidget::setAutoRangeOnVariableInitialization(bool value)
415 {
416 impl->m_VariableAutoRangeOnInit = value;
417 }
418
382 QVector<SqpRange> VisualizationGraphWidget::selectionZoneRanges() const
419 QVector<SqpRange> VisualizationGraphWidget::selectionZoneRanges() const
383 {
420 {
384 QVector<SqpRange> ranges;
421 QVector<SqpRange> ranges;
385 for (auto zone : impl->m_SelectionZones) {
422 for (auto zone : impl->m_SelectionZones) {
386 ranges << zone->range();
423 ranges << zone->range();
387 }
424 }
388
425
389 return ranges;
426 return ranges;
390 }
427 }
391
428
392 void VisualizationGraphWidget::addSelectionZones(const QVector<SqpRange> &ranges)
429 void VisualizationGraphWidget::addSelectionZones(const QVector<SqpRange> &ranges)
393 {
430 {
394 for (const auto &range : ranges) {
431 for (const auto &range : ranges) {
395 // note: ownership is transfered to QCustomPlot
432 // note: ownership is transfered to QCustomPlot
396 auto zone = new VisualizationSelectionZoneItem(&plot());
433 auto zone = new VisualizationSelectionZoneItem(&plot());
397 zone->setRange(range.m_TStart, range.m_TEnd);
434 zone->setRange(range.m_TStart, range.m_TEnd);
398 impl->addSelectionZone(zone);
435 impl->addSelectionZone(zone);
399 }
436 }
400
437
401 plot().replot(QCustomPlot::rpQueuedReplot);
438 plot().replot(QCustomPlot::rpQueuedReplot);
402 }
439 }
403
440
441 VisualizationSelectionZoneItem *VisualizationGraphWidget::addSelectionZone(const QString &name,
442 const SqpRange &range)
443 {
444 // note: ownership is transfered to QCustomPlot
445 auto zone = new VisualizationSelectionZoneItem(&plot());
446 zone->setName(name);
447 zone->setRange(range.m_TStart, range.m_TEnd);
448 impl->addSelectionZone(zone);
449
450 plot().replot(QCustomPlot::rpQueuedReplot);
451
452 return zone;
453 }
454
404 void VisualizationGraphWidget::removeSelectionZone(VisualizationSelectionZoneItem *selectionZone)
455 void VisualizationGraphWidget::removeSelectionZone(VisualizationSelectionZoneItem *selectionZone)
405 {
456 {
406 parentVisualizationWidget()->selectionZoneManager().setSelected(selectionZone, false);
457 parentVisualizationWidget()->selectionZoneManager().setSelected(selectionZone, false);
407
458
408 if (impl->m_HoveredZone == selectionZone) {
459 if (impl->m_HoveredZone == selectionZone) {
409 impl->m_HoveredZone = nullptr;
460 impl->m_HoveredZone = nullptr;
410 setCursor(Qt::ArrowCursor);
461 setCursor(Qt::ArrowCursor);
411 }
462 }
412
463
413 impl->m_SelectionZones.removeAll(selectionZone);
464 impl->m_SelectionZones.removeAll(selectionZone);
414 plot().removeItem(selectionZone);
465 plot().removeItem(selectionZone);
415 plot().replot(QCustomPlot::rpQueuedReplot);
466 plot().replot(QCustomPlot::rpQueuedReplot);
416 }
467 }
417
468
418 void VisualizationGraphWidget::undoZoom()
469 void VisualizationGraphWidget::undoZoom()
419 {
470 {
420 auto zoom = impl->m_ZoomStack.pop();
471 auto zoom = impl->m_ZoomStack.pop();
421 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
472 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
422 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
473 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
423
474
424 axisX->setRange(zoom.first);
475 axisX->setRange(zoom.first);
425 axisY->setRange(zoom.second);
476 axisY->setRange(zoom.second);
426
477
427 plot().replot(QCustomPlot::rpQueuedReplot);
478 plot().replot(QCustomPlot::rpQueuedReplot);
428 }
479 }
429
480
430 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
481 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
431 {
482 {
432 if (visitor) {
483 if (visitor) {
433 visitor->visit(this);
484 visitor->visit(this);
434 }
485 }
435 else {
486 else {
436 qCCritical(LOG_VisualizationGraphWidget())
487 qCCritical(LOG_VisualizationGraphWidget())
437 << tr("Can't visit widget : the visitor is null");
488 << tr("Can't visit widget : the visitor is null");
438 }
489 }
439 }
490 }
440
491
441 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
492 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
442 {
493 {
443 auto isSpectrogram = [](const auto &variable) {
494 auto isSpectrogram = [](const auto &variable) {
444 return std::dynamic_pointer_cast<SpectrogramSeries>(variable.dataSeries()) != nullptr;
495 return std::dynamic_pointer_cast<SpectrogramSeries>(variable.dataSeries()) != nullptr;
445 };
496 };
446
497
447 // - A spectrogram series can't be dropped on graph with existing plottables
498 // - A spectrogram series can't be dropped on graph with existing plottables
448 // - No data series can be dropped on graph with existing spectrogram series
499 // - No data series can be dropped on graph with existing spectrogram series
449 return isSpectrogram(variable)
500 return isSpectrogram(variable)
450 ? impl->m_VariableToPlotMultiMap.empty()
501 ? impl->m_VariableToPlotMultiMap.empty()
451 : std::none_of(
502 : std::none_of(
452 impl->m_VariableToPlotMultiMap.cbegin(), impl->m_VariableToPlotMultiMap.cend(),
503 impl->m_VariableToPlotMultiMap.cbegin(), impl->m_VariableToPlotMultiMap.cend(),
453 [isSpectrogram](const auto &entry) { return isSpectrogram(*entry.first); });
504 [isSpectrogram](const auto &entry) { return isSpectrogram(*entry.first); });
454 }
505 }
455
506
456 bool VisualizationGraphWidget::contains(const Variable &variable) const
507 bool VisualizationGraphWidget::contains(const Variable &variable) const
457 {
508 {
458 // Finds the variable among the keys of the map
509 // Finds the variable among the keys of the map
459 auto variablePtr = &variable;
510 auto variablePtr = &variable;
460 auto findVariable
511 auto findVariable
461 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
512 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
462
513
463 auto end = impl->m_VariableToPlotMultiMap.cend();
514 auto end = impl->m_VariableToPlotMultiMap.cend();
464 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
515 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
465 return it != end;
516 return it != end;
466 }
517 }
467
518
468 QString VisualizationGraphWidget::name() const
519 QString VisualizationGraphWidget::name() const
469 {
520 {
470 return impl->m_Name;
521 return impl->m_Name;
471 }
522 }
472
523
473 QMimeData *VisualizationGraphWidget::mimeData(const QPoint &position) const
524 QMimeData *VisualizationGraphWidget::mimeData(const QPoint &position) const
474 {
525 {
475 auto mimeData = new QMimeData;
526 auto mimeData = new QMimeData;
476
527
477 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(position, plot());
528 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(position, plot());
478 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
529 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
479 && selectionZoneItemUnderCursor) {
530 && selectionZoneItemUnderCursor) {
480 mimeData->setData(MIME_TYPE_TIME_RANGE, TimeController::mimeDataForTimeRange(
531 mimeData->setData(MIME_TYPE_TIME_RANGE, TimeController::mimeDataForTimeRange(
481 selectionZoneItemUnderCursor->range()));
532 selectionZoneItemUnderCursor->range()));
482 mimeData->setData(MIME_TYPE_SELECTION_ZONE, TimeController::mimeDataForTimeRange(
533 mimeData->setData(MIME_TYPE_SELECTION_ZONE, TimeController::mimeDataForTimeRange(
483 selectionZoneItemUnderCursor->range()));
534 selectionZoneItemUnderCursor->range()));
484 }
535 }
485 else {
536 else {
486 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
537 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
487
538
488 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
539 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
489 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
540 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
490 }
541 }
491
542
492 return mimeData;
543 return mimeData;
493 }
544 }
494
545
495 QPixmap VisualizationGraphWidget::customDragPixmap(const QPoint &dragPosition)
546 QPixmap VisualizationGraphWidget::customDragPixmap(const QPoint &dragPosition)
496 {
547 {
497 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(dragPosition, plot());
548 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(dragPosition, plot());
498 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
549 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
499 && selectionZoneItemUnderCursor) {
550 && selectionZoneItemUnderCursor) {
500
551
501 auto zoneTopLeft = selectionZoneItemUnderCursor->topLeft->pixelPosition();
552 auto zoneTopLeft = selectionZoneItemUnderCursor->topLeft->pixelPosition();
502 auto zoneBottomRight = selectionZoneItemUnderCursor->bottomRight->pixelPosition();
553 auto zoneBottomRight = selectionZoneItemUnderCursor->bottomRight->pixelPosition();
503
554
504 auto zoneSize = QSizeF{qAbs(zoneBottomRight.x() - zoneTopLeft.x()),
555 auto zoneSize = QSizeF{qAbs(zoneBottomRight.x() - zoneTopLeft.x()),
505 qAbs(zoneBottomRight.y() - zoneTopLeft.y())}
556 qAbs(zoneBottomRight.y() - zoneTopLeft.y())}
506 .toSize();
557 .toSize();
507
558
508 auto pixmap = QPixmap(zoneSize);
559 auto pixmap = QPixmap(zoneSize);
509 render(&pixmap, QPoint(), QRegion{QRect{zoneTopLeft.toPoint(), zoneSize}});
560 render(&pixmap, QPoint(), QRegion{QRect{zoneTopLeft.toPoint(), zoneSize}});
510
561
511 return pixmap;
562 return pixmap;
512 }
563 }
513
564
514 return QPixmap();
565 return QPixmap();
515 }
566 }
516
567
517 bool VisualizationGraphWidget::isDragAllowed() const
568 bool VisualizationGraphWidget::isDragAllowed() const
518 {
569 {
519 return true;
570 return true;
520 }
571 }
521
572
522 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
573 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
523 {
574 {
524 if (highlighted) {
575 if (highlighted) {
525 plot().setBackground(QBrush(QColor("#BBD5EE")));
576 plot().setBackground(QBrush(QColor("#BBD5EE")));
526 }
577 }
527 else {
578 else {
528 plot().setBackground(QBrush(Qt::white));
579 plot().setBackground(QBrush(Qt::white));
529 }
580 }
530
581
531 plot().update();
582 plot().update();
532 }
583 }
533
584
534 void VisualizationGraphWidget::addVerticalCursor(double time)
585 void VisualizationGraphWidget::addVerticalCursor(double time)
535 {
586 {
536 impl->m_VerticalCursor->setPosition(time);
587 impl->m_VerticalCursor->setPosition(time);
537 impl->m_VerticalCursor->setVisible(true);
588 impl->m_VerticalCursor->setVisible(true);
538
589
539 auto text
590 auto text
540 = DateUtils::dateTime(time).toString(CURSOR_LABELS_DATETIME_FORMAT).replace(' ', '\n');
591 = DateUtils::dateTime(time).toString(CURSOR_LABELS_DATETIME_FORMAT).replace(' ', '\n');
541 impl->m_VerticalCursor->setLabelText(text);
592 impl->m_VerticalCursor->setLabelText(text);
542 }
593 }
543
594
544 void VisualizationGraphWidget::addVerticalCursorAtViewportPosition(double position)
595 void VisualizationGraphWidget::addVerticalCursorAtViewportPosition(double position)
545 {
596 {
546 impl->m_VerticalCursor->setAbsolutePosition(position);
597 impl->m_VerticalCursor->setAbsolutePosition(position);
547 impl->m_VerticalCursor->setVisible(true);
598 impl->m_VerticalCursor->setVisible(true);
548
599
549 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
600 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
550 auto text
601 auto text
551 = DateUtils::dateTime(axis->pixelToCoord(position)).toString(CURSOR_LABELS_DATETIME_FORMAT);
602 = DateUtils::dateTime(axis->pixelToCoord(position)).toString(CURSOR_LABELS_DATETIME_FORMAT);
552 impl->m_VerticalCursor->setLabelText(text);
603 impl->m_VerticalCursor->setLabelText(text);
553 }
604 }
554
605
555 void VisualizationGraphWidget::removeVerticalCursor()
606 void VisualizationGraphWidget::removeVerticalCursor()
556 {
607 {
557 impl->m_VerticalCursor->setVisible(false);
608 impl->m_VerticalCursor->setVisible(false);
558 plot().replot(QCustomPlot::rpQueuedReplot);
609 plot().replot(QCustomPlot::rpQueuedReplot);
559 }
610 }
560
611
561 void VisualizationGraphWidget::addHorizontalCursor(double value)
612 void VisualizationGraphWidget::addHorizontalCursor(double value)
562 {
613 {
563 impl->m_HorizontalCursor->setPosition(value);
614 impl->m_HorizontalCursor->setPosition(value);
564 impl->m_HorizontalCursor->setVisible(true);
615 impl->m_HorizontalCursor->setVisible(true);
565 impl->m_HorizontalCursor->setLabelText(QString::number(value));
616 impl->m_HorizontalCursor->setLabelText(QString::number(value));
566 }
617 }
567
618
568 void VisualizationGraphWidget::addHorizontalCursorAtViewportPosition(double position)
619 void VisualizationGraphWidget::addHorizontalCursorAtViewportPosition(double position)
569 {
620 {
570 impl->m_HorizontalCursor->setAbsolutePosition(position);
621 impl->m_HorizontalCursor->setAbsolutePosition(position);
571 impl->m_HorizontalCursor->setVisible(true);
622 impl->m_HorizontalCursor->setVisible(true);
572
623
573 auto axis = plot().axisRect()->axis(QCPAxis::atLeft);
624 auto axis = plot().axisRect()->axis(QCPAxis::atLeft);
574 impl->m_HorizontalCursor->setLabelText(QString::number(axis->pixelToCoord(position)));
625 impl->m_HorizontalCursor->setLabelText(QString::number(axis->pixelToCoord(position)));
575 }
626 }
576
627
577 void VisualizationGraphWidget::removeHorizontalCursor()
628 void VisualizationGraphWidget::removeHorizontalCursor()
578 {
629 {
579 impl->m_HorizontalCursor->setVisible(false);
630 impl->m_HorizontalCursor->setVisible(false);
580 plot().replot(QCustomPlot::rpQueuedReplot);
631 plot().replot(QCustomPlot::rpQueuedReplot);
581 }
632 }
582
633
583 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
634 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
584 {
635 {
585 Q_UNUSED(event);
636 Q_UNUSED(event);
586
637
587 // Prevents that all variables will be removed from graph when it will be closed
638 // Prevents that all variables will be removed from graph when it will be closed
588 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
639 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
589 emit variableAboutToBeRemoved(variableEntry.first);
640 emit variableAboutToBeRemoved(variableEntry.first);
590 }
641 }
591 }
642 }
592
643
593 void VisualizationGraphWidget::enterEvent(QEvent *event)
644 void VisualizationGraphWidget::enterEvent(QEvent *event)
594 {
645 {
595 Q_UNUSED(event);
646 Q_UNUSED(event);
596 impl->m_RenderingDelegate->showGraphOverlay(true);
647 impl->m_RenderingDelegate->showGraphOverlay(true);
597 }
648 }
598
649
599 void VisualizationGraphWidget::leaveEvent(QEvent *event)
650 void VisualizationGraphWidget::leaveEvent(QEvent *event)
600 {
651 {
601 Q_UNUSED(event);
652 Q_UNUSED(event);
602 impl->m_RenderingDelegate->showGraphOverlay(false);
653 impl->m_RenderingDelegate->showGraphOverlay(false);
603
654
604 if (auto parentZone = parentZoneWidget()) {
655 if (auto parentZone = parentZoneWidget()) {
605 parentZone->notifyMouseLeaveGraph(this);
656 parentZone->notifyMouseLeaveGraph(this);
606 }
657 }
607 else {
658 else {
608 qCWarning(LOG_VisualizationGraphWidget()) << "leaveEvent: No parent zone widget";
659 qCWarning(LOG_VisualizationGraphWidget()) << "leaveEvent: No parent zone widget";
609 }
660 }
610
661
611 if (impl->m_HoveredZone) {
662 if (impl->m_HoveredZone) {
612 impl->m_HoveredZone->setHovered(false);
663 impl->m_HoveredZone->setHovered(false);
613 impl->m_HoveredZone = nullptr;
664 impl->m_HoveredZone = nullptr;
614 }
665 }
615 }
666 }
616
667
617 QCustomPlot &VisualizationGraphWidget::plot() const noexcept
668 QCustomPlot &VisualizationGraphWidget::plot() const noexcept
618 {
669 {
619 return *ui->widget;
670 return *ui->widget;
620 }
671 }
621
672
622 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
673 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
623 {
674 {
624 QMenu graphMenu{};
675 QMenu graphMenu{};
625
676
626 // Iterates on variables (unique keys)
677 // Iterates on variables (unique keys)
627 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
678 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
628 end = impl->m_VariableToPlotMultiMap.cend();
679 end = impl->m_VariableToPlotMultiMap.cend();
629 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
680 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
630 // 'Remove variable' action
681 // 'Remove variable' action
631 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
682 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
632 [ this, var = it->first ]() { removeVariable(var); });
683 [ this, var = it->first ]() { removeVariable(var); });
633 }
684 }
634
685
635 if (!impl->m_ZoomStack.isEmpty()) {
686 if (!impl->m_ZoomStack.isEmpty()) {
636 if (!graphMenu.isEmpty()) {
687 if (!graphMenu.isEmpty()) {
637 graphMenu.addSeparator();
688 graphMenu.addSeparator();
638 }
689 }
639
690
640 graphMenu.addAction(tr("Undo Zoom"), [this]() { undoZoom(); });
691 graphMenu.addAction(tr("Undo Zoom"), [this]() { undoZoom(); });
641 }
692 }
642
693
643 // Selection Zone Actions
694 // Selection Zone Actions
644 auto selectionZoneItem = impl->selectionZoneAt(pos, plot());
695 auto selectionZoneItem = impl->selectionZoneAt(pos, plot());
645 if (selectionZoneItem) {
696 if (selectionZoneItem) {
646 auto selectedItems = parentVisualizationWidget()->selectionZoneManager().selectedItems();
697 auto selectedItems = parentVisualizationWidget()->selectionZoneManager().selectedItems();
647 selectedItems.removeAll(selectionZoneItem);
698 selectedItems.removeAll(selectionZoneItem);
648 selectedItems.prepend(selectionZoneItem); // Put the current selection zone first
699 selectedItems.prepend(selectionZoneItem); // Put the current selection zone first
649
700
650 auto zoneActions = sqpApp->actionsGuiController().selectionZoneActions();
701 auto zoneActions = sqpApp->actionsGuiController().selectionZoneActions();
651 if (!zoneActions.isEmpty() && !graphMenu.isEmpty()) {
702 if (!zoneActions.isEmpty() && !graphMenu.isEmpty()) {
652 graphMenu.addSeparator();
703 graphMenu.addSeparator();
653 }
704 }
654
705
655 QHash<QString, QMenu *> subMenus;
706 QHash<QString, QMenu *> subMenus;
656 QHash<QString, bool> subMenusEnabled;
707 QHash<QString, bool> subMenusEnabled;
657
708
658 for (auto zoneAction : zoneActions) {
709 for (auto zoneAction : zoneActions) {
659
710
660 auto isEnabled = zoneAction->isEnabled(selectedItems);
711 auto isEnabled = zoneAction->isEnabled(selectedItems);
661
712
662 auto menu = &graphMenu;
713 auto menu = &graphMenu;
663 for (auto subMenuName : zoneAction->subMenuList()) {
714 for (auto subMenuName : zoneAction->subMenuList()) {
664 if (!subMenus.contains(subMenuName)) {
715 if (!subMenus.contains(subMenuName)) {
665 menu = menu->addMenu(subMenuName);
716 menu = menu->addMenu(subMenuName);
666 subMenus[subMenuName] = menu;
717 subMenus[subMenuName] = menu;
667 subMenusEnabled[subMenuName] = isEnabled;
718 subMenusEnabled[subMenuName] = isEnabled;
668 }
719 }
669 else {
720 else {
670 menu = subMenus.value(subMenuName);
721 menu = subMenus.value(subMenuName);
671 if (isEnabled) {
722 if (isEnabled) {
672 // The sub menu is enabled if at least one of its actions is enabled
723 // The sub menu is enabled if at least one of its actions is enabled
673 subMenusEnabled[subMenuName] = true;
724 subMenusEnabled[subMenuName] = true;
674 }
725 }
675 }
726 }
676 }
727 }
677
728
678 auto action = menu->addAction(zoneAction->name());
729 auto action = menu->addAction(zoneAction->name());
679 action->setEnabled(isEnabled);
730 action->setEnabled(isEnabled);
680 action->setShortcut(zoneAction->displayedShortcut());
731 action->setShortcut(zoneAction->displayedShortcut());
681 QObject::connect(action, &QAction::triggered,
732 QObject::connect(action, &QAction::triggered,
682 [zoneAction, selectedItems]() { zoneAction->execute(selectedItems); });
733 [zoneAction, selectedItems]() { zoneAction->execute(selectedItems); });
683 }
734 }
684
735
685 for (auto it = subMenus.cbegin(); it != subMenus.cend(); ++it) {
736 for (auto it = subMenus.cbegin(); it != subMenus.cend(); ++it) {
686 it.value()->setEnabled(subMenusEnabled[it.key()]);
737 it.value()->setEnabled(subMenusEnabled[it.key()]);
687 }
738 }
688 }
739 }
689
740
690 if (!graphMenu.isEmpty()) {
741 if (!graphMenu.isEmpty()) {
691 graphMenu.exec(QCursor::pos());
742 graphMenu.exec(QCursor::pos());
692 }
743 }
693 }
744 }
694
745
695 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
746 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
696 {
747 {
697 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
748 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
698 << QThread::currentThread()->objectName() << "DoAcqui"
749 << QThread::currentThread()->objectName() << "DoAcqui"
699 << impl->m_Flags.testFlag(GraphFlag::EnableAcquisition);
750 << impl->m_Flags.testFlag(GraphFlag::EnableAcquisition);
700
751
701 auto graphRange = SqpRange{t1.lower, t1.upper};
752 auto graphRange = SqpRange{t1.lower, t1.upper};
702 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
753 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
703
754
704 if (impl->m_Flags.testFlag(GraphFlag::EnableAcquisition)) {
755 if (impl->m_Flags.testFlag(GraphFlag::EnableAcquisition)) {
705 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
756 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
706
757
707 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
758 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
708 end = impl->m_VariableToPlotMultiMap.end();
759 end = impl->m_VariableToPlotMultiMap.end();
709 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
760 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
710 variableUnderGraphVector.push_back(it->first);
761 variableUnderGraphVector.push_back(it->first);
711 }
762 }
712 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
763 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
713 !impl->m_IsCalibration);
764 !impl->m_IsCalibration);
714 }
765 }
715
766
716 if (impl->m_Flags.testFlag(GraphFlag::EnableSynchronization) && !impl->m_IsCalibration) {
767 if (impl->m_Flags.testFlag(GraphFlag::EnableSynchronization) && !impl->m_IsCalibration) {
717 qCDebug(LOG_VisualizationGraphWidget())
768 qCDebug(LOG_VisualizationGraphWidget())
718 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
769 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
719 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
770 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
720 emit synchronize(graphRange, oldGraphRange);
771 emit synchronize(graphRange, oldGraphRange);
721 }
772 }
722
773
723 auto pos = mapFromGlobal(QCursor::pos());
774 auto pos = mapFromGlobal(QCursor::pos());
724 auto axisPos = impl->posToAxisPos(pos, plot());
775 auto axisPos = impl->posToAxisPos(pos, plot());
725 if (auto parentZone = parentZoneWidget()) {
776 if (auto parentZone = parentZoneWidget()) {
726 if (impl->pointIsInAxisRect(axisPos, plot())) {
777 if (impl->pointIsInAxisRect(axisPos, plot())) {
727 parentZone->notifyMouseMoveInGraph(pos, axisPos, this);
778 parentZone->notifyMouseMoveInGraph(pos, axisPos, this);
728 }
779 }
729 else {
780 else {
730 parentZone->notifyMouseLeaveGraph(this);
781 parentZone->notifyMouseLeaveGraph(this);
731 }
782 }
732 }
783 }
733 else {
784 else {
734 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
785 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
735 }
786 }
736
787
737 // Quits calibration
788 // Quits calibration
738 impl->m_IsCalibration = false;
789 impl->m_IsCalibration = false;
739 }
790 }
740
791
741 void VisualizationGraphWidget::onMouseDoubleClick(QMouseEvent *event) noexcept
792 void VisualizationGraphWidget::onMouseDoubleClick(QMouseEvent *event) noexcept
742 {
793 {
743 impl->m_RenderingDelegate->onMouseDoubleClick(event);
794 impl->m_RenderingDelegate->onMouseDoubleClick(event);
744 }
795 }
745
796
746 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
797 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
747 {
798 {
748 // Handles plot rendering when mouse is moving
799 // Handles plot rendering when mouse is moving
749 impl->m_RenderingDelegate->onMouseMove(event);
800 impl->m_RenderingDelegate->onMouseMove(event);
750
801
751 auto axisPos = impl->posToAxisPos(event->pos(), plot());
802 auto axisPos = impl->posToAxisPos(event->pos(), plot());
752
803
753 // Zoom box and zone drawing
804 // Zoom box and zone drawing
754 if (impl->m_DrawingZoomRect) {
805 if (impl->m_DrawingZoomRect) {
755 impl->m_DrawingZoomRect->bottomRight->setCoords(axisPos);
806 impl->m_DrawingZoomRect->bottomRight->setCoords(axisPos);
756 }
807 }
757 else if (impl->m_DrawingZone) {
808 else if (impl->m_DrawingZone) {
758 impl->m_DrawingZone->setEnd(axisPos.x());
809 impl->m_DrawingZone->setEnd(axisPos.x());
759 }
810 }
760
811
761 // Cursor
812 // Cursor
762 if (auto parentZone = parentZoneWidget()) {
813 if (auto parentZone = parentZoneWidget()) {
763 if (impl->pointIsInAxisRect(axisPos, plot())) {
814 if (impl->pointIsInAxisRect(axisPos, plot())) {
764 parentZone->notifyMouseMoveInGraph(event->pos(), axisPos, this);
815 parentZone->notifyMouseMoveInGraph(event->pos(), axisPos, this);
765 }
816 }
766 else {
817 else {
767 parentZone->notifyMouseLeaveGraph(this);
818 parentZone->notifyMouseLeaveGraph(this);
768 }
819 }
769 }
820 }
770 else {
821 else {
771 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
822 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
772 }
823 }
773
824
774 // Search for the selection zone under the mouse
825 // Search for the selection zone under the mouse
775 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
826 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
776 if (selectionZoneItemUnderCursor && !impl->m_DrawingZone
827 if (selectionZoneItemUnderCursor && !impl->m_DrawingZone
777 && sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones) {
828 && sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones) {
778
829
779 // Sets the appropriate cursor shape
830 // Sets the appropriate cursor shape
780 auto cursorShape = selectionZoneItemUnderCursor->curshorShapeForPosition(event->pos());
831 auto cursorShape = selectionZoneItemUnderCursor->curshorShapeForPosition(event->pos());
781 setCursor(cursorShape);
832 setCursor(cursorShape);
782
833
783 // Manages the hovered zone
834 // Manages the hovered zone
784 if (selectionZoneItemUnderCursor != impl->m_HoveredZone) {
835 if (selectionZoneItemUnderCursor != impl->m_HoveredZone) {
785 if (impl->m_HoveredZone) {
836 if (impl->m_HoveredZone) {
786 impl->m_HoveredZone->setHovered(false);
837 impl->m_HoveredZone->setHovered(false);
787 }
838 }
788 selectionZoneItemUnderCursor->setHovered(true);
839 selectionZoneItemUnderCursor->setHovered(true);
789 impl->m_HoveredZone = selectionZoneItemUnderCursor;
840 impl->m_HoveredZone = selectionZoneItemUnderCursor;
790 plot().replot(QCustomPlot::rpQueuedReplot);
841 plot().replot(QCustomPlot::rpQueuedReplot);
791 }
842 }
792 }
843 }
793 else {
844 else {
794 // There is no zone under the mouse or the interaction mode is not "selection zones"
845 // There is no zone under the mouse or the interaction mode is not "selection zones"
795 if (impl->m_HoveredZone) {
846 if (impl->m_HoveredZone) {
796 impl->m_HoveredZone->setHovered(false);
847 impl->m_HoveredZone->setHovered(false);
797 impl->m_HoveredZone = nullptr;
848 impl->m_HoveredZone = nullptr;
798 }
849 }
799
850
800 setCursor(Qt::ArrowCursor);
851 setCursor(Qt::ArrowCursor);
801 }
852 }
802
853
803 impl->m_HasMovedMouse = true;
854 impl->m_HasMovedMouse = true;
804 VisualizationDragWidget::mouseMoveEvent(event);
855 VisualizationDragWidget::mouseMoveEvent(event);
805 }
856 }
806
857
807 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
858 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
808 {
859 {
809 auto value = event->angleDelta().x() + event->angleDelta().y();
860 auto value = event->angleDelta().x() + event->angleDelta().y();
810 if (value != 0) {
861 if (value != 0) {
811
862
812 auto direction = value > 0 ? 1.0 : -1.0;
863 auto direction = value > 0 ? 1.0 : -1.0;
813 auto isZoomX = event->modifiers().testFlag(HORIZONTAL_ZOOM_MODIFIER);
864 auto isZoomX = event->modifiers().testFlag(HORIZONTAL_ZOOM_MODIFIER);
814 auto isZoomY = event->modifiers().testFlag(VERTICAL_ZOOM_MODIFIER);
865 auto isZoomY = event->modifiers().testFlag(VERTICAL_ZOOM_MODIFIER);
815 impl->m_IsCalibration = event->modifiers().testFlag(VERTICAL_PAN_MODIFIER);
866 impl->m_IsCalibration = event->modifiers().testFlag(VERTICAL_PAN_MODIFIER);
816
867
817 auto zoomOrientations = QFlags<Qt::Orientation>{};
868 auto zoomOrientations = QFlags<Qt::Orientation>{};
818 zoomOrientations.setFlag(Qt::Horizontal, isZoomX);
869 zoomOrientations.setFlag(Qt::Horizontal, isZoomX);
819 zoomOrientations.setFlag(Qt::Vertical, isZoomY);
870 zoomOrientations.setFlag(Qt::Vertical, isZoomY);
820
871
821 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
872 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
822
873
823 if (!isZoomX && !isZoomY) {
874 if (!isZoomX && !isZoomY) {
824 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
875 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
825 auto diff = direction * (axis->range().size() * (PAN_SPEED / 100.0));
876 auto diff = direction * (axis->range().size() * (PAN_SPEED / 100.0));
826
877
827 axis->setRange(axis->range() + diff);
878 axis->setRange(axis->range() + diff);
828
879
829 if (plot().noAntialiasingOnDrag()) {
880 if (plot().noAntialiasingOnDrag()) {
830 plot().setNotAntialiasedElements(QCP::aeAll);
881 plot().setNotAntialiasedElements(QCP::aeAll);
831 }
882 }
832
883
833 plot().replot(QCustomPlot::rpQueuedReplot);
884 plot().replot(QCustomPlot::rpQueuedReplot);
834 }
885 }
835 }
886 }
836 }
887 }
837
888
838 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
889 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
839 {
890 {
840 auto isDragDropClick = event->modifiers().testFlag(DRAG_DROP_MODIFIER);
891 auto isDragDropClick = event->modifiers().testFlag(DRAG_DROP_MODIFIER);
841 auto isSelectionZoneMode
892 auto isSelectionZoneMode
842 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
893 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
843 auto isLeftClick = event->buttons().testFlag(Qt::LeftButton);
894 auto isLeftClick = event->buttons().testFlag(Qt::LeftButton);
844
895
845 if (!isDragDropClick && isLeftClick) {
896 if (!isDragDropClick && isLeftClick) {
846 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::ZoomBox) {
897 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::ZoomBox) {
847 // Starts a zoom box
898 // Starts a zoom box
848 impl->startDrawingRect(event->pos(), plot());
899 impl->startDrawingRect(event->pos(), plot());
849 }
900 }
850 else if (isSelectionZoneMode && impl->m_DrawingZone == nullptr) {
901 else if (isSelectionZoneMode && impl->m_DrawingZone == nullptr) {
851 // Starts a new selection zone
902 // Starts a new selection zone
852 auto zoneAtPos = impl->selectionZoneAt(event->pos(), plot());
903 auto zoneAtPos = impl->selectionZoneAt(event->pos(), plot());
853 if (!zoneAtPos) {
904 if (!zoneAtPos) {
854 impl->startDrawingZone(event->pos(), this);
905 impl->startDrawingZone(event->pos(), this);
855 }
906 }
856 }
907 }
857 }
908 }
858
909
859 // Allows mouse panning only in default mode
910 // Allows mouse panning only in default mode
860 plot().setInteraction(QCP::iRangeDrag, sqpApp->plotsInteractionMode()
911 plot().setInteraction(QCP::iRangeDrag, sqpApp->plotsInteractionMode()
861 == SqpApplication::PlotsInteractionMode::None
912 == SqpApplication::PlotsInteractionMode::None
862 && !isDragDropClick);
913 && !isDragDropClick);
863
914
864 // Allows zone edition only in selection zone mode without drag&drop
915 // Allows zone edition only in selection zone mode without drag&drop
865 impl->setSelectionZonesEditionEnabled(isSelectionZoneMode && !isDragDropClick);
916 impl->setSelectionZonesEditionEnabled(isSelectionZoneMode && !isDragDropClick);
866
917
867 // Selection / Deselection
918 // Selection / Deselection
868 if (isSelectionZoneMode) {
919 if (isSelectionZoneMode) {
869 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
920 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
870 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
921 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
871
922
872
923
873 if (selectionZoneItemUnderCursor && !selectionZoneItemUnderCursor->selected()
924 if (selectionZoneItemUnderCursor && !selectionZoneItemUnderCursor->selected()
874 && !isMultiSelectionClick) {
925 && !isMultiSelectionClick) {
875 parentVisualizationWidget()->selectionZoneManager().select(
926 parentVisualizationWidget()->selectionZoneManager().select(
876 {selectionZoneItemUnderCursor});
927 {selectionZoneItemUnderCursor});
877 }
928 }
878 else if (!selectionZoneItemUnderCursor && !isMultiSelectionClick && isLeftClick) {
929 else if (!selectionZoneItemUnderCursor && !isMultiSelectionClick && isLeftClick) {
879 parentVisualizationWidget()->selectionZoneManager().clearSelection();
930 parentVisualizationWidget()->selectionZoneManager().clearSelection();
880 }
931 }
881 else {
932 else {
882 // No selection change
933 // No selection change
883 }
934 }
884
935
885 if (selectionZoneItemUnderCursor && isLeftClick) {
936 if (selectionZoneItemUnderCursor && isLeftClick) {
886 selectionZoneItemUnderCursor->setAssociatedEditedZones(
937 selectionZoneItemUnderCursor->setAssociatedEditedZones(
887 parentVisualizationWidget()->selectionZoneManager().selectedItems());
938 parentVisualizationWidget()->selectionZoneManager().selectedItems());
888 }
939 }
889 }
940 }
890
941
891
942
892 impl->m_HasMovedMouse = false;
943 impl->m_HasMovedMouse = false;
893 VisualizationDragWidget::mousePressEvent(event);
944 VisualizationDragWidget::mousePressEvent(event);
894 }
945 }
895
946
896 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
947 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
897 {
948 {
898 if (impl->m_DrawingZoomRect) {
949 if (impl->m_DrawingZoomRect) {
899
950
900 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
951 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
901 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
952 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
902
953
903 auto newAxisXRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().x(),
954 auto newAxisXRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().x(),
904 impl->m_DrawingZoomRect->bottomRight->coords().x()};
955 impl->m_DrawingZoomRect->bottomRight->coords().x()};
905
956
906 auto newAxisYRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().y(),
957 auto newAxisYRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().y(),
907 impl->m_DrawingZoomRect->bottomRight->coords().y()};
958 impl->m_DrawingZoomRect->bottomRight->coords().y()};
908
959
909 impl->removeDrawingRect(plot());
960 impl->removeDrawingRect(plot());
910
961
911 if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)
962 if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)
912 && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)) {
963 && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)) {
913 impl->m_ZoomStack.push(qMakePair(axisX->range(), axisY->range()));
964 impl->m_ZoomStack.push(qMakePair(axisX->range(), axisY->range()));
914 axisX->setRange(newAxisXRange);
965 axisX->setRange(newAxisXRange);
915 axisY->setRange(newAxisYRange);
966 axisY->setRange(newAxisYRange);
916
967
917 plot().replot(QCustomPlot::rpQueuedReplot);
968 plot().replot(QCustomPlot::rpQueuedReplot);
918 }
969 }
919 }
970 }
920
971
921 impl->endDrawingZone(this);
972 impl->endDrawingZone(this);
922
973
923 // Selection / Deselection
974 // Selection / Deselection
924 auto isSelectionZoneMode
975 auto isSelectionZoneMode
925 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
976 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
926 if (isSelectionZoneMode) {
977 if (isSelectionZoneMode) {
927 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
978 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
928 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
979 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
929 if (selectionZoneItemUnderCursor && event->button() == Qt::LeftButton
980 if (selectionZoneItemUnderCursor && event->button() == Qt::LeftButton
930 && !impl->m_HasMovedMouse) {
981 && !impl->m_HasMovedMouse) {
931
982
932 auto zonesUnderCursor = impl->selectionZonesAt(event->pos(), plot());
983 auto zonesUnderCursor = impl->selectionZonesAt(event->pos(), plot());
933 if (zonesUnderCursor.count() > 1) {
984 if (zonesUnderCursor.count() > 1) {
934 // There are multiple zones under the mouse.
985 // There are multiple zones under the mouse.
935 // Performs the selection with a selection dialog.
986 // Performs the selection with a selection dialog.
936 VisualizationMultiZoneSelectionDialog dialog{this};
987 VisualizationMultiZoneSelectionDialog dialog{this};
937 dialog.setZones(zonesUnderCursor);
988 dialog.setZones(zonesUnderCursor);
938 dialog.move(mapToGlobal(event->pos() - QPoint(dialog.width() / 2, 20)));
989 dialog.move(mapToGlobal(event->pos() - QPoint(dialog.width() / 2, 20)));
939 dialog.activateWindow();
990 dialog.activateWindow();
940 dialog.raise();
991 dialog.raise();
941 if (dialog.exec() == QDialog::Accepted) {
992 if (dialog.exec() == QDialog::Accepted) {
942 auto selection = dialog.selectedZones();
993 auto selection = dialog.selectedZones();
943
994
944 if (!isMultiSelectionClick) {
995 if (!isMultiSelectionClick) {
945 parentVisualizationWidget()->selectionZoneManager().clearSelection();
996 parentVisualizationWidget()->selectionZoneManager().clearSelection();
946 }
997 }
947
998
948 for (auto it = selection.cbegin(); it != selection.cend(); ++it) {
999 for (auto it = selection.cbegin(); it != selection.cend(); ++it) {
949 auto zone = it.key();
1000 auto zone = it.key();
950 auto isSelected = it.value();
1001 auto isSelected = it.value();
951 parentVisualizationWidget()->selectionZoneManager().setSelected(zone,
1002 parentVisualizationWidget()->selectionZoneManager().setSelected(zone,
952 isSelected);
1003 isSelected);
953
1004
954 if (isSelected) {
1005 if (isSelected) {
955 // Puts the zone on top of the stack so it can be moved or resized
1006 // Puts the zone on top of the stack so it can be moved or resized
956 impl->moveSelectionZoneOnTop(zone, plot());
1007 impl->moveSelectionZoneOnTop(zone, plot());
957 }
1008 }
958 }
1009 }
959 }
1010 }
960 }
1011 }
961 else {
1012 else {
962 if (!isMultiSelectionClick) {
1013 if (!isMultiSelectionClick) {
963 parentVisualizationWidget()->selectionZoneManager().select(
1014 parentVisualizationWidget()->selectionZoneManager().select(
964 {selectionZoneItemUnderCursor});
1015 {selectionZoneItemUnderCursor});
965 impl->moveSelectionZoneOnTop(selectionZoneItemUnderCursor, plot());
1016 impl->moveSelectionZoneOnTop(selectionZoneItemUnderCursor, plot());
966 }
1017 }
967 else {
1018 else {
968 parentVisualizationWidget()->selectionZoneManager().setSelected(
1019 parentVisualizationWidget()->selectionZoneManager().setSelected(
969 selectionZoneItemUnderCursor, !selectionZoneItemUnderCursor->selected()
1020 selectionZoneItemUnderCursor, !selectionZoneItemUnderCursor->selected()
970 || event->button() == Qt::RightButton);
1021 || event->button() == Qt::RightButton);
971 }
1022 }
972 }
1023 }
973 }
1024 }
974 else {
1025 else {
975 // No selection change
1026 // No selection change
976 }
1027 }
977 }
1028 }
978 }
1029 }
979
1030
980 void VisualizationGraphWidget::onDataCacheVariableUpdated()
1031 void VisualizationGraphWidget::onDataCacheVariableUpdated()
981 {
1032 {
982 auto graphRange = ui->widget->xAxis->range();
1033 auto graphRange = ui->widget->xAxis->range();
983 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
1034 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
984
1035
985 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
1036 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
986 auto variable = variableEntry.first;
1037 auto variable = variableEntry.first;
987 qCDebug(LOG_VisualizationGraphWidget())
1038 qCDebug(LOG_VisualizationGraphWidget())
988 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
1039 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
989 qCDebug(LOG_VisualizationGraphWidget())
1040 qCDebug(LOG_VisualizationGraphWidget())
990 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
1041 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
991 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
1042 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
992 impl->updateData(variableEntry.second, variable->dataSeries(), variable->range());
1043 impl->updateData(variableEntry.second, variable, variable->range());
993 }
1044 }
994 }
1045 }
995 }
1046 }
996
1047
997 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
1048 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
998 const SqpRange &range)
1049 const SqpRange &range)
999 {
1050 {
1000 auto it = impl->m_VariableToPlotMultiMap.find(variable);
1051 auto it = impl->m_VariableToPlotMultiMap.find(variable);
1001 if (it != impl->m_VariableToPlotMultiMap.end()) {
1052 if (it != impl->m_VariableToPlotMultiMap.end()) {
1002 impl->updateData(it->second, variable->dataSeries(), range);
1053 impl->updateData(it->second, variable, range);
1003 }
1054 }
1004 }
1055 }
@@ -1,440 +1,443
1 #include "Visualization/VisualizationSelectionZoneItem.h"
1 #include "Visualization/VisualizationSelectionZoneItem.h"
2 #include "Visualization/VisualizationGraphWidget.h"
2 #include "Visualization/VisualizationGraphWidget.h"
3 #include "Visualization/VisualizationSelectionZoneManager.h"
3 #include "Visualization/VisualizationSelectionZoneManager.h"
4 #include "Visualization/VisualizationWidget.h"
4 #include "Visualization/VisualizationWidget.h"
5
5
6 const QString &DEFAULT_COLOR = QStringLiteral("#E79D41");
6 const QString &DEFAULT_COLOR = QStringLiteral("#E79D41");
7
7
8 struct VisualizationSelectionZoneItem::VisualizationSelectionZoneItemPrivate {
8 struct VisualizationSelectionZoneItem::VisualizationSelectionZoneItemPrivate {
9
9
10 QCustomPlot *m_Plot;
10 QCustomPlot *m_Plot;
11 double m_T1 = 0;
11 double m_T1 = 0;
12 double m_T2 = 0;
12 double m_T2 = 0;
13 QColor m_Color;
13 QColor m_Color;
14
14
15 bool m_IsEditionEnabled = true;
15 bool m_IsEditionEnabled = true;
16 double m_MovedOrinalT1 = 0;
16 double m_MovedOrinalT1 = 0;
17 double m_MovedOrinalT2 = 0;
17 double m_MovedOrinalT2 = 0;
18
18
19 QCPItemStraightLine *m_LeftLine;
19 QCPItemStraightLine *m_LeftLine;
20 QCPItemStraightLine *m_RightLine;
20 QCPItemStraightLine *m_RightLine;
21 QCPItemText *m_NameLabelItem = nullptr;
21 QCPItemText *m_NameLabelItem = nullptr;
22
22
23 enum class EditionMode { NoEdition, ResizeLeft, ResizeRight, Move };
23 enum class EditionMode { NoEdition, ResizeLeft, ResizeRight, Move };
24 EditionMode m_CurrentEditionMode;
24 EditionMode m_CurrentEditionMode;
25
25
26 QVector<VisualizationSelectionZoneItem *> m_AssociatedEditedZones;
26 QVector<VisualizationSelectionZoneItem *> m_AssociatedEditedZones;
27
27
28 VisualizationSelectionZoneItemPrivate(QCustomPlot *plot)
28 VisualizationSelectionZoneItemPrivate(QCustomPlot *plot)
29 : m_Plot(plot), m_Color(Qt::blue), m_CurrentEditionMode(EditionMode::NoEdition)
29 : m_Plot(plot), m_Color(Qt::blue), m_CurrentEditionMode(EditionMode::NoEdition)
30 {
30 {
31 }
31 }
32
32
33 void updatePosition(VisualizationSelectionZoneItem *item)
33 void updatePosition(VisualizationSelectionZoneItem *item)
34 {
34 {
35 item->topLeft->setCoords(m_T1, 0);
35 item->topLeft->setCoords(m_T1, 0);
36 item->bottomRight->setCoords(m_T2, 1);
36 item->bottomRight->setCoords(m_T2, 1);
37 }
37 }
38
38
39 EditionMode getEditionMode(const QPoint &pos, const VisualizationSelectionZoneItem *zoneItem)
39 EditionMode getEditionMode(const QPoint &pos, const VisualizationSelectionZoneItem *zoneItem)
40 {
40 {
41 auto distanceLeft = m_LeftLine->selectTest(pos, false);
41 auto distanceLeft = m_LeftLine->selectTest(pos, false);
42 auto distanceRight = m_RightLine->selectTest(pos, false);
42 auto distanceRight = m_RightLine->selectTest(pos, false);
43 auto distance = zoneItem->selectTest(pos, false);
43 auto distance = zoneItem->selectTest(pos, false);
44
44
45 if (distanceRight <= distance) {
45 if (distanceRight <= distance) {
46 return VisualizationSelectionZoneItemPrivate::EditionMode::ResizeRight;
46 return VisualizationSelectionZoneItemPrivate::EditionMode::ResizeRight;
47 }
47 }
48 else if (distanceLeft <= distance) {
48 else if (distanceLeft <= distance) {
49 return VisualizationSelectionZoneItemPrivate::EditionMode::ResizeLeft;
49 return VisualizationSelectionZoneItemPrivate::EditionMode::ResizeLeft;
50 }
50 }
51
51
52 return VisualizationSelectionZoneItemPrivate::EditionMode::Move;
52 return VisualizationSelectionZoneItemPrivate::EditionMode::Move;
53 }
53 }
54
54
55 double pixelSizeToAxisXSize(double pixels)
55 double pixelSizeToAxisXSize(double pixels)
56 {
56 {
57 auto axis = m_Plot->axisRect()->axis(QCPAxis::atBottom);
57 auto axis = m_Plot->axisRect()->axis(QCPAxis::atBottom);
58 return axis->pixelToCoord(pixels) - axis->pixelToCoord(0);
58 return axis->pixelToCoord(pixels) - axis->pixelToCoord(0);
59 }
59 }
60
60
61 bool alignZones(VisualizationSelectionZoneItem *referenceZone,
61 bool alignZones(VisualizationSelectionZoneItem *referenceZone,
62 const QVector<VisualizationSelectionZoneItem *> &zonesToAlign, bool alignOnLeft,
62 const QVector<VisualizationSelectionZoneItem *> &zonesToAlign, bool alignOnLeft,
63 bool allowResize, bool vertically)
63 bool allowResize, bool vertically)
64 {
64 {
65 auto result = false;
65 auto result = false;
66
66
67 auto referenceTime
67 auto referenceTime
68 = alignOnLeft ? referenceZone->range().m_TStart : referenceZone->range().m_TEnd;
68 = alignOnLeft ? referenceZone->range().m_TStart : referenceZone->range().m_TEnd;
69
69
70 auto referenceBottomAxis = m_Plot->axisRect()->axis(QCPAxis::atBottom);
70 auto referenceBottomAxis = m_Plot->axisRect()->axis(QCPAxis::atBottom);
71 auto referenceVerticalPosition = referenceBottomAxis->coordToPixel(referenceTime);
71 auto referenceVerticalPosition = referenceBottomAxis->coordToPixel(referenceTime);
72
72
73 for (auto otherZone : zonesToAlign) {
73 for (auto otherZone : zonesToAlign) {
74
74
75 auto otherZoneRange = otherZone->range();
75 auto otherZoneRange = otherZone->range();
76 auto newZoneStart = otherZoneRange.m_TStart;
76 auto newZoneStart = otherZoneRange.m_TStart;
77 auto newZoneEnd = otherZoneRange.m_TEnd;
77 auto newZoneEnd = otherZoneRange.m_TEnd;
78
78
79 auto alignedTime = referenceTime;
79 auto alignedTime = referenceTime;
80 if (vertically) {
80 if (vertically) {
81 auto otherZoneAxis = otherZone->parentPlot()->axisRect()->axis(QCPAxis::atBottom);
81 auto otherZoneAxis = otherZone->parentPlot()->axisRect()->axis(QCPAxis::atBottom);
82 alignedTime = otherZoneAxis->pixelToCoord(referenceVerticalPosition);
82 alignedTime = otherZoneAxis->pixelToCoord(referenceVerticalPosition);
83 }
83 }
84
84
85 if (alignOnLeft) {
85 if (alignOnLeft) {
86 newZoneStart = alignedTime;
86 newZoneStart = alignedTime;
87 if (!allowResize) {
87 if (!allowResize) {
88 newZoneEnd = alignedTime + (otherZoneRange.m_TEnd - otherZoneRange.m_TStart);
88 newZoneEnd = alignedTime + (otherZoneRange.m_TEnd - otherZoneRange.m_TStart);
89 }
89 }
90 }
90 }
91 else { // align on right
91 else { // align on right
92 newZoneEnd = alignedTime;
92 newZoneEnd = alignedTime;
93 if (!allowResize) {
93 if (!allowResize) {
94 newZoneStart = alignedTime - (otherZoneRange.m_TEnd - otherZoneRange.m_TStart);
94 newZoneStart = alignedTime - (otherZoneRange.m_TEnd - otherZoneRange.m_TStart);
95 }
95 }
96 }
96 }
97
97
98 if (newZoneStart < newZoneEnd) {
98 if (newZoneStart < newZoneEnd) {
99 result = true;
99 result = true;
100 otherZone->setRange(newZoneStart, newZoneEnd);
100 otherZone->setRange(newZoneStart, newZoneEnd);
101 otherZone->parentPlot()->replot();
101 otherZone->parentPlot()->replot();
102 }
102 }
103 }
103 }
104
104
105 return result;
105 return result;
106 }
106 }
107 };
107 };
108
108
109 VisualizationSelectionZoneItem::VisualizationSelectionZoneItem(QCustomPlot *plot)
109 VisualizationSelectionZoneItem::VisualizationSelectionZoneItem(QCustomPlot *plot)
110 : QCPItemRect(plot),
110 : QCPItemRect(plot),
111 impl{spimpl::make_unique_impl<VisualizationSelectionZoneItemPrivate>(plot)}
111 impl{spimpl::make_unique_impl<VisualizationSelectionZoneItemPrivate>(plot)}
112 {
112 {
113 topLeft->setTypeX(QCPItemPosition::ptPlotCoords);
113 topLeft->setTypeX(QCPItemPosition::ptPlotCoords);
114 topLeft->setTypeY(QCPItemPosition::ptAxisRectRatio);
114 topLeft->setTypeY(QCPItemPosition::ptAxisRectRatio);
115 bottomRight->setTypeX(QCPItemPosition::ptPlotCoords);
115 bottomRight->setTypeX(QCPItemPosition::ptPlotCoords);
116 bottomRight->setTypeY(QCPItemPosition::ptAxisRectRatio);
116 bottomRight->setTypeY(QCPItemPosition::ptAxisRectRatio);
117 setSelectable(false);
117 setSelectable(false);
118
118
119 impl->m_RightLine = new QCPItemStraightLine(plot);
119 impl->m_RightLine = new QCPItemStraightLine(plot);
120 impl->m_RightLine->point1->setParentAnchor(topRight);
120 impl->m_RightLine->point1->setParentAnchor(topRight);
121 impl->m_RightLine->point2->setParentAnchor(bottomRight);
121 impl->m_RightLine->point2->setParentAnchor(bottomRight);
122 impl->m_RightLine->point1->setTypeX(QCPItemPosition::ptAbsolute);
122 impl->m_RightLine->point1->setTypeX(QCPItemPosition::ptAbsolute);
123 impl->m_RightLine->point1->setTypeY(QCPItemPosition::ptAbsolute);
123 impl->m_RightLine->point1->setTypeY(QCPItemPosition::ptAbsolute);
124 impl->m_RightLine->point2->setTypeX(QCPItemPosition::ptAbsolute);
124 impl->m_RightLine->point2->setTypeX(QCPItemPosition::ptAbsolute);
125 impl->m_RightLine->point2->setTypeY(QCPItemPosition::ptAbsolute);
125 impl->m_RightLine->point2->setTypeY(QCPItemPosition::ptAbsolute);
126 impl->m_RightLine->setSelectable(false);
126 impl->m_RightLine->setSelectable(false);
127
127
128 impl->m_LeftLine = new QCPItemStraightLine(plot);
128 impl->m_LeftLine = new QCPItemStraightLine(plot);
129 impl->m_LeftLine->point1->setParentAnchor(topLeft);
129 impl->m_LeftLine->point1->setParentAnchor(topLeft);
130 impl->m_LeftLine->point2->setParentAnchor(bottomLeft);
130 impl->m_LeftLine->point2->setParentAnchor(bottomLeft);
131 impl->m_LeftLine->point1->setTypeX(QCPItemPosition::ptAbsolute);
131 impl->m_LeftLine->point1->setTypeX(QCPItemPosition::ptAbsolute);
132 impl->m_LeftLine->point1->setTypeY(QCPItemPosition::ptAbsolute);
132 impl->m_LeftLine->point1->setTypeY(QCPItemPosition::ptAbsolute);
133 impl->m_LeftLine->point2->setTypeX(QCPItemPosition::ptAbsolute);
133 impl->m_LeftLine->point2->setTypeX(QCPItemPosition::ptAbsolute);
134 impl->m_LeftLine->point2->setTypeY(QCPItemPosition::ptAbsolute);
134 impl->m_LeftLine->point2->setTypeY(QCPItemPosition::ptAbsolute);
135 impl->m_LeftLine->setSelectable(false);
135 impl->m_LeftLine->setSelectable(false);
136
136
137 connect(this, &VisualizationSelectionZoneItem::selectionChanged, impl->m_RightLine,
137 connect(this, &VisualizationSelectionZoneItem::selectionChanged, impl->m_RightLine,
138 &QCPItemStraightLine::setSelected);
138 &QCPItemStraightLine::setSelected);
139 connect(this, &VisualizationSelectionZoneItem::selectionChanged, impl->m_LeftLine,
139 connect(this, &VisualizationSelectionZoneItem::selectionChanged, impl->m_LeftLine,
140 &QCPItemStraightLine::setSelected);
140 &QCPItemStraightLine::setSelected);
141
141
142 setColor(QColor(DEFAULT_COLOR));
142 setColor(QColor(DEFAULT_COLOR));
143 }
143 }
144
144
145 VisualizationSelectionZoneItem::~VisualizationSelectionZoneItem()
145 VisualizationSelectionZoneItem::~VisualizationSelectionZoneItem()
146 {
146 {
147 }
147 }
148
148
149 VisualizationGraphWidget *VisualizationSelectionZoneItem::parentGraphWidget() const noexcept
149 VisualizationGraphWidget *VisualizationSelectionZoneItem::parentGraphWidget() const noexcept
150 {
150 {
151 auto parent = impl->m_Plot->parentWidget();
151 auto parent = impl->m_Plot->parentWidget();
152 while (parent != nullptr && !qobject_cast<VisualizationGraphWidget *>(parent)) {
152 while (parent != nullptr && !qobject_cast<VisualizationGraphWidget *>(parent)) {
153 parent = parent->parentWidget();
153 parent = parent->parentWidget();
154 }
154 }
155
155
156 return qobject_cast<VisualizationGraphWidget *>(parent);
156 return qobject_cast<VisualizationGraphWidget *>(parent);
157 }
157 }
158
158
159 void VisualizationSelectionZoneItem::setName(const QString &name)
159 void VisualizationSelectionZoneItem::setName(const QString &name)
160 {
160 {
161 if (name.isEmpty() && impl->m_NameLabelItem) {
161 if (name.isEmpty() && impl->m_NameLabelItem) {
162 impl->m_Plot->removeItem(impl->m_NameLabelItem);
162 impl->m_Plot->removeItem(impl->m_NameLabelItem);
163 impl->m_NameLabelItem = nullptr;
163 impl->m_NameLabelItem = nullptr;
164 }
164 }
165 else if (!impl->m_NameLabelItem) {
165 else if (!impl->m_NameLabelItem) {
166 impl->m_NameLabelItem = new QCPItemText(impl->m_Plot);
166 impl->m_NameLabelItem = new QCPItemText(impl->m_Plot);
167 impl->m_NameLabelItem->setText(name);
167 impl->m_NameLabelItem->setText(name);
168 impl->m_NameLabelItem->setPositionAlignment(Qt::AlignHCenter | Qt::AlignTop);
168 impl->m_NameLabelItem->setPositionAlignment(Qt::AlignHCenter | Qt::AlignTop);
169 impl->m_NameLabelItem->setColor(impl->m_Color);
169 impl->m_NameLabelItem->setColor(impl->m_Color);
170 impl->m_NameLabelItem->position->setParentAnchor(top);
170 impl->m_NameLabelItem->position->setParentAnchor(top);
171 }
171 }
172 }
172 }
173
173
174 QString VisualizationSelectionZoneItem::name() const
174 QString VisualizationSelectionZoneItem::name() const
175 {
175 {
176 if (!impl->m_NameLabelItem) {
176 if (!impl->m_NameLabelItem) {
177 return QString();
177 return QString();
178 }
178 }
179
179
180 return impl->m_NameLabelItem->text();
180 return impl->m_NameLabelItem->text();
181 }
181 }
182
182
183 SqpRange VisualizationSelectionZoneItem::range() const
183 SqpRange VisualizationSelectionZoneItem::range() const
184 {
184 {
185 SqpRange range;
185 SqpRange range;
186 range.m_TStart = impl->m_T1 <= impl->m_T2 ? impl->m_T1 : impl->m_T2;
186 range.m_TStart = impl->m_T1 <= impl->m_T2 ? impl->m_T1 : impl->m_T2;
187 range.m_TEnd = impl->m_T1 > impl->m_T2 ? impl->m_T1 : impl->m_T2;
187 range.m_TEnd = impl->m_T1 > impl->m_T2 ? impl->m_T1 : impl->m_T2;
188 return range;
188 return range;
189 }
189 }
190
190
191 void VisualizationSelectionZoneItem::setRange(double tstart, double tend)
191 void VisualizationSelectionZoneItem::setRange(double tstart, double tend)
192 {
192 {
193 impl->m_T1 = tstart;
193 impl->m_T1 = tstart;
194 impl->m_T2 = tend;
194 impl->m_T2 = tend;
195 impl->updatePosition(this);
195 impl->updatePosition(this);
196 }
196 }
197
197
198 void VisualizationSelectionZoneItem::setStart(double tstart)
198 void VisualizationSelectionZoneItem::setStart(double tstart)
199 {
199 {
200 impl->m_T1 = tstart;
200 impl->m_T1 = tstart;
201 impl->updatePosition(this);
201 impl->updatePosition(this);
202 }
202 }
203
203
204 void VisualizationSelectionZoneItem::setEnd(double tend)
204 void VisualizationSelectionZoneItem::setEnd(double tend)
205 {
205 {
206 impl->m_T2 = tend;
206 impl->m_T2 = tend;
207 impl->updatePosition(this);
207 impl->updatePosition(this);
208 }
208 }
209
209
210 void VisualizationSelectionZoneItem::setColor(const QColor &color)
210 void VisualizationSelectionZoneItem::setColor(const QColor &color)
211 {
211 {
212 impl->m_Color = color;
212 impl->m_Color = color;
213
213
214 auto brushColor = color;
214 auto brushColor = color;
215 brushColor.setAlpha(80);
215 brushColor.setAlpha(80);
216 setBrush(QBrush(brushColor));
216 setBrush(QBrush(brushColor));
217 setPen(QPen(Qt::NoPen));
217 setPen(QPen(Qt::NoPen));
218
218
219 auto selectedBrushColor = brushColor;
219 auto selectedBrushColor = brushColor;
220 selectedBrushColor.setAlpha(150);
220 selectedBrushColor.setAlpha(150);
221 setSelectedBrush(QBrush(selectedBrushColor));
221 setSelectedBrush(QBrush(selectedBrushColor));
222 setSelectedPen(QPen(Qt::NoPen));
222 setSelectedPen(QPen(Qt::NoPen));
223
223
224 auto linePen = QPen(color);
224 auto linePen = QPen(color);
225 linePen.setStyle(Qt::SolidLine);
225 linePen.setStyle(Qt::SolidLine);
226 linePen.setWidth(4);
226 linePen.setWidth(4);
227
227
228 auto selectedLinePen = linePen;
228 auto selectedLinePen = linePen;
229 selectedLinePen.setColor(color.darker(120));
229 selectedLinePen.setColor(color.darker(120));
230 selectedLinePen.setWidth(4);
230 selectedLinePen.setWidth(4);
231
231
232 impl->m_LeftLine->setPen(linePen);
232 impl->m_LeftLine->setPen(linePen);
233 impl->m_RightLine->setPen(linePen);
233 impl->m_RightLine->setPen(linePen);
234
234
235 impl->m_LeftLine->setSelectedPen(selectedLinePen);
235 impl->m_LeftLine->setSelectedPen(selectedLinePen);
236 impl->m_RightLine->setSelectedPen(selectedLinePen);
236 impl->m_RightLine->setSelectedPen(selectedLinePen);
237 }
237 }
238
238
239 void VisualizationSelectionZoneItem::setEditionEnabled(bool value)
239 void VisualizationSelectionZoneItem::setEditionEnabled(bool value)
240 {
240 {
241 impl->m_IsEditionEnabled = value;
241 impl->m_IsEditionEnabled = value;
242 setSelectable(value);
242 setSelectable(value);
243 if (!value) {
243 if (!value) {
244 setSelected(false);
244 setSelected(false);
245 impl->m_CurrentEditionMode = VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition;
245 impl->m_CurrentEditionMode = VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition;
246 }
246 }
247 }
247 }
248
248
249 bool VisualizationSelectionZoneItem::isEditionEnabled() const
249 bool VisualizationSelectionZoneItem::isEditionEnabled() const
250 {
250 {
251 return impl->m_IsEditionEnabled;
251 return impl->m_IsEditionEnabled;
252 }
252 }
253
253
254 void VisualizationSelectionZoneItem::moveToTop()
254 void VisualizationSelectionZoneItem::moveToTop()
255 {
255 {
256 moveToLayer(layer(), false);
256 moveToLayer(layer(), false);
257 }
257 }
258
258
259 Qt::CursorShape
259 Qt::CursorShape
260 VisualizationSelectionZoneItem::curshorShapeForPosition(const QPoint &position) const
260 VisualizationSelectionZoneItem::curshorShapeForPosition(const QPoint &position) const
261 {
261 {
262 auto mode = impl->m_CurrentEditionMode
262 auto mode = impl->m_CurrentEditionMode
263 == VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition
263 == VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition
264 ? impl->getEditionMode(position, this)
264 ? impl->getEditionMode(position, this)
265 : impl->m_CurrentEditionMode;
265 : impl->m_CurrentEditionMode;
266 switch (mode) {
266 switch (mode) {
267 case VisualizationSelectionZoneItemPrivate::EditionMode::Move:
267 case VisualizationSelectionZoneItemPrivate::EditionMode::Move:
268 return Qt::SizeAllCursor;
268 return Qt::SizeAllCursor;
269 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeLeft:
269 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeLeft:
270 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeRight: // fallthrough
270 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeRight: // fallthrough
271 return Qt::SizeHorCursor;
271 return Qt::SizeHorCursor;
272 default:
272 default:
273 return Qt::ArrowCursor;
273 return Qt::ArrowCursor;
274 }
274 }
275 }
275 }
276
276
277 void VisualizationSelectionZoneItem::setHovered(bool value)
277 void VisualizationSelectionZoneItem::setHovered(bool value)
278 {
278 {
279 if (value) {
279 if (value) {
280 auto linePen = impl->m_LeftLine->pen();
280 auto linePen = impl->m_LeftLine->pen();
281 linePen.setStyle(Qt::DotLine);
281 linePen.setStyle(Qt::DotLine);
282 linePen.setWidth(3);
282 linePen.setWidth(3);
283
283
284 auto selectedLinePen = impl->m_LeftLine->selectedPen();
284 auto selectedLinePen = impl->m_LeftLine->selectedPen();
285 ;
285 ;
286 selectedLinePen.setStyle(Qt::DotLine);
286 selectedLinePen.setStyle(Qt::DotLine);
287 selectedLinePen.setWidth(3);
287 selectedLinePen.setWidth(3);
288
288
289 impl->m_LeftLine->setPen(linePen);
289 impl->m_LeftLine->setPen(linePen);
290 impl->m_RightLine->setPen(linePen);
290 impl->m_RightLine->setPen(linePen);
291
291
292 impl->m_LeftLine->setSelectedPen(selectedLinePen);
292 impl->m_LeftLine->setSelectedPen(selectedLinePen);
293 impl->m_RightLine->setSelectedPen(selectedLinePen);
293 impl->m_RightLine->setSelectedPen(selectedLinePen);
294 }
294 }
295 else {
295 else {
296 setColor(impl->m_Color);
296 setColor(impl->m_Color);
297 }
297 }
298 }
298 }
299
299
300 void VisualizationSelectionZoneItem::setAssociatedEditedZones(
300 void VisualizationSelectionZoneItem::setAssociatedEditedZones(
301 const QVector<VisualizationSelectionZoneItem *> &associatedZones)
301 const QVector<VisualizationSelectionZoneItem *> &associatedZones)
302 {
302 {
303 impl->m_AssociatedEditedZones = associatedZones;
303 impl->m_AssociatedEditedZones = associatedZones;
304 impl->m_AssociatedEditedZones.removeAll(this);
304 impl->m_AssociatedEditedZones.removeAll(this);
305 }
305 }
306
306
307 bool VisualizationSelectionZoneItem::alignZonesVerticallyOnLeft(
307 bool VisualizationSelectionZoneItem::alignZonesVerticallyOnLeft(
308 const QVector<VisualizationSelectionZoneItem *> &zonesToAlign, bool allowResize)
308 const QVector<VisualizationSelectionZoneItem *> &zonesToAlign, bool allowResize)
309 {
309 {
310 return impl->alignZones(this, zonesToAlign, true, allowResize, true);
310 return impl->alignZones(this, zonesToAlign, true, allowResize, true);
311 }
311 }
312
312
313 bool VisualizationSelectionZoneItem::alignZonesVerticallyOnRight(
313 bool VisualizationSelectionZoneItem::alignZonesVerticallyOnRight(
314 const QVector<VisualizationSelectionZoneItem *> &zonesToAlign, bool allowResize)
314 const QVector<VisualizationSelectionZoneItem *> &zonesToAlign, bool allowResize)
315 {
315 {
316 return impl->alignZones(this, zonesToAlign, false, allowResize, true);
316 return impl->alignZones(this, zonesToAlign, false, allowResize, true);
317 }
317 }
318
318
319 bool VisualizationSelectionZoneItem::alignZonesTemporallyOnLeft(
319 bool VisualizationSelectionZoneItem::alignZonesTemporallyOnLeft(
320 const QVector<VisualizationSelectionZoneItem *> &zonesToAlign, bool allowResize)
320 const QVector<VisualizationSelectionZoneItem *> &zonesToAlign, bool allowResize)
321 {
321 {
322 return impl->alignZones(this, zonesToAlign, true, allowResize, false);
322 return impl->alignZones(this, zonesToAlign, true, allowResize, false);
323 }
323 }
324
324
325 bool VisualizationSelectionZoneItem::alignZonesTemporallyOnRight(
325 bool VisualizationSelectionZoneItem::alignZonesTemporallyOnRight(
326 const QVector<VisualizationSelectionZoneItem *> &zonesToAlign, bool allowResize)
326 const QVector<VisualizationSelectionZoneItem *> &zonesToAlign, bool allowResize)
327 {
327 {
328 return impl->alignZones(this, zonesToAlign, false, allowResize, false);
328 return impl->alignZones(this, zonesToAlign, false, allowResize, false);
329 }
329 }
330
330
331 void VisualizationSelectionZoneItem::mousePressEvent(QMouseEvent *event, const QVariant &details)
331 void VisualizationSelectionZoneItem::mousePressEvent(QMouseEvent *event, const QVariant &details)
332 {
332 {
333 Q_UNUSED(details);
333 Q_UNUSED(details);
334
334
335 if (isEditionEnabled() && event->button() == Qt::LeftButton) {
335 if (isEditionEnabled() && event->button() == Qt::LeftButton) {
336 impl->m_CurrentEditionMode = impl->getEditionMode(event->pos(), this);
336 impl->m_CurrentEditionMode = impl->getEditionMode(event->pos(), this);
337
337
338 impl->m_MovedOrinalT1 = impl->m_T1;
338 impl->m_MovedOrinalT1 = impl->m_T1;
339 impl->m_MovedOrinalT2 = impl->m_T2;
339 impl->m_MovedOrinalT2 = impl->m_T2;
340 for (auto associatedZone : impl->m_AssociatedEditedZones) {
340 for (auto associatedZone : impl->m_AssociatedEditedZones) {
341 associatedZone->impl->m_MovedOrinalT1 = associatedZone->impl->m_T1;
341 associatedZone->impl->m_MovedOrinalT1 = associatedZone->impl->m_T1;
342 associatedZone->impl->m_MovedOrinalT2 = associatedZone->impl->m_T2;
342 associatedZone->impl->m_MovedOrinalT2 = associatedZone->impl->m_T2;
343 }
343 }
344 }
344 }
345 else {
345 else {
346 impl->m_CurrentEditionMode = VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition;
346 impl->m_CurrentEditionMode = VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition;
347 event->ignore();
347 event->ignore();
348 }
348 }
349 }
349 }
350
350
351 void VisualizationSelectionZoneItem::mouseMoveEvent(QMouseEvent *event, const QPointF &startPos)
351 void VisualizationSelectionZoneItem::mouseMoveEvent(QMouseEvent *event, const QPointF &startPos)
352 {
352 {
353 if (isEditionEnabled()) {
353 if (isEditionEnabled()) {
354 if (!selected()) {
354 if (!selected()) {
355 // Force the item to be selected during the edition
355 // Force the item to be selected during the edition
356 parentGraphWidget()->parentVisualizationWidget()->selectionZoneManager().setSelected(
356 parentGraphWidget()->parentVisualizationWidget()->selectionZoneManager().setSelected(
357 this, true);
357 this, true);
358 }
358 }
359
359
360 auto axis = impl->m_Plot->axisRect()->axis(QCPAxis::atBottom);
360 auto axis = impl->m_Plot->axisRect()->axis(QCPAxis::atBottom);
361 auto pixelDiff = event->pos().x() - startPos.x();
361 auto pixelDiff = event->pos().x() - startPos.x();
362 auto diff = impl->pixelSizeToAxisXSize(pixelDiff);
362 auto diff = impl->pixelSizeToAxisXSize(pixelDiff);
363
363
364 switch (impl->m_CurrentEditionMode) {
364 switch (impl->m_CurrentEditionMode) {
365 case VisualizationSelectionZoneItemPrivate::EditionMode::Move:
365 case VisualizationSelectionZoneItemPrivate::EditionMode::Move:
366 setRange(impl->m_MovedOrinalT1 + diff, impl->m_MovedOrinalT2 + diff);
366 setRange(impl->m_MovedOrinalT1 + diff, impl->m_MovedOrinalT2 + diff);
367 for (auto associatedZone : impl->m_AssociatedEditedZones) {
367 for (auto associatedZone : impl->m_AssociatedEditedZones) {
368 associatedZone->move(pixelDiff);
368 associatedZone->move(pixelDiff);
369 }
369 }
370 break;
370 break;
371 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeLeft:
371 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeLeft:
372 setStart(impl->m_MovedOrinalT1 + diff);
372 setStart(impl->m_MovedOrinalT1 + diff);
373 for (auto associatedZone : impl->m_AssociatedEditedZones) {
373 for (auto associatedZone : impl->m_AssociatedEditedZones) {
374 impl->m_MovedOrinalT1 < impl->m_MovedOrinalT2
374 impl->m_MovedOrinalT1 < impl->m_MovedOrinalT2
375 ? associatedZone->resizeLeft(pixelDiff)
375 ? associatedZone->resizeLeft(pixelDiff)
376 : associatedZone->resizeRight(pixelDiff);
376 : associatedZone->resizeRight(pixelDiff);
377 }
377 }
378 break;
378 break;
379 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeRight:
379 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeRight:
380 setEnd(impl->m_MovedOrinalT2 + diff);
380 setEnd(impl->m_MovedOrinalT2 + diff);
381 for (auto associatedZone : impl->m_AssociatedEditedZones) {
381 for (auto associatedZone : impl->m_AssociatedEditedZones) {
382 impl->m_MovedOrinalT1 < impl->m_MovedOrinalT2
382 impl->m_MovedOrinalT1 < impl->m_MovedOrinalT2
383 ? associatedZone->resizeRight(pixelDiff)
383 ? associatedZone->resizeRight(pixelDiff)
384 : associatedZone->resizeLeft(pixelDiff);
384 : associatedZone->resizeLeft(pixelDiff);
385 }
385 }
386 break;
386 break;
387 default:
387 default:
388 break;
388 break;
389 }
389 }
390
390
391 emit rangeEdited(range());
392
391 for (auto associatedZone : impl->m_AssociatedEditedZones) {
393 for (auto associatedZone : impl->m_AssociatedEditedZones) {
392 associatedZone->parentPlot()->replot();
394 associatedZone->parentPlot()->replot();
395 emit associatedZone->rangeEdited(associatedZone->range());
393 }
396 }
394 }
397 }
395 else {
398 else {
396 event->ignore();
399 event->ignore();
397 }
400 }
398 }
401 }
399
402
400 void VisualizationSelectionZoneItem::mouseReleaseEvent(QMouseEvent *event, const QPointF &startPos)
403 void VisualizationSelectionZoneItem::mouseReleaseEvent(QMouseEvent *event, const QPointF &startPos)
401 {
404 {
402 Q_UNUSED(startPos);
405 Q_UNUSED(startPos);
403
406
404 if (isEditionEnabled()) {
407 if (isEditionEnabled()) {
405 impl->m_CurrentEditionMode = VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition;
408 impl->m_CurrentEditionMode = VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition;
406 }
409 }
407 else {
410 else {
408 event->ignore();
411 event->ignore();
409 }
412 }
410
413
411 impl->m_AssociatedEditedZones.clear();
414 impl->m_AssociatedEditedZones.clear();
412 }
415 }
413
416
414 void VisualizationSelectionZoneItem::resizeLeft(double pixelDiff)
417 void VisualizationSelectionZoneItem::resizeLeft(double pixelDiff)
415 {
418 {
416 auto diff = impl->pixelSizeToAxisXSize(pixelDiff);
419 auto diff = impl->pixelSizeToAxisXSize(pixelDiff);
417 if (impl->m_MovedOrinalT1 <= impl->m_MovedOrinalT2) {
420 if (impl->m_MovedOrinalT1 <= impl->m_MovedOrinalT2) {
418 setStart(impl->m_MovedOrinalT1 + diff);
421 setStart(impl->m_MovedOrinalT1 + diff);
419 }
422 }
420 else {
423 else {
421 setEnd(impl->m_MovedOrinalT2 + diff);
424 setEnd(impl->m_MovedOrinalT2 + diff);
422 }
425 }
423 }
426 }
424
427
425 void VisualizationSelectionZoneItem::resizeRight(double pixelDiff)
428 void VisualizationSelectionZoneItem::resizeRight(double pixelDiff)
426 {
429 {
427 auto diff = impl->pixelSizeToAxisXSize(pixelDiff);
430 auto diff = impl->pixelSizeToAxisXSize(pixelDiff);
428 if (impl->m_MovedOrinalT1 > impl->m_MovedOrinalT2) {
431 if (impl->m_MovedOrinalT1 > impl->m_MovedOrinalT2) {
429 setStart(impl->m_MovedOrinalT1 + diff);
432 setStart(impl->m_MovedOrinalT1 + diff);
430 }
433 }
431 else {
434 else {
432 setEnd(impl->m_MovedOrinalT2 + diff);
435 setEnd(impl->m_MovedOrinalT2 + diff);
433 }
436 }
434 }
437 }
435
438
436 void VisualizationSelectionZoneItem::move(double pixelDiff)
439 void VisualizationSelectionZoneItem::move(double pixelDiff)
437 {
440 {
438 auto diff = impl->pixelSizeToAxisXSize(pixelDiff);
441 auto diff = impl->pixelSizeToAxisXSize(pixelDiff);
439 setRange(impl->m_MovedOrinalT1 + diff, impl->m_MovedOrinalT2 + diff);
442 setRange(impl->m_MovedOrinalT1 + diff, impl->m_MovedOrinalT2 + diff);
440 }
443 }
@@ -1,354 +1,389
1 #include "Visualization/VisualizationTabWidget.h"
1 #include "Visualization/VisualizationTabWidget.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 #include "ui_VisualizationTabWidget.h"
3 #include "ui_VisualizationTabWidget.h"
4
4
5 #include "Visualization/VisualizationGraphWidget.h"
5 #include "Visualization/VisualizationGraphWidget.h"
6 #include "Visualization/VisualizationZoneWidget.h"
6 #include "Visualization/VisualizationZoneWidget.h"
7
7
8 #include "Visualization/MacScrollBarStyle.h"
8 #include "Visualization/MacScrollBarStyle.h"
9
9
10 #include "DataSource/DataSourceController.h"
10 #include "Variable/VariableController.h"
11 #include "Variable/VariableController.h"
11
12
12 #include "Common/MimeTypesDef.h"
13 #include "Common/MimeTypesDef.h"
13
14
14 #include "DragAndDrop/DragDropGuiController.h"
15 #include "DragAndDrop/DragDropGuiController.h"
15 #include "SqpApplication.h"
16 #include "SqpApplication.h"
16
17
17 Q_LOGGING_CATEGORY(LOG_VisualizationTabWidget, "VisualizationTabWidget")
18 Q_LOGGING_CATEGORY(LOG_VisualizationTabWidget, "VisualizationTabWidget")
18
19
19 namespace {
20 namespace {
20
21
21 /**
22 /**
22 * Applies a function to all zones of the tab represented by its layout
23 * Applies a function to all zones of the tab represented by its layout
23 * @param layout the layout that contains zones
24 * @param layout the layout that contains zones
24 * @param fun the function to apply to each zone
25 * @param fun the function to apply to each zone
25 */
26 */
26 template <typename Fun>
27 template <typename Fun>
27 void processZones(QLayout &layout, Fun fun)
28 void processZones(QLayout &layout, Fun fun)
28 {
29 {
29 for (auto i = 0; i < layout.count(); ++i) {
30 for (auto i = 0; i < layout.count(); ++i) {
30 if (auto item = layout.itemAt(i)) {
31 if (auto item = layout.itemAt(i)) {
31 if (auto visualizationZoneWidget
32 if (auto visualizationZoneWidget
32 = qobject_cast<VisualizationZoneWidget *>(item->widget())) {
33 = qobject_cast<VisualizationZoneWidget *>(item->widget())) {
33 fun(*visualizationZoneWidget);
34 fun(*visualizationZoneWidget);
34 }
35 }
35 }
36 }
36 }
37 }
37 }
38 }
38
39
39 /// Generates a default name for a new zone, according to the number of zones already displayed in
40 /// Generates a default name for a new zone, according to the number of zones already displayed in
40 /// the tab
41 /// the tab
41 QString defaultZoneName(QLayout &layout)
42 QString defaultZoneName(QLayout &layout)
42 {
43 {
43 QSet<QString> existingNames;
44 QSet<QString> existingNames;
44 processZones(layout,
45 processZones(layout,
45 [&existingNames](auto &zoneWidget) { existingNames.insert(zoneWidget.name()); });
46 [&existingNames](auto &zoneWidget) { existingNames.insert(zoneWidget.name()); });
46
47
47 int zoneNum = 1;
48 int zoneNum = 1;
48 QString name;
49 QString name;
49 do {
50 do {
50 name = QObject::tr("Zone ").append(QString::number(zoneNum));
51 name = QObject::tr("Zone ").append(QString::number(zoneNum));
51 ++zoneNum;
52 ++zoneNum;
52 } while (existingNames.contains(name));
53 } while (existingNames.contains(name));
53
54
54 return name;
55 return name;
55 }
56 }
56
57
57 } // namespace
58 } // namespace
58
59
59 struct VisualizationTabWidget::VisualizationTabWidgetPrivate {
60 struct VisualizationTabWidget::VisualizationTabWidgetPrivate {
60 explicit VisualizationTabWidgetPrivate(const QString &name) : m_Name{name} {}
61 explicit VisualizationTabWidgetPrivate(const QString &name) : m_Name{name} {}
61
62
62 QString m_Name;
63 QString m_Name;
63
64
64 #ifdef Q_OS_MAC
65 #ifdef Q_OS_MAC
65 std::unique_ptr<MacScrollBarStyle> m_MacScrollBarStyle = std::make_unique<MacScrollBarStyle>();
66 std::unique_ptr<MacScrollBarStyle> m_MacScrollBarStyle = std::make_unique<MacScrollBarStyle>();
66 #endif
67 #endif
67
68
68 void dropGraph(int index, VisualizationTabWidget *tabWidget);
69 void dropGraph(int index, VisualizationTabWidget *tabWidget);
69 void dropZone(int index, VisualizationTabWidget *tabWidget);
70 void dropZone(int index, VisualizationTabWidget *tabWidget);
70 void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index,
71 void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index,
71 VisualizationTabWidget *tabWidget);
72 VisualizationTabWidget *tabWidget);
73 void dropProducts(const QVariantList &productsMetaData, int index,
74 VisualizationTabWidget *tabWidget);
72 };
75 };
73
76
74 VisualizationTabWidget::VisualizationTabWidget(const QString &name, QWidget *parent)
77 VisualizationTabWidget::VisualizationTabWidget(const QString &name, QWidget *parent)
75 : QWidget{parent},
78 : QWidget{parent},
76 ui{new Ui::VisualizationTabWidget},
79 ui{new Ui::VisualizationTabWidget},
77 impl{spimpl::make_unique_impl<VisualizationTabWidgetPrivate>(name)}
80 impl{spimpl::make_unique_impl<VisualizationTabWidgetPrivate>(name)}
78 {
81 {
79 ui->setupUi(this);
82 ui->setupUi(this);
80
83
81 #ifdef Q_OS_MAC
84 #ifdef Q_OS_MAC
82 impl->m_MacScrollBarStyle->selfInstallOn(ui->scrollArea, true);
85 impl->m_MacScrollBarStyle->selfInstallOn(ui->scrollArea, true);
83 #endif
86 #endif
84
87
85 ui->dragDropContainer->setPlaceHolderType(DragDropGuiController::PlaceHolderType::Zone, "Zone");
88 ui->dragDropContainer->setPlaceHolderType(DragDropGuiController::PlaceHolderType::Zone, "Zone");
86 ui->dragDropContainer->layout()->setContentsMargins(0, 0, 0, 12);
89 ui->dragDropContainer->layout()->setContentsMargins(0, 0, 0, 12);
87 ui->dragDropContainer->layout()->setSpacing(0);
90 ui->dragDropContainer->layout()->setSpacing(0);
88 ui->dragDropContainer->setMimeType(MIME_TYPE_GRAPH,
91 ui->dragDropContainer->setMimeType(MIME_TYPE_GRAPH,
89 VisualizationDragDropContainer::DropBehavior::Inserted);
92 VisualizationDragDropContainer::DropBehavior::Inserted);
90 ui->dragDropContainer->setMimeType(MIME_TYPE_ZONE,
93 ui->dragDropContainer->setMimeType(MIME_TYPE_ZONE,
91 VisualizationDragDropContainer::DropBehavior::Inserted);
94 VisualizationDragDropContainer::DropBehavior::Inserted);
92 ui->dragDropContainer->setMimeType(MIME_TYPE_VARIABLE_LIST,
95 ui->dragDropContainer->setMimeType(MIME_TYPE_VARIABLE_LIST,
93 VisualizationDragDropContainer::DropBehavior::Inserted);
96 VisualizationDragDropContainer::DropBehavior::Inserted);
97 ui->dragDropContainer->setMimeType(MIME_TYPE_PRODUCT_LIST,
98 VisualizationDragDropContainer::DropBehavior::Inserted);
94
99
95 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
100 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
96 return sqpApp->dragDropGuiController().checkMimeDataForVisualization(mimeData,
101 return sqpApp->dragDropGuiController().checkMimeDataForVisualization(mimeData,
97 ui->dragDropContainer);
102 ui->dragDropContainer);
98 });
103 });
99
104
100 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this,
105 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this,
101 &VisualizationTabWidget::dropMimeData);
106 &VisualizationTabWidget::dropMimeData);
102
107
103 sqpApp->dragDropGuiController().addDragDropScrollArea(ui->scrollArea);
108 sqpApp->dragDropGuiController().addDragDropScrollArea(ui->scrollArea);
104
109
105 // Widget is deleted when closed
110 // Widget is deleted when closed
106 setAttribute(Qt::WA_DeleteOnClose);
111 setAttribute(Qt::WA_DeleteOnClose);
107 }
112 }
108
113
109 VisualizationTabWidget::~VisualizationTabWidget()
114 VisualizationTabWidget::~VisualizationTabWidget()
110 {
115 {
111 sqpApp->dragDropGuiController().removeDragDropScrollArea(ui->scrollArea);
116 sqpApp->dragDropGuiController().removeDragDropScrollArea(ui->scrollArea);
112 delete ui;
117 delete ui;
113 }
118 }
114
119
115 void VisualizationTabWidget::addZone(VisualizationZoneWidget *zoneWidget)
120 void VisualizationTabWidget::addZone(VisualizationZoneWidget *zoneWidget)
116 {
121 {
117 ui->dragDropContainer->addDragWidget(zoneWidget);
122 ui->dragDropContainer->addDragWidget(zoneWidget);
118 }
123 }
119
124
120 void VisualizationTabWidget::insertZone(int index, VisualizationZoneWidget *zoneWidget)
125 void VisualizationTabWidget::insertZone(int index, VisualizationZoneWidget *zoneWidget)
121 {
126 {
122 ui->dragDropContainer->insertDragWidget(index, zoneWidget);
127 ui->dragDropContainer->insertDragWidget(index, zoneWidget);
123 }
128 }
124
129
125 QStringList VisualizationTabWidget::availableZoneWidgets() const
130 QStringList VisualizationTabWidget::availableZoneWidgets() const
126 {
131 {
127 QStringList zones;
132 QStringList zones;
128 processZones(tabLayout(),
133 processZones(tabLayout(),
129 [&zones](VisualizationZoneWidget &zoneWidget) { zones << zoneWidget.name(); });
134 [&zones](VisualizationZoneWidget &zoneWidget) { zones << zoneWidget.name(); });
130
135
131 return zones;
136 return zones;
132 }
137 }
133
138
134 VisualizationZoneWidget *VisualizationTabWidget::getZoneWithName(const QString &zoneName)
139 VisualizationZoneWidget *VisualizationTabWidget::getZoneWithName(const QString &zoneName)
135 {
140 {
136 VisualizationZoneWidget *result = nullptr;
141 VisualizationZoneWidget *result = nullptr;
137 processZones(tabLayout(), [&zoneName, &result](VisualizationZoneWidget &zoneWidget) {
142 processZones(tabLayout(), [&zoneName, &result](VisualizationZoneWidget &zoneWidget) {
138 if (!result && zoneWidget.name() == zoneName) {
143 if (!result && zoneWidget.name() == zoneName) {
139 result = &zoneWidget;
144 result = &zoneWidget;
140 }
145 }
141 });
146 });
142
147
143 return result;
148 return result;
144 }
149 }
145
150
146 VisualizationZoneWidget *VisualizationTabWidget::createZone(std::shared_ptr<Variable> variable)
151 VisualizationZoneWidget *VisualizationTabWidget::createZone(std::shared_ptr<Variable> variable)
147 {
152 {
148 return createZone({variable}, -1);
153 return createZone({variable}, -1);
149 }
154 }
150
155
151 VisualizationZoneWidget *
156 VisualizationZoneWidget *
152 VisualizationTabWidget::createZone(const QList<std::shared_ptr<Variable> > &variables, int index)
157 VisualizationTabWidget::createZone(const QList<std::shared_ptr<Variable> > &variables, int index)
153 {
158 {
154 auto zoneWidget = createEmptyZone(index);
159 auto zoneWidget = createEmptyZone(index);
155
160
156 // Creates a new graph into the zone
161 // Creates a new graph into the zone
157 zoneWidget->createGraph(variables, index);
162 zoneWidget->createGraph(variables, index);
158
163
159 return zoneWidget;
164 return zoneWidget;
160 }
165 }
161
166
162 VisualizationZoneWidget *VisualizationTabWidget::createEmptyZone(int index)
167 VisualizationZoneWidget *VisualizationTabWidget::createEmptyZone(int index)
163 {
168 {
164 auto zoneWidget
169 auto zoneWidget
165 = new VisualizationZoneWidget{defaultZoneName(*ui->dragDropContainer->layout()), this};
170 = new VisualizationZoneWidget{defaultZoneName(*ui->dragDropContainer->layout()), this};
166 this->insertZone(index, zoneWidget);
171 this->insertZone(index, zoneWidget);
167
172
168 return zoneWidget;
173 return zoneWidget;
169 }
174 }
170
175
171 void VisualizationTabWidget::accept(IVisualizationWidgetVisitor *visitor)
176 void VisualizationTabWidget::accept(IVisualizationWidgetVisitor *visitor)
172 {
177 {
173 if (visitor) {
178 if (visitor) {
174 visitor->visitEnter(this);
179 visitor->visitEnter(this);
175
180
176 // Apply visitor to zone children: widgets different from zones are not visited (no action)
181 // Apply visitor to zone children: widgets different from zones are not visited (no action)
177 processZones(tabLayout(), [visitor](VisualizationZoneWidget &zoneWidget) {
182 processZones(tabLayout(), [visitor](VisualizationZoneWidget &zoneWidget) {
178 zoneWidget.accept(visitor);
183 zoneWidget.accept(visitor);
179 });
184 });
180
185
181 visitor->visitLeave(this);
186 visitor->visitLeave(this);
182 }
187 }
183 else {
188 else {
184 qCCritical(LOG_VisualizationTabWidget()) << tr("Can't visit widget : the visitor is null");
189 qCCritical(LOG_VisualizationTabWidget()) << tr("Can't visit widget : the visitor is null");
185 }
190 }
186 }
191 }
187
192
188 bool VisualizationTabWidget::canDrop(const Variable &variable) const
193 bool VisualizationTabWidget::canDrop(const Variable &variable) const
189 {
194 {
190 // A tab can always accomodate a variable
195 // A tab can always accomodate a variable
191 Q_UNUSED(variable);
196 Q_UNUSED(variable);
192 return true;
197 return true;
193 }
198 }
194
199
195 bool VisualizationTabWidget::contains(const Variable &variable) const
200 bool VisualizationTabWidget::contains(const Variable &variable) const
196 {
201 {
197 Q_UNUSED(variable);
202 Q_UNUSED(variable);
198 return false;
203 return false;
199 }
204 }
200
205
201 QString VisualizationTabWidget::name() const
206 QString VisualizationTabWidget::name() const
202 {
207 {
203 return impl->m_Name;
208 return impl->m_Name;
204 }
209 }
205
210
206 void VisualizationTabWidget::closeEvent(QCloseEvent *event)
211 void VisualizationTabWidget::closeEvent(QCloseEvent *event)
207 {
212 {
208 // Closes zones in the tab
213 // Closes zones in the tab
209 processZones(tabLayout(), [](VisualizationZoneWidget &zoneWidget) { zoneWidget.close(); });
214 processZones(tabLayout(), [](VisualizationZoneWidget &zoneWidget) { zoneWidget.close(); });
210
215
211 QWidget::closeEvent(event);
216 QWidget::closeEvent(event);
212 }
217 }
213
218
214 QLayout &VisualizationTabWidget::tabLayout() const noexcept
219 QLayout &VisualizationTabWidget::tabLayout() const noexcept
215 {
220 {
216 return *ui->dragDropContainer->layout();
221 return *ui->dragDropContainer->layout();
217 }
222 }
218
223
219 void VisualizationTabWidget::dropMimeData(int index, const QMimeData *mimeData)
224 void VisualizationTabWidget::dropMimeData(int index, const QMimeData *mimeData)
220 {
225 {
221 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
226 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
222 impl->dropGraph(index, this);
227 impl->dropGraph(index, this);
223 }
228 }
224 else if (mimeData->hasFormat(MIME_TYPE_ZONE)) {
229 else if (mimeData->hasFormat(MIME_TYPE_ZONE)) {
225 impl->dropZone(index, this);
230 impl->dropZone(index, this);
226 }
231 }
227 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
232 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
228 auto variables = sqpApp->variableController().variablesForMimeData(
233 auto variables = sqpApp->variableController().variablesForMimeData(
229 mimeData->data(MIME_TYPE_VARIABLE_LIST));
234 mimeData->data(MIME_TYPE_VARIABLE_LIST));
230 impl->dropVariables(variables, index, this);
235 impl->dropVariables(variables, index, this);
231 }
236 }
237 else if (mimeData->hasFormat(MIME_TYPE_PRODUCT_LIST)) {
238 auto productsData = sqpApp->dataSourceController().productsDataForMimeData(
239 mimeData->data(MIME_TYPE_PRODUCT_LIST));
240 impl->dropProducts(productsData, index, this);
241 }
232 else {
242 else {
233 qCWarning(LOG_VisualizationZoneWidget())
243 qCWarning(LOG_VisualizationZoneWidget())
234 << tr("VisualizationTabWidget::dropMimeData, unknown MIME data received.");
244 << tr("VisualizationTabWidget::dropMimeData, unknown MIME data received.");
235 }
245 }
236 }
246 }
237
247
238 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropGraph(
248 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropGraph(
239 int index, VisualizationTabWidget *tabWidget)
249 int index, VisualizationTabWidget *tabWidget)
240 {
250 {
241 auto &helper = sqpApp->dragDropGuiController();
251 auto &helper = sqpApp->dragDropGuiController();
242
252
243 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
253 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
244 if (!graphWidget) {
254 if (!graphWidget) {
245 qCWarning(LOG_VisualizationZoneWidget())
255 qCWarning(LOG_VisualizationZoneWidget())
246 << tr("VisualizationTabWidget::dropGraph, drop aborted, the dropped graph is not "
256 << tr("VisualizationTabWidget::dropGraph, drop aborted, the dropped graph is not "
247 "found or invalid.");
257 "found or invalid.");
248 Q_ASSERT(false);
258 Q_ASSERT(false);
249 return;
259 return;
250 }
260 }
251
261
252 auto parentDragDropContainer
262 auto parentDragDropContainer
253 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
263 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
254 if (!parentDragDropContainer) {
264 if (!parentDragDropContainer) {
255 qCWarning(LOG_VisualizationZoneWidget())
265 qCWarning(LOG_VisualizationZoneWidget())
256 << tr("VisualizationTabWidget::dropGraph, drop aborted, the parent container of "
266 << tr("VisualizationTabWidget::dropGraph, drop aborted, the parent container of "
257 "the dropped graph is not found.");
267 "the dropped graph is not found.");
258 Q_ASSERT(false);
268 Q_ASSERT(false);
259 return;
269 return;
260 }
270 }
261
271
262 auto nbGraph = parentDragDropContainer->countDragWidget();
272 auto nbGraph = parentDragDropContainer->countDragWidget();
263
273
264 const auto &variables = graphWidget->variables();
274 const auto &variables = graphWidget->variables();
265
275
266 if (!variables.isEmpty()) {
276 if (!variables.isEmpty()) {
267 // Abort the requests for the variables (if any)
277 // Abort the requests for the variables (if any)
268 // Commented, because it's not sure if it's needed or not
278 // Commented, because it's not sure if it's needed or not
269 // for (const auto& var : variables)
279 // for (const auto& var : variables)
270 //{
280 //{
271 // sqpApp->variableController().onAbortProgressRequested(var);
281 // sqpApp->variableController().onAbortProgressRequested(var);
272 //}
282 //}
273
283
274 if (nbGraph == 1) {
284 if (nbGraph == 1) {
275 // This is the only graph in the previous zone, close the zone
285 // This is the only graph in the previous zone, close the zone
276 helper.delayedCloseWidget(graphWidget->parentZoneWidget());
286 helper.delayedCloseWidget(graphWidget->parentZoneWidget());
277 }
287 }
278 else {
288 else {
279 // Close the graph
289 // Close the graph
280 helper.delayedCloseWidget(graphWidget);
290 helper.delayedCloseWidget(graphWidget);
281 }
291 }
282
292
283 auto zoneWidget = tabWidget->createZone(variables, index);
293 auto zoneWidget = tabWidget->createZone(variables, index);
284 auto firstGraph = zoneWidget->firstGraph();
294 auto firstGraph = zoneWidget->firstGraph();
285 if (firstGraph) {
295 if (firstGraph) {
286 firstGraph->addSelectionZones(graphWidget->selectionZoneRanges());
296 firstGraph->addSelectionZones(graphWidget->selectionZoneRanges());
287 }
297 }
288 else {
298 else {
289 qCWarning(LOG_VisualizationZoneWidget())
299 qCWarning(LOG_VisualizationZoneWidget())
290 << tr("VisualizationTabWidget::dropGraph, no graph added in the widget.");
300 << tr("VisualizationTabWidget::dropGraph, no graph added in the widget.");
291 Q_ASSERT(false);
301 Q_ASSERT(false);
292 }
302 }
293 }
303 }
294 else {
304 else {
295 // The graph is empty, create an empty zone and move the graph inside
305 // The graph is empty, create an empty zone and move the graph inside
296
306
297 auto parentZoneWidget = graphWidget->parentZoneWidget();
307 auto parentZoneWidget = graphWidget->parentZoneWidget();
298
308
299 parentDragDropContainer->layout()->removeWidget(graphWidget);
309 parentDragDropContainer->layout()->removeWidget(graphWidget);
300
310
301 auto zoneWidget = tabWidget->createEmptyZone(index);
311 auto zoneWidget = tabWidget->createEmptyZone(index);
302 zoneWidget->addGraph(graphWidget);
312 zoneWidget->addGraph(graphWidget);
303
313
304 // Close the old zone if it was the only graph inside
314 // Close the old zone if it was the only graph inside
305 if (nbGraph == 1) {
315 if (nbGraph == 1) {
306 helper.delayedCloseWidget(parentZoneWidget);
316 helper.delayedCloseWidget(parentZoneWidget);
307 }
317 }
308 }
318 }
309 }
319 }
310
320
311 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropZone(
321 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropZone(
312 int index, VisualizationTabWidget *tabWidget)
322 int index, VisualizationTabWidget *tabWidget)
313 {
323 {
314 auto &helper = sqpApp->dragDropGuiController();
324 auto &helper = sqpApp->dragDropGuiController();
315
325
316 auto zoneWidget = qobject_cast<VisualizationZoneWidget *>(helper.getCurrentDragWidget());
326 auto zoneWidget = qobject_cast<VisualizationZoneWidget *>(helper.getCurrentDragWidget());
317 if (!zoneWidget) {
327 if (!zoneWidget) {
318 qCWarning(LOG_VisualizationZoneWidget())
328 qCWarning(LOG_VisualizationZoneWidget())
319 << tr("VisualizationTabWidget::dropZone, drop aborted, the dropped zone is not "
329 << tr("VisualizationTabWidget::dropZone, drop aborted, the dropped zone is not "
320 "found or invalid.");
330 "found or invalid.");
321 Q_ASSERT(false);
331 Q_ASSERT(false);
322 return;
332 return;
323 }
333 }
324
334
325 auto parentDragDropContainer
335 auto parentDragDropContainer
326 = qobject_cast<VisualizationDragDropContainer *>(zoneWidget->parentWidget());
336 = qobject_cast<VisualizationDragDropContainer *>(zoneWidget->parentWidget());
327 if (!parentDragDropContainer) {
337 if (!parentDragDropContainer) {
328 qCWarning(LOG_VisualizationZoneWidget())
338 qCWarning(LOG_VisualizationZoneWidget())
329 << tr("VisualizationTabWidget::dropZone, drop aborted, the parent container of "
339 << tr("VisualizationTabWidget::dropZone, drop aborted, the parent container of "
330 "the dropped zone is not found.");
340 "the dropped zone is not found.");
331 Q_ASSERT(false);
341 Q_ASSERT(false);
332 return;
342 return;
333 }
343 }
334
344
335 // Simple move of the zone, no variable operation associated
345 // Simple move of the zone, no variable operation associated
336 parentDragDropContainer->layout()->removeWidget(zoneWidget);
346 parentDragDropContainer->layout()->removeWidget(zoneWidget);
337 tabWidget->ui->dragDropContainer->insertDragWidget(index, zoneWidget);
347 tabWidget->ui->dragDropContainer->insertDragWidget(index, zoneWidget);
338 }
348 }
339
349
340 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropVariables(
350 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropVariables(
341 const QList<std::shared_ptr<Variable> > &variables, int index,
351 const QList<std::shared_ptr<Variable> > &variables, int index,
342 VisualizationTabWidget *tabWidget)
352 VisualizationTabWidget *tabWidget)
343 {
353 {
344 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
354 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
345 // compatible variable here
355 // compatible variable here
346 if (variables.count() > 1) {
356 if (variables.count() > 1) {
347 qCWarning(LOG_VisualizationZoneWidget())
357 qCWarning(LOG_VisualizationZoneWidget())
348 << tr("VisualizationTabWidget::dropVariables, dropping multiple variables, operation "
358 << tr("VisualizationTabWidget::dropVariables, dropping multiple variables, operation "
349 "aborted.");
359 "aborted.");
350 return;
360 return;
351 }
361 }
352
362
353 tabWidget->createZone(variables, index);
363 tabWidget->createZone(variables, index);
354 }
364 }
365
366 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropProducts(
367 const QVariantList &productsMetaData, int index, VisualizationTabWidget *tabWidget)
368 {
369 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
370 // compatible variable here
371 if (productsMetaData.count() != 1) {
372 qCWarning(LOG_VisualizationZoneWidget())
373 << tr("VisualizationTabWidget::dropProducts, dropping multiple products, operation "
374 "aborted.");
375 return;
376 }
377
378 auto context = new QObject{tabWidget};
379 connect(&sqpApp->variableController(), &VariableController::variableAdded, context,
380 [this, index, tabWidget, context](auto variable) {
381 tabWidget->createZone({variable}, index);
382 delete context; // removes the connection
383 },
384 Qt::QueuedConnection);
385
386 auto productData = productsMetaData.first().toHash();
387 QMetaObject::invokeMethod(&sqpApp->dataSourceController(), "requestVariable",
388 Qt::QueuedConnection, Q_ARG(QVariantHash, productData));
389 }
@@ -1,601 +1,652
1 #include "Visualization/VisualizationZoneWidget.h"
1 #include "Visualization/VisualizationZoneWidget.h"
2
2
3 #include "Visualization/IVisualizationWidgetVisitor.h"
3 #include "Visualization/IVisualizationWidgetVisitor.h"
4 #include "Visualization/QCustomPlotSynchronizer.h"
4 #include "Visualization/QCustomPlotSynchronizer.h"
5 #include "Visualization/VisualizationGraphWidget.h"
5 #include "Visualization/VisualizationGraphWidget.h"
6 #include "Visualization/VisualizationWidget.h"
6 #include "Visualization/VisualizationWidget.h"
7 #include "ui_VisualizationZoneWidget.h"
7 #include "ui_VisualizationZoneWidget.h"
8
8
9 #include "Common/MimeTypesDef.h"
9 #include "Common/MimeTypesDef.h"
10 #include "Common/VisualizationDef.h"
10 #include "Common/VisualizationDef.h"
11
11
12 #include <Data/SqpRange.h>
12 #include <Data/SqpRange.h>
13 #include <DataSource/DataSourceController.h>
13 #include <Time/TimeController.h>
14 #include <Time/TimeController.h>
14 #include <Variable/Variable.h>
15 #include <Variable/Variable.h>
15 #include <Variable/VariableController.h>
16 #include <Variable/VariableController.h>
16
17
17 #include <Visualization/operations/FindVariableOperation.h>
18 #include <Visualization/operations/FindVariableOperation.h>
18
19
19 #include <DragAndDrop/DragDropGuiController.h>
20 #include <DragAndDrop/DragDropGuiController.h>
20 #include <QUuid>
21 #include <QUuid>
21 #include <SqpApplication.h>
22 #include <SqpApplication.h>
22 #include <cmath>
23 #include <cmath>
23
24
24 #include <QLayout>
25 #include <QLayout>
25
26
26 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
27 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
27
28
28 namespace {
29 namespace {
29
30
30 /**
31 /**
31 * Applies a function to all graphs of the zone represented by its layout
32 * Applies a function to all graphs of the zone represented by its layout
32 * @param layout the layout that contains graphs
33 * @param layout the layout that contains graphs
33 * @param fun the function to apply to each graph
34 * @param fun the function to apply to each graph
34 */
35 */
35 template <typename Fun>
36 template <typename Fun>
36 void processGraphs(QLayout &layout, Fun fun)
37 void processGraphs(QLayout &layout, Fun fun)
37 {
38 {
38 for (auto i = 0; i < layout.count(); ++i) {
39 for (auto i = 0; i < layout.count(); ++i) {
39 if (auto item = layout.itemAt(i)) {
40 if (auto item = layout.itemAt(i)) {
40 if (auto visualizationGraphWidget
41 if (auto visualizationGraphWidget
41 = qobject_cast<VisualizationGraphWidget *>(item->widget())) {
42 = qobject_cast<VisualizationGraphWidget *>(item->widget())) {
42 fun(*visualizationGraphWidget);
43 fun(*visualizationGraphWidget);
43 }
44 }
44 }
45 }
45 }
46 }
46 }
47 }
47
48
48 /// Generates a default name for a new graph, according to the number of graphs already displayed in
49 /// Generates a default name for a new graph, according to the number of graphs already displayed in
49 /// the zone
50 /// the zone
50 QString defaultGraphName(QLayout &layout)
51 QString defaultGraphName(QLayout &layout)
51 {
52 {
52 QSet<QString> existingNames;
53 QSet<QString> existingNames;
53 processGraphs(
54 processGraphs(
54 layout, [&existingNames](auto &graphWidget) { existingNames.insert(graphWidget.name()); });
55 layout, [&existingNames](auto &graphWidget) { existingNames.insert(graphWidget.name()); });
55
56
56 int zoneNum = 1;
57 int zoneNum = 1;
57 QString name;
58 QString name;
58 do {
59 do {
59 name = QObject::tr("Graph ").append(QString::number(zoneNum));
60 name = QObject::tr("Graph ").append(QString::number(zoneNum));
60 ++zoneNum;
61 ++zoneNum;
61 } while (existingNames.contains(name));
62 } while (existingNames.contains(name));
62
63
63 return name;
64 return name;
64 }
65 }
65
66
66 } // namespace
67 } // namespace
67
68
68 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate {
69 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate {
69
70
70 explicit VisualizationZoneWidgetPrivate()
71 explicit VisualizationZoneWidgetPrivate()
71 : m_SynchronisationGroupId{QUuid::createUuid()},
72 : m_SynchronisationGroupId{QUuid::createUuid()},
72 m_Synchronizer{std::make_unique<QCustomPlotSynchronizer>()}
73 m_Synchronizer{std::make_unique<QCustomPlotSynchronizer>()}
73 {
74 {
74 }
75 }
75 QUuid m_SynchronisationGroupId;
76 QUuid m_SynchronisationGroupId;
76 std::unique_ptr<IGraphSynchronizer> m_Synchronizer;
77 std::unique_ptr<IGraphSynchronizer> m_Synchronizer;
77
78
78 void dropGraph(int index, VisualizationZoneWidget *zoneWidget);
79 void dropGraph(int index, VisualizationZoneWidget *zoneWidget);
79 void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index,
80 void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index,
80 VisualizationZoneWidget *zoneWidget);
81 VisualizationZoneWidget *zoneWidget);
82 void dropProducts(const QVariantList &productsData, int index,
83 VisualizationZoneWidget *zoneWidget);
81 };
84 };
82
85
83 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
86 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
84 : VisualizationDragWidget{parent},
87 : VisualizationDragWidget{parent},
85 ui{new Ui::VisualizationZoneWidget},
88 ui{new Ui::VisualizationZoneWidget},
86 impl{spimpl::make_unique_impl<VisualizationZoneWidgetPrivate>()}
89 impl{spimpl::make_unique_impl<VisualizationZoneWidgetPrivate>()}
87 {
90 {
88 ui->setupUi(this);
91 ui->setupUi(this);
89
92
90 ui->zoneNameLabel->setText(name);
93 ui->zoneNameLabel->setText(name);
91
94
92 ui->dragDropContainer->setPlaceHolderType(DragDropGuiController::PlaceHolderType::Graph);
95 ui->dragDropContainer->setPlaceHolderType(DragDropGuiController::PlaceHolderType::Graph);
93 ui->dragDropContainer->setMimeType(MIME_TYPE_GRAPH,
96 ui->dragDropContainer->setMimeType(MIME_TYPE_GRAPH,
94 VisualizationDragDropContainer::DropBehavior::Inserted);
97 VisualizationDragDropContainer::DropBehavior::Inserted);
95 ui->dragDropContainer->setMimeType(
98 ui->dragDropContainer->setMimeType(
96 MIME_TYPE_VARIABLE_LIST, VisualizationDragDropContainer::DropBehavior::InsertedAndMerged);
99 MIME_TYPE_VARIABLE_LIST, VisualizationDragDropContainer::DropBehavior::InsertedAndMerged);
100 ui->dragDropContainer->setMimeType(
101 MIME_TYPE_PRODUCT_LIST, VisualizationDragDropContainer::DropBehavior::InsertedAndMerged);
97 ui->dragDropContainer->setMimeType(MIME_TYPE_TIME_RANGE,
102 ui->dragDropContainer->setMimeType(MIME_TYPE_TIME_RANGE,
98 VisualizationDragDropContainer::DropBehavior::Merged);
103 VisualizationDragDropContainer::DropBehavior::Merged);
99 ui->dragDropContainer->setMimeType(MIME_TYPE_ZONE,
104 ui->dragDropContainer->setMimeType(MIME_TYPE_ZONE,
100 VisualizationDragDropContainer::DropBehavior::Forbidden);
105 VisualizationDragDropContainer::DropBehavior::Forbidden);
101 ui->dragDropContainer->setMimeType(MIME_TYPE_SELECTION_ZONE,
106 ui->dragDropContainer->setMimeType(MIME_TYPE_SELECTION_ZONE,
102 VisualizationDragDropContainer::DropBehavior::Forbidden);
107 VisualizationDragDropContainer::DropBehavior::Forbidden);
103 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
108 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
104 return sqpApp->dragDropGuiController().checkMimeDataForVisualization(mimeData,
109 return sqpApp->dragDropGuiController().checkMimeDataForVisualization(mimeData,
105 ui->dragDropContainer);
110 ui->dragDropContainer);
106 });
111 });
107
112
108 auto acceptDragWidgetFun = [](auto dragWidget, auto mimeData) {
113 auto acceptDragWidgetFun = [](auto dragWidget, auto mimeData) {
109 if (!mimeData) {
114 if (!mimeData) {
110 return false;
115 return false;
111 }
116 }
112
117
113 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
118 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
114 auto variables = sqpApp->variableController().variablesForMimeData(
119 auto variables = sqpApp->variableController().variablesForMimeData(
115 mimeData->data(MIME_TYPE_VARIABLE_LIST));
120 mimeData->data(MIME_TYPE_VARIABLE_LIST));
116
121
117 if (variables.count() != 1) {
122 if (variables.count() != 1) {
118 return false;
123 return false;
119 }
124 }
120 auto variable = variables.first();
125 auto variable = variables.first();
121
126
122 if (auto graphWidget = dynamic_cast<const VisualizationGraphWidget *>(dragWidget)) {
127 if (auto graphWidget = dynamic_cast<const VisualizationGraphWidget *>(dragWidget)) {
123 return graphWidget->canDrop(*variable);
128 return graphWidget->canDrop(*variable);
124 }
129 }
125 }
130 }
126
131
127 return true;
132 return true;
128 };
133 };
129 ui->dragDropContainer->setAcceptDragWidgetFunction(acceptDragWidgetFun);
134 ui->dragDropContainer->setAcceptDragWidgetFunction(acceptDragWidgetFun);
130
135
131 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this,
136 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this,
132 &VisualizationZoneWidget::dropMimeData);
137 &VisualizationZoneWidget::dropMimeData);
133 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredOnWidget, this,
138 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredOnWidget, this,
134 &VisualizationZoneWidget::dropMimeDataOnGraph);
139 &VisualizationZoneWidget::dropMimeDataOnGraph);
135
140
136 // 'Close' options : widget is deleted when closed
141 // 'Close' options : widget is deleted when closed
137 setAttribute(Qt::WA_DeleteOnClose);
142 setAttribute(Qt::WA_DeleteOnClose);
138 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
143 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
139 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
144 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
140
145
141 // Synchronisation id
146 // Synchronisation id
142 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronizationGroupId",
147 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronizationGroupId",
143 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
148 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
144 }
149 }
145
150
146 VisualizationZoneWidget::~VisualizationZoneWidget()
151 VisualizationZoneWidget::~VisualizationZoneWidget()
147 {
152 {
148 delete ui;
153 delete ui;
149 }
154 }
150
155
151 void VisualizationZoneWidget::setZoneRange(const SqpRange &range)
156 void VisualizationZoneWidget::setZoneRange(const SqpRange &range)
152 {
157 {
153 if (auto graph = firstGraph()) {
158 if (auto graph = firstGraph()) {
154 graph->setGraphRange(range);
159 graph->setGraphRange(range);
155 }
160 }
156 else {
161 else {
157 qCWarning(LOG_VisualizationZoneWidget())
162 qCWarning(LOG_VisualizationZoneWidget())
158 << tr("setZoneRange:Cannot set the range of an empty zone.");
163 << tr("setZoneRange:Cannot set the range of an empty zone.");
159 }
164 }
160 }
165 }
161
166
162 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
167 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
163 {
168 {
164 // Synchronize new graph with others in the zone
169 // Synchronize new graph with others in the zone
165 impl->m_Synchronizer->addGraph(*graphWidget);
170 impl->m_Synchronizer->addGraph(*graphWidget);
166
171
167 ui->dragDropContainer->addDragWidget(graphWidget);
172 ui->dragDropContainer->addDragWidget(graphWidget);
168 }
173 }
169
174
170 void VisualizationZoneWidget::insertGraph(int index, VisualizationGraphWidget *graphWidget)
175 void VisualizationZoneWidget::insertGraph(int index, VisualizationGraphWidget *graphWidget)
171 {
176 {
172 // Synchronize new graph with others in the zone
177 // Synchronize new graph with others in the zone
173 impl->m_Synchronizer->addGraph(*graphWidget);
178 impl->m_Synchronizer->addGraph(*graphWidget);
174
179
175 ui->dragDropContainer->insertDragWidget(index, graphWidget);
180 ui->dragDropContainer->insertDragWidget(index, graphWidget);
176 }
181 }
177
182
178 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
183 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
179 {
184 {
180 return createGraph(variable, -1);
185 return createGraph(variable, -1);
181 }
186 }
182
187
183 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable,
188 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable,
184 int index)
189 int index)
185 {
190 {
186 auto graphWidget
191 auto graphWidget
187 = new VisualizationGraphWidget{defaultGraphName(*ui->dragDropContainer->layout()), this};
192 = new VisualizationGraphWidget{defaultGraphName(*ui->dragDropContainer->layout()), this};
188
193
189
194
190 // Set graph properties
195 // Set graph properties
191 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
196 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
192 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
197 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
193
198
194
199
195 // Lambda to synchronize zone widget
200 // Lambda to synchronize zone widget
196 auto synchronizeZoneWidget = [this, graphWidget](const SqpRange &graphRange,
201 auto synchronizeZoneWidget = [this, graphWidget](const SqpRange &graphRange,
197 const SqpRange &oldGraphRange) {
202 const SqpRange &oldGraphRange) {
198
203
199 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
204 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
200 auto frameLayout = ui->dragDropContainer->layout();
205 auto frameLayout = ui->dragDropContainer->layout();
201 for (auto i = 0; i < frameLayout->count(); ++i) {
206 for (auto i = 0; i < frameLayout->count(); ++i) {
202 auto graphChild
207 auto graphChild
203 = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
208 = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
204 if (graphChild && (graphChild != graphWidget)) {
209 if (graphChild && (graphChild != graphWidget)) {
205
210
206 auto graphChildRange = graphChild->graphRange();
211 auto graphChildRange = graphChild->graphRange();
207 switch (zoomType) {
212 switch (zoomType) {
208 case AcquisitionZoomType::ZoomIn: {
213 case AcquisitionZoomType::ZoomIn: {
209 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
214 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
210 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
215 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
211 graphChildRange.m_TStart += deltaLeft;
216 graphChildRange.m_TStart += deltaLeft;
212 graphChildRange.m_TEnd -= deltaRight;
217 graphChildRange.m_TEnd -= deltaRight;
213 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomIn");
218 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomIn");
214 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
219 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
215 << deltaLeft;
220 << deltaLeft;
216 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
221 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
217 << deltaRight;
222 << deltaRight;
218 qCDebug(LOG_VisualizationZoneWidget())
223 qCDebug(LOG_VisualizationZoneWidget())
219 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
224 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
220
225
221 break;
226 break;
222 }
227 }
223
228
224 case AcquisitionZoomType::ZoomOut: {
229 case AcquisitionZoomType::ZoomOut: {
225 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomOut");
230 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomOut");
226 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
231 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
227 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
232 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
228 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
233 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
229 << deltaLeft;
234 << deltaLeft;
230 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
235 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
231 << deltaRight;
236 << deltaRight;
232 qCDebug(LOG_VisualizationZoneWidget())
237 qCDebug(LOG_VisualizationZoneWidget())
233 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
238 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
234 graphChildRange.m_TStart -= deltaLeft;
239 graphChildRange.m_TStart -= deltaLeft;
235 graphChildRange.m_TEnd += deltaRight;
240 graphChildRange.m_TEnd += deltaRight;
236 break;
241 break;
237 }
242 }
238 case AcquisitionZoomType::PanRight: {
243 case AcquisitionZoomType::PanRight: {
239 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanRight");
244 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanRight");
240 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
245 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
241 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
246 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
242 graphChildRange.m_TStart += deltaLeft;
247 graphChildRange.m_TStart += deltaLeft;
243 graphChildRange.m_TEnd += deltaRight;
248 graphChildRange.m_TEnd += deltaRight;
244 qCDebug(LOG_VisualizationZoneWidget())
249 qCDebug(LOG_VisualizationZoneWidget())
245 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
250 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
246 break;
251 break;
247 }
252 }
248 case AcquisitionZoomType::PanLeft: {
253 case AcquisitionZoomType::PanLeft: {
249 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanLeft");
254 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanLeft");
250 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
255 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
251 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
256 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
252 graphChildRange.m_TStart -= deltaLeft;
257 graphChildRange.m_TStart -= deltaLeft;
253 graphChildRange.m_TEnd -= deltaRight;
258 graphChildRange.m_TEnd -= deltaRight;
254 break;
259 break;
255 }
260 }
256 case AcquisitionZoomType::Unknown: {
261 case AcquisitionZoomType::Unknown: {
257 qCDebug(LOG_VisualizationZoneWidget())
262 qCDebug(LOG_VisualizationZoneWidget())
258 << tr("Impossible to synchronize: zoom type unknown");
263 << tr("Impossible to synchronize: zoom type unknown");
259 break;
264 break;
260 }
265 }
261 default:
266 default:
262 qCCritical(LOG_VisualizationZoneWidget())
267 qCCritical(LOG_VisualizationZoneWidget())
263 << tr("Impossible to synchronize: zoom type not take into account");
268 << tr("Impossible to synchronize: zoom type not take into account");
264 // No action
269 // No action
265 break;
270 break;
266 }
271 }
267 graphChild->setFlags(GraphFlag::DisableAll);
272 graphChild->setFlags(GraphFlag::DisableAll);
268 qCDebug(LOG_VisualizationZoneWidget())
273 qCDebug(LOG_VisualizationZoneWidget())
269 << tr("TORM: Range before: ") << graphChild->graphRange();
274 << tr("TORM: Range before: ") << graphChild->graphRange();
270 qCDebug(LOG_VisualizationZoneWidget())
275 qCDebug(LOG_VisualizationZoneWidget())
271 << tr("TORM: Range after : ") << graphChildRange;
276 << tr("TORM: Range after : ") << graphChildRange;
272 qCDebug(LOG_VisualizationZoneWidget())
277 qCDebug(LOG_VisualizationZoneWidget())
273 << tr("TORM: child dt") << graphChildRange.m_TEnd - graphChildRange.m_TStart;
278 << tr("TORM: child dt") << graphChildRange.m_TEnd - graphChildRange.m_TStart;
274 graphChild->setGraphRange(graphChildRange);
279 graphChild->setGraphRange(graphChildRange);
275 graphChild->setFlags(GraphFlag::EnableAll);
280 graphChild->setFlags(GraphFlag::EnableAll);
276 }
281 }
277 }
282 }
278 };
283 };
279
284
280 // connection for synchronization
285 // connection for synchronization
281 connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
286 connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
282 connect(graphWidget, &VisualizationGraphWidget::variableAdded, this,
287 connect(graphWidget, &VisualizationGraphWidget::variableAdded, this,
283 &VisualizationZoneWidget::onVariableAdded);
288 &VisualizationZoneWidget::onVariableAdded);
284 connect(graphWidget, &VisualizationGraphWidget::variableAboutToBeRemoved, this,
289 connect(graphWidget, &VisualizationGraphWidget::variableAboutToBeRemoved, this,
285 &VisualizationZoneWidget::onVariableAboutToBeRemoved);
290 &VisualizationZoneWidget::onVariableAboutToBeRemoved);
286
291
287 auto range = SqpRange{};
292 auto range = SqpRange{};
288 if (auto firstGraph = this->firstGraph()) {
293 if (auto firstGraph = this->firstGraph()) {
289 // Case of a new graph in a existant zone
294 // Case of a new graph in a existant zone
290 range = firstGraph->graphRange();
295 range = firstGraph->graphRange();
291 }
296 }
292 else {
297 else {
293 // Case of a new graph as the first of the zone
298 // Case of a new graph as the first of the zone
294 range = variable->range();
299 range = variable->range();
295 }
300 }
296
301
297 this->insertGraph(index, graphWidget);
302 this->insertGraph(index, graphWidget);
298
303
299 graphWidget->addVariable(variable, range);
304 graphWidget->addVariable(variable, range);
300 graphWidget->setYRange(variable);
305 graphWidget->setYRange(variable);
301
306
302 return graphWidget;
307 return graphWidget;
303 }
308 }
304
309
305 VisualizationGraphWidget *
310 VisualizationGraphWidget *
306 VisualizationZoneWidget::createGraph(const QList<std::shared_ptr<Variable> > variables, int index)
311 VisualizationZoneWidget::createGraph(const QList<std::shared_ptr<Variable> > variables, int index)
307 {
312 {
308 if (variables.isEmpty()) {
313 if (variables.isEmpty()) {
309 return nullptr;
314 return nullptr;
310 }
315 }
311
316
312 auto graphWidget = createGraph(variables.first(), index);
317 auto graphWidget = createGraph(variables.first(), index);
313 for (auto variableIt = variables.cbegin() + 1; variableIt != variables.cend(); ++variableIt) {
318 for (auto variableIt = variables.cbegin() + 1; variableIt != variables.cend(); ++variableIt) {
314 graphWidget->addVariable(*variableIt, graphWidget->graphRange());
319 graphWidget->addVariable(*variableIt, graphWidget->graphRange());
315 }
320 }
316
321
317 return graphWidget;
322 return graphWidget;
318 }
323 }
319
324
320 VisualizationGraphWidget *VisualizationZoneWidget::firstGraph() const
325 VisualizationGraphWidget *VisualizationZoneWidget::firstGraph() const
321 {
326 {
322 VisualizationGraphWidget *firstGraph = nullptr;
327 VisualizationGraphWidget *firstGraph = nullptr;
323 auto layout = ui->dragDropContainer->layout();
328 auto layout = ui->dragDropContainer->layout();
324 if (layout->count() > 0) {
329 if (layout->count() > 0) {
325 if (auto visualizationGraphWidget
330 if (auto visualizationGraphWidget
326 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
331 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
327 firstGraph = visualizationGraphWidget;
332 firstGraph = visualizationGraphWidget;
328 }
333 }
329 }
334 }
330
335
331 return firstGraph;
336 return firstGraph;
332 }
337 }
333
338
334 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
339 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
335 {
340 {
336 if (visitor) {
341 if (visitor) {
337 visitor->visitEnter(this);
342 visitor->visitEnter(this);
338
343
339 // Apply visitor to graph children: widgets different from graphs are not visited (no
344 // Apply visitor to graph children: widgets different from graphs are not visited (no
340 // action)
345 // action)
341 processGraphs(
346 processGraphs(
342 *ui->dragDropContainer->layout(),
347 *ui->dragDropContainer->layout(),
343 [visitor](VisualizationGraphWidget &graphWidget) { graphWidget.accept(visitor); });
348 [visitor](VisualizationGraphWidget &graphWidget) { graphWidget.accept(visitor); });
344
349
345 visitor->visitLeave(this);
350 visitor->visitLeave(this);
346 }
351 }
347 else {
352 else {
348 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
353 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
349 }
354 }
350 }
355 }
351
356
352 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
357 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
353 {
358 {
354 // A tab can always accomodate a variable
359 // A tab can always accomodate a variable
355 Q_UNUSED(variable);
360 Q_UNUSED(variable);
356 return true;
361 return true;
357 }
362 }
358
363
359 bool VisualizationZoneWidget::contains(const Variable &variable) const
364 bool VisualizationZoneWidget::contains(const Variable &variable) const
360 {
365 {
361 Q_UNUSED(variable);
366 Q_UNUSED(variable);
362 return false;
367 return false;
363 }
368 }
364
369
365 QString VisualizationZoneWidget::name() const
370 QString VisualizationZoneWidget::name() const
366 {
371 {
367 return ui->zoneNameLabel->text();
372 return ui->zoneNameLabel->text();
368 }
373 }
369
374
370 QMimeData *VisualizationZoneWidget::mimeData(const QPoint &position) const
375 QMimeData *VisualizationZoneWidget::mimeData(const QPoint &position) const
371 {
376 {
372 Q_UNUSED(position);
377 Q_UNUSED(position);
373
378
374 auto mimeData = new QMimeData;
379 auto mimeData = new QMimeData;
375 mimeData->setData(MIME_TYPE_ZONE, QByteArray{});
380 mimeData->setData(MIME_TYPE_ZONE, QByteArray{});
376
381
377 if (auto firstGraph = this->firstGraph()) {
382 if (auto firstGraph = this->firstGraph()) {
378 auto timeRangeData = TimeController::mimeDataForTimeRange(firstGraph->graphRange());
383 auto timeRangeData = TimeController::mimeDataForTimeRange(firstGraph->graphRange());
379 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
384 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
380 }
385 }
381
386
382 return mimeData;
387 return mimeData;
383 }
388 }
384
389
385 bool VisualizationZoneWidget::isDragAllowed() const
390 bool VisualizationZoneWidget::isDragAllowed() const
386 {
391 {
387 return true;
392 return true;
388 }
393 }
389
394
390 void VisualizationZoneWidget::notifyMouseMoveInGraph(const QPointF &graphPosition,
395 void VisualizationZoneWidget::notifyMouseMoveInGraph(const QPointF &graphPosition,
391 const QPointF &plotPosition,
396 const QPointF &plotPosition,
392 VisualizationGraphWidget *graphWidget)
397 VisualizationGraphWidget *graphWidget)
393 {
398 {
394 processGraphs(*ui->dragDropContainer->layout(), [&graphPosition, &plotPosition, &graphWidget](
399 processGraphs(*ui->dragDropContainer->layout(), [&graphPosition, &plotPosition, &graphWidget](
395 VisualizationGraphWidget &processedGraph) {
400 VisualizationGraphWidget &processedGraph) {
396
401
397 switch (sqpApp->plotsCursorMode()) {
402 switch (sqpApp->plotsCursorMode()) {
398 case SqpApplication::PlotsCursorMode::Vertical:
403 case SqpApplication::PlotsCursorMode::Vertical:
399 processedGraph.removeHorizontalCursor();
404 processedGraph.removeHorizontalCursor();
400 processedGraph.addVerticalCursorAtViewportPosition(graphPosition.x());
405 processedGraph.addVerticalCursorAtViewportPosition(graphPosition.x());
401 break;
406 break;
402 case SqpApplication::PlotsCursorMode::Temporal:
407 case SqpApplication::PlotsCursorMode::Temporal:
403 processedGraph.addVerticalCursor(plotPosition.x());
408 processedGraph.addVerticalCursor(plotPosition.x());
404 processedGraph.removeHorizontalCursor();
409 processedGraph.removeHorizontalCursor();
405 break;
410 break;
406 case SqpApplication::PlotsCursorMode::Horizontal:
411 case SqpApplication::PlotsCursorMode::Horizontal:
407 processedGraph.removeVerticalCursor();
412 processedGraph.removeVerticalCursor();
408 if (&processedGraph == graphWidget) {
413 if (&processedGraph == graphWidget) {
409 processedGraph.addHorizontalCursorAtViewportPosition(graphPosition.y());
414 processedGraph.addHorizontalCursorAtViewportPosition(graphPosition.y());
410 }
415 }
411 else {
416 else {
412 processedGraph.removeHorizontalCursor();
417 processedGraph.removeHorizontalCursor();
413 }
418 }
414 break;
419 break;
415 case SqpApplication::PlotsCursorMode::Cross:
420 case SqpApplication::PlotsCursorMode::Cross:
416 if (&processedGraph == graphWidget) {
421 if (&processedGraph == graphWidget) {
417 processedGraph.addVerticalCursorAtViewportPosition(graphPosition.x());
422 processedGraph.addVerticalCursorAtViewportPosition(graphPosition.x());
418 processedGraph.addHorizontalCursorAtViewportPosition(graphPosition.y());
423 processedGraph.addHorizontalCursorAtViewportPosition(graphPosition.y());
419 }
424 }
420 else {
425 else {
421 processedGraph.removeHorizontalCursor();
426 processedGraph.removeHorizontalCursor();
422 processedGraph.removeVerticalCursor();
427 processedGraph.removeVerticalCursor();
423 }
428 }
424 break;
429 break;
425 case SqpApplication::PlotsCursorMode::NoCursor:
430 case SqpApplication::PlotsCursorMode::NoCursor:
426 processedGraph.removeHorizontalCursor();
431 processedGraph.removeHorizontalCursor();
427 processedGraph.removeVerticalCursor();
432 processedGraph.removeVerticalCursor();
428 break;
433 break;
429 }
434 }
430
435
431
436
432 });
437 });
433 }
438 }
434
439
435 void VisualizationZoneWidget::notifyMouseLeaveGraph(VisualizationGraphWidget *graphWidget)
440 void VisualizationZoneWidget::notifyMouseLeaveGraph(VisualizationGraphWidget *graphWidget)
436 {
441 {
437 processGraphs(*ui->dragDropContainer->layout(), [](VisualizationGraphWidget &processedGraph) {
442 processGraphs(*ui->dragDropContainer->layout(), [](VisualizationGraphWidget &processedGraph) {
438 processedGraph.removeHorizontalCursor();
443 processedGraph.removeHorizontalCursor();
439 processedGraph.removeVerticalCursor();
444 processedGraph.removeVerticalCursor();
440 });
445 });
441 }
446 }
442
447
443 void VisualizationZoneWidget::closeEvent(QCloseEvent *event)
448 void VisualizationZoneWidget::closeEvent(QCloseEvent *event)
444 {
449 {
445 // Closes graphs in the zone
450 // Closes graphs in the zone
446 processGraphs(*ui->dragDropContainer->layout(),
451 processGraphs(*ui->dragDropContainer->layout(),
447 [](VisualizationGraphWidget &graphWidget) { graphWidget.close(); });
452 [](VisualizationGraphWidget &graphWidget) { graphWidget.close(); });
448
453
449 // Delete synchronization group from variable controller
454 // Delete synchronization group from variable controller
450 QMetaObject::invokeMethod(&sqpApp->variableController(), "onRemoveSynchronizationGroupId",
455 QMetaObject::invokeMethod(&sqpApp->variableController(), "onRemoveSynchronizationGroupId",
451 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
456 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
452
457
453 QWidget::closeEvent(event);
458 QWidget::closeEvent(event);
454 }
459 }
455
460
456 void VisualizationZoneWidget::onVariableAdded(std::shared_ptr<Variable> variable)
461 void VisualizationZoneWidget::onVariableAdded(std::shared_ptr<Variable> variable)
457 {
462 {
458 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronized",
463 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronized",
459 Qt::QueuedConnection, Q_ARG(std::shared_ptr<Variable>, variable),
464 Qt::QueuedConnection, Q_ARG(std::shared_ptr<Variable>, variable),
460 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
465 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
461 }
466 }
462
467
463 void VisualizationZoneWidget::onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable)
468 void VisualizationZoneWidget::onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable)
464 {
469 {
465 QMetaObject::invokeMethod(&sqpApp->variableController(), "desynchronize", Qt::QueuedConnection,
470 QMetaObject::invokeMethod(&sqpApp->variableController(), "desynchronize", Qt::QueuedConnection,
466 Q_ARG(std::shared_ptr<Variable>, variable),
471 Q_ARG(std::shared_ptr<Variable>, variable),
467 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
472 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
468 }
473 }
469
474
470 void VisualizationZoneWidget::dropMimeData(int index, const QMimeData *mimeData)
475 void VisualizationZoneWidget::dropMimeData(int index, const QMimeData *mimeData)
471 {
476 {
472 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
477 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
473 impl->dropGraph(index, this);
478 impl->dropGraph(index, this);
474 }
479 }
475 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
480 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
476 auto variables = sqpApp->variableController().variablesForMimeData(
481 auto variables = sqpApp->variableController().variablesForMimeData(
477 mimeData->data(MIME_TYPE_VARIABLE_LIST));
482 mimeData->data(MIME_TYPE_VARIABLE_LIST));
478 impl->dropVariables(variables, index, this);
483 impl->dropVariables(variables, index, this);
479 }
484 }
485 else if (mimeData->hasFormat(MIME_TYPE_PRODUCT_LIST)) {
486 auto products = sqpApp->dataSourceController().productsDataForMimeData(
487 mimeData->data(MIME_TYPE_PRODUCT_LIST));
488 impl->dropProducts(products, index, this);
489 }
480 else {
490 else {
481 qCWarning(LOG_VisualizationZoneWidget())
491 qCWarning(LOG_VisualizationZoneWidget())
482 << tr("VisualizationZoneWidget::dropMimeData, unknown MIME data received.");
492 << tr("VisualizationZoneWidget::dropMimeData, unknown MIME data received.");
483 }
493 }
484 }
494 }
485
495
486 void VisualizationZoneWidget::dropMimeDataOnGraph(VisualizationDragWidget *dragWidget,
496 void VisualizationZoneWidget::dropMimeDataOnGraph(VisualizationDragWidget *dragWidget,
487 const QMimeData *mimeData)
497 const QMimeData *mimeData)
488 {
498 {
489 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(dragWidget);
499 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(dragWidget);
490 if (!graphWidget) {
500 if (!graphWidget) {
491 qCWarning(LOG_VisualizationZoneWidget())
501 qCWarning(LOG_VisualizationZoneWidget())
492 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, dropping in an unknown widget, "
502 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, dropping in an unknown widget, "
493 "drop aborted");
503 "drop aborted");
494 Q_ASSERT(false);
504 Q_ASSERT(false);
495 return;
505 return;
496 }
506 }
497
507
498 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
508 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
499 auto variables = sqpApp->variableController().variablesForMimeData(
509 auto variables = sqpApp->variableController().variablesForMimeData(
500 mimeData->data(MIME_TYPE_VARIABLE_LIST));
510 mimeData->data(MIME_TYPE_VARIABLE_LIST));
501 for (const auto &var : variables) {
511 for (const auto &var : variables) {
502 graphWidget->addVariable(var, graphWidget->graphRange());
512 graphWidget->addVariable(var, graphWidget->graphRange());
503 }
513 }
504 }
514 }
515 else if (mimeData->hasFormat(MIME_TYPE_PRODUCT_LIST)) {
516 auto products = sqpApp->dataSourceController().productsDataForMimeData(
517 mimeData->data(MIME_TYPE_PRODUCT_LIST));
518
519 auto context = new QObject{this};
520 connect(&sqpApp->variableController(), &VariableController::variableAdded, context,
521 [this, graphWidget, context](auto variable) {
522 graphWidget->addVariable(variable, graphWidget->graphRange());
523 delete context; // removes the connection
524 },
525 Qt::QueuedConnection);
526
527 auto productData = products.first().toHash();
528 QMetaObject::invokeMethod(&sqpApp->dataSourceController(), "requestVariable",
529 Qt::QueuedConnection, Q_ARG(QVariantHash, productData));
530 }
505 else if (mimeData->hasFormat(MIME_TYPE_TIME_RANGE)) {
531 else if (mimeData->hasFormat(MIME_TYPE_TIME_RANGE)) {
506 auto range = TimeController::timeRangeForMimeData(mimeData->data(MIME_TYPE_TIME_RANGE));
532 auto range = TimeController::timeRangeForMimeData(mimeData->data(MIME_TYPE_TIME_RANGE));
507 graphWidget->setGraphRange(range);
533 graphWidget->setGraphRange(range);
508 }
534 }
509 else {
535 else {
510 qCWarning(LOG_VisualizationZoneWidget())
536 qCWarning(LOG_VisualizationZoneWidget())
511 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, unknown MIME data received.");
537 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, unknown MIME data received.");
512 }
538 }
513 }
539 }
514
540
515 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropGraph(
541 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropGraph(
516 int index, VisualizationZoneWidget *zoneWidget)
542 int index, VisualizationZoneWidget *zoneWidget)
517 {
543 {
518 auto &helper = sqpApp->dragDropGuiController();
544 auto &helper = sqpApp->dragDropGuiController();
519
545
520 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
546 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
521 if (!graphWidget) {
547 if (!graphWidget) {
522 qCWarning(LOG_VisualizationZoneWidget())
548 qCWarning(LOG_VisualizationZoneWidget())
523 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the dropped graph is not "
549 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the dropped graph is not "
524 "found or invalid.");
550 "found or invalid.");
525 Q_ASSERT(false);
551 Q_ASSERT(false);
526 return;
552 return;
527 }
553 }
528
554
529 auto parentDragDropContainer
555 auto parentDragDropContainer
530 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
556 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
531 if (!parentDragDropContainer) {
557 if (!parentDragDropContainer) {
532 qCWarning(LOG_VisualizationZoneWidget())
558 qCWarning(LOG_VisualizationZoneWidget())
533 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the parent container of "
559 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the parent container of "
534 "the dropped graph is not found.");
560 "the dropped graph is not found.");
535 Q_ASSERT(false);
561 Q_ASSERT(false);
536 return;
562 return;
537 }
563 }
538
564
539 const auto &variables = graphWidget->variables();
565 const auto &variables = graphWidget->variables();
540
566
541 if (parentDragDropContainer != zoneWidget->ui->dragDropContainer && !variables.isEmpty()) {
567 if (parentDragDropContainer != zoneWidget->ui->dragDropContainer && !variables.isEmpty()) {
542 // The drop didn't occur in the same zone
568 // The drop didn't occur in the same zone
543
569
544 // Abort the requests for the variables (if any)
570 // Abort the requests for the variables (if any)
545 // Commented, because it's not sure if it's needed or not
571 // Commented, because it's not sure if it's needed or not
546 // for (const auto& var : variables)
572 // for (const auto& var : variables)
547 //{
573 //{
548 // sqpApp->variableController().onAbortProgressRequested(var);
574 // sqpApp->variableController().onAbortProgressRequested(var);
549 //}
575 //}
550
576
551 auto previousParentZoneWidget = graphWidget->parentZoneWidget();
577 auto previousParentZoneWidget = graphWidget->parentZoneWidget();
552 auto nbGraph = parentDragDropContainer->countDragWidget();
578 auto nbGraph = parentDragDropContainer->countDragWidget();
553 if (nbGraph == 1) {
579 if (nbGraph == 1) {
554 // This is the only graph in the previous zone, close the zone
580 // This is the only graph in the previous zone, close the zone
555 helper.delayedCloseWidget(previousParentZoneWidget);
581 helper.delayedCloseWidget(previousParentZoneWidget);
556 }
582 }
557 else {
583 else {
558 // Close the graph
584 // Close the graph
559 helper.delayedCloseWidget(graphWidget);
585 helper.delayedCloseWidget(graphWidget);
560 }
586 }
561
587
562 // Creates the new graph in the zone
588 // Creates the new graph in the zone
563 auto newGraphWidget = zoneWidget->createGraph(variables, index);
589 auto newGraphWidget = zoneWidget->createGraph(variables, index);
564 newGraphWidget->addSelectionZones(graphWidget->selectionZoneRanges());
590 newGraphWidget->addSelectionZones(graphWidget->selectionZoneRanges());
565 }
591 }
566 else {
592 else {
567 // The drop occurred in the same zone or the graph is empty
593 // The drop occurred in the same zone or the graph is empty
568 // Simple move of the graph, no variable operation associated
594 // Simple move of the graph, no variable operation associated
569 parentDragDropContainer->layout()->removeWidget(graphWidget);
595 parentDragDropContainer->layout()->removeWidget(graphWidget);
570
596
571 if (variables.isEmpty() && parentDragDropContainer != zoneWidget->ui->dragDropContainer) {
597 if (variables.isEmpty() && parentDragDropContainer != zoneWidget->ui->dragDropContainer) {
572 // The graph is empty and dropped in a different zone.
598 // The graph is empty and dropped in a different zone.
573 // Take the range of the first graph in the zone (if existing).
599 // Take the range of the first graph in the zone (if existing).
574 auto layout = zoneWidget->ui->dragDropContainer->layout();
600 auto layout = zoneWidget->ui->dragDropContainer->layout();
575 if (layout->count() > 0) {
601 if (layout->count() > 0) {
576 if (auto visualizationGraphWidget
602 if (auto visualizationGraphWidget
577 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
603 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
578 graphWidget->setGraphRange(visualizationGraphWidget->graphRange());
604 graphWidget->setGraphRange(visualizationGraphWidget->graphRange());
579 }
605 }
580 }
606 }
581 }
607 }
582
608
583 zoneWidget->ui->dragDropContainer->insertDragWidget(index, graphWidget);
609 zoneWidget->ui->dragDropContainer->insertDragWidget(index, graphWidget);
584 }
610 }
585 }
611 }
586
612
587 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropVariables(
613 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropVariables(
588 const QList<std::shared_ptr<Variable> > &variables, int index,
614 const QList<std::shared_ptr<Variable> > &variables, int index,
589 VisualizationZoneWidget *zoneWidget)
615 VisualizationZoneWidget *zoneWidget)
590 {
616 {
591 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
617 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
592 // compatible variable here
618 // compatible variable here
593 if (variables.count() > 1) {
619 if (variables.count() > 1) {
594 qCWarning(LOG_VisualizationZoneWidget())
620 qCWarning(LOG_VisualizationZoneWidget())
595 << tr("VisualizationZoneWidget::dropVariables, dropping multiple variables, operation "
621 << tr("VisualizationZoneWidget::dropVariables, dropping multiple variables, operation "
596 "aborted.");
622 "aborted.");
597 return;
623 return;
598 }
624 }
599
625
600 zoneWidget->createGraph(variables, index);
626 zoneWidget->createGraph(variables, index);
601 }
627 }
628
629 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropProducts(
630 const QVariantList &productsData, int index, VisualizationZoneWidget *zoneWidget)
631 {
632 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
633 // compatible variable here
634 if (productsData.count() != 1) {
635 qCWarning(LOG_VisualizationZoneWidget())
636 << tr("VisualizationTabWidget::dropProducts, dropping multiple products, operation "
637 "aborted.");
638 return;
639 }
640
641 auto context = new QObject{zoneWidget};
642 connect(&sqpApp->variableController(), &VariableController::variableAdded, context,
643 [this, index, zoneWidget, context](auto variable) {
644 zoneWidget->createGraph(variable, index);
645 delete context; // removes the connection
646 },
647 Qt::QueuedConnection);
648
649 auto productData = productsData.first().toHash();
650 QMetaObject::invokeMethod(&sqpApp->dataSourceController(), "requestVariable",
651 Qt::QueuedConnection, Q_ARG(QVariantHash, productData));
652 }
@@ -1,148 +1,145
1 <?xml version="1.0" encoding="UTF-8"?>
1 <?xml version="1.0" encoding="UTF-8"?>
2 <ui version="4.0">
2 <ui version="4.0">
3 <class>CatalogueEventsWidget</class>
3 <class>CatalogueEventsWidget</class>
4 <widget class="QWidget" name="CatalogueEventsWidget">
4 <widget class="QWidget" name="CatalogueEventsWidget">
5 <property name="geometry">
5 <property name="geometry">
6 <rect>
6 <rect>
7 <x>0</x>
7 <x>0</x>
8 <y>0</y>
8 <y>0</y>
9 <width>566</width>
9 <width>566</width>
10 <height>258</height>
10 <height>258</height>
11 </rect>
11 </rect>
12 </property>
12 </property>
13 <property name="windowTitle">
13 <property name="windowTitle">
14 <string>Form</string>
14 <string>Form</string>
15 </property>
15 </property>
16 <layout class="QVBoxLayout" name="verticalLayout">
16 <layout class="QVBoxLayout" name="verticalLayout">
17 <property name="leftMargin">
17 <property name="leftMargin">
18 <number>0</number>
18 <number>0</number>
19 </property>
19 </property>
20 <property name="topMargin">
20 <property name="topMargin">
21 <number>0</number>
21 <number>0</number>
22 </property>
22 </property>
23 <property name="rightMargin">
23 <property name="rightMargin">
24 <number>0</number>
24 <number>0</number>
25 </property>
25 </property>
26 <property name="bottomMargin">
26 <property name="bottomMargin">
27 <number>0</number>
27 <number>0</number>
28 </property>
28 </property>
29 <item>
29 <item>
30 <layout class="QHBoxLayout" name="horizontalLayout">
30 <layout class="QHBoxLayout" name="horizontalLayout">
31 <item>
31 <item>
32 <widget class="QToolButton" name="btnAdd">
32 <widget class="QToolButton" name="btnAdd">
33 <property name="enabled">
33 <property name="enabled">
34 <bool>false</bool>
34 <bool>false</bool>
35 </property>
35 </property>
36 <property name="text">
36 <property name="text">
37 <string>+</string>
37 <string>+</string>
38 </property>
38 </property>
39 <property name="icon">
39 <property name="icon">
40 <iconset resource="../../resources/sqpguiresources.qrc">
40 <iconset resource="../../resources/sqpguiresources.qrc">
41 <normaloff>:/icones/add.png</normaloff>:/icones/add.png</iconset>
41 <normaloff>:/icones/add.png</normaloff>:/icones/add.png</iconset>
42 </property>
42 </property>
43 <property name="autoRaise">
43 <property name="autoRaise">
44 <bool>true</bool>
44 <bool>true</bool>
45 </property>
45 </property>
46 </widget>
46 </widget>
47 </item>
47 </item>
48 <item>
48 <item>
49 <widget class="QToolButton" name="btnRemove">
49 <widget class="QToolButton" name="btnRemove">
50 <property name="text">
50 <property name="text">
51 <string> - </string>
51 <string> - </string>
52 </property>
52 </property>
53 <property name="icon">
53 <property name="icon">
54 <iconset resource="../../resources/sqpguiresources.qrc">
54 <iconset resource="../../resources/sqpguiresources.qrc">
55 <normaloff>:/icones/remove.png</normaloff>:/icones/remove.png</iconset>
55 <normaloff>:/icones/remove.png</normaloff>:/icones/remove.png</iconset>
56 </property>
56 </property>
57 <property name="autoRaise">
57 <property name="autoRaise">
58 <bool>true</bool>
58 <bool>true</bool>
59 </property>
59 </property>
60 </widget>
60 </widget>
61 </item>
61 </item>
62 <item>
62 <item>
63 <widget class="Line" name="line">
63 <widget class="Line" name="line">
64 <property name="orientation">
64 <property name="orientation">
65 <enum>Qt::Vertical</enum>
65 <enum>Qt::Vertical</enum>
66 </property>
66 </property>
67 </widget>
67 </widget>
68 </item>
68 </item>
69 <item>
69 <item>
70 <widget class="QToolButton" name="btnTime">
70 <widget class="QToolButton" name="btnTime">
71 <property name="text">
71 <property name="text">
72 <string>T</string>
72 <string>T</string>
73 </property>
73 </property>
74 <property name="icon">
74 <property name="icon">
75 <iconset resource="../../resources/sqpguiresources.qrc">
75 <iconset resource="../../resources/sqpguiresources.qrc">
76 <normaloff>:/icones/time.png</normaloff>:/icones/time.png</iconset>
76 <normaloff>:/icones/time.png</normaloff>:/icones/time.png</iconset>
77 </property>
77 </property>
78 <property name="checkable">
78 <property name="checkable">
79 <bool>true</bool>
79 <bool>true</bool>
80 </property>
80 </property>
81 <property name="autoRaise">
81 <property name="autoRaise">
82 <bool>true</bool>
82 <bool>true</bool>
83 </property>
83 </property>
84 </widget>
84 </widget>
85 </item>
85 </item>
86 <item>
86 <item>
87 <widget class="QToolButton" name="btnChart">
87 <widget class="QToolButton" name="btnChart">
88 <property name="enabled">
89 <bool>false</bool>
90 </property>
91 <property name="text">
88 <property name="text">
92 <string>G</string>
89 <string>G</string>
93 </property>
90 </property>
94 <property name="icon">
91 <property name="icon">
95 <iconset resource="../../resources/sqpguiresources.qrc">
92 <iconset resource="../../resources/sqpguiresources.qrc">
96 <normaloff>:/icones/chart.png</normaloff>:/icones/chart.png</iconset>
93 <normaloff>:/icones/chart.png</normaloff>:/icones/chart.png</iconset>
97 </property>
94 </property>
98 <property name="checkable">
95 <property name="checkable">
99 <bool>true</bool>
96 <bool>true</bool>
100 </property>
97 </property>
101 <property name="autoRaise">
98 <property name="autoRaise">
102 <bool>true</bool>
99 <bool>true</bool>
103 </property>
100 </property>
104 </widget>
101 </widget>
105 </item>
102 </item>
106 <item>
103 <item>
107 <widget class="Line" name="line_2">
104 <widget class="Line" name="line_2">
108 <property name="orientation">
105 <property name="orientation">
109 <enum>Qt::Vertical</enum>
106 <enum>Qt::Vertical</enum>
110 </property>
107 </property>
111 </widget>
108 </widget>
112 </item>
109 </item>
113 <item>
110 <item>
114 <widget class="QLineEdit" name="lineEdit">
111 <widget class="QLineEdit" name="lineEdit">
115 <property name="enabled">
112 <property name="enabled">
116 <bool>false</bool>
113 <bool>false</bool>
117 </property>
114 </property>
118 </widget>
115 </widget>
119 </item>
116 </item>
120 </layout>
117 </layout>
121 </item>
118 </item>
122 <item>
119 <item>
123 <widget class="QTreeView" name="treeView">
120 <widget class="QTreeView" name="treeView">
124 <property name="dragEnabled">
121 <property name="dragEnabled">
125 <bool>true</bool>
122 <bool>true</bool>
126 </property>
123 </property>
127 <property name="dragDropMode">
124 <property name="dragDropMode">
128 <enum>QAbstractItemView::DragDrop</enum>
125 <enum>QAbstractItemView::DragDrop</enum>
129 </property>
126 </property>
130 <property name="selectionMode">
127 <property name="selectionMode">
131 <enum>QAbstractItemView::ExtendedSelection</enum>
128 <enum>QAbstractItemView::ExtendedSelection</enum>
132 </property>
129 </property>
133 <property name="selectionBehavior">
130 <property name="selectionBehavior">
134 <enum>QAbstractItemView::SelectRows</enum>
131 <enum>QAbstractItemView::SelectRows</enum>
135 </property>
132 </property>
136 <attribute name="headerStretchLastSection">
133 <attribute name="headerStretchLastSection">
137 <bool>false</bool>
134 <bool>false</bool>
138 </attribute>
135 </attribute>
139 </widget>
136 </widget>
140 </item>
137 </item>
141 </layout>
138 </layout>
142 </widget>
139 </widget>
143 <resources>
140 <resources>
144 <include location="../../resources/sqpguiresources.qrc"/>
141 <include location="../../resources/sqpguiresources.qrc"/>
145 <include location="../../resources/sqpguiresources.qrc"/>
142 <include location="../../resources/sqpguiresources.qrc"/>
146 </resources>
143 </resources>
147 <connections/>
144 <connections/>
148 </ui>
145 </ui>
@@ -1,21 +1,21
1 #ifndef SCIQLOP_AMDARESULTPARSER_H
1 #ifndef SCIQLOP_AMDARESULTPARSER_H
2 #define SCIQLOP_AMDARESULTPARSER_H
2 #define SCIQLOP_AMDARESULTPARSER_H
3
3
4 #include "AmdaGlobal.h"
4 #include "AmdaGlobal.h"
5
5
6 #include <Data/DataSeriesType.h>
7
6 #include <QLoggingCategory>
8 #include <QLoggingCategory>
7
9
8 #include <memory>
10 #include <memory>
9
11
10 class IDataSeries;
12 class IDataSeries;
11
13
12 Q_DECLARE_LOGGING_CATEGORY(LOG_AmdaResultParser)
14 Q_DECLARE_LOGGING_CATEGORY(LOG_AmdaResultParser)
13
15
14 struct SCIQLOP_AMDA_EXPORT AmdaResultParser {
16 struct SCIQLOP_AMDA_EXPORT AmdaResultParser {
15 enum class ValueType { SCALAR, SPECTROGRAM, VECTOR, UNKNOWN };
16
17 static std::shared_ptr<IDataSeries> readTxt(const QString &filePath,
17 static std::shared_ptr<IDataSeries> readTxt(const QString &filePath,
18 ValueType valueType) noexcept;
18 DataSeriesType valueType) noexcept;
19 };
19 };
20
20
21 #endif // SCIQLOP_AMDARESULTPARSER_H
21 #endif // SCIQLOP_AMDARESULTPARSER_H
@@ -1,288 +1,274
1 #include "AmdaProvider.h"
1 #include "AmdaProvider.h"
2 #include "AmdaDefs.h"
2 #include "AmdaDefs.h"
3 #include "AmdaResultParser.h"
3 #include "AmdaResultParser.h"
4 #include "AmdaServer.h"
4 #include "AmdaServer.h"
5
5
6 #include <Common/DateUtils.h>
6 #include <Common/DateUtils.h>
7 #include <Data/DataProviderParameters.h>
7 #include <Data/DataProviderParameters.h>
8 #include <Network/NetworkController.h>
8 #include <Network/NetworkController.h>
9 #include <SqpApplication.h>
9 #include <SqpApplication.h>
10 #include <Variable/Variable.h>
10 #include <Variable/Variable.h>
11
11
12 #include <QNetworkAccessManager>
12 #include <QNetworkAccessManager>
13 #include <QNetworkReply>
13 #include <QNetworkReply>
14 #include <QTemporaryFile>
14 #include <QTemporaryFile>
15 #include <QThread>
15 #include <QThread>
16
16
17 Q_LOGGING_CATEGORY(LOG_AmdaProvider, "AmdaProvider")
17 Q_LOGGING_CATEGORY(LOG_AmdaProvider, "AmdaProvider")
18
18
19 namespace {
19 namespace {
20
20
21 /// URL format for a request on AMDA server. The parameters are as follows:
21 /// URL format for a request on AMDA server. The parameters are as follows:
22 /// - %1: server URL
22 /// - %1: server URL
23 /// - %2: start date
23 /// - %2: start date
24 /// - %3: end date
24 /// - %3: end date
25 /// - %4: parameter id
25 /// - %4: parameter id
26 /// AMDA V2: http://amdatest.irap.omp.eu/php/rest/
26 /// AMDA V2: http://amdatest.irap.omp.eu/php/rest/
27 const auto AMDA_URL_FORMAT = QStringLiteral(
27 const auto AMDA_URL_FORMAT = QStringLiteral(
28 "http://%1/php/rest/"
28 "http://%1/php/rest/"
29 "getParameter.php?startTime=%2&stopTime=%3&parameterID=%4&outputFormat=ASCII&"
29 "getParameter.php?startTime=%2&stopTime=%3&parameterID=%4&outputFormat=ASCII&"
30 "timeFormat=ISO8601&gzip=0");
30 "timeFormat=ISO8601&gzip=0");
31
31
32 /// Dates format passed in the URL (e.g 2013-09-23T09:00)
32 /// Dates format passed in the URL (e.g 2013-09-23T09:00)
33 const auto AMDA_TIME_FORMAT = QStringLiteral("yyyy-MM-ddThh:mm:ss");
33 const auto AMDA_TIME_FORMAT = QStringLiteral("yyyy-MM-ddThh:mm:ss");
34
34
35 /// Formats a time to a date that can be passed in URL
35 /// Formats a time to a date that can be passed in URL
36 QString dateFormat(double sqpRange) noexcept
36 QString dateFormat(double sqpRange) noexcept
37 {
37 {
38 auto dateTime = DateUtils::dateTime(sqpRange);
38 auto dateTime = DateUtils::dateTime(sqpRange);
39 return dateTime.toString(AMDA_TIME_FORMAT);
39 return dateTime.toString(AMDA_TIME_FORMAT);
40 }
40 }
41
41
42 AmdaResultParser::ValueType valueType(const QString &valueType)
43 {
44 if (valueType == QStringLiteral("scalar")) {
45 return AmdaResultParser::ValueType::SCALAR;
46 }
47 else if (valueType == QStringLiteral("spectrogram")) {
48 return AmdaResultParser::ValueType::SPECTROGRAM;
49 }
50 else if (valueType == QStringLiteral("vector")) {
51 return AmdaResultParser::ValueType::VECTOR;
52 }
53 else {
54 return AmdaResultParser::ValueType::UNKNOWN;
55 }
56 }
57
42
58 } // namespace
43 } // namespace
59
44
60 AmdaProvider::AmdaProvider()
45 AmdaProvider::AmdaProvider()
61 {
46 {
62 qCDebug(LOG_AmdaProvider()) << tr("AmdaProvider::AmdaProvider") << QThread::currentThread();
47 qCDebug(LOG_AmdaProvider()) << tr("AmdaProvider::AmdaProvider") << QThread::currentThread();
63 if (auto app = sqpApp) {
48 if (auto app = sqpApp) {
64 auto &networkController = app->networkController();
49 auto &networkController = app->networkController();
65 connect(this, SIGNAL(requestConstructed(std::shared_ptr<QNetworkRequest>, QUuid,
50 connect(this, SIGNAL(requestConstructed(std::shared_ptr<QNetworkRequest>, QUuid,
66 std::function<void(QNetworkReply *, QUuid)>)),
51 std::function<void(QNetworkReply *, QUuid)>)),
67 &networkController,
52 &networkController,
68 SLOT(onProcessRequested(std::shared_ptr<QNetworkRequest>, QUuid,
53 SLOT(onProcessRequested(std::shared_ptr<QNetworkRequest>, QUuid,
69 std::function<void(QNetworkReply *, QUuid)>)));
54 std::function<void(QNetworkReply *, QUuid)>)));
70
55
71
56
72 connect(&sqpApp->networkController(),
57 connect(&sqpApp->networkController(),
73 SIGNAL(replyDownloadProgress(QUuid, std::shared_ptr<QNetworkRequest>, double)),
58 SIGNAL(replyDownloadProgress(QUuid, std::shared_ptr<QNetworkRequest>, double)),
74 this,
59 this,
75 SLOT(onReplyDownloadProgress(QUuid, std::shared_ptr<QNetworkRequest>, double)));
60 SLOT(onReplyDownloadProgress(QUuid, std::shared_ptr<QNetworkRequest>, double)));
76 }
61 }
77 }
62 }
78
63
79 std::shared_ptr<IDataProvider> AmdaProvider::clone() const
64 std::shared_ptr<IDataProvider> AmdaProvider::clone() const
80 {
65 {
81 // No copy is made in the clone
66 // No copy is made in the clone
82 return std::make_shared<AmdaProvider>();
67 return std::make_shared<AmdaProvider>();
83 }
68 }
84
69
85 void AmdaProvider::requestDataLoading(QUuid acqIdentifier, const DataProviderParameters &parameters)
70 void AmdaProvider::requestDataLoading(QUuid acqIdentifier, const DataProviderParameters &parameters)
86 {
71 {
87 // NOTE: Try to use multithread if possible
72 // NOTE: Try to use multithread if possible
88 const auto times = parameters.m_Times;
73 const auto times = parameters.m_Times;
89 const auto data = parameters.m_Data;
74 const auto data = parameters.m_Data;
90 for (const auto &dateTime : qAsConst(times)) {
75 for (const auto &dateTime : qAsConst(times)) {
91 qCDebug(LOG_AmdaProvider()) << tr("TORM AmdaProvider::requestDataLoading ") << acqIdentifier
76 qCDebug(LOG_AmdaProvider()) << tr("TORM AmdaProvider::requestDataLoading ") << acqIdentifier
92 << dateTime;
77 << dateTime;
93 this->retrieveData(acqIdentifier, dateTime, data);
78 this->retrieveData(acqIdentifier, dateTime, data);
94
79
95
80
96 // TORM when AMDA will support quick asynchrone request
81 // TORM when AMDA will support quick asynchrone request
97 QThread::msleep(1000);
82 QThread::msleep(1000);
98 }
83 }
99 }
84 }
100
85
101 void AmdaProvider::requestDataAborting(QUuid acqIdentifier)
86 void AmdaProvider::requestDataAborting(QUuid acqIdentifier)
102 {
87 {
103 if (auto app = sqpApp) {
88 if (auto app = sqpApp) {
104 auto &networkController = app->networkController();
89 auto &networkController = app->networkController();
105 networkController.onReplyCanceled(acqIdentifier);
90 networkController.onReplyCanceled(acqIdentifier);
106 }
91 }
107 }
92 }
108
93
109 void AmdaProvider::onReplyDownloadProgress(QUuid acqIdentifier,
94 void AmdaProvider::onReplyDownloadProgress(QUuid acqIdentifier,
110 std::shared_ptr<QNetworkRequest> networkRequest,
95 std::shared_ptr<QNetworkRequest> networkRequest,
111 double progress)
96 double progress)
112 {
97 {
113 qCDebug(LOG_AmdaProvider()) << tr("onReplyDownloadProgress") << acqIdentifier
98 qCDebug(LOG_AmdaProvider()) << tr("onReplyDownloadProgress") << acqIdentifier
114 << networkRequest.get() << progress;
99 << networkRequest.get() << progress;
115 auto acqIdToRequestProgressMapIt = m_AcqIdToRequestProgressMap.find(acqIdentifier);
100 auto acqIdToRequestProgressMapIt = m_AcqIdToRequestProgressMap.find(acqIdentifier);
116 if (acqIdToRequestProgressMapIt != m_AcqIdToRequestProgressMap.end()) {
101 if (acqIdToRequestProgressMapIt != m_AcqIdToRequestProgressMap.end()) {
117
102
118 // Update the progression for the current request
103 // Update the progression for the current request
119 auto requestPtr = networkRequest;
104 auto requestPtr = networkRequest;
120 auto findRequest = [requestPtr](const auto &entry) { return requestPtr == entry.first; };
105 auto findRequest = [requestPtr](const auto &entry) { return requestPtr == entry.first; };
121
106
122 auto &requestProgressMap = acqIdToRequestProgressMapIt->second;
107 auto &requestProgressMap = acqIdToRequestProgressMapIt->second;
123 auto requestProgressMapEnd = requestProgressMap.end();
108 auto requestProgressMapEnd = requestProgressMap.end();
124 auto requestProgressMapIt
109 auto requestProgressMapIt
125 = std::find_if(requestProgressMap.begin(), requestProgressMapEnd, findRequest);
110 = std::find_if(requestProgressMap.begin(), requestProgressMapEnd, findRequest);
126
111
127 if (requestProgressMapIt != requestProgressMapEnd) {
112 if (requestProgressMapIt != requestProgressMapEnd) {
128 requestProgressMapIt->second = progress;
113 requestProgressMapIt->second = progress;
129 }
114 }
130 else {
115 else {
131 // This case can happened when a progression is send after the request has been
116 // This case can happened when a progression is send after the request has been
132 // finished.
117 // finished.
133 // Generaly the case when aborting a request
118 // Generaly the case when aborting a request
134 qCDebug(LOG_AmdaProvider()) << tr("Can't retrieve Request in progress") << acqIdentifier
119 qCDebug(LOG_AmdaProvider()) << tr("Can't retrieve Request in progress") << acqIdentifier
135 << networkRequest.get() << progress;
120 << networkRequest.get() << progress;
136 }
121 }
137
122
138 // Compute the current final progress and notify it
123 // Compute the current final progress and notify it
139 double finalProgress = 0.0;
124 double finalProgress = 0.0;
140
125
141 auto fraq = requestProgressMap.size();
126 auto fraq = requestProgressMap.size();
142
127
143 for (auto requestProgress : requestProgressMap) {
128 for (auto requestProgress : requestProgressMap) {
144 finalProgress += requestProgress.second;
129 finalProgress += requestProgress.second;
145 qCDebug(LOG_AmdaProvider()) << tr("Current final progress without fraq:")
130 qCDebug(LOG_AmdaProvider()) << tr("Current final progress without fraq:")
146 << finalProgress << requestProgress.second;
131 << finalProgress << requestProgress.second;
147 }
132 }
148
133
149 if (fraq > 0) {
134 if (fraq > 0) {
150 finalProgress = finalProgress / fraq;
135 finalProgress = finalProgress / fraq;
151 }
136 }
152
137
153 qCDebug(LOG_AmdaProvider()) << tr("Current final progress: ") << fraq << finalProgress;
138 qCDebug(LOG_AmdaProvider()) << tr("Current final progress: ") << fraq << finalProgress;
154 emit dataProvidedProgress(acqIdentifier, finalProgress);
139 emit dataProvidedProgress(acqIdentifier, finalProgress);
155 }
140 }
156 else {
141 else {
157 // This case can happened when a progression is send after the request has been finished.
142 // This case can happened when a progression is send after the request has been finished.
158 // Generaly the case when aborting a request
143 // Generaly the case when aborting a request
159 emit dataProvidedProgress(acqIdentifier, 100.0);
144 emit dataProvidedProgress(acqIdentifier, 100.0);
160 }
145 }
161 }
146 }
162
147
163 void AmdaProvider::retrieveData(QUuid token, const SqpRange &dateTime, const QVariantHash &data)
148 void AmdaProvider::retrieveData(QUuid token, const SqpRange &dateTime, const QVariantHash &data)
164 {
149 {
165 // Retrieves product ID from data: if the value is invalid, no request is made
150 // Retrieves product ID from data: if the value is invalid, no request is made
166 auto productId = data.value(AMDA_XML_ID_KEY).toString();
151 auto productId = data.value(AMDA_XML_ID_KEY).toString();
167 if (productId.isNull()) {
152 if (productId.isNull()) {
168 qCCritical(LOG_AmdaProvider()) << tr("Can't retrieve data: unknown product id");
153 qCCritical(LOG_AmdaProvider()) << tr("Can't retrieve data: unknown product id");
169 return;
154 return;
170 }
155 }
171
156
172 // Retrieves the data type that determines whether the expected format for the result file is
157 // Retrieves the data type that determines whether the expected format for the result file is
173 // scalar, vector...
158 // scalar, vector...
174 auto productValueType = valueType(data.value(AMDA_DATA_TYPE_KEY).toString());
159 auto productValueType
160 = DataSeriesTypeUtils::fromString(data.value(AMDA_DATA_TYPE_KEY).toString());
175
161
176 // /////////// //
162 // /////////// //
177 // Creates URL //
163 // Creates URL //
178 // /////////// //
164 // /////////// //
179
165
180 auto startDate = dateFormat(dateTime.m_TStart);
166 auto startDate = dateFormat(dateTime.m_TStart);
181 auto endDate = dateFormat(dateTime.m_TEnd);
167 auto endDate = dateFormat(dateTime.m_TEnd);
182
168
183 QVariantHash urlProperties{{AMDA_SERVER_KEY, data.value(AMDA_SERVER_KEY)}};
169 QVariantHash urlProperties{{AMDA_SERVER_KEY, data.value(AMDA_SERVER_KEY)}};
184 auto url = QUrl{QString{AMDA_URL_FORMAT}.arg(AmdaServer::instance().url(urlProperties),
170 auto url = QUrl{QString{AMDA_URL_FORMAT}.arg(AmdaServer::instance().url(urlProperties),
185 startDate, endDate, productId)};
171 startDate, endDate, productId)};
186 qCInfo(LOG_AmdaProvider()) << tr("TORM AmdaProvider::retrieveData url:") << url;
172 qCInfo(LOG_AmdaProvider()) << tr("TORM AmdaProvider::retrieveData url:") << url;
187 auto tempFile = std::make_shared<QTemporaryFile>();
173 auto tempFile = std::make_shared<QTemporaryFile>();
188
174
189 // LAMBDA
175 // LAMBDA
190 auto httpDownloadFinished = [this, dateTime, tempFile,
176 auto httpDownloadFinished = [this, dateTime, tempFile,
191 productValueType](QNetworkReply *reply, QUuid dataId) noexcept {
177 productValueType](QNetworkReply *reply, QUuid dataId) noexcept {
192
178
193 // Don't do anything if the reply was abort
179 // Don't do anything if the reply was abort
194 if (reply->error() == QNetworkReply::NoError) {
180 if (reply->error() == QNetworkReply::NoError) {
195
181
196 if (tempFile) {
182 if (tempFile) {
197 auto replyReadAll = reply->readAll();
183 auto replyReadAll = reply->readAll();
198 if (!replyReadAll.isEmpty()) {
184 if (!replyReadAll.isEmpty()) {
199 tempFile->write(replyReadAll);
185 tempFile->write(replyReadAll);
200 }
186 }
201 tempFile->close();
187 tempFile->close();
202
188
203 // Parse results file
189 // Parse results file
204 if (auto dataSeries
190 if (auto dataSeries
205 = AmdaResultParser::readTxt(tempFile->fileName(), productValueType)) {
191 = AmdaResultParser::readTxt(tempFile->fileName(), productValueType)) {
206 emit dataProvided(dataId, dataSeries, dateTime);
192 emit dataProvided(dataId, dataSeries, dateTime);
207 }
193 }
208 else {
194 else {
209 /// @todo ALX : debug
195 /// @todo ALX : debug
210 emit dataProvidedFailed(dataId);
196 emit dataProvidedFailed(dataId);
211 }
197 }
212 }
198 }
213 m_AcqIdToRequestProgressMap.erase(dataId);
199 m_AcqIdToRequestProgressMap.erase(dataId);
214 }
200 }
215 else {
201 else {
216 qCCritical(LOG_AmdaProvider()) << tr("httpDownloadFinished ERROR");
202 qCCritical(LOG_AmdaProvider()) << tr("httpDownloadFinished ERROR");
217 emit dataProvidedFailed(dataId);
203 emit dataProvidedFailed(dataId);
218 }
204 }
219
205
220 };
206 };
221 auto httpFinishedLambda
207 auto httpFinishedLambda
222 = [this, httpDownloadFinished, tempFile](QNetworkReply *reply, QUuid dataId) noexcept {
208 = [this, httpDownloadFinished, tempFile](QNetworkReply *reply, QUuid dataId) noexcept {
223
209
224 // Don't do anything if the reply was abort
210 // Don't do anything if the reply was abort
225 if (reply->error() == QNetworkReply::NoError) {
211 if (reply->error() == QNetworkReply::NoError) {
226 auto downloadFileUrl = QUrl{QString{reply->readAll()}.trimmed()};
212 auto downloadFileUrl = QUrl{QString{reply->readAll()}.trimmed()};
227
213
228 qCInfo(LOG_AmdaProvider())
214 qCInfo(LOG_AmdaProvider())
229 << tr("TORM AmdaProvider::retrieveData downloadFileUrl:") << downloadFileUrl;
215 << tr("TORM AmdaProvider::retrieveData downloadFileUrl:") << downloadFileUrl;
230 // Executes request for downloading file //
216 // Executes request for downloading file //
231
217
232 // Creates destination file
218 // Creates destination file
233 if (tempFile->open()) {
219 if (tempFile->open()) {
234 // Executes request and store the request for progression
220 // Executes request and store the request for progression
235 auto request = std::make_shared<QNetworkRequest>(downloadFileUrl);
221 auto request = std::make_shared<QNetworkRequest>(downloadFileUrl);
236 updateRequestProgress(dataId, request, 0.0);
222 updateRequestProgress(dataId, request, 0.0);
237 emit requestConstructed(request, dataId, httpDownloadFinished);
223 emit requestConstructed(request, dataId, httpDownloadFinished);
238 }
224 }
239 else {
225 else {
240 emit dataProvidedFailed(dataId);
226 emit dataProvidedFailed(dataId);
241 }
227 }
242 }
228 }
243 else {
229 else {
244 qCCritical(LOG_AmdaProvider()) << tr("httpFinishedLambda ERROR");
230 qCCritical(LOG_AmdaProvider()) << tr("httpFinishedLambda ERROR");
245 m_AcqIdToRequestProgressMap.erase(dataId);
231 m_AcqIdToRequestProgressMap.erase(dataId);
246 emit dataProvidedFailed(dataId);
232 emit dataProvidedFailed(dataId);
247 }
233 }
248 };
234 };
249
235
250 // //////////////// //
236 // //////////////// //
251 // Executes request //
237 // Executes request //
252 // //////////////// //
238 // //////////////// //
253
239
254 auto request = std::make_shared<QNetworkRequest>(url);
240 auto request = std::make_shared<QNetworkRequest>(url);
255 qCDebug(LOG_AmdaProvider()) << tr("First Request creation") << request.get();
241 qCDebug(LOG_AmdaProvider()) << tr("First Request creation") << request.get();
256 updateRequestProgress(token, request, 0.0);
242 updateRequestProgress(token, request, 0.0);
257
243
258 emit requestConstructed(request, token, httpFinishedLambda);
244 emit requestConstructed(request, token, httpFinishedLambda);
259 }
245 }
260
246
261 void AmdaProvider::updateRequestProgress(QUuid acqIdentifier,
247 void AmdaProvider::updateRequestProgress(QUuid acqIdentifier,
262 std::shared_ptr<QNetworkRequest> request, double progress)
248 std::shared_ptr<QNetworkRequest> request, double progress)
263 {
249 {
264 qCDebug(LOG_AmdaProvider()) << tr("updateRequestProgress request") << request.get();
250 qCDebug(LOG_AmdaProvider()) << tr("updateRequestProgress request") << request.get();
265 auto acqIdToRequestProgressMapIt = m_AcqIdToRequestProgressMap.find(acqIdentifier);
251 auto acqIdToRequestProgressMapIt = m_AcqIdToRequestProgressMap.find(acqIdentifier);
266 if (acqIdToRequestProgressMapIt != m_AcqIdToRequestProgressMap.end()) {
252 if (acqIdToRequestProgressMapIt != m_AcqIdToRequestProgressMap.end()) {
267 auto &requestProgressMap = acqIdToRequestProgressMapIt->second;
253 auto &requestProgressMap = acqIdToRequestProgressMapIt->second;
268 auto requestProgressMapIt = requestProgressMap.find(request);
254 auto requestProgressMapIt = requestProgressMap.find(request);
269 if (requestProgressMapIt != requestProgressMap.end()) {
255 if (requestProgressMapIt != requestProgressMap.end()) {
270 requestProgressMapIt->second = progress;
256 requestProgressMapIt->second = progress;
271 qCDebug(LOG_AmdaProvider()) << tr("updateRequestProgress new progress for request")
257 qCDebug(LOG_AmdaProvider()) << tr("updateRequestProgress new progress for request")
272 << acqIdentifier << request.get() << progress;
258 << acqIdentifier << request.get() << progress;
273 }
259 }
274 else {
260 else {
275 qCDebug(LOG_AmdaProvider()) << tr("updateRequestProgress new request") << acqIdentifier
261 qCDebug(LOG_AmdaProvider()) << tr("updateRequestProgress new request") << acqIdentifier
276 << request.get() << progress;
262 << request.get() << progress;
277 acqIdToRequestProgressMapIt->second.insert(std::make_pair(request, progress));
263 acqIdToRequestProgressMapIt->second.insert(std::make_pair(request, progress));
278 }
264 }
279 }
265 }
280 else {
266 else {
281 qCDebug(LOG_AmdaProvider()) << tr("updateRequestProgress new acqIdentifier")
267 qCDebug(LOG_AmdaProvider()) << tr("updateRequestProgress new acqIdentifier")
282 << acqIdentifier << request.get() << progress;
268 << acqIdentifier << request.get() << progress;
283 auto requestProgressMap = std::map<std::shared_ptr<QNetworkRequest>, double>{};
269 auto requestProgressMap = std::map<std::shared_ptr<QNetworkRequest>, double>{};
284 requestProgressMap.insert(std::make_pair(request, progress));
270 requestProgressMap.insert(std::make_pair(request, progress));
285 m_AcqIdToRequestProgressMap.insert(
271 m_AcqIdToRequestProgressMap.insert(
286 std::make_pair(acqIdentifier, std::move(requestProgressMap)));
272 std::make_pair(acqIdentifier, std::move(requestProgressMap)));
287 }
273 }
288 }
274 }
@@ -1,133 +1,133
1 #include "AmdaResultParser.h"
1 #include "AmdaResultParser.h"
2
2
3 #include "AmdaResultParserHelper.h"
3 #include "AmdaResultParserHelper.h"
4
4
5 #include <QFile>
5 #include <QFile>
6
6
7 #include <cmath>
7 #include <cmath>
8
8
9 Q_LOGGING_CATEGORY(LOG_AmdaResultParser, "AmdaResultParser")
9 Q_LOGGING_CATEGORY(LOG_AmdaResultParser, "AmdaResultParser")
10
10
11 namespace {
11 namespace {
12
12
13 /// Message in result file when the file was not found on server
13 /// Message in result file when the file was not found on server
14 const auto FILE_NOT_FOUND_MESSAGE = QStringLiteral("Not Found");
14 const auto FILE_NOT_FOUND_MESSAGE = QStringLiteral("Not Found");
15
15
16 /// Checks if a line is a comment line
16 /// Checks if a line is a comment line
17 bool isCommentLine(const QString &line)
17 bool isCommentLine(const QString &line)
18 {
18 {
19 return line.startsWith("#");
19 return line.startsWith("#");
20 }
20 }
21
21
22 /**
22 /**
23 * Creates helper that will be used to read AMDA file, according to the type passed as parameter
23 * Creates helper that will be used to read AMDA file, according to the type passed as parameter
24 * @param valueType the type of values expected in the AMDA file (scalars, vectors, spectrograms...)
24 * @param valueType the type of values expected in the AMDA file (scalars, vectors, spectrograms...)
25 * @return the helper created
25 * @return the helper created
26 */
26 */
27 std::unique_ptr<IAmdaResultParserHelper> createHelper(AmdaResultParser::ValueType valueType)
27 std::unique_ptr<IAmdaResultParserHelper> createHelper(DataSeriesType valueType)
28 {
28 {
29 switch (valueType) {
29 switch (valueType) {
30 case AmdaResultParser::ValueType::SCALAR:
30 case DataSeriesType::SCALAR:
31 return std::make_unique<ScalarParserHelper>();
31 return std::make_unique<ScalarParserHelper>();
32 case AmdaResultParser::ValueType::SPECTROGRAM:
32 case DataSeriesType::SPECTROGRAM:
33 return std::make_unique<SpectrogramParserHelper>();
33 return std::make_unique<SpectrogramParserHelper>();
34 case AmdaResultParser::ValueType::VECTOR:
34 case DataSeriesType::VECTOR:
35 return std::make_unique<VectorParserHelper>();
35 return std::make_unique<VectorParserHelper>();
36 case AmdaResultParser::ValueType::UNKNOWN:
36 case DataSeriesType::UNKNOWN:
37 // Invalid case
37 // Invalid case
38 break;
38 break;
39 }
39 }
40
40
41 // Invalid cases
41 // Invalid cases
42 qCCritical(LOG_AmdaResultParser())
42 qCCritical(LOG_AmdaResultParser())
43 << QObject::tr("Can't create helper to read result file: unsupported type");
43 << QObject::tr("Can't create helper to read result file: unsupported type");
44 return nullptr;
44 return nullptr;
45 }
45 }
46
46
47 /**
47 /**
48 * Reads properties of the stream passed as parameter
48 * Reads properties of the stream passed as parameter
49 * @param helper the helper used to read properties line by line
49 * @param helper the helper used to read properties line by line
50 * @param stream the stream to read
50 * @param stream the stream to read
51 */
51 */
52 void readProperties(IAmdaResultParserHelper &helper, QTextStream &stream)
52 void readProperties(IAmdaResultParserHelper &helper, QTextStream &stream)
53 {
53 {
54 // Searches properties in the comment lines (as long as the reading has not reached the data)
54 // Searches properties in the comment lines (as long as the reading has not reached the data)
55 // AMDA V2: while (stream.readLineInto(&line) && !line.contains(DATA_HEADER_REGEX)) {
55 // AMDA V2: while (stream.readLineInto(&line) && !line.contains(DATA_HEADER_REGEX)) {
56 QString line{};
56 QString line{};
57 while (stream.readLineInto(&line) && isCommentLine(line)) {
57 while (stream.readLineInto(&line) && isCommentLine(line)) {
58 helper.readPropertyLine(line);
58 helper.readPropertyLine(line);
59 }
59 }
60 }
60 }
61
61
62 /**
62 /**
63 * Reads results of the stream passed as parameter
63 * Reads results of the stream passed as parameter
64 * @param helper the helper used to read results line by line
64 * @param helper the helper used to read results line by line
65 * @param stream the stream to read
65 * @param stream the stream to read
66 */
66 */
67 void readResults(IAmdaResultParserHelper &helper, QTextStream &stream)
67 void readResults(IAmdaResultParserHelper &helper, QTextStream &stream)
68 {
68 {
69 QString line{};
69 QString line{};
70
70
71 // Skip comment lines
71 // Skip comment lines
72 while (stream.readLineInto(&line) && isCommentLine(line)) {
72 while (stream.readLineInto(&line) && isCommentLine(line)) {
73 }
73 }
74
74
75 if (!stream.atEnd()) {
75 if (!stream.atEnd()) {
76 do {
76 do {
77 helper.readResultLine(line);
77 helper.readResultLine(line);
78 } while (stream.readLineInto(&line));
78 } while (stream.readLineInto(&line));
79 }
79 }
80 }
80 }
81
81
82 } // namespace
82 } // namespace
83
83
84 std::shared_ptr<IDataSeries> AmdaResultParser::readTxt(const QString &filePath,
84 std::shared_ptr<IDataSeries> AmdaResultParser::readTxt(const QString &filePath,
85 ValueType valueType) noexcept
85 DataSeriesType type) noexcept
86 {
86 {
87 if (valueType == ValueType::UNKNOWN) {
87 if (type == DataSeriesType::UNKNOWN) {
88 qCCritical(LOG_AmdaResultParser())
88 qCCritical(LOG_AmdaResultParser())
89 << QObject::tr("Can't retrieve AMDA data: the type of values to be read is unknown");
89 << QObject::tr("Can't retrieve AMDA data: the type of values to be read is unknown");
90 return nullptr;
90 return nullptr;
91 }
91 }
92
92
93 QFile file{filePath};
93 QFile file{filePath};
94
94
95 if (!file.open(QFile::ReadOnly | QIODevice::Text)) {
95 if (!file.open(QFile::ReadOnly | QIODevice::Text)) {
96 qCCritical(LOG_AmdaResultParser())
96 qCCritical(LOG_AmdaResultParser())
97 << QObject::tr("Can't retrieve AMDA data from file %1: %2")
97 << QObject::tr("Can't retrieve AMDA data from file %1: %2")
98 .arg(filePath, file.errorString());
98 .arg(filePath, file.errorString());
99 return nullptr;
99 return nullptr;
100 }
100 }
101
101
102 QTextStream stream{&file};
102 QTextStream stream{&file};
103
103
104 // Checks if the file was found on the server
104 // Checks if the file was found on the server
105 auto firstLine = stream.readLine();
105 auto firstLine = stream.readLine();
106 if (firstLine.compare(FILE_NOT_FOUND_MESSAGE) == 0) {
106 if (firstLine.compare(FILE_NOT_FOUND_MESSAGE) == 0) {
107 qCCritical(LOG_AmdaResultParser())
107 qCCritical(LOG_AmdaResultParser())
108 << QObject::tr("Can't retrieve AMDA data from file %1: file was not found on server")
108 << QObject::tr("Can't retrieve AMDA data from file %1: file was not found on server")
109 .arg(filePath);
109 .arg(filePath);
110 return nullptr;
110 return nullptr;
111 }
111 }
112
112
113 auto helper = createHelper(valueType);
113 auto helper = createHelper(type);
114 Q_ASSERT(helper != nullptr);
114 Q_ASSERT(helper != nullptr);
115
115
116 // Reads header file to retrieve properties
116 // Reads header file to retrieve properties
117 stream.seek(0); // returns to the beginning of the file
117 stream.seek(0); // returns to the beginning of the file
118 readProperties(*helper, stream);
118 readProperties(*helper, stream);
119
119
120 // Checks properties
120 // Checks properties
121 if (helper->checkProperties()) {
121 if (helper->checkProperties()) {
122 // Reads results
122 // Reads results
123 // AMDA V2: remove line
123 // AMDA V2: remove line
124 stream.seek(0); // returns to the beginning of the file
124 stream.seek(0); // returns to the beginning of the file
125 readResults(*helper, stream);
125 readResults(*helper, stream);
126
126
127 // Creates data series
127 // Creates data series
128 return helper->createSeries();
128 return helper->createSeries();
129 }
129 }
130 else {
130 else {
131 return nullptr;
131 return nullptr;
132 }
132 }
133 }
133 }
@@ -1,164 +1,164
1 #include "AmdaProvider.h"
1 #include "AmdaProvider.h"
2 #include "AmdaResultParser.h"
2 #include "AmdaResultParser.h"
3
3
4 #include "SqpApplication.h"
4 #include "SqpApplication.h"
5 #include <Data/DataSeries.h>
5 #include <Data/DataSeries.h>
6 #include <Data/IDataSeries.h>
6 #include <Data/IDataSeries.h>
7 #include <Data/ScalarSeries.h>
7 #include <Data/ScalarSeries.h>
8 #include <Time/TimeController.h>
8 #include <Time/TimeController.h>
9 #include <Variable/Variable.h>
9 #include <Variable/Variable.h>
10 #include <Variable/VariableController.h>
10 #include <Variable/VariableController.h>
11
11
12 #include <QObject>
12 #include <QObject>
13 #include <QtTest>
13 #include <QtTest>
14
14
15 #include <memory>
15 #include <memory>
16
16
17 // TEST with REF:
17 // TEST with REF:
18 // AmdaData-2012-01-01-12-00-00_2012-01-03-12-00-00
18 // AmdaData-2012-01-01-12-00-00_2012-01-03-12-00-00
19 // imf(0) - Type : Local Parameter @ CDPP/AMDA -
19 // imf(0) - Type : Local Parameter @ CDPP/AMDA -
20 // Name : bx_gse - Units : nT - Size : 1 -
20 // Name : bx_gse - Units : nT - Size : 1 -
21 // Frame : GSE - Mission : ACE -
21 // Frame : GSE - Mission : ACE -
22 // Instrument : MFI - Dataset : mfi_final-prelim
22 // Instrument : MFI - Dataset : mfi_final-prelim
23 // REFERENCE DOWNLOAD FILE =
23 // REFERENCE DOWNLOAD FILE =
24 // http://amdatest.irap.omp.eu/php/rest/getParameter.php?startTime=2012-01-01T12:00:00&stopTime=2012-01-03T12:00:00&parameterID=imf(0)&outputFormat=ASCII&timeFormat=ISO8601&gzip=0
24 // http://amdatest.irap.omp.eu/php/rest/getParameter.php?startTime=2012-01-01T12:00:00&stopTime=2012-01-03T12:00:00&parameterID=imf(0)&outputFormat=ASCII&timeFormat=ISO8601&gzip=0
25
25
26 namespace {
26 namespace {
27
27
28 /// Path for the tests
28 /// Path for the tests
29 const auto TESTS_RESOURCES_PATH
29 const auto TESTS_RESOURCES_PATH
30 = QFileInfo{QString{AMDA_TESTS_RESOURCES_DIR}, "TestAmdaAcquisition"}.absoluteFilePath();
30 = QFileInfo{QString{AMDA_TESTS_RESOURCES_DIR}, "TestAmdaAcquisition"}.absoluteFilePath();
31
31
32 /// Delay after each operation on the variable before validating it (in ms)
32 /// Delay after each operation on the variable before validating it (in ms)
33 const auto OPERATION_DELAY = 10000;
33 const auto OPERATION_DELAY = 10000;
34
34
35 template <typename T>
35 template <typename T>
36 bool compareDataSeries(std::shared_ptr<IDataSeries> candidate, SqpRange candidateCacheRange,
36 bool compareDataSeries(std::shared_ptr<IDataSeries> candidate, SqpRange candidateCacheRange,
37 std::shared_ptr<IDataSeries> reference)
37 std::shared_ptr<IDataSeries> reference)
38 {
38 {
39 auto compareLambda = [](const auto &it1, const auto &it2) {
39 auto compareLambda = [](const auto &it1, const auto &it2) {
40 return (it1.x() == it2.x()) && (it1.value() == it2.value());
40 return (it1.x() == it2.x()) && (it1.value() == it2.value());
41 };
41 };
42
42
43 auto candidateDS = std::dynamic_pointer_cast<T>(candidate);
43 auto candidateDS = std::dynamic_pointer_cast<T>(candidate);
44 auto referenceDS = std::dynamic_pointer_cast<T>(reference);
44 auto referenceDS = std::dynamic_pointer_cast<T>(reference);
45
45
46 if (candidateDS && referenceDS) {
46 if (candidateDS && referenceDS) {
47
47
48 auto itRefs
48 auto itRefs
49 = referenceDS->xAxisRange(candidateCacheRange.m_TStart, candidateCacheRange.m_TEnd);
49 = referenceDS->xAxisRange(candidateCacheRange.m_TStart, candidateCacheRange.m_TEnd);
50 qDebug() << " DISTANCE" << std::distance(candidateDS->cbegin(), candidateDS->cend())
50 qDebug() << " DISTANCE" << std::distance(candidateDS->cbegin(), candidateDS->cend())
51 << std::distance(itRefs.first, itRefs.second);
51 << std::distance(itRefs.first, itRefs.second);
52
52
53 return std::equal(candidateDS->cbegin(), candidateDS->cend(), itRefs.first, itRefs.second,
53 return std::equal(candidateDS->cbegin(), candidateDS->cend(), itRefs.first, itRefs.second,
54 compareLambda);
54 compareLambda);
55 }
55 }
56 else {
56 else {
57 return false;
57 return false;
58 }
58 }
59 }
59 }
60 }
60 }
61
61
62 class TestAmdaAcquisition : public QObject {
62 class TestAmdaAcquisition : public QObject {
63 Q_OBJECT
63 Q_OBJECT
64
64
65 private slots:
65 private slots:
66 /// Input data for @sa testAcquisition()
66 /// Input data for @sa testAcquisition()
67 void testAcquisition_data();
67 void testAcquisition_data();
68 void testAcquisition();
68 void testAcquisition();
69 };
69 };
70
70
71 void TestAmdaAcquisition::testAcquisition_data()
71 void TestAmdaAcquisition::testAcquisition_data()
72 {
72 {
73 // ////////////// //
73 // ////////////// //
74 // Test structure //
74 // Test structure //
75 // ////////////// //
75 // ////////////// //
76
76
77 QTest::addColumn<QString>("dataFilename"); // File containing expected data of acquisitions
77 QTest::addColumn<QString>("dataFilename"); // File containing expected data of acquisitions
78 QTest::addColumn<SqpRange>("initialRange"); // First acquisition
78 QTest::addColumn<SqpRange>("initialRange"); // First acquisition
79 QTest::addColumn<std::vector<SqpRange> >("operations"); // Acquisitions to make
79 QTest::addColumn<std::vector<SqpRange> >("operations"); // Acquisitions to make
80
80
81 // ////////// //
81 // ////////// //
82 // Test cases //
82 // Test cases //
83 // ////////// //
83 // ////////// //
84
84
85 auto dateTime = [](int year, int month, int day, int hours, int minutes, int seconds) {
85 auto dateTime = [](int year, int month, int day, int hours, int minutes, int seconds) {
86 return DateUtils::secondsSinceEpoch(
86 return DateUtils::secondsSinceEpoch(
87 QDateTime{{year, month, day}, {hours, minutes, seconds}, Qt::UTC});
87 QDateTime{{year, month, day}, {hours, minutes, seconds}, Qt::UTC});
88 };
88 };
89
89
90
90
91 QTest::newRow("amda")
91 QTest::newRow("amda")
92 << "AmdaData-2012-01-01-12-00-00_2012-01-03-12-00-00.txt"
92 << "AmdaData-2012-01-01-12-00-00_2012-01-03-12-00-00.txt"
93 << SqpRange{dateTime(2012, 1, 2, 2, 3, 0), dateTime(2012, 1, 2, 2, 4, 0)}
93 << SqpRange{dateTime(2012, 1, 2, 2, 3, 0), dateTime(2012, 1, 2, 2, 4, 0)}
94 << std::vector<SqpRange>{
94 << std::vector<SqpRange>{
95 // 2 : pan (jump) left for two min
95 // 2 : pan (jump) left for two min
96 SqpRange{dateTime(2012, 1, 2, 2, 1, 0), dateTime(2012, 1, 2, 2, 2, 0)},
96 SqpRange{dateTime(2012, 1, 2, 2, 1, 0), dateTime(2012, 1, 2, 2, 2, 0)},
97 // 3 : pan (jump) right for four min
97 // 3 : pan (jump) right for four min
98 SqpRange{dateTime(2012, 1, 2, 2, 5, 0), dateTime(2012, 1, 2, 2, 6, 0)},
98 SqpRange{dateTime(2012, 1, 2, 2, 5, 0), dateTime(2012, 1, 2, 2, 6, 0)},
99 // 4 : pan (overlay) right for 30 sec
99 // 4 : pan (overlay) right for 30 sec
100 /*SqpRange{dateTime(2012, 1, 2, 2, 5, 30), dateTime(2012, 1, 2, 2, 6, 30)},
100 /*SqpRange{dateTime(2012, 1, 2, 2, 5, 30), dateTime(2012, 1, 2, 2, 6, 30)},
101 // 5 : pan (overlay) left for 30 sec
101 // 5 : pan (overlay) left for 30 sec
102 SqpRange{dateTime(2012, 1, 2, 2, 5, 0), dateTime(2012, 1, 2, 2, 6, 0)},
102 SqpRange{dateTime(2012, 1, 2, 2, 5, 0), dateTime(2012, 1, 2, 2, 6, 0)},
103 // 6 : pan (overlay) left for 30 sec - BIS
103 // 6 : pan (overlay) left for 30 sec - BIS
104 SqpRange{dateTime(2012, 1, 2, 2, 4, 30), dateTime(2012, 1, 2, 2, 5, 30)},
104 SqpRange{dateTime(2012, 1, 2, 2, 4, 30), dateTime(2012, 1, 2, 2, 5, 30)},
105 // 7 : Zoom in Inside 20 sec range
105 // 7 : Zoom in Inside 20 sec range
106 SqpRange{dateTime(2012, 1, 2, 2, 4, 50), dateTime(2012, 1, 2, 2, 5, 10)},
106 SqpRange{dateTime(2012, 1, 2, 2, 4, 50), dateTime(2012, 1, 2, 2, 5, 10)},
107 // 8 : Zoom out Inside 20 sec range
107 // 8 : Zoom out Inside 20 sec range
108 SqpRange{dateTime(2012, 1, 2, 2, 4, 30), dateTime(2012, 1, 2, 2, 5, 30)}*/};
108 SqpRange{dateTime(2012, 1, 2, 2, 4, 30), dateTime(2012, 1, 2, 2, 5, 30)}*/};
109 }
109 }
110
110
111 void TestAmdaAcquisition::testAcquisition()
111 void TestAmdaAcquisition::testAcquisition()
112 {
112 {
113 /// @todo: update test to be compatible with AMDA v2
113 /// @todo: update test to be compatible with AMDA v2
114
114
115 // Retrieves data file
115 // Retrieves data file
116 QFETCH(QString, dataFilename);
116 QFETCH(QString, dataFilename);
117 auto filePath = QFileInfo{TESTS_RESOURCES_PATH, dataFilename}.absoluteFilePath();
117 auto filePath = QFileInfo{TESTS_RESOURCES_PATH, dataFilename}.absoluteFilePath();
118 auto results = AmdaResultParser::readTxt(filePath, AmdaResultParser::ValueType::SCALAR);
118 auto results = AmdaResultParser::readTxt(filePath, DataSeriesType::SCALAR);
119
119
120 /// Lambda used to validate a variable at each step
120 /// Lambda used to validate a variable at each step
121 auto validateVariable = [results](std::shared_ptr<Variable> variable, const SqpRange &range) {
121 auto validateVariable = [results](std::shared_ptr<Variable> variable, const SqpRange &range) {
122 // Checks that the variable's range has changed
122 // Checks that the variable's range has changed
123 qInfo() << tr("Compare var range vs range") << variable->range() << range;
123 qInfo() << tr("Compare var range vs range") << variable->range() << range;
124 QCOMPARE(variable->range(), range);
124 QCOMPARE(variable->range(), range);
125
125
126 // Checks the variable's data series
126 // Checks the variable's data series
127 QVERIFY(compareDataSeries<ScalarSeries>(variable->dataSeries(), variable->cacheRange(),
127 QVERIFY(compareDataSeries<ScalarSeries>(variable->dataSeries(), variable->cacheRange(),
128 results));
128 results));
129 qInfo() << "\n";
129 qInfo() << "\n";
130 };
130 };
131
131
132 // Creates variable
132 // Creates variable
133 QFETCH(SqpRange, initialRange);
133 QFETCH(SqpRange, initialRange);
134 sqpApp->timeController().onTimeToUpdate(initialRange);
134 sqpApp->timeController().onTimeToUpdate(initialRange);
135 auto provider = std::make_shared<AmdaProvider>();
135 auto provider = std::make_shared<AmdaProvider>();
136 auto variable = sqpApp->variableController().createVariable(
136 auto variable = sqpApp->variableController().createVariable(
137 "bx_gse", {{"dataType", "scalar"}, {"xml:id", "imf(0)"}}, provider);
137 "bx_gse", {{"dataType", "scalar"}, {"xml:id", "imf(0)"}}, provider);
138
138
139 QTest::qWait(OPERATION_DELAY);
139 QTest::qWait(OPERATION_DELAY);
140 validateVariable(variable, initialRange);
140 validateVariable(variable, initialRange);
141
141
142 // Makes operations on the variable
142 // Makes operations on the variable
143 QFETCH(std::vector<SqpRange>, operations);
143 QFETCH(std::vector<SqpRange>, operations);
144 for (const auto &operation : operations) {
144 for (const auto &operation : operations) {
145 // Asks request on the variable and waits during its execution
145 // Asks request on the variable and waits during its execution
146 sqpApp->variableController().onRequestDataLoading({variable}, operation, false);
146 sqpApp->variableController().onRequestDataLoading({variable}, operation, false);
147
147
148 QTest::qWait(OPERATION_DELAY);
148 QTest::qWait(OPERATION_DELAY);
149 validateVariable(variable, operation);
149 validateVariable(variable, operation);
150 }
150 }
151 }
151 }
152
152
153 int main(int argc, char *argv[])
153 int main(int argc, char *argv[])
154 {
154 {
155 SqpApplication app(argc, argv);
155 SqpApplication app(argc, argv);
156 app.setAttribute(Qt::AA_Use96Dpi, true);
156 app.setAttribute(Qt::AA_Use96Dpi, true);
157 TestAmdaAcquisition tc;
157 TestAmdaAcquisition tc;
158 QTEST_SET_MAIN_SOURCE_PATH
158 QTEST_SET_MAIN_SOURCE_PATH
159 return QTest::qExec(&tc, argc, argv);
159 return QTest::qExec(&tc, argc, argv);
160 }
160 }
161
161
162 // QTEST_MAIN(TestAmdaAcquisition)
162 // QTEST_MAIN(TestAmdaAcquisition)
163
163
164 #include "TestAmdaAcquisition.moc"
164 #include "TestAmdaAcquisition.moc"
@@ -1,579 +1,579
1 #include "AmdaResultParser.h"
1 #include "AmdaResultParser.h"
2
2
3 #include <Data/ScalarSeries.h>
3 #include <Data/ScalarSeries.h>
4 #include <Data/SpectrogramSeries.h>
4 #include <Data/SpectrogramSeries.h>
5 #include <Data/VectorSeries.h>
5 #include <Data/VectorSeries.h>
6
6
7 #include <QObject>
7 #include <QObject>
8 #include <QtTest>
8 #include <QtTest>
9
9
10 namespace {
10 namespace {
11
11
12 /// Path for the tests
12 /// Path for the tests
13 const auto TESTS_RESOURCES_PATH
13 const auto TESTS_RESOURCES_PATH
14 = QFileInfo{QString{AMDA_TESTS_RESOURCES_DIR}, "TestAmdaResultParser"}.absoluteFilePath();
14 = QFileInfo{QString{AMDA_TESTS_RESOURCES_DIR}, "TestAmdaResultParser"}.absoluteFilePath();
15
15
16 QDateTime dateTime(int year, int month, int day, int hours, int minutes, int seconds)
16 QDateTime dateTime(int year, int month, int day, int hours, int minutes, int seconds)
17 {
17 {
18 return QDateTime{{year, month, day}, {hours, minutes, seconds}, Qt::UTC};
18 return QDateTime{{year, month, day}, {hours, minutes, seconds}, Qt::UTC};
19 }
19 }
20
20
21 QString inputFilePath(const QString &inputFileName)
21 QString inputFilePath(const QString &inputFileName)
22 {
22 {
23 return QFileInfo{TESTS_RESOURCES_PATH, inputFileName}.absoluteFilePath();
23 return QFileInfo{TESTS_RESOURCES_PATH, inputFileName}.absoluteFilePath();
24 }
24 }
25
25
26 template <typename T>
26 template <typename T>
27 struct ExpectedResults {
27 struct ExpectedResults {
28
28
29 ExpectedResults &setParsingOK(bool parsingOK)
29 ExpectedResults &setParsingOK(bool parsingOK)
30 {
30 {
31 m_ParsingOK = parsingOK;
31 m_ParsingOK = parsingOK;
32 return *this;
32 return *this;
33 }
33 }
34
34
35 ExpectedResults &setXAxisUnit(Unit xAxisUnit)
35 ExpectedResults &setXAxisUnit(Unit xAxisUnit)
36 {
36 {
37 m_XAxisUnit = std::move(xAxisUnit);
37 m_XAxisUnit = std::move(xAxisUnit);
38 return *this;
38 return *this;
39 }
39 }
40
40
41 ExpectedResults &setXAxisData(const QVector<QDateTime> &xAxisData)
41 ExpectedResults &setXAxisData(const QVector<QDateTime> &xAxisData)
42 {
42 {
43 m_XAxisData.clear();
43 m_XAxisData.clear();
44
44
45 // Converts QVector<QDateTime> to QVector<double>
45 // Converts QVector<QDateTime> to QVector<double>
46 std::transform(xAxisData.cbegin(), xAxisData.cend(), std::back_inserter(m_XAxisData),
46 std::transform(xAxisData.cbegin(), xAxisData.cend(), std::back_inserter(m_XAxisData),
47 [](const auto &dateTime) { return dateTime.toMSecsSinceEpoch() / 1000.; });
47 [](const auto &dateTime) { return dateTime.toMSecsSinceEpoch() / 1000.; });
48
48
49 return *this;
49 return *this;
50 }
50 }
51
51
52 ExpectedResults &setValuesUnit(Unit valuesUnit)
52 ExpectedResults &setValuesUnit(Unit valuesUnit)
53 {
53 {
54 m_ValuesUnit = std::move(valuesUnit);
54 m_ValuesUnit = std::move(valuesUnit);
55 return *this;
55 return *this;
56 }
56 }
57
57
58 ExpectedResults &setValuesData(QVector<double> valuesData)
58 ExpectedResults &setValuesData(QVector<double> valuesData)
59 {
59 {
60 m_ValuesData.clear();
60 m_ValuesData.clear();
61 m_ValuesData.push_back(std::move(valuesData));
61 m_ValuesData.push_back(std::move(valuesData));
62 return *this;
62 return *this;
63 }
63 }
64
64
65 ExpectedResults &setValuesData(QVector<QVector<double> > valuesData)
65 ExpectedResults &setValuesData(QVector<QVector<double> > valuesData)
66 {
66 {
67 m_ValuesData = std::move(valuesData);
67 m_ValuesData = std::move(valuesData);
68 return *this;
68 return *this;
69 }
69 }
70
70
71 ExpectedResults &setYAxisEnabled(bool yAxisEnabled)
71 ExpectedResults &setYAxisEnabled(bool yAxisEnabled)
72 {
72 {
73 m_YAxisEnabled = yAxisEnabled;
73 m_YAxisEnabled = yAxisEnabled;
74 return *this;
74 return *this;
75 }
75 }
76
76
77 ExpectedResults &setYAxisUnit(Unit yAxisUnit)
77 ExpectedResults &setYAxisUnit(Unit yAxisUnit)
78 {
78 {
79 m_YAxisUnit = std::move(yAxisUnit);
79 m_YAxisUnit = std::move(yAxisUnit);
80 return *this;
80 return *this;
81 }
81 }
82
82
83 ExpectedResults &setYAxisData(QVector<double> yAxisData)
83 ExpectedResults &setYAxisData(QVector<double> yAxisData)
84 {
84 {
85 m_YAxisData = std::move(yAxisData);
85 m_YAxisData = std::move(yAxisData);
86 return *this;
86 return *this;
87 }
87 }
88
88
89 /**
89 /**
90 * Validates a DataSeries compared to the expected results
90 * Validates a DataSeries compared to the expected results
91 * @param results the DataSeries to validate
91 * @param results the DataSeries to validate
92 */
92 */
93 void validate(std::shared_ptr<IDataSeries> results)
93 void validate(std::shared_ptr<IDataSeries> results)
94 {
94 {
95 if (m_ParsingOK) {
95 if (m_ParsingOK) {
96 auto dataSeries = dynamic_cast<T *>(results.get());
96 auto dataSeries = dynamic_cast<T *>(results.get());
97 if (dataSeries == nullptr) {
97 if (dataSeries == nullptr) {
98
98
99 // No unit detected, parsink ok but data is nullptr
99 // No unit detected, parsink ok but data is nullptr
100 // TODO, improve the test to verify that the data is null
100 // TODO, improve the test to verify that the data is null
101 return;
101 return;
102 }
102 }
103
103
104 // Checks units
104 // Checks units
105 QVERIFY(dataSeries->xAxisUnit() == m_XAxisUnit);
105 QVERIFY(dataSeries->xAxisUnit() == m_XAxisUnit);
106 QVERIFY(dataSeries->valuesUnit() == m_ValuesUnit);
106 QVERIFY(dataSeries->valuesUnit() == m_ValuesUnit);
107
107
108 auto verifyRange = [dataSeries](const auto &expectedData, const auto &equalFun) {
108 auto verifyRange = [dataSeries](const auto &expectedData, const auto &equalFun) {
109 QVERIFY(std::equal(dataSeries->cbegin(), dataSeries->cend(), expectedData.cbegin(),
109 QVERIFY(std::equal(dataSeries->cbegin(), dataSeries->cend(), expectedData.cbegin(),
110 expectedData.cend(),
110 expectedData.cend(),
111 [&equalFun](const auto &dataSeriesIt, const auto &expectedX) {
111 [&equalFun](const auto &dataSeriesIt, const auto &expectedX) {
112 return equalFun(dataSeriesIt, expectedX);
112 return equalFun(dataSeriesIt, expectedX);
113 }));
113 }));
114 };
114 };
115
115
116 // Checks x-axis data
116 // Checks x-axis data
117 verifyRange(m_XAxisData, [](const auto &seriesIt, const auto &value) {
117 verifyRange(m_XAxisData, [](const auto &seriesIt, const auto &value) {
118 return seriesIt.x() == value;
118 return seriesIt.x() == value;
119 });
119 });
120
120
121 // Checks values data of each component
121 // Checks values data of each component
122 for (auto i = 0; i < m_ValuesData.size(); ++i) {
122 for (auto i = 0; i < m_ValuesData.size(); ++i) {
123 verifyRange(m_ValuesData.at(i), [i](const auto &seriesIt, const auto &value) {
123 verifyRange(m_ValuesData.at(i), [i](const auto &seriesIt, const auto &value) {
124 auto itValue = seriesIt.value(i);
124 auto itValue = seriesIt.value(i);
125 return (std::isnan(itValue) && std::isnan(value)) || seriesIt.value(i) == value;
125 return (std::isnan(itValue) && std::isnan(value)) || seriesIt.value(i) == value;
126 });
126 });
127 }
127 }
128
128
129 // Checks y-axis (if defined)
129 // Checks y-axis (if defined)
130 auto yAxis = dataSeries->yAxis();
130 auto yAxis = dataSeries->yAxis();
131 QCOMPARE(yAxis.isDefined(), m_YAxisEnabled);
131 QCOMPARE(yAxis.isDefined(), m_YAxisEnabled);
132
132
133 if (m_YAxisEnabled) {
133 if (m_YAxisEnabled) {
134 // Unit
134 // Unit
135 QCOMPARE(yAxis.unit(), m_YAxisUnit);
135 QCOMPARE(yAxis.unit(), m_YAxisUnit);
136
136
137 // Data
137 // Data
138 QVERIFY(std::equal(yAxis.cbegin(), yAxis.cend(), m_YAxisData.cbegin(),
138 QVERIFY(std::equal(yAxis.cbegin(), yAxis.cend(), m_YAxisData.cbegin(),
139 m_YAxisData.cend(), [](const auto &it, const auto &expectedVal) {
139 m_YAxisData.cend(), [](const auto &it, const auto &expectedVal) {
140 return it.first() == expectedVal;
140 return it.first() == expectedVal;
141 }));
141 }));
142 }
142 }
143 }
143 }
144 else {
144 else {
145 QVERIFY(results == nullptr);
145 QVERIFY(results == nullptr);
146 }
146 }
147 }
147 }
148
148
149 // Parsing was successfully completed
149 // Parsing was successfully completed
150 bool m_ParsingOK{false};
150 bool m_ParsingOK{false};
151 // Expected x-axis unit
151 // Expected x-axis unit
152 Unit m_XAxisUnit{};
152 Unit m_XAxisUnit{};
153 // Expected x-axis data
153 // Expected x-axis data
154 QVector<double> m_XAxisData{};
154 QVector<double> m_XAxisData{};
155 // Expected values unit
155 // Expected values unit
156 Unit m_ValuesUnit{};
156 Unit m_ValuesUnit{};
157 // Expected values data
157 // Expected values data
158 QVector<QVector<double> > m_ValuesData{};
158 QVector<QVector<double> > m_ValuesData{};
159 // Expected data series has y-axis
159 // Expected data series has y-axis
160 bool m_YAxisEnabled{false};
160 bool m_YAxisEnabled{false};
161 // Expected y-axis unit (if axis defined)
161 // Expected y-axis unit (if axis defined)
162 Unit m_YAxisUnit{};
162 Unit m_YAxisUnit{};
163 // Expected y-axis data (if axis defined)
163 // Expected y-axis data (if axis defined)
164 QVector<double> m_YAxisData{};
164 QVector<double> m_YAxisData{};
165 };
165 };
166
166
167 } // namespace
167 } // namespace
168
168
169 Q_DECLARE_METATYPE(ExpectedResults<ScalarSeries>)
169 Q_DECLARE_METATYPE(ExpectedResults<ScalarSeries>)
170 Q_DECLARE_METATYPE(ExpectedResults<SpectrogramSeries>)
170 Q_DECLARE_METATYPE(ExpectedResults<SpectrogramSeries>)
171 Q_DECLARE_METATYPE(ExpectedResults<VectorSeries>)
171 Q_DECLARE_METATYPE(ExpectedResults<VectorSeries>)
172
172
173 class TestAmdaResultParser : public QObject {
173 class TestAmdaResultParser : public QObject {
174 Q_OBJECT
174 Q_OBJECT
175 private:
175 private:
176 template <typename T>
176 template <typename T>
177 void testReadDataStructure()
177 void testReadDataStructure()
178 {
178 {
179 // ////////////// //
179 // ////////////// //
180 // Test structure //
180 // Test structure //
181 // ////////////// //
181 // ////////////// //
182
182
183 // Name of TXT file to read
183 // Name of TXT file to read
184 QTest::addColumn<QString>("inputFileName");
184 QTest::addColumn<QString>("inputFileName");
185 // Expected results
185 // Expected results
186 QTest::addColumn<ExpectedResults<T> >("expectedResults");
186 QTest::addColumn<ExpectedResults<T> >("expectedResults");
187 }
187 }
188
188
189 template <typename T>
189 template <typename T>
190 void testRead(AmdaResultParser::ValueType valueType)
190 void testRead(DataSeriesType valueType)
191 {
191 {
192 QFETCH(QString, inputFileName);
192 QFETCH(QString, inputFileName);
193 QFETCH(ExpectedResults<T>, expectedResults);
193 QFETCH(ExpectedResults<T>, expectedResults);
194
194
195 // Parses file
195 // Parses file
196 auto filePath = inputFilePath(inputFileName);
196 auto filePath = inputFilePath(inputFileName);
197 auto results = AmdaResultParser::readTxt(filePath, valueType);
197 auto results = AmdaResultParser::readTxt(filePath, valueType);
198
198
199 // ///////////////// //
199 // ///////////////// //
200 // Validates results //
200 // Validates results //
201 // ///////////////// //
201 // ///////////////// //
202 expectedResults.validate(results);
202 expectedResults.validate(results);
203 }
203 }
204
204
205 private slots:
205 private slots:
206 /// Input test data
206 /// Input test data
207 /// @sa testReadScalarTxt()
207 /// @sa testReadScalarTxt()
208 void testReadScalarTxt_data();
208 void testReadScalarTxt_data();
209
209
210 /// Tests parsing scalar series of a TXT file
210 /// Tests parsing scalar series of a TXT file
211 void testReadScalarTxt();
211 void testReadScalarTxt();
212
212
213 /// Input test data
213 /// Input test data
214 /// @sa testReadSpectrogramTxt()
214 /// @sa testReadSpectrogramTxt()
215 void testReadSpectrogramTxt_data();
215 void testReadSpectrogramTxt_data();
216
216
217 /// Tests parsing spectrogram series of a TXT file
217 /// Tests parsing spectrogram series of a TXT file
218 void testReadSpectrogramTxt();
218 void testReadSpectrogramTxt();
219
219
220 /// Input test data
220 /// Input test data
221 /// @sa testReadVectorTxt()
221 /// @sa testReadVectorTxt()
222 void testReadVectorTxt_data();
222 void testReadVectorTxt_data();
223
223
224 /// Tests parsing vector series of a TXT file
224 /// Tests parsing vector series of a TXT file
225 void testReadVectorTxt();
225 void testReadVectorTxt();
226 };
226 };
227
227
228 void TestAmdaResultParser::testReadScalarTxt_data()
228 void TestAmdaResultParser::testReadScalarTxt_data()
229 {
229 {
230 testReadDataStructure<ScalarSeries>();
230 testReadDataStructure<ScalarSeries>();
231
231
232 // ////////// //
232 // ////////// //
233 // Test cases //
233 // Test cases //
234 // ////////// //
234 // ////////// //
235
235
236 // Valid files
236 // Valid files
237 QTest::newRow("Valid file")
237 QTest::newRow("Valid file")
238 << QStringLiteral("ValidScalar1.txt")
238 << QStringLiteral("ValidScalar1.txt")
239 << ExpectedResults<ScalarSeries>{}
239 << ExpectedResults<ScalarSeries>{}
240 .setParsingOK(true)
240 .setParsingOK(true)
241 .setXAxisUnit(Unit{"nT", true})
241 .setXAxisUnit(Unit{"nT", true})
242 .setXAxisData({dateTime(2013, 9, 23, 9, 0, 30), dateTime(2013, 9, 23, 9, 1, 30),
242 .setXAxisData({dateTime(2013, 9, 23, 9, 0, 30), dateTime(2013, 9, 23, 9, 1, 30),
243 dateTime(2013, 9, 23, 9, 2, 30), dateTime(2013, 9, 23, 9, 3, 30),
243 dateTime(2013, 9, 23, 9, 2, 30), dateTime(2013, 9, 23, 9, 3, 30),
244 dateTime(2013, 9, 23, 9, 4, 30), dateTime(2013, 9, 23, 9, 5, 30),
244 dateTime(2013, 9, 23, 9, 4, 30), dateTime(2013, 9, 23, 9, 5, 30),
245 dateTime(2013, 9, 23, 9, 6, 30), dateTime(2013, 9, 23, 9, 7, 30),
245 dateTime(2013, 9, 23, 9, 6, 30), dateTime(2013, 9, 23, 9, 7, 30),
246 dateTime(2013, 9, 23, 9, 8, 30), dateTime(2013, 9, 23, 9, 9, 30)})
246 dateTime(2013, 9, 23, 9, 8, 30), dateTime(2013, 9, 23, 9, 9, 30)})
247 .setValuesData({-2.83950, -2.71850, -2.52150, -2.57633, -2.58050, -2.48325, -2.63025,
247 .setValuesData({-2.83950, -2.71850, -2.52150, -2.57633, -2.58050, -2.48325, -2.63025,
248 -2.55800, -2.43250, -2.42200});
248 -2.55800, -2.43250, -2.42200});
249
249
250 QTest::newRow("Valid file (value of first line is invalid but it is converted to NaN")
250 QTest::newRow("Valid file (value of first line is invalid but it is converted to NaN")
251 << QStringLiteral("WrongValue.txt")
251 << QStringLiteral("WrongValue.txt")
252 << ExpectedResults<ScalarSeries>{}
252 << ExpectedResults<ScalarSeries>{}
253 .setParsingOK(true)
253 .setParsingOK(true)
254 .setXAxisUnit(Unit{"nT", true})
254 .setXAxisUnit(Unit{"nT", true})
255 .setXAxisData({dateTime(2013, 9, 23, 9, 0, 30), dateTime(2013, 9, 23, 9, 1, 30),
255 .setXAxisData({dateTime(2013, 9, 23, 9, 0, 30), dateTime(2013, 9, 23, 9, 1, 30),
256 dateTime(2013, 9, 23, 9, 2, 30)})
256 dateTime(2013, 9, 23, 9, 2, 30)})
257 .setValuesData({std::numeric_limits<double>::quiet_NaN(), -2.71850, -2.52150});
257 .setValuesData({std::numeric_limits<double>::quiet_NaN(), -2.71850, -2.52150});
258
258
259 QTest::newRow("Valid file that contains NaN values")
259 QTest::newRow("Valid file that contains NaN values")
260 << QStringLiteral("NaNValue.txt")
260 << QStringLiteral("NaNValue.txt")
261 << ExpectedResults<ScalarSeries>{}
261 << ExpectedResults<ScalarSeries>{}
262 .setParsingOK(true)
262 .setParsingOK(true)
263 .setXAxisUnit(Unit{("nT"), true})
263 .setXAxisUnit(Unit{("nT"), true})
264 .setXAxisData({dateTime(2013, 9, 23, 9, 0, 30), dateTime(2013, 9, 23, 9, 1, 30),
264 .setXAxisData({dateTime(2013, 9, 23, 9, 0, 30), dateTime(2013, 9, 23, 9, 1, 30),
265 dateTime(2013, 9, 23, 9, 2, 30)})
265 dateTime(2013, 9, 23, 9, 2, 30)})
266 .setValuesData({std::numeric_limits<double>::quiet_NaN(), -2.71850, -2.52150});
266 .setValuesData({std::numeric_limits<double>::quiet_NaN(), -2.71850, -2.52150});
267
267
268 // Valid files but with some invalid lines (wrong unit, wrong values, etc.)
268 // Valid files but with some invalid lines (wrong unit, wrong values, etc.)
269 QTest::newRow("No unit file")
269 QTest::newRow("No unit file")
270 << QStringLiteral("NoUnit.txt")
270 << QStringLiteral("NoUnit.txt")
271 << ExpectedResults<ScalarSeries>{}.setParsingOK(true).setXAxisUnit(Unit{"", true});
271 << ExpectedResults<ScalarSeries>{}.setParsingOK(true).setXAxisUnit(Unit{"", true});
272
272
273 QTest::newRow("Wrong unit file")
273 QTest::newRow("Wrong unit file")
274 << QStringLiteral("WrongUnit.txt")
274 << QStringLiteral("WrongUnit.txt")
275 << ExpectedResults<ScalarSeries>{}
275 << ExpectedResults<ScalarSeries>{}
276 .setParsingOK(true)
276 .setParsingOK(true)
277 .setXAxisUnit(Unit{"", true})
277 .setXAxisUnit(Unit{"", true})
278 .setXAxisData({dateTime(2013, 9, 23, 9, 0, 30), dateTime(2013, 9, 23, 9, 1, 30),
278 .setXAxisData({dateTime(2013, 9, 23, 9, 0, 30), dateTime(2013, 9, 23, 9, 1, 30),
279 dateTime(2013, 9, 23, 9, 2, 30)})
279 dateTime(2013, 9, 23, 9, 2, 30)})
280 .setValuesData({-2.83950, -2.71850, -2.52150});
280 .setValuesData({-2.83950, -2.71850, -2.52150});
281
281
282 QTest::newRow("Wrong results file (date of first line is invalid")
282 QTest::newRow("Wrong results file (date of first line is invalid")
283 << QStringLiteral("WrongDate.txt")
283 << QStringLiteral("WrongDate.txt")
284 << ExpectedResults<ScalarSeries>{}
284 << ExpectedResults<ScalarSeries>{}
285 .setParsingOK(true)
285 .setParsingOK(true)
286 .setXAxisUnit(Unit{"nT", true})
286 .setXAxisUnit(Unit{"nT", true})
287 .setXAxisData({dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)})
287 .setXAxisData({dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)})
288 .setValuesData({-2.71850, -2.52150});
288 .setValuesData({-2.71850, -2.52150});
289
289
290 QTest::newRow("Wrong results file (too many values for first line")
290 QTest::newRow("Wrong results file (too many values for first line")
291 << QStringLiteral("TooManyValues.txt")
291 << QStringLiteral("TooManyValues.txt")
292 << ExpectedResults<ScalarSeries>{}
292 << ExpectedResults<ScalarSeries>{}
293 .setParsingOK(true)
293 .setParsingOK(true)
294 .setXAxisUnit(Unit{"nT", true})
294 .setXAxisUnit(Unit{"nT", true})
295 .setXAxisData({dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)})
295 .setXAxisData({dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)})
296 .setValuesData({-2.71850, -2.52150});
296 .setValuesData({-2.71850, -2.52150});
297
297
298 QTest::newRow("Wrong results file (x of first line is NaN")
298 QTest::newRow("Wrong results file (x of first line is NaN")
299 << QStringLiteral("NaNX.txt")
299 << QStringLiteral("NaNX.txt")
300 << ExpectedResults<ScalarSeries>{}
300 << ExpectedResults<ScalarSeries>{}
301 .setParsingOK(true)
301 .setParsingOK(true)
302 .setXAxisUnit(Unit{"nT", true})
302 .setXAxisUnit(Unit{"nT", true})
303 .setXAxisData({dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)})
303 .setXAxisData({dateTime(2013, 9, 23, 9, 1, 30), dateTime(2013, 9, 23, 9, 2, 30)})
304 .setValuesData({-2.71850, -2.52150});
304 .setValuesData({-2.71850, -2.52150});
305
305
306 QTest::newRow("Invalid file type (vector)")
306 QTest::newRow("Invalid file type (vector)")
307 << QStringLiteral("ValidVector1.txt")
307 << QStringLiteral("ValidVector1.txt")
308 << ExpectedResults<ScalarSeries>{}.setParsingOK(true).setXAxisUnit(Unit{"nT", true});
308 << ExpectedResults<ScalarSeries>{}.setParsingOK(true).setXAxisUnit(Unit{"nT", true});
309
309
310 // Invalid files
310 // Invalid files
311 QTest::newRow("Invalid file (unexisting file)")
311 QTest::newRow("Invalid file (unexisting file)")
312 << QStringLiteral("UnexistingFile.txt")
312 << QStringLiteral("UnexistingFile.txt")
313 << ExpectedResults<ScalarSeries>{}.setParsingOK(false);
313 << ExpectedResults<ScalarSeries>{}.setParsingOK(false);
314
314
315 QTest::newRow("Invalid file (file not found on server)")
315 QTest::newRow("Invalid file (file not found on server)")
316 << QStringLiteral("FileNotFound.txt")
316 << QStringLiteral("FileNotFound.txt")
317 << ExpectedResults<ScalarSeries>{}.setParsingOK(false);
317 << ExpectedResults<ScalarSeries>{}.setParsingOK(false);
318 }
318 }
319
319
320 void TestAmdaResultParser::testReadScalarTxt()
320 void TestAmdaResultParser::testReadScalarTxt()
321 {
321 {
322 testRead<ScalarSeries>(AmdaResultParser::ValueType::SCALAR);
322 testRead<ScalarSeries>(DataSeriesType::SCALAR);
323 }
323 }
324
324
325 void TestAmdaResultParser::testReadSpectrogramTxt_data()
325 void TestAmdaResultParser::testReadSpectrogramTxt_data()
326 {
326 {
327 testReadDataStructure<SpectrogramSeries>();
327 testReadDataStructure<SpectrogramSeries>();
328
328
329 // ////////// //
329 // ////////// //
330 // Test cases //
330 // Test cases //
331 // ////////// //
331 // ////////// //
332
332
333 // Valid files
333 // Valid files
334 QTest::newRow("Valid file (three bands)")
334 QTest::newRow("Valid file (three bands)")
335 << QStringLiteral("spectro/ValidSpectrogram1.txt")
335 << QStringLiteral("spectro/ValidSpectrogram1.txt")
336 << ExpectedResults<SpectrogramSeries>{}
336 << ExpectedResults<SpectrogramSeries>{}
337 .setParsingOK(true)
337 .setParsingOK(true)
338 .setXAxisUnit(Unit{"t", true})
338 .setXAxisUnit(Unit{"t", true})
339 .setXAxisData({dateTime(2012, 11, 6, 9, 14, 35), dateTime(2012, 11, 6, 9, 16, 10),
339 .setXAxisData({dateTime(2012, 11, 6, 9, 14, 35), dateTime(2012, 11, 6, 9, 16, 10),
340 dateTime(2012, 11, 6, 9, 17, 45), dateTime(2012, 11, 6, 9, 19, 20),
340 dateTime(2012, 11, 6, 9, 17, 45), dateTime(2012, 11, 6, 9, 19, 20),
341 dateTime(2012, 11, 6, 9, 20, 55)})
341 dateTime(2012, 11, 6, 9, 20, 55)})
342 .setYAxisEnabled(true)
342 .setYAxisEnabled(true)
343 .setYAxisUnit(Unit{"eV"})
343 .setYAxisUnit(Unit{"eV"})
344 .setYAxisData({5.75, 7.6, 10.05}) // middle of the intervals of each band
344 .setYAxisData({5.75, 7.6, 10.05}) // middle of the intervals of each band
345 .setValuesUnit(Unit{"eV/(cm^2-s-sr-eV)"})
345 .setValuesUnit(Unit{"eV/(cm^2-s-sr-eV)"})
346 .setValuesData(QVector<QVector<double> >{
346 .setValuesData(QVector<QVector<double> >{
347 {16313.780, 12631.465, 8223.368, 27595.301, 12820.613},
347 {16313.780, 12631.465, 8223.368, 27595.301, 12820.613},
348 {15405.838, 11957.925, 15026.249, 25617.533, 11179.109},
348 {15405.838, 11957.925, 15026.249, 25617.533, 11179.109},
349 {8946.475, 18133.158, 10875.621, 24051.619, 19283.221}});
349 {8946.475, 18133.158, 10875.621, 24051.619, 19283.221}});
350
350
351 auto fourBandsResult
351 auto fourBandsResult
352 = ExpectedResults<SpectrogramSeries>{}
352 = ExpectedResults<SpectrogramSeries>{}
353 .setParsingOK(true)
353 .setParsingOK(true)
354 .setXAxisUnit(Unit{"t", true})
354 .setXAxisUnit(Unit{"t", true})
355 .setXAxisData({dateTime(2012, 11, 6, 9, 14, 35), dateTime(2012, 11, 6, 9, 16, 10),
355 .setXAxisData({dateTime(2012, 11, 6, 9, 14, 35), dateTime(2012, 11, 6, 9, 16, 10),
356 dateTime(2012, 11, 6, 9, 17, 45), dateTime(2012, 11, 6, 9, 19, 20),
356 dateTime(2012, 11, 6, 9, 17, 45), dateTime(2012, 11, 6, 9, 19, 20),
357 dateTime(2012, 11, 6, 9, 20, 55)})
357 dateTime(2012, 11, 6, 9, 20, 55)})
358 .setYAxisEnabled(true)
358 .setYAxisEnabled(true)
359 .setYAxisUnit(Unit{"eV"})
359 .setYAxisUnit(Unit{"eV"})
360 .setYAxisData({5.75, 7.6, 10.05, 13.}) // middle of the intervals of each band
360 .setYAxisData({5.75, 7.6, 10.05, 13.}) // middle of the intervals of each band
361 .setValuesUnit(Unit{"eV/(cm^2-s-sr-eV)"})
361 .setValuesUnit(Unit{"eV/(cm^2-s-sr-eV)"})
362 .setValuesData(QVector<QVector<double> >{
362 .setValuesData(QVector<QVector<double> >{
363 {16313.780, 12631.465, 8223.368, 27595.301, 12820.613},
363 {16313.780, 12631.465, 8223.368, 27595.301, 12820.613},
364 {15405.838, 11957.925, 15026.249, 25617.533, 11179.109},
364 {15405.838, 11957.925, 15026.249, 25617.533, 11179.109},
365 {8946.475, 18133.158, 10875.621, 24051.619, 19283.221},
365 {8946.475, 18133.158, 10875.621, 24051.619, 19283.221},
366 {20907.664, 32076.725, 13008.381, 13142.759, 23226.998}});
366 {20907.664, 32076.725, 13008.381, 13142.759, 23226.998}});
367
367
368 QTest::newRow("Valid file (four bands)") << QStringLiteral("spectro/ValidSpectrogram2.txt")
368 QTest::newRow("Valid file (four bands)") << QStringLiteral("spectro/ValidSpectrogram2.txt")
369 << fourBandsResult;
369 << fourBandsResult;
370 QTest::newRow("Valid file (four unsorted bands)")
370 QTest::newRow("Valid file (four unsorted bands)")
371 << QStringLiteral("spectro/ValidSpectrogram3.txt")
371 << QStringLiteral("spectro/ValidSpectrogram3.txt")
372 << fourBandsResult; // Bands and values are sorted
372 << fourBandsResult; // Bands and values are sorted
373
373
374 auto nan = std::numeric_limits<double>::quiet_NaN();
374 auto nan = std::numeric_limits<double>::quiet_NaN();
375
375
376 auto nanValuesResult
376 auto nanValuesResult
377 = ExpectedResults<SpectrogramSeries>{}
377 = ExpectedResults<SpectrogramSeries>{}
378 .setParsingOK(true)
378 .setParsingOK(true)
379 .setXAxisUnit(Unit{"t", true})
379 .setXAxisUnit(Unit{"t", true})
380 .setXAxisData({dateTime(2012, 11, 6, 9, 14, 35), dateTime(2012, 11, 6, 9, 16, 10),
380 .setXAxisData({dateTime(2012, 11, 6, 9, 14, 35), dateTime(2012, 11, 6, 9, 16, 10),
381 dateTime(2012, 11, 6, 9, 17, 45), dateTime(2012, 11, 6, 9, 19, 20),
381 dateTime(2012, 11, 6, 9, 17, 45), dateTime(2012, 11, 6, 9, 19, 20),
382 dateTime(2012, 11, 6, 9, 20, 55)})
382 dateTime(2012, 11, 6, 9, 20, 55)})
383 .setYAxisEnabled(true)
383 .setYAxisEnabled(true)
384 .setYAxisUnit(Unit{"eV"})
384 .setYAxisUnit(Unit{"eV"})
385 .setYAxisData({5.75, 7.6, 10.05, 13.}) // middle of the intervals of each band
385 .setYAxisData({5.75, 7.6, 10.05, 13.}) // middle of the intervals of each band
386 .setValuesUnit(Unit{"eV/(cm^2-s-sr-eV)"})
386 .setValuesUnit(Unit{"eV/(cm^2-s-sr-eV)"})
387 .setValuesData(
387 .setValuesData(
388 QVector<QVector<double> >{{nan, 12631.465, 8223.368, 27595.301, 12820.613},
388 QVector<QVector<double> >{{nan, 12631.465, 8223.368, 27595.301, 12820.613},
389 {15405.838, nan, nan, 25617.533, 11179.109},
389 {15405.838, nan, nan, 25617.533, 11179.109},
390 {8946.475, 18133.158, 10875.621, 24051.619, 19283.221},
390 {8946.475, 18133.158, 10875.621, 24051.619, 19283.221},
391 {nan, nan, nan, nan, nan}});
391 {nan, nan, nan, nan, nan}});
392
392
393 QTest::newRow("Valid file (containing NaN values)")
393 QTest::newRow("Valid file (containing NaN values)")
394 << QStringLiteral("spectro/ValidSpectrogramNaNValues.txt") << nanValuesResult;
394 << QStringLiteral("spectro/ValidSpectrogramNaNValues.txt") << nanValuesResult;
395 QTest::newRow("Valid file (containing fill values)")
395 QTest::newRow("Valid file (containing fill values)")
396 << QStringLiteral("spectro/ValidSpectrogramFillValues.txt")
396 << QStringLiteral("spectro/ValidSpectrogramFillValues.txt")
397 << nanValuesResult; // Fill values are replaced by NaN values in the data series
397 << nanValuesResult; // Fill values are replaced by NaN values in the data series
398
398
399 QTest::newRow("Valid file (containing data holes, resolution = 3 minutes)")
399 QTest::newRow("Valid file (containing data holes, resolution = 3 minutes)")
400 << QStringLiteral("spectro/ValidSpectrogramDataHoles.txt")
400 << QStringLiteral("spectro/ValidSpectrogramDataHoles.txt")
401 << ExpectedResults<SpectrogramSeries>{}
401 << ExpectedResults<SpectrogramSeries>{}
402 .setParsingOK(true)
402 .setParsingOK(true)
403 .setXAxisUnit(Unit{"t", true})
403 .setXAxisUnit(Unit{"t", true})
404 .setXAxisData({dateTime(2011, 12, 10, 12, 10, 54), //
404 .setXAxisData({dateTime(2011, 12, 10, 12, 10, 54), //
405 dateTime(2011, 12, 10, 12, 13, 54), // Data hole
405 dateTime(2011, 12, 10, 12, 13, 54), // Data hole
406 dateTime(2011, 12, 10, 12, 16, 54), // Data hole
406 dateTime(2011, 12, 10, 12, 16, 54), // Data hole
407 dateTime(2011, 12, 10, 12, 17, 23), //
407 dateTime(2011, 12, 10, 12, 17, 23), //
408 dateTime(2011, 12, 10, 12, 20, 23), // Data hole
408 dateTime(2011, 12, 10, 12, 20, 23), // Data hole
409 dateTime(2011, 12, 10, 12, 23, 23), // Data hole
409 dateTime(2011, 12, 10, 12, 23, 23), // Data hole
410 dateTime(2011, 12, 10, 12, 23, 51), //
410 dateTime(2011, 12, 10, 12, 23, 51), //
411 dateTime(2011, 12, 10, 12, 26, 51), // Data hole
411 dateTime(2011, 12, 10, 12, 26, 51), // Data hole
412 dateTime(2011, 12, 10, 12, 29, 51), // Data hole
412 dateTime(2011, 12, 10, 12, 29, 51), // Data hole
413 dateTime(2011, 12, 10, 12, 30, 19), //
413 dateTime(2011, 12, 10, 12, 30, 19), //
414 dateTime(2011, 12, 10, 12, 33, 19), // Data hole
414 dateTime(2011, 12, 10, 12, 33, 19), // Data hole
415 dateTime(2011, 12, 10, 12, 35, 04), //
415 dateTime(2011, 12, 10, 12, 35, 04), //
416 dateTime(2011, 12, 10, 12, 36, 41), //
416 dateTime(2011, 12, 10, 12, 36, 41), //
417 dateTime(2011, 12, 10, 12, 38, 18), //
417 dateTime(2011, 12, 10, 12, 38, 18), //
418 dateTime(2011, 12, 10, 12, 39, 55)})
418 dateTime(2011, 12, 10, 12, 39, 55)})
419 .setYAxisEnabled(true)
419 .setYAxisEnabled(true)
420 .setYAxisUnit(Unit{"eV"})
420 .setYAxisUnit(Unit{"eV"})
421 .setYAxisData({16485.85, 20996.1}) // middle of the intervals of each band
421 .setYAxisData({16485.85, 20996.1}) // middle of the intervals of each band
422 .setValuesUnit(Unit{"eV/(cm^2-s-sr-eV)"})
422 .setValuesUnit(Unit{"eV/(cm^2-s-sr-eV)"})
423 .setValuesData(QVector<QVector<double> >{{2577578.000, //
423 .setValuesData(QVector<QVector<double> >{{2577578.000, //
424 nan, // Data hole
424 nan, // Data hole
425 nan, // Data hole
425 nan, // Data hole
426 2314121.500, //
426 2314121.500, //
427 nan, // Data hole
427 nan, // Data hole
428 nan, // Data hole
428 nan, // Data hole
429 2063608.750, //
429 2063608.750, //
430 nan, // Data hole
430 nan, // Data hole
431 nan, // Data hole
431 nan, // Data hole
432 2234525.500, //
432 2234525.500, //
433 nan, // Data hole
433 nan, // Data hole
434 1670215.250, //
434 1670215.250, //
435 1689243.250, //
435 1689243.250, //
436 1654617.125, //
436 1654617.125, //
437 1504983.750},
437 1504983.750},
438 {2336016.000, //
438 {2336016.000, //
439 nan, // Data hole
439 nan, // Data hole
440 nan, // Data hole
440 nan, // Data hole
441 1712093.125, //
441 1712093.125, //
442 nan, // Data hole
442 nan, // Data hole
443 nan, // Data hole
443 nan, // Data hole
444 1614491.625, //
444 1614491.625, //
445 nan, // Data hole
445 nan, // Data hole
446 nan, // Data hole
446 nan, // Data hole
447 1764516.500, //
447 1764516.500, //
448 nan, // Data hole
448 nan, // Data hole
449 1688078.500, //
449 1688078.500, //
450 1743183.500, //
450 1743183.500, //
451 1733603.250, //
451 1733603.250, //
452 1708356.500}});
452 1708356.500}});
453
453
454 QTest::newRow(
454 QTest::newRow(
455 "Valid file (containing data holes at the beginning and the end, resolution = 4 minutes)")
455 "Valid file (containing data holes at the beginning and the end, resolution = 4 minutes)")
456 << QStringLiteral("spectro/ValidSpectrogramDataHoles2.txt")
456 << QStringLiteral("spectro/ValidSpectrogramDataHoles2.txt")
457 << ExpectedResults<SpectrogramSeries>{}
457 << ExpectedResults<SpectrogramSeries>{}
458 .setParsingOK(true)
458 .setParsingOK(true)
459 .setXAxisUnit(Unit{"t", true})
459 .setXAxisUnit(Unit{"t", true})
460 .setXAxisData({
460 .setXAxisData({
461 dateTime(2011, 12, 10, 12, 2, 54), // Data hole
461 dateTime(2011, 12, 10, 12, 2, 54), // Data hole
462 dateTime(2011, 12, 10, 12, 6, 54), // Data hole
462 dateTime(2011, 12, 10, 12, 6, 54), // Data hole
463 dateTime(2011, 12, 10, 12, 10, 54), //
463 dateTime(2011, 12, 10, 12, 10, 54), //
464 dateTime(2011, 12, 10, 12, 14, 54), // Data hole
464 dateTime(2011, 12, 10, 12, 14, 54), // Data hole
465 dateTime(2011, 12, 10, 12, 17, 23), //
465 dateTime(2011, 12, 10, 12, 17, 23), //
466 dateTime(2011, 12, 10, 12, 21, 23), // Data hole
466 dateTime(2011, 12, 10, 12, 21, 23), // Data hole
467 dateTime(2011, 12, 10, 12, 23, 51), //
467 dateTime(2011, 12, 10, 12, 23, 51), //
468 dateTime(2011, 12, 10, 12, 27, 51), // Data hole
468 dateTime(2011, 12, 10, 12, 27, 51), // Data hole
469 dateTime(2011, 12, 10, 12, 30, 19), //
469 dateTime(2011, 12, 10, 12, 30, 19), //
470 dateTime(2011, 12, 10, 12, 34, 19), // Data hole
470 dateTime(2011, 12, 10, 12, 34, 19), // Data hole
471 dateTime(2011, 12, 10, 12, 35, 04), //
471 dateTime(2011, 12, 10, 12, 35, 04), //
472 dateTime(2011, 12, 10, 12, 36, 41), //
472 dateTime(2011, 12, 10, 12, 36, 41), //
473 dateTime(2011, 12, 10, 12, 38, 18), //
473 dateTime(2011, 12, 10, 12, 38, 18), //
474 dateTime(2011, 12, 10, 12, 39, 55),
474 dateTime(2011, 12, 10, 12, 39, 55),
475 dateTime(2011, 12, 10, 12, 43, 55), // Data hole
475 dateTime(2011, 12, 10, 12, 43, 55), // Data hole
476 dateTime(2011, 12, 10, 12, 47, 55), // Data hole
476 dateTime(2011, 12, 10, 12, 47, 55), // Data hole
477 dateTime(2011, 12, 10, 12, 51, 55), // Data hole
477 dateTime(2011, 12, 10, 12, 51, 55), // Data hole
478 dateTime(2011, 12, 10, 12, 55, 55), // Data hole
478 dateTime(2011, 12, 10, 12, 55, 55), // Data hole
479 dateTime(2011, 12, 10, 12, 59, 55) // Data hole
479 dateTime(2011, 12, 10, 12, 59, 55) // Data hole
480 })
480 })
481 .setYAxisEnabled(true)
481 .setYAxisEnabled(true)
482 .setYAxisUnit(Unit{"eV"})
482 .setYAxisUnit(Unit{"eV"})
483 .setYAxisData({16485.85, 20996.1}) // middle of the intervals of each band
483 .setYAxisData({16485.85, 20996.1}) // middle of the intervals of each band
484 .setValuesUnit(Unit{"eV/(cm^2-s-sr-eV)"})
484 .setValuesUnit(Unit{"eV/(cm^2-s-sr-eV)"})
485 .setValuesData(QVector<QVector<double> >{{
485 .setValuesData(QVector<QVector<double> >{{
486 nan, // Data hole
486 nan, // Data hole
487 nan, // Data hole
487 nan, // Data hole
488 2577578.000, //
488 2577578.000, //
489 nan, // Data hole
489 nan, // Data hole
490 2314121.500, //
490 2314121.500, //
491 nan, // Data hole
491 nan, // Data hole
492 2063608.750, //
492 2063608.750, //
493 nan, // Data hole
493 nan, // Data hole
494 2234525.500, //
494 2234525.500, //
495 nan, // Data hole
495 nan, // Data hole
496 1670215.250, //
496 1670215.250, //
497 1689243.250, //
497 1689243.250, //
498 1654617.125, //
498 1654617.125, //
499 1504983.750, //
499 1504983.750, //
500 nan, // Data hole
500 nan, // Data hole
501 nan, // Data hole
501 nan, // Data hole
502 nan, // Data hole
502 nan, // Data hole
503 nan, // Data hole
503 nan, // Data hole
504 nan // Data hole
504 nan // Data hole
505 },
505 },
506 {
506 {
507 nan, // Data hole
507 nan, // Data hole
508 nan, // Data hole
508 nan, // Data hole
509 2336016.000, //
509 2336016.000, //
510 nan, // Data hole
510 nan, // Data hole
511 1712093.125, //
511 1712093.125, //
512 nan, // Data hole
512 nan, // Data hole
513 1614491.625, //
513 1614491.625, //
514 nan, // Data hole
514 nan, // Data hole
515 1764516.500, //
515 1764516.500, //
516 nan, // Data hole
516 nan, // Data hole
517 1688078.500, //
517 1688078.500, //
518 1743183.500, //
518 1743183.500, //
519 1733603.250, //
519 1733603.250, //
520 1708356.500, //
520 1708356.500, //
521 nan, // Data hole
521 nan, // Data hole
522 nan, // Data hole
522 nan, // Data hole
523 nan, // Data hole
523 nan, // Data hole
524 nan, // Data hole
524 nan, // Data hole
525 nan // Data hole
525 nan // Data hole
526 }});
526 }});
527
527
528 // Invalid files
528 // Invalid files
529 QTest::newRow("Invalid file (inconsistent bands)")
529 QTest::newRow("Invalid file (inconsistent bands)")
530 << QStringLiteral("spectro/InvalidSpectrogramWrongBands.txt")
530 << QStringLiteral("spectro/InvalidSpectrogramWrongBands.txt")
531 << ExpectedResults<SpectrogramSeries>{}.setParsingOK(false);
531 << ExpectedResults<SpectrogramSeries>{}.setParsingOK(false);
532 }
532 }
533
533
534 void TestAmdaResultParser::testReadSpectrogramTxt()
534 void TestAmdaResultParser::testReadSpectrogramTxt()
535 {
535 {
536 testRead<SpectrogramSeries>(AmdaResultParser::ValueType::SPECTROGRAM);
536 testRead<SpectrogramSeries>(DataSeriesType::SPECTROGRAM);
537 }
537 }
538
538
539 void TestAmdaResultParser::testReadVectorTxt_data()
539 void TestAmdaResultParser::testReadVectorTxt_data()
540 {
540 {
541 testReadDataStructure<VectorSeries>();
541 testReadDataStructure<VectorSeries>();
542
542
543 // ////////// //
543 // ////////// //
544 // Test cases //
544 // Test cases //
545 // ////////// //
545 // ////////// //
546
546
547 // Valid files
547 // Valid files
548 QTest::newRow("Valid file")
548 QTest::newRow("Valid file")
549 << QStringLiteral("ValidVector1.txt")
549 << QStringLiteral("ValidVector1.txt")
550 << ExpectedResults<VectorSeries>{}
550 << ExpectedResults<VectorSeries>{}
551 .setParsingOK(true)
551 .setParsingOK(true)
552 .setXAxisUnit(Unit{"nT", true})
552 .setXAxisUnit(Unit{"nT", true})
553 .setXAxisData({dateTime(2013, 7, 2, 9, 13, 50), dateTime(2013, 7, 2, 9, 14, 6),
553 .setXAxisData({dateTime(2013, 7, 2, 9, 13, 50), dateTime(2013, 7, 2, 9, 14, 6),
554 dateTime(2013, 7, 2, 9, 14, 22), dateTime(2013, 7, 2, 9, 14, 38),
554 dateTime(2013, 7, 2, 9, 14, 22), dateTime(2013, 7, 2, 9, 14, 38),
555 dateTime(2013, 7, 2, 9, 14, 54), dateTime(2013, 7, 2, 9, 15, 10),
555 dateTime(2013, 7, 2, 9, 14, 54), dateTime(2013, 7, 2, 9, 15, 10),
556 dateTime(2013, 7, 2, 9, 15, 26), dateTime(2013, 7, 2, 9, 15, 42),
556 dateTime(2013, 7, 2, 9, 15, 26), dateTime(2013, 7, 2, 9, 15, 42),
557 dateTime(2013, 7, 2, 9, 15, 58), dateTime(2013, 7, 2, 9, 16, 14)})
557 dateTime(2013, 7, 2, 9, 15, 58), dateTime(2013, 7, 2, 9, 16, 14)})
558 .setValuesData(
558 .setValuesData(
559 {{-0.332, -1.011, -1.457, -1.293, -1.217, -1.443, -1.278, -1.202, -1.22, -1.259},
559 {{-0.332, -1.011, -1.457, -1.293, -1.217, -1.443, -1.278, -1.202, -1.22, -1.259},
560 {3.206, 2.999, 2.785, 2.736, 2.612, 2.564, 2.892, 2.862, 2.859, 2.764},
560 {3.206, 2.999, 2.785, 2.736, 2.612, 2.564, 2.892, 2.862, 2.859, 2.764},
561 {0.058, 0.496, 1.018, 1.485, 1.662, 1.505, 1.168, 1.244, 1.15, 1.358}});
561 {0.058, 0.496, 1.018, 1.485, 1.662, 1.505, 1.168, 1.244, 1.15, 1.358}});
562
562
563 // Valid files but with some invalid lines (wrong unit, wrong values, etc.)
563 // Valid files but with some invalid lines (wrong unit, wrong values, etc.)
564 QTest::newRow("Invalid file type (scalar)")
564 QTest::newRow("Invalid file type (scalar)")
565 << QStringLiteral("ValidScalar1.txt")
565 << QStringLiteral("ValidScalar1.txt")
566 << ExpectedResults<VectorSeries>{}
566 << ExpectedResults<VectorSeries>{}
567 .setParsingOK(true)
567 .setParsingOK(true)
568 .setXAxisUnit(Unit{"nT", true})
568 .setXAxisUnit(Unit{"nT", true})
569 .setXAxisData({})
569 .setXAxisData({})
570 .setValuesData(QVector<QVector<double> >{{}, {}, {}});
570 .setValuesData(QVector<QVector<double> >{{}, {}, {}});
571 }
571 }
572
572
573 void TestAmdaResultParser::testReadVectorTxt()
573 void TestAmdaResultParser::testReadVectorTxt()
574 {
574 {
575 testRead<VectorSeries>(AmdaResultParser::ValueType::VECTOR);
575 testRead<VectorSeries>(DataSeriesType::VECTOR);
576 }
576 }
577
577
578 QTEST_MAIN(TestAmdaResultParser)
578 QTEST_MAIN(TestAmdaResultParser)
579 #include "TestAmdaResultParser.moc"
579 #include "TestAmdaResultParser.moc"
General Comments 0
You need to be logged in to leave comments. Login now